串口读取.docx
- 文档编号:1134961
- 上传时间:2023-04-30
- 格式:DOCX
- 页数:31
- 大小:20.83KB
串口读取.docx
《串口读取.docx》由会员分享,可在线阅读,更多相关《串口读取.docx(31页珍藏版)》请在冰点文库上搜索。
串口读取
在Linux下串口信息的读取有了一点心得体会。
1.打开串口
与其他的关于设备编程的方法一样,在Linux下,操作、控制串口也是通过操作起设备文件进行的。
在Linux下,串口的设备文件是/dev/ttyS0或/dev/ttyS1等。
因此要读写串口,我们首先要打开串口:
char*dev="/dev/ttyS0";//串口1
intfd=open(dev,O_RDWR);
//|O_NOCTTY|O_NDELAY
if(-1==fd)
{
perror("Can'tOpenSerialPort");
return-1;
}
else
returnfd;
2.设置串口速度
打开串口成功后,我们就可以对其进行读写了。
首先要设置串口的波特率:
intspeed_arr[]={B38400,B19200,B9600,B4800,B2400,B1200,B300,
B38400,B19200,B9600,B4800,B2400,B1200,B300,};
intname_arr[]={38400,19200,9600,4800,2400,1200,300,38400,
19200,9600,4800,2400,1200,300,};
voidset_speed(intfd,intspeed){
inti;
intstatus;
structtermiosOpt;
tcgetattr(fd,&Opt);
for(i=0;i if(speed==name_arr){ tcflush(fd,TCIOFLUSH); cfsetispeed(&Opt,speed_arr); cfsetospeed(&Opt,speed_arr); status=tcsetattr(fd,TCSANOW,&Opt); if(status! =0){ perror("tcsetattrfd"); return; } tcflush(fd,TCIOFLUSH); } } } 3.设置串口信息 这主要包括: 数据位、停止位、奇偶校验位这些主要的信息。 /** *@brief设置串口数据位,停止位和效验位 *@paramfd类型int打开的串口文件句柄 *@paramdatabits类型int数据位取值为7或者8 *@paramstopbits类型int停止位取值为1或者2 *@paramparity类型int效验类型取值为N,E,O,,S */ intset_Parity(intfd,intdatabits,intstopbits,intparity) { structtermiosoptions; if(tcgetattr(fd,&options)! =0){ perror("SetupSerial1"); return(FALSE); } options.c_cflag&=~CSIZE; options.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);/*Input*/ options.c_oflag&=~OPOST;/*Output*/ switch(databits)/*设置数据位数*/ { case7: options.c_cflag|=CS7; break; case8: options.c_cflag|=CS8; break; default: fprintf(stderr,"Unsupporteddatasize\n");return(FALSE); } switch(parity) { case'n': case'N': options.c_cflag&=~PARENB;/*Clearparityenable*/ options.c_iflag&=~INPCK;/*Enableparitychecking*/ break; case'o': case'O': options.c_cflag|=(PARODD|PARENB);/*设置为奇效验*/ options.c_iflag|=INPCK;/*Disnableparitychecking*/ break; case'e': case'E': options.c_cflag|=PARENB;/*Enableparity*/ options.c_cflag&=~PARODD;/*转换为偶效验*/ options.c_iflag|=INPCK;/*Disnableparitychecking*/ break; case'S': case's': /*asnoparity*/ options.c_cflag&=~PARENB; options.c_cflag&=~CSTOPB;break; default: fprintf(stderr,"Unsupportedparity\n"); return(FALSE); } /*设置停止位*/ switch(stopbits) { case1: options.c_cflag&=~CSTOPB; break; case2: options.c_cflag|=CSTOPB; break; default: fprintf(stderr,"Unsupportedstopbits\n"); return(FALSE); } /*Setinputparityoption*/ if(parity! ='n') options.c_iflag|=INPCK; tcflush(fd,TCIFLUSH); options.c_cc[VTIME]=0;/*设置超时0seconds*/ options.c_cc[VMIN]=13;/*definetheminimumbytesdatatobereaded*/ if(tcsetattr(fd,TCSANOW,&options)! =0) { perror("SetupSerial3"); return(FALSE); } return(TRUE); } 在上述代码中,有两句话特别重要: options.c_cc[VTIME]=0;/*设置超时0seconds*/ options.c_cc[VMIN]=13;/*definetheminimumbytesdatatobereaded*/ 这两句话决定了对串口读取的函数read()的一些功能。 我将着重介绍一下他们对read()函数的影响。 对串口操作的结构体是 Struct{ tcflag_tc_iflag;/*输入模式标记*/ tcflag_tc_oflag;/*输出模式标记*/ tcflag_tc_cflag;/*控制模式标记*/ tcflag_tc_lflag;/*本地模式标记*/ cc_tc_line;/*线路规程*/ cc_tc_cc[NCCS];/*控制符号*/ }; 其中cc_tc_line只有在一些特殊的系统程序(比如,设置通过tty设备来通信的网络协议)中才会用。 在数组c_cc中有两个下标(VTIME和VMIN)对应的元素不是控制符,并且只是在原始模式下有效。 只有在原始模式下,他们决定了read()函数在什么时候返回。 在标准模式下,除非设置了O_NONBLOCK选项,否则只有当遇到文件结束符或各行的字符都已经编辑完毕后才返回。 控制符VTIME和VMIN之间有着复杂的关系。 VTIME定义要求等待的零到几百毫秒的时间量(通常是一个8位的unsignedchar变量,取值不能大于cc_t)。 VMIN定义了要求等待的最小字节数(不是要求读的字节数——read()的第三个参数才是指定要求读的最大字节数),这个字节数可能是0. l如果VTIME取0,VMIN定义了要求等待读取的最小字节数。 函数read()只有在读取了VMIN个字节的数据或者收到一个信号的时候才返回。 l如果VMIN取0,VTIME定义了即使没有数据可以读取,read()函数返回前也要等待几百毫秒的时间量。 这时,read()函数不需要像其通常情况那样要遇到一个文件结束标志才返回0. l如果VTIME和VMIN都不取0,VTIME定义的是当接收到第一个字节的数据后开始计算等待的时间量。 如果当调用read函数时可以得到数据,计时器马上开始计时。 如果当调用read函数时还没有任何数据可读,则等接收到第一个字节的数据后,计时器开始计时。 函数read可能会在读取到VMIN个字节的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。 不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。 l如果VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回。 同时,返回值0表示read函数不需要等待文件结束标志就返回了。 这就是这两个变量对read函数的影响。 我使用的读卡器每次传送的数据是13个字节,一开始,我把它们设置成 options.c_cc[VTIME]=150 options.c_cc[VMIN]=0; 结果,每次读取的信息只有8个字节,剩下的5个字节要等到下一次打卡时才能收到。 就是由于这个原因造成的。 根据上面规则的第一条,我把VTIME取0,VMIN=13,也就是正好等于一次需要接收的字节数。 这样就实现了一次读取13个字节值。 同时,得出这样的结论,如果读卡器送出的数据为n个字节,那么就把VMIN=n,这样一次读取的信息正好为读卡器送出的信息,并且读取的时候不需要进行循环读取。 4.读取数据 有了上面的函数后,我设置了串口的基本信息,根据我们自己的实际情况,设置了相应的参数,就可以读取数据了。 voidgetcardinfo(char*buff){ intfd; intnread,count=0; chartempbuff[13]; char*dev="/dev/ttyS0";//串口1 fd=OpenDev(dev); set_speed(fd,9600); if(set_Parity(fd,8,1,'N')==FALSE){ printf("SetParityError\n"); //return-1; } while (1)//循环读取数据 { count=0; //sleep(5000); while (1) { if((nread=read(fd,tempbuff,13))>0) { //printf("\nLen%d\n",nread); memcpy(&buff[count],tempbuff,nread); count+=nread; } if(count==13) { buff[count+1]='\0'; //printf("\n%s",buff); break; } } //break; } //returnbuff; close(fd); pthread_exit(NULL); //close(fd); //exit(0); } 这是我原来的程序,其实把VMIN设置以后,可以改成: voidgetcardinfo(char*buff){ intfd; intnread,count=0; chartempbuff[13]; char*dev="/dev/ttyS0";//串口1 fd=OpenDev(dev); set_speed(fd,9600); if(set_Parity(fd,8,1,'N')==FALSE){ printf("SetParityError\n"); //return-1; } nread=read(fd,buff,13) close(fd); } 5.程序完整代码: #include/*标准输入输出定义*/ #include/*标准函数库定义*/ #include/*Unix标准函数定义*/ #include #include #include/*文件控制定义*/ #include/*PPSIX终端控制定义*/ #include/*错误号定义*/ #defineFALSE-1 #defineTRUE0 /** *@brief设置串口通信速率 *@paramfd类型int打开串口的文件句柄 *@paramspeed类型int串口速度 *@returnvoid */ intspeed_arr[]={B38400,B19200,B9600,B4800,B2400,B1200,B300, B38400,B19200,B9600,B4800,B2400,B1200,B300,}; intname_arr[]={38400,19200,9600,4800,2400,1200,300,38400, 19200,9600,4800,2400,1200,300,}; voidset_speed(intfd,intspeed){ inti; intstatus; structtermiosOpt; tcgetattr(fd,&Opt); for(i=0;i if(speed==name_arr){ tcflush(fd,TCIOFLUSH); cfsetispeed(&Opt,speed_arr); cfsetospeed(&Opt,speed_arr); status=tcsetattr(fd,TCSANOW,&Opt); if(status! =0){ perror("tcsetattrfd"); return; } tcflush(fd,TCIOFLUSH); } } } /** *@brief设置串口数据位,停止位和效验位 *@paramfd类型int打开的串口文件句柄 *@paramdatabits类型int数据位取值为7或者8 *@paramstopbits类型int停止位取值为1或者2 *@paramparity类型int效验类型取值为N,E,O,,S */ intset_Parity(intfd,intdatabits,intstopbits,intparity) { structtermiosoptions; if(tcgetattr(fd,&options)! =0){ perror("SetupSerial1"); return(FALSE); } options.c_cflag&=~CSIZE; options.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);/*Input*/ options.c_oflag&=~OPOST;/*Output*/ switch(databits)/*设置数据位数*/ { case7: options.c_cflag|=CS7; break; case8: options.c_cflag|=CS8; break; default: fprintf(stderr,"Unsupporteddatasize\n");return(FALSE); } switch(parity) { case'n': case'N': options.c_cflag&=~PARENB;/*Clearparityenable*/ options.c_iflag&=~INPCK;/*Enableparitychecking*/ break; case'o': case'O': options.c_cflag|=(PARODD|PARENB);/*设置为奇效验*/ options.c_iflag|=INPCK;/*Disnableparitychecking*/ break; case'e': case'E': options.c_cflag|=PARENB;/*Enableparity*/ options .c_cflag&=~PARODD;/*转换为偶效验*/ options.c_iflag|=INPCK;/*Disnableparitychecking*/ break; case'S': case's': /*asnoparity*/ options.c_cflag&=~PARENB; options.c_cflag&=~CSTOPB;break; default: fprintf(stderr,"Unsupportedparity\n"); return(FALSE); } /*设置停止位*/ switch(stopbits) { case1: options.c_cflag&=~CSTOPB; break; case2: options.c_cflag|=CSTOPB; break; default: fprintf(stderr,"Unsupportedstopbits\n"); return(FALSE); } /*Setinputparityoption*/ if(parity! ='n') options.c_iflag|=INPCK; tcflush(fd,TCIFLUSH); options.c_cc[VTIME]=0;/*设置超时15seconds*/ options.c_cc[VMIN]=13;/*definetheminimumbytesdatatobereaded*/ if(tcsetattr(fd,TCSANOW,&options)! =0) { perror("SetupSerial3"); return(FALSE); } return(TRUE); } /********************************************************************** 代码说明: 使用串口一测试的,发送的数据是字符, 但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号 **********************************************************************/ /*****************************
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 串口 读取
![提示](https://static.bingdoc.com/images/bang_tan.gif)