串口高性能处理串口数据,按位读取处理案例
在现在的工控或者家用设备通信项目中,用到很多串口或者类串口通信协议,其中 很多协议需要读取操作,在读取中为了防止阻塞,提高处理性能,缩短处理时间经常用到 select 函数来 读取串口数据,select 是linux 真是个 神器啊,监控某一个文件或者设备,当有缓冲过来即可处理,而为了试用不同协议的长短不一,比如心跳包,和数据包,的处理不同,比较合适的做法就是按位读取,当是心跳包的头时,读取接下来的心跳包,处理心跳。当是数据包的时候,读取接下来的数据包,处理数据包。以下是串口读取案例
接口函数 uart_raw.c:
//#include "uni_serial.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <errno.h> #include <limits.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <pthread.h> //extern int deal_with_uart_byteBybyte(char buffer); /* typedef struct node { char p_send_buff[61];; node* pNext; }Node; Node* head = NULL; //创建链表,头结点data=0,pNext=NULL; bool createNodeList() { head = (Node*) malloc(sizeof(Node)); if(NULL == head) { return false; } else { memset(head->p_send_buff,0,sizeof(char)*61); head->pNext = NULL; return true; } } Node* init_node(char *buff ) { Node* node = (Node*)malloc(sizeof(Node)); int i=0; for(i=0;i<61;i++) head->p_send_buff[i]=buff[i]; node->pNext = NULL; return node2; } //增加节点 bool addNode(Node* node) { if(NULL == head) { return false; } Node* p = head->pNext; Node* q = head; while(NULL != p) { q = p; p = p->pNext; } q->pNext = node; node->pNext = NULL; return true; } //遍历节点 int num_node(Node* node) { int num_n=0; if(NULL == head) { return 0; } Node* p = head->pNext; //Node* q = head; while(NULL != p) { //q = p; p = p->pNext; num_n++; } return num_n; } //删除节点 bool deleteNode(int index) { if(NULL == head) { return false; } Node* p = head->pNext; int length = 0; while(NULL != p) { length ++; p = p->pNext; } if(length < index) { return false; } else { Node* q = head; p = head; for(int i=0;i<index;i++) { q = p; p = p->pNext; } Node* t = p->pNext; q->pNext = t; free(p); return true; } } int send_reoute() { while(num_node(uart_node) > 5) { Node* p = head->pNext; Node* q = head; //遍历到最后一个节点 while(NULL != p) { //q = p; p = p->pNext; } // 发送最后一个数据的 BUFF // 删除最后一个 节点 // 释放最后一个节点 内存 指针 // 长度 减少 } return 0; } */ int deal_with_uart_byteBybyte(unsigned char buffer); int uart_fd; int uart_flag_ok=0; struct termios options; speed_t speed; //speed=B2400; unsigned char BCC_CheckSum(unsigned char *buf, int len) { unsigned char i; unsigned char checksum = 0; for(i = 0; i < len; i++) { checksum ^= *buf++; } return checksum; } int uni_send_protocol(const unsigned char* buf, int n) { //tcflush(uart_fd, TCIOFLUSH); int rc = 0; int i = 0; fprintf(stderr,"SEND serial>>>>>>>>>>>>>>>> ------------\n"); for(i = 0; i < n; i++){ printf("%02X ", buf[i]); } rc = write(uart_fd, buf, n); sync(); usleep(5000);//5ms tcflush(uart_fd, TCIOFLUSH); return rc; } int set_speed() // 波特率 9600 { int status; //struct termios opt; tcgetattr(uart_fd,&options); tcflush(uart_fd,TCIOFLUSH); //cfsetispeed(&options,speed); cfsetispeed(&options,B9600); status = tcsetattr(uart_fd,TCSANOW,&options); if(0 != status){ perror("error: tcsetattr failed!"); return -1; } tcflush(uart_fd,TCIOFLUSH); return 0; } int set_option() { cfmakeraw(&options);/* 配置为原始模式 */ options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; //options.c_cflag &= ~PARENB; //opt.c_cflag |= CS8; //校验位 偶校验 options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; //停止位 options.c_cflag &= ~CSTOPB; /*设置等待时间和最小接收字符*/ options.c_cc[VTIME] = 0; options.c_cc[VMIN] = 1; return 1; } int set_parity() { if (tcgetattr(uart_fd,&options)!=0) { perror("error set_parity:tcgetattr."); return -1; } set_option(); if (tcsetattr(uart_fd,TCSANOW,&options) != 0) { perror("error set_parity:tcsetattr"); return -1; } tcflush(uart_fd,TCIOFLUSH); return 0; } int uni_InitUart() { const char device[] = "/dev/ttyS2"; int flags = O_RDWR | O_NOCTTY | O_NDELAY |O_SYNC; uart_fd = open(device, flags ); if(-1 == uart_fd){ printf("open %s failed\n", device); return -1; } set_speed(); if (set_parity() < 0){ printf("set parity error !\n"); return -1; } return uart_fd; } int Uart_receive_callBack(char p, int (*ptr)()) { (*ptr)(p); } void* run_uart_receive_pid() { int rc; char buffer; unsigned char buffer1; fd_set rfds; struct timeval tv; int retval; int ret; while(1) { FD_ZERO(&rfds); FD_SET(uart_fd, &rfds); tv.tv_sec = 1; tv.tv_usec = 1000; retval = select(uart_fd + 1, &rfds, NULL, NULL, &tv); //fprintf(stderr,"select!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); if (retval < 0) perror("select()"); else if (retval) { if(FD_ISSET(uart_fd, &rfds) ) { rc = read(uart_fd, &buffer, 1); if(rc >= 0){ //printf("%02X ", buffer); } Uart_receive_callBack(buffer, deal_with_uart_byteBybyte);// 读取一个处理一个 buffer=0x00; uart_flag_ok=1; } }else{ //return 1; //printf("No data within few times.\n"); } //printf("get out a serial data!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); //tcflush(uart_fd, TCIOFLUSH); } } int uni_InitUart_recv_pthread() { pthread_t uart_receive_pid; int ret = pthread_create(&uart_receive_pid, NULL, &run_uart_receive_pid, NULL); if (ret != 0) { fprintf(stderr,"%s","uni_receive_serial pthread_create fail!\n"); return ret; } } int uni_recv_protocol(unsigned char* buf, int n) { int rc, i; int count = 0; fprintf(stderr,"GET serial<<<<<<<<<<<<< ------------\n"); for(i = 0; i < n; i++){ rc = read(uart_fd, &buf[i], 1); printf("%02X ", buf[i]); if(rc <= 0){ return rc; } count++; } tcflush(uart_fd, TCIOFLUSH); return count; } void uni_release_serial() { close(uart_fd); }
主函数调用实例函数:
处理函数最好做成回调函数,在引用文件中直接用 extern 来注明外部函数即可。
extern int deal_with_uart_byteBybyte(char buffer); int i_uart_index; int length_uart; char buffer_command[16]; char old_command[16]; int deal_with_uart_byteBybyte(char buffer) { int i ; int count_sum = 0; //printf("%02X \n", buffer); if(i_uart_index == 0){ //判断第一个位 if(buffer == 0xf1){// 主机心跳包 length_uart = 1; buffer_command[0] = buffer; //buff == 0xf1 i_uart_index++; }else if(buffer == 0x11){//主机数据帧 buffer_command[0] = buffer; i_uart_index++; } }else if(i_uart_index == 1){ //判断第二个位数 if(buffer_command[0] == 0xf1){ if(buffer == 0x7a){ printf("get a heart beat message !!!!!!!!!!!!!!!!\n"); //printf("send >>>>>>>>>>\n"); char buff_heart[2]={0}; buff_heart[0]=0XF9; buff_heart[1]=0X7A; //char buff_heart[8]={0XBB,0X00,0X01,0X04,0X02,0X01,0X00,0XBD}; if(uni_send_protocol(buff_heart,2) < 0) { printf("write ERROR!\n"); return 0; } i_uart_index = 0; } }else if(buffer_command[0] == 0x11){ length_uart = buffer - 0x00; buffer_command[1] = buffer; i_uart_index++; } }else{ //判断之后的位数 if((length_uart+3) > i_uart_index && 16 > i_uart_index){ buffer_command[i_uart_index] = buffer; i_uart_index++; }else if ((length_uart+3) == i_uart_index){ printf("get a data message !!!!!!!!!!!!!!!!\n"); for(i =0; i < i_uart_index; i++){ printf("%02X \n", buffer_command[i]); //old_command[i]=buffer_command[i];//复制到 old_buff } for(i =0; i < i_uart_index-1; i++){ count_sum += buffer_command[i] - 0x00; } if((count_sum % 256) == buffer_command[i_uart_index -1]){ printf("data command check OK!!!!!!!!!!!!!!!!\n"); //int i=0; //TODO deal with command message /* char buff_heart[8]={0XBB,0X00,0X01,0X04,0X02,0X01,0X00,0XBD}; if(uni_send_protocol(buff_heart,8) < 0) { printf("write ERROR!\n"); return 0; }*/ //第一次 if(recved_times==1) { for(i =0; i < i_uart_index; i++){ old_command[i]=buffer_command[i]; } recved_times=0;//清零 只同步一次 } else{ deal_uart_buff(buffer_command,old_command,i_uart_index); for(i =0; i < i_uart_index; i++){ old_command[i]=buffer_command[i]; } } i_uart_index = 0; }else{ printf("data command check fail!!!!!!!!!!!!!!!!\n"); i_uart_index = 0; } }else{ i_uart_index = 0; } } } int main() { uni_InitUart(); uni_InitUart_recv_pthread(); return 0; }