liunx C 串口接收缓存区不够时 接收数据方法
主要思路:飞快的从缓存区取数据(完).
1.将堵塞接收改为超时接收
/* * serial.h * * Created on: 2021年11月22日 * Author: dell */ #include <asm/termios.h> #ifndef SERIAL_H_ #define SERIAL_H_ static void set_baudrate (struct termios *opt, unsigned int baudrate) { switch(baudrate) { case 460800: baudrate = B460800; break; case 115200: baudrate = B115200; break; case 19200: baudrate = B19200; break; case 9600: baudrate = B9600; break; case 2400: baudrate = B2400; break; default : baudrate = B9600; break; } speed_t speed = baudrate; cfsetispeed(opt, speed); cfsetospeed(opt, speed); } static void set_data_bit (struct termios *opt, unsigned int databit) { opt->c_cflag &= ~CSIZE; switch (databit) { case 8: opt->c_cflag |= CS8; break; case 7: opt->c_cflag |= CS7; break; case 6: opt->c_cflag |= CS6; break; case 5: opt->c_cflag |= CS5; break; default: opt->c_cflag |= CS8; break; } } static void set_parity (struct termios *opt, char parity) { switch (parity) { case 'N': /* 无校验 */ case 'n': opt->c_cflag &= ~PARENB; break; case 'E': /* 偶校验 */ case 'e': opt->c_cflag |= PARENB; opt->c_cflag &= ~PARODD; break; case 'O': /* 奇校验 */ case 'o': opt->c_cflag |= PARENB; opt->c_cflag |= ~PARODD; break; default: /* 其它选择为无校验 */ opt->c_cflag &= ~PARENB; break; } } static void set_stopbit (struct termios *opt, const char *stopbit) { if (0 == strcmp (stopbit, "1")) { opt->c_cflag &= ~CSTOPB; /* 1 位停止位 t */ } else if (0 == strcmp (stopbit, "1.5")) { opt->c_cflag &= ~CSTOPB; /* 1.5 位停止位 */ } else if (0 == strcmp (stopbit, "2")) { opt->c_cflag |= CSTOPB; /* 2 位停止位 */ } else { opt->c_cflag &= ~CSTOPB; /* 1 位停止位 */ } } int set_port_attr ( int fd,struct termios *opt, int baudrate, int databit, const char *stopbit, char parity, int vtime, int vmin ) { // struct termios opt; tcgetattr(fd, opt); // 读取串口设置 set_baudrate(opt, baudrate); // 设置波特率 opt->c_cflag &= ~(CSIZE | PARENB); // 输出标志 /* | CRTSCTS */ set_data_bit(opt, databit); // 数据位 set_parity(opt, parity); // 奇偶校验 set_stopbit(opt, stopbit); // 停止位 opt->c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); //禁止将输入的CR转换为NL opt->c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); // 本地标志 opt->c_oflag &= ~OPOST; // 输出标志 opt->c_cc[VTIME] = vtime; // 超时时间 opt->c_cc[VMIN] = vmin; // 最小字节数 tcflush (fd, TCIFLUSH); return (int)tcsetattr (fd, TCSANOW, opt);// 设置串口设置 } /******************************************* * receive data * 返回实际读入的字节数 * ********************************************/ int PortRecv(int fdcom, char *data, int datalen) { int readlen, fs_sel; fd_set fs_read; struct timeval tv_timeout; FD_ZERO(&fs_read); FD_SET(fdcom, &fs_read); tv_timeout.tv_sec = 0; tv_timeout.tv_usec = 10000; fs_sel = select(fdcom+1, &fs_read, NULL, NULL, &tv_timeout); if(fs_sel) { readlen = read(fdcom, data, datalen); return(readlen); } else{ return(-1); } return (readlen); } #endif /* SERIAL_H_ */
函数调用
// 打开串口
fd= open(serial_address,O_RDWR | O_NOCTTY);// O_NOCTTY 告诉liunx本程序不作为串口控制终端 if(fd<0) { perror("open error"); return -1; }
// 设置串口 res = set_port_attr (fd,&opt, baudrate, 8, "1", 'N', 1, 1 ); if(res < 0) { perror("set uart arrt failed \n"); exit(-1); }
// 接收数据
int buf_count = PortRecv(p->fd, tt, 255); /* 在串口读入字符串 */
2. 飞快从缓存区取数据,同时对报文进行区分
void *serial_read(struct thread_parameter *p) { int i; char tt[255]; int count; while(1) { char buf[1024]; count=0; while(1) {
// 每隔1毫秒就从缓存区取出所有数据,
// 取出字节数为0时代表你这一帧接收完了 usleep(1); int buf_count = PortRecv(p->fd, tt, 255); /* 在串口读入字符串 */ if(buf_count>0) { for(i=0;i<buf_count;i++) { buf[count] = tt[i]; count++; } } else { break; } } if(count > 0) { pthread_mutex_lock(p->lock); AddList_T(p->data,buf,count); pthread_mutex_unlock(p->lock); fflush(stdout); } usleep(1); } pthread_exit(NULL); }