串口高性能处理串口数据,按位读取处理案例

在现在的工控或者家用设备通信项目中,用到很多串口或者类串口通信协议,其中 很多协议需要读取操作,在读取中为了防止阻塞,提高处理性能,缩短处理时间经常用到 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>>>>>>>>>>>>>>>> ------------
");
    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
", device);
        return -1;
    }

    set_speed();
    if (set_parity() < 0){
        printf("set parity error !
");
        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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
");

        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.
");
        }

    //printf("get out a serial data!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
");
    //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!
");
        return ret;
    }
}



int uni_recv_protocol(unsigned char* buf, int n)
{
    int rc, i;
    int count = 0;
    fprintf(stderr,"GET serial<<<<<<<<<<<<< ------------
");
    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);
}
View Code

主函数调用实例函数:

处理函数最好做成回调函数,在引用文件中直接用 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 
", 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 !!!!!!!!!!!!!!!!
");
                //printf("send >>>>>>>>>>
");
                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!
");
                    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 !!!!!!!!!!!!!!!!
");
            for(i =0; i < i_uart_index; i++){
                printf("%02X 
", 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!!!!!!!!!!!!!!!!
");
                //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!
");
                    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!!!!!!!!!!!!!!!!
");
                i_uart_index = 0;
            }
        }else{
            i_uart_index = 0;
        }
    
    }
}




int main()
{
    
    uni_InitUart();
    uni_InitUart_recv_pthread();
    return 0;
}
原文地址:https://www.cnblogs.com/hongzhunzhun/p/6541766.html