串口编程流程:(串口发送部分)
int set_opt(int,int,int,char,int); void main() { int fd,wr_static,i=10; char *uart3 = "/dev/ttySAC3"; char *buffer = "hello world!\n"; printf("\r\nitop4412 uart3 writetest start\r\n"); if((fd = open(uart3, O_RDWR|O_NOCTTY|O_NDELAY))<0){//打开串口 printf("open %s is failed",uart3); } else{ printf("open %s is success\n",uart3); set_opt(fd, 115200, 8, 'N', 1); //串口配置 while(i--) { wr_static = write(fd,buffer, strlen(buffer));//串口发送 if(wr_static<0) printf("write failed\n"); else{ printf("wr_static is %d\n",wr_static); } sleep(1); } } close(fd); }
串口的初始化程序,基本上是通用的:
内核中关于串口初始化的结构体 arch/arm/include/asm/termios.h
termio 结构体:
#define NCC 8 struct termio { unsigned short c_iflag; /* input mode flags */ unsigned short c_oflag; /* output mode flags */ unsigned short c_cflag; /* control mode flags */ unsigned short c_lflag; /* local mode flags */ unsigned char c_line; /* line discipline */ unsigned char c_cc[NCC]; /* control characters */ };
串口初始化步骤是:
– 读取当前参数
– 修改参数
– 配置参数
tcgetattr 函数 读取当前参数函数
man 3 tcgetattr
int tcgetattr(int fd, struct termios *termios_p);
获取当前波特率函数
speed_t cfgetispeed(const struct termios *termios_p); speed_t cfgetospeed(const struct termios *termios_p); – *termios_p:前面介绍的结构体 – 失败返回-1;成功返回波特率
波特率设置函数
int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed); – 参数*termios_p:前面介绍的结构体。 – 参数speed:speed 波特率,常用的B2400,B4800,B9600,B115200, B460800 等等。 – 执行成功返回0,失败返回-1
清空串口BUFFER中的数据函数
int tcflush(int fd, int queue_selector); – 参数1:fd 是open 返回的文件句柄。 – 参数2:控制tcflush 的操作。有三个常用数值,TCIFLUSH 清除正收到的数 据,且不会读取出来;TCOFLUSH 清除正写入的数据,且不会发送至终 端;TCIOFLUSH 清除所有正在发生的I/O 数据。 – 执行成功返回0,失败返回-1
设置串口参数函数
int tcsetattr(int fd, int optional_actions,const struct termios *termios_p); – 参数fd:open 返回的文件句柄。 – 参数optional_actions:参数生效的时间。有三个常用的值:TCSANOW: 不等数据传输完毕就立即改变属性;TCSADRAIN:等待所有数据传输结束 才改变属性;TCSAFLUSH:清空输入输出缓冲区才改变属性。 – 参数*termios_p :在旧的参数基础上修改的后的参数。 – 返回值:执行成功返回0,失败返回-1 – 一般在初始化最后会使用这个函数
完整的串口初始化程序:
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop) { struct termios newtio,oldtio; if ( tcgetattr( fd,&oldtio) != 0) //读取当前串口参数到名为oldtio的 termio 类型结构体中 { perror("SetupSerial 1"); return -1; } bzero( &newtio, sizeof( newtio ) ); //bzero() 会将内存块(字符串)的前n个字节清零 newtio.c_cflag |= CLOCAL | CREAD; //控制模式 newtio.c_cflag &= ~CSIZE; switch( nBits ) //判断 bits { case 7: newtio.c_cflag |= CS7; //CS5 CS6 break; case 8: newtio.c_cflag |= CS8; break; } switch( nEvent ) //奇偶校验 { case 'O': newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP); break; case 'E': newtio.c_iflag |= (INPCK | ISTRIP); newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD; break; case 'N': newtio.c_cflag &= ~PARENB; break; } switch( nSpeed ) //波特率 { case 2400: cfsetispeed(&newtio, B2400); cfsetospeed(&newtio, B2400); break; case 4800: cfsetispeed(&newtio, B4800); cfsetospeed(&newtio, B4800); break; case 9600: cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break; case 115200: cfsetispeed(&newtio, B115200); cfsetospeed(&newtio, B115200); break; case 460800: cfsetispeed(&newtio, B460800); cfsetospeed(&newtio, B460800); break; default: cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break; } if( nStop == 1 ) //停止位 newtio.c_cflag &= ~CSTOPB; else if ( nStop == 2 ) newtio.c_cflag |= CSTOPB; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 0; tcflush(fd,TCIFLUSH); //清空Buffer中的数据 if((tcsetattr(fd,TCSANOW,&newtio))!=0) //写入新的结构体 { perror("com set error"); return -1; } // printf("set done!\n\r"); return 0; }
串口接收部分
int set_opt(int,int,int,char,int); //"/dev/ttySAC3"是con2,靠近耳机接口的串口 void main() { int fd,nByte; char *uart3 = "/dev/ttySAC3"; char buffer[512]; char *uart_out = "please input\r\n"; memset(buffer, 0, sizeof(buffer)); if((fd = open(uart3, O_RDWR|O_NOCTTY))<0) printf("open %s is failed",uart3); else{ set_opt(fd, 115200, 8, 'N', 1); write(fd,uart_out, strlen(uart_out)); while(1){ while((nByte = read(fd, buffer, 512))>0){ buffer[nByte+1] = '\0'; write(fd,buffer,strlen(buffer)); memset(buffer, 0, strlen(buffer)); nByte = 0; } } } }