Linux串口编程总结
来源:互联网 发布:dos启动windows 编辑:程序博客网 时间:2024/06/05 11:38
对串口的操作一般分为四步:打开串口、设置串口、读写串口和关闭串口。Linux下,可以通过设备文件访问串口只需要open()相应的设备文件即可。串口的设备文件名:1.直接连接的串口,串口的设备文件为/dev/ttyS0、/dev/ttyS1等等,S0对应串口1,以此类推。2.通过USB转串口连接,设备文件为/dev/ttyUSB0$dmesg|grep ttyS* 命令可以显示系统串口拔插信息。需要注意的是,普通用户不能打开设备文件。可以提升shell的权限$sudo -s,这样就使shell拥有了超级权限。$sudo su username 可以退回普通权限。
打开串口:{intfd = open( Dev, O_RDWR ); if (-1 == fd){ perror("Can't Open Serial Port");return -1;}elsereturn fd;}设置串口:
设置串口的关键在于termios结构体的设置。termios的详细文档在这个链接。
termios函数族提供了一个常规的终端接口,用于控制非同步通信端口。这个结构体包含了至少下列成员:
tcflag_t c_iflag; /* 输入模式 */
tcflag_t c_oflag; /* 输出模式 */
tcflag_t c_cflag; /* 控制模式 */
tcflag_t c_lflag; /* 本地模式 */
cc_t c_cc[NCCS]; /* 控制字符 */
设置串口通信速率:
/* 设置串口通信速率fd 类型 int 打开串口的文件句柄speed 类型 int 串口速度*/int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, };int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };void set_speed(int fd, int speed){ 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); }}设置串口停止位、数据位、校验位:
/*设置串口数据位,停止位和效验位fd 类型 int 打开的串口文件句柄databits 类型 int 数据位 取值 为 7 或者8stopbits 类型 int 停止位 取值为 1 或者2parity 类型 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 */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') options.c_iflag |= INPCK; options.c_cc[VTIME] = 150; // 15 seconds options.c_cc[VMIN] = 0; tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { perror("SetupSerial 3");return (FALSE);} return (TRUE); }读写串口:
while(1) { while((nread = read(fd,buff,512))>0) {<span style="white-space:pre"></span>for(i=0;i<nread;i++){printf("%3x",buff[i]);} <span style="white-space:pre"></span>printf("\n"); <span style="white-space:pre"></span>write(fd,buff,nread); } }关闭串口:
close(fd)在编程过程中出现的问题:
1.多串口同时读写操作。
多串口读写需要在打开设备文件后设置为非阻塞型读写。
fd = OpenDev(dev);fcntl(fd,F_SETFL,FNDELAY); //非阻塞2.发送0x00~0xff全部十六进制数。
(1)收到05 06 07 08 09 0a
修改终端I/O的输入处理模式为非规范输入方式。规范方式输入处理中,终端输入以行为单位进行处理,0x0a即'/n',相当于按下了enter键,本行才输出。
Opt.c_lflag &= ~(ICANON); //非规范方式输入(2)收到05 06 07 08 09 0a 0b 0c 0a 0e ...
0x05之前的数据都相当于特殊的控制字符,所以要去除。
Opt.c_lflag &= ~(ICANON|ISIG); //非规范方式输入、去除ISIG(3)收到01 02 03 ... 0a 0b 0c 0a 0e 0f...
window下的回车编码为“0x0d 0x0a”,而Linux下的回车编码为“0x0a“。所以要取消回车与新行符的映射。
Opt.c_iflag &= ~(INLCR|ICRNL|IGNCR);//取消映射 关闭软件流控制 Opt.c_oflag &= ~(ONLCR|OCRNL); //取消映射(4)0x11、0x13收不到
0x11和0x13是软件流控制符。
Opt.c_iflag &= ~(INLCR|ICRNL|IGNCR|IXON|IXOFF);//取消映射 关闭软件流控制(5)从0x80开始往后,数据printf为ffffff80 。定义字符是应定义为无符号型。
//char buff[512]; unsigned char buff[512];
(6)完整接收0x00到0xff。
3.串口read一次最多读8个字节。与串口的缓存有关,一般一次最多缓存8个字节。
最后附上完整的双串口读写程序:
#include <stdio.h> /*标准输入输出定义*/#include <stdlib.h> /*标准函数库定义*/#include <unistd.h> /*Unix标准函数定义*/#include <sys/types.h> /**/#include <sys/stat.h> /**/#include <fcntl.h> /*文件控制定义*/#include <termios.h> /*PPSIX终端控制定义*/#include <errno.h> /*错误号定义*//***@brief 设置串口通信速率*@param fd 类型 int 打开串口的文件句柄*@param speed 类型 int 串口速度*@return void*/#define FALSE -1#define TRUE 0int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, };int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };void set_speed(int fd, int speed){ int i; int status; struct termios Opt; tcgetattr(fd, &Opt); Opt.c_lflag &= ~(ICANON|ISIG); //非规范方式输入 Opt.c_iflag &= ~(INLCR|ICRNL|IGNCR); Opt.c_oflag &= ~(ONLCR|OCRNL); //取消映射 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 */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') options.c_iflag |= INPCK; options.c_cc[VTIME] = 150; // 15 seconds options.c_cc[VMIN] = 0; tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { perror("SetupSerial 3");return (FALSE);}/*options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_iflag &= ~(INLCR | ICRNL | IGNCR); options.c_oflag &= ~(ONLCR | OCRNL);*/ return (TRUE); }/***@breif 打开串口*/int OpenDev(char *Dev){intfd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAYif (-1 == fd){ /*设置数据位数*/perror("Can't Open Serial Port");return -1;}elsereturn fd;}/***@breif main()*/int main(int argc, char **argv){int fd_1,fd_2;int i;int nread_1,nread_2;char buff_1[512],buff_2[512];char *dev_1="/dev/ttyS0";char *dev_2="/dev/ttyUSB0";fd_1 = OpenDev(dev_1);fd_2 = OpenDev(dev_2);fcntl(fd_1,F_SETFL,FNDELAY);fcntl(fd_2,F_SETFL,FNDELAY); //设置为非阻塞型if (fd_1>0)set_speed(fd_1,19200);else{printf("Can't Open Serial Port 1!\n");exit(0);}if (set_Parity(fd_1,8,1,'N')== FALSE) { printf("Set Parity 1 Error\n"); exit(1); }if (fd_2>0) set_speed(fd_2,19200); else { printf("Can't Open Serial Port 2!\n"); exit(0); } if (set_Parity(fd_2,8,1,'N')== FALSE) { printf("Set Parity 2 Error\n"); exit(1); } while(1) {while((nread_1 = read(fd_1,buff_1,512))>0) { /*printf("\nLen %d\n",nread); buff[nread+1]='\0'; printf("\n%s",buff);*/printf("Serial_Port_1:%d\n",nread_1);for(i=0;i<nread_1;i++){//printf("%d\n",nread);//printf("%d\n",i);printf("%3x",buff_1[i]);}printf("\n");write(fd_1,buff_1,nread_1); }while((nread_2 = read(fd_2,buff_2,512))>0){printf("Serial_Port_2:%d\n",nread_2);for(i=0;i<nread_2;i++){printf("%3x",buff_2[i]);}printf("\n");write(fd_2,buff_2,nread_2);} } //close(fd); //exit(0);}
参考文章:
Linux串口编程详解
串口通信编程(linux)
Linux系统下串口接收数据,部分特殊字符丢失的解决方法
0 0
- linux串口编程总结
- Linux串口编程总结
- Linux下串口编程总结
- linux串口编程(要点总结)
- 关于linux串口编程的一点总结
- 《Linux C》04 串口编程总结
- 串口编程总结
- win23串口编程总结
- win23串口编程总结
- MFC 串口编程总结
- android 串口编程总结
- 串口编程总结
- Linux串口调试(编程)总结(ARM通信)
- Linux 串口编程
- Linux下串口编程
- Linux串口编程分析
- Linux串口编程
- Linux串口编程
- 一天内研究 Spring、Spring MVC、MyBatis 的纯干成果
- android之Http下载 和xml 解析(SAX)
- PPTP +Radius + DaloRadius 打造VPN用户/流量管理平台
- Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id)等
- Naive Bayes Model
- Linux串口编程总结
- C语言(高速算法)去除二值图中的小面积连通区域
- 4、maven报错Project configuration is not up-to-date with pom.xml
- 第13周项目5 -字符串操作(2.3)
- 《JAVA与模式》26天系列—第14天—桥梁模式
- Android 三种定位方式
- B-Tree索引在sqlserver和mysql中的应用
- 第一个小程序
- 安卓创建新工程时的几个选项的说明(http://developer.android.com/)