转载来源:嵌入式系统之初学者点滴 (百度空间)

在这篇文章()中,实现了Linux环境下的串口读写操作,程序也运行成功了。但是再进一步测试时发现,如果开机之后直接如上文中所说,分别运行读程序和写程序,再用导体同时触碰串口的2、3针的话。此时将显示写入串口成功,但是读串口数据失败。

这个奇怪的问题当时之所以没有被发现出来,是因为在这之前,曾经打开过一次minicom。后来实验表明,如果打开过一次minicom,哪怕打开又关闭的话,再次运行上文中的串口读写程序就没有问题了。但是重启机器之后,错误又出现了:只要不运行minicom一下,程序读取总是会有问题。

为了查找错误究竟是在什么地方,分别在刚刚开机、运行过一次自己编写的串口程序、运行过一次minicom这三种情况下使用命令stty -a < /dev/ttyS0查看了COM1的相关参数。然后主要根据自己的读取程序和minicom对串口的设置差异进行了相应的修改,现将读取程序的全部贴在下面。经过修改后,该程序运行之后的/dev/ttyS0的环境参数与直接运行minicom后/dev/ttyS0的环境参数完全相同。

注:程序中红色部分是与 文中的程序相比加入的主要内容。

/*********************************** read_serial ************************************/

#include

#include

#include

#include

#include

#include

#include

#define FALSE -1

#define TRUE   0

void set_speed(int, int);

int set_Parity(int,int,int,int);

int main()

{

int fd,flag,rd_num=0;

struct termios term;

struct timeval timeout;

speed_t baud_rate_i,baud_rate_o;

char recv_buf[20];

fd=open("/dev/ttyS0",O_RDWR|O_NONBLOCK);

if(fd==-1)

printf("can not open the COM1!\n");

else

printf("open COM1 ok!\n");

flag=tcgetattr(fd,&term);

baud_rate_i=cfgetispeed(&term);

baud_rate_o=cfgetospeed(&term);

printf("设置之前的输入波特率是%d,输出波特率是%d\n",baud_rate_i,baud_rate_o);

set_speed(fd,1200);

flag=tcgetattr(fd,&term);

baud_rate_i=cfgetispeed(&term);

baud_rate_o=cfgetospeed(&term);

printf("设置之后的输入波特率是%d,输出波特率是%d\n",baud_rate_i,baud_rate_o);

if (set_Parity(fd,8,1,'N')== FALSE)

{

printf("Set Parity Error\n");

exit(1);

}

int transfer_started=0;

int i=0;

while(1)

{

rd_num=read(fd,recv_buf,sizeof(recv_buf));

timeout.tv_sec=0;

timeout.tv_usec=200000;

if(rd_num>0)

{

printf("%d(间隔%4.3fs):we can read \"%s\" from the COM1,total:%d characters.\n",++i,timeout.tv_sec+timeout.tv_usec*0.000001,recv_buf,rd_num);

transfer_started=1;

}

else

printf("%d(间隔%4.3fs):read fail! rd_num=%d。本次数据传输%s\n",++i,timeout.tv_sec+timeout.tv_usec*0.000001,rd_num,transfer_started==1?"已经结束":"尚未开始");

//        sleep(1);   粗糙定时

select(0,NULL,NULL,NULL,&timeout);/*精确定时*/

}

}

int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300};

int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300};

void set_speed(int fd, int speed){

unsigned int   i;

int   status;

struct termios   Opt;

tcgetattr(fd, &Opt);

for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {

if (speed == name_arr[i]) {

tcflush(fd, TCIOFLUSH);

cfsetispeed(&Opt, speed_arr[i]);

cfsetospeed(&Opt, speed_arr[i]);

status = tcsetattr(fd, TCSANOW, &Opt);

if (status != 0) {

perror("tcsetattr fd1");

return;

}

tcflush(fd,TCIOFLUSH);

}

}

}

/**

*@brief   设置串口数据位,停止位和效验位

*@param fd     类型 int 打开的串口文件句柄*

*@param databits 类型 int 数据位   取值 为 7 或者8*

*@param stopbits 类型 int 停止位   取值为 1 或者2*

*@param parity 类型 int 效验类型 取值为N,E,O,,S

*/

int set_Parity(int fd,int databits,int stopbits,int parity)

{

struct termios options;

if ( tcgetattr( fd,&options) != 0)

{

perror("SetupSerial 1");

return(FALSE);

}

options.c_cflag &= ~CSIZE;

switch (databits) /*设置数据位数*/

{

case 7:

options.c_cflag |= CS7;

break;

case 8:

options.c_cflag |= CS8;

break;

default:

fprintf(stderr,"Unsupported data size\n");

return (FALSE);

}

switch (parity)

{

case 'n':

case 'N':

//        options.c_cflag &= ~PARENB;   /* Clear parity enable */

//        options.c_iflag &= ~INPCK;     /* Enable parity checking */

options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/

options.c_oflag &= ~OPOST;   /*Output*/

break;

case 'o':

case 'O':

options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/

options.c_iflag |= INPCK;             /* Disnable parity checking */

break;

case 'e':

case 'E':

options.c_cflag |= PARENB;     /* Enable parity */

options.c_cflag &= ~PARODD;   /* 转换为偶效验*/

options.c_iflag |= INPCK;       /* Disnable parity checking */

break;

case 'S':

case 's': /*as no parity*/

options.c_cflag &= ~PARENB;

options.c_cflag &= ~CSTOPB;

break;

default:

fprintf(stderr,"Unsupported parity\n");

return (FALSE);

}

/* 设置停止位*/

switch (stopbits)

{

case 1:

options.c_cflag &= ~CSTOPB;

break;

case 2:

options.c_cflag |= CSTOPB;

break;

default:

fprintf(stderr,"Unsupported stop bits\n");

return (FALSE);

}

/* Set input parity option */

if ((parity != 'n')&&(parity != 'N'))

options.c_iflag |= INPCK;

options.c_cc[VTIME] = 5; // 0.5 seconds

options.c_cc[VMIN] = 1;

options.c_cflag &= ~HUPCL;

options.c_iflag &= ~INPCK;

options.c_iflag |= IGNBRK;

options.c_iflag &= ~ICRNL;

options.c_iflag &= ~IXON;

options.c_lflag &= ~IEXTEN;

options.c_lflag &= ~ECHOK;

options.c_lflag &= ~ECHOCTL;

options.c_lflag &= ~ECHOKE;

options.c_oflag &= ~ONLCR;

tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */

if (tcsetattr(fd,TCSANOW,&options) != 0)

{

perror("SetupSerial 3");

return (FALSE);

}

return (TRUE);

}

这样的话,读程序就可以直接接收到串口过来的数据,而不需要先运行一次minicom了。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐