linux串口demo 解析原创代码没有完全测试

it2023-01-21  52

/* ******************************************************************************** ******************************************************************************* */ #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> /*错误号定义*/ #include<string.h> #include<pthread.h> #define RET_ERR -1 #define RET_OK 0 #define LEN_BUF_RECV_UNPACK 16 #define LEN_BUF_RECV 64 static int g_fd; static char s_buf_recv[LEN_BUF_RECV_UNPACK]; /* ****************************************************************** *名称: uart_open *功能: 打开串口并返回串口设备文件描述 *入口参数: fd 文件描述符 dev 串口号(ttyS0,ttyS1,ttyS2) *出口参数:正确返回为0,错误返回为-1 ****************************************************************** */ int uart_open(char*dev, int *fd) { int ret; *fd = open(dev, O_RDWR|O_NOCTTY|O_NDELAY); printf("fd->open=%d\n", *fd); if (0 > *fd) { printf("Can't Open Serial Port"); return RET_ERR; } //恢复串口为阻塞状态 ret = fcntl(*fd, F_SETFL, 0); printf("fcntl=%d\n", ret); if(0 > ret) { printf("fcntl failed!\n"); return RET_ERR; } //测试是否为终端设备 if(0 == isatty(STDIN_FILENO)) { printf("standard input is not a terminal device\n"); return RET_ERR; } printf("isatty success!\n"); return RET_OK; } /* ****************************************************************** *名称: uart_close *功能: 关闭串口并返回串口设备文件描述 *入口参数: fd 文件描述符 port 串口号(ttyS0,ttyS1,ttyS2) *出口参数:void ****************************************************************** */ void uart_close(int fd) { close(fd); } /* ****************************************************************** *名称: uart_set *功能: 设置串口数据位,停止位和效验位 *入口参数: fd 串口文件描述符 * speed 串口速度 * flow_ctrl 数据流控制 * databits 数据位 取值为 7 或者8 * stopbits 停止位 取值为 1 或者2 * parity 效验类型 取值为N,E,O,,S *出口参数:正确返回为0,错误返回为-1 ****************************************************************** */ int uart_set(int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity) { int i, status; int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300}; int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300}; struct termios options; /* tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确, 该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1. */ if(0 != tcgetattr(fd, &options)) { printf("SetupSerial 1\n"); return RET_ERR; } //设置串口输入波特率和输出波特率 for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (speed == name_arr[i]) { cfsetispeed(&options, speed_arr[i]); cfsetospeed(&options, speed_arr[i]); } } //修改控制模式,保证程序不会占用串口 options.c_cflag |= CLOCAL; //修改控制模式,使得能够从串口中读取输入数据 options.c_cflag |= CREAD; //设置数据流控制 switch(flow_ctrl) { case 0://不使用流控制 options.c_cflag &= ~CRTSCTS; break; case 1://使用硬件流控制 options.c_cflag |= CRTSCTS; break; case 2://使用软件流控制 options.c_cflag |= IXON | IXOFF | IXANY; break; } //设置数据位 //屏蔽其他标志位 options.c_cflag &= ~CSIZE; switch (databits) { case 5: options.c_cflag |= CS5; break; case 6: options.c_cflag |= CS6; break; case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: printf("Unsupported data size\n"); return RET_ERR; } //设置校验位 switch (parity) { case 'n': case 'N': //无奇偶校验位。 options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break; case 'o': case 'O'://设置为奇校验 options.c_cflag |= (PARODD | PARENB); options.c_iflag |= INPCK; break; case 'e': case 'E'://设置为偶校验 options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; break; case 's': case 'S': //设置为空格 options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: printf("Unsupported parity\n"); return RET_ERR; } // 设置停止位 switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: printf("Unsupported stop bits\n"); return RET_ERR; } //修改输出模式,原始数据输出 options.c_oflag &= ~OPOST; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //options.c_lflag &= ~(ISIG | ICANON); options.c_iflag &= ~ICRNL; //禁止将输入的CR转换为NL options.c_iflag &= ~(IXON); //清bit位 关闭流控字符 //设置等待时间和最小接收字符 options.c_cc[VTIME] = 0; /* 读取一个字符等待1*(1/10)s */ options.c_cc[VMIN] = 0; /* 读取字符的最少个数为1 */ //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读 tcflush(fd,TCIFLUSH); //激活配置 (将修改后的termios数据设置到串口中) if (0 != tcsetattr(fd,TCSANOW,&options)) { printf("com set error!\n"); return RET_ERR; } return RET_OK; } /* ****************************************************************** *名称: uart_init() *功能: 串口初始化 *入口参数: fd 文件描述符 * speed 串口速度 * flow_ctrl 数据流控制 * databits 数据位 取值为 7 或者8 * stopbits 停止位 取值为 1 或者2 * parity 效验类型 取值为N,E,O,,S * *出口参数:正确返回为0,错误返回为-1 ****************************************************************** */ int uart_init(int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity) { int ret; //设置串口数据帧格式 //ret = uart_set(fd, 115200, 0, 8, 1, 'N'); ret = uart_set(fd, speed, flow_ctrl, databits, stopbits, parity); return ret; } /* ******************************************************************* * 名称: uart_send * 功能: 发送数据 * 入口参数: fd 文件描述符 * buf 存放串口发送数据 * data_len 一帧数据的个数 * 出口参数: 正确返回为0,错误返回为-1 ****************************************************************** */ int uart_send(int fd, char *buf, int data_len) { int len = 0; len = write(fd, buf, data_len); printf("send data is %s\n", buf); if (len != data_len) { tcflush(fd, TCOFLUSH); return RET_ERR; } return RET_OK; } /* ****************************************************************** * 名称: uart_unpack * 功能: 串口数据解包 * 入口参数: c 串口数据 * * 出口参数: 正确返回为0,错误返回为-1 ****************************************************************** */ static int uart_unpack(unsigned char c) { //printf("%s is running\r\n",__FUNCTION__); static int flg, index; /*接收到的数据开头为A*/ if('A' == c) { flg = 1; index = 0; } else if('\n' == c && 0 < index && '\r' == s_buf_recv[index - 1]) { /*以回车换行结束如:A123456\r\n*/ //buf[index] = c; index = 0; flg = 0; return RET_OK; } /*没找到继续找*/ if (1 == flg) { s_buf_recv[index++] = c; if(index >= sizeof(s_buf_recv)) index = 0; } return RET_ERR; } /* ****************************************************************** * 名称: uart_recv_data_frame * 功能: 串口数据每帧数据解析 * 入口参数: * 出口参数: 正确返回为0,错误返回为-1 ****************************************************************** */ static int uart_recv_data_frame() { int len; unsigned char type; printf("buf0-7 %x %x %x %x %x %x %x %x", s_buf_recv[0], s_buf_recv[1],s_buf_recv[2],s_buf_recv[3],s_buf_recv[4],s_buf_recv[5],s_buf_recv[6],s_buf_recv[7]); len = s_buf_recv[1]; if ('A' != s_buf_recv[0] || 0 >= len || sizeof(s_buf_recv) <= len + 2 || 0x0d != s_buf_recv[len + 2]) { printf("unknow uart_recv_data_frame:%d\n", len); return RET_ERR; } type = (unsigned char)s_buf_recv[2]; switch(type){ case 0xAA: printf("uart_recv_data_frame:0xaa\n"); break; default: printf("unknow uart_recv_data_frame:%x\n", type); break; } return RET_OK; } /* ****************************************************************** * 名称: uart_recv_thread * 功能: 接收串口数据线程 * 入口参数: * 出口参数: 错误返回为-1 ****************************************************************** */ static void *uart_recv_thread(void *arg) { int ret, i, n; fd_set readfds; char buf[LEN_BUF_RECV]; while(1) { FD_ZERO(&readfds); FD_SET(g_fd, &readfds); ret = select(g_fd + 1, &readfds, NULL, NULL, NULL); //memset(buf, 0, sizeof(buf)); if(0 >= ret) { printf("select failed %d\n", ret); //0超时 1失败 continue; } if(0 >= FD_ISSET(g_fd, &readfds)){ printf("FD_ISSET failed\n"); continue; } do { n = read(g_fd, buf, LEN_BUF_RECV); //配置为非阻塞 if(0 >= n) { printf("read failed %d\n", n); //conitnue; break; } for (i = 0; i < n; i++) { ret = uart_unpack(buf[i]); if (RET_OK == ret) { uart_recv_data_frame(); } } }while(0 < n); } return NULL; } /* ******************************************************************************** ******************************************************************************* */ int main(int argc, char **argv) { int ret, len, i; char rcv_buf[256]; char send_buf[256]; pthread_t p_serial; if(argc != 2) { printf("Usage: %s /dev/ttySn 0 #(send data)\n",argv[0]); printf("Usage: %s /dev/ttySn 1 #1(receive data)\n",argv[1]); printf("open failure : %s\n", strerror(errno)); return RET_ERR; } ret = uart_open(argv[1], &g_fd); //打开串口,返回文件描述符 // fd=open("dev/ttyS1", O_RDWR); //printf("fd= \n",fd); ret = uart_init(g_fd, 9600, 0, 8, 1, 'N'); printf("Set Port Exactly!\n"); //sleep(1); if(RET_ERR == ret) { printf("ret init = %d\n",ret); return RET_ERR; } pthread_create(&p_serial, NULL, uart_recv_thread, NULL);/*线程函数在下面*/ fgets(send_buf, 256, stdin); //输入内容,最大不超过40字节,fgets能吸收回车符,这样pc收到的数据就能自动换行 for(i = 0; i < 10; i++) { len = uart_send(g_fd, send_buf, 40); if(len > 0) printf(" %d time send %d data successful\n",i,len); else printf("send data failed!\n"); sleep(1); } uart_close(g_fd); }

 

最新回复(0)