精华内容
下载资源
问答
  • 1、实时解析串口数据并绘制相关曲线 | 2、串口单独一个进程(不影响GUI刷新) | 3、曲线、串口参数可配置、可保存
  • Arduino解析串口数据超简单方法

    千次阅读 2020-05-09 15:03:01
    Arduino解析串口数据超简单方法 String str=""; str = mySerial.readString(); if(str.length()!=0){ sscanf(str.c_str(),"m%d d%d",&cur_model,&cur_dangwei); Serial.println("cur_model = "+ ...

     

    Arduino解析串口数据超简单方法

    发送:

    Serial.println("m"+String(cur_model)+" d"+String(cur_dangwei));  

    接收: 

    String str="";
    str = mySerial.readString();
    if(str.length()!=0){
        sscanf(str.c_str(),"m%d d%d",&cur_model,&cur_dangwei);
        Serial.println("cur_model = "+ String(cur_model));
        Serial.println("cur_dangwei = "+ String(cur_dangwei));
    }

     

    展开全文
  • C 解析串口数据

    千次阅读 2019-07-09 17:07:52
    用C语言写一个程序,此程序持续从串口读取数据(串口速率是115200,偶校验),串口数据有可能包含DL-T 645协议格式或者DL-T 698协议格式的数据帧(协议见word文档)。 要求把收到的符合以上两种格式的数据帧检出来。...
    最近面试,收到一份面试题,特此研究下C的串口解析
    

    题目要求如下:

    • 用C语言写一个程序,此程序持续从串口读取数据(串口速率是115200,偶校验),串口数据有可能包含DL-T 645协议格式或者DL-T 698协议格式的数据帧(协议见word文档)。
      要求把收到的符合以上两种格式的数据帧检出来。
      附加要求:注意程序的可扩展性(如果以后此程序再支持其他协议数据解析,要容易扩展)。*

    由于文档比较内容繁琐,特贴出来,协议格式

    DL-T 645协议格式
    (以下简称协议A)
    在这里插入图片描述
    DL-T 698协议格式
    (以下简称协议B)
    在这里插入图片描述
    串口解析思路

     - 一、串口数据接收: 	
     		定义一个1024字节的buf,将串口接收到的数据依次追加到此buf中; 
     - 二、解析串口数据流程:
     		1、从buf中检索起始字符0x68的位置,->2
     		2、去匹配是否符合协议A,会有三种解析结果
     			a.解析到完整的一帧数据,->5
     			b.数据未接收完 ->3
     			c.解析不满足规则 ->3
     		3、去匹配是否符合协议B,会有三种解析结果
     			a.解析到完整的一帧数据, ->5
     			b.数据未接收完 ->6
     			c.解析不满足规则
     				协议A也不满足规则 ->7
     				协议A未接收完 ->6
     		5、解析到完整的一帧数据,->10
     		6、协议匹配未接收完 ->9
     		7、两个协议解析都不满足,->8
     		8、从1中的位置继续寻找下一个0x68的位置
     			a.找到0x68    ->1
     			b.未找到0x68 ->6
     		9、继续循环,等待串口数据过来
     		10、解析完成,将buf中剩余数据前移到位置0,
    

    代码如下:
    先定义两种协议对应的结构体

    typedef struct dl_t_698
    {
        uint8_t st_byte;//起始字符
        uint16_t data_length;//长度域--此处注意大小端的问题
        uint8_t control_byte;//控制域
        uint8_t address_bytes[100];//地址域
        uint16_t frame_head_hcs;//帧头校验
        uint8_t user_data[100];//用户数据
        uint16_t frame_crc_fcs;//帧校验
        uint8_t end_byte;//结束字符
    }dlt_698_frame_body;
    
    typedef struct dl_t_645
    {
        uint8_t st_byte;//帧起始符
        uint8_t address_bytes[5];//地址欲
        uint8_t mid_st_byte;//帧起始符
        uint8_t control_byte;//控制码
        uint16_t data_length;//长度域--此处注意大小端的问题-- 前面字符长度为10
        uint8_t user_data[100];//数据data
        uint16_t frame_crc_cs;//校验
        uint8_t end_byte;//结束字符
    }dlt_645_frame_body;
    
    //解析到一帧数据可能出现的情况
    typedef enum frame_result
    {
        UNKNOWN,
        OK,               //成功找到一帧
        UNFINISHED,//未接收完成
        ERROR,        //不满足此协议
    } frame_result_t;
    
    //定义协议类型
    typedef enum protocol_type {
        PROTOCOL_UNKNOWN,
        PROTOCOL_DL_T_698,
        PROTOCOL_DL_T_645,
        PROTOCOL_OTHER,
    }protocol_type_t;
    
    char uart_rcvd_buf[UART_BUFFER_LEN];//接收串口发送过来的数据
    char frame_buf[FRAME_BUFFER_LEN];//用来存取一帧数据
    uint16_t uart_rcvd_pos = 0;//当前buf接收到的数据长度
    
    dlt_698_frame_body s_dlt_698_frame_body;
    dlt_645_frame_body s_dlt_645_frame_body;
    
    /*
     * 功能:接收串口过来的数据
     **/
    /*void uart_rev_data(uint8_t data)
    {
        uart_rcvd_buf[uart_rcvd_len] = data;
        uart_rcvd_len++; 
    
        if (uart_rcvd_len >= UART_BUFFER_LEN) {
            //清空所有命令
            uart_rcvd_len = 0;
            //my_memset(uart_rcvd_buf,0,sizeof(uart_rcvd_buf));
        } 
    }*/
    
    /*
     * 该函数由库函数调用
     **/
    /*void UART_INT_Func(void)
    {
        uint8_t u8TempData=0;
    
        if(1 == M0P_UART1->ISR_f.RI)
        {    
            u8TempData = M0P_UART1->SBUF_f.SBUF; 
            uart_rev_data(u8TempData);          
            
            M0P_UART1->ICR_f.RICLR = 0;
        }    
    }*/
    
    /*
     * 功能:检索一帧数据将值赋给结构体       
     * 校验OK return 1;
     **/
    uint8_t parse_dlt645_frame(char *p_frame, uint16_t frame_len, dlt_645_frame_body* sframe_body) {
        uint16_t temp16_t = 0;//一帧数据的总长度
        uint16_t i = 0;
    
        //计算校验码
        for (i = 0; i < frame_len - 3; i ++) {
            temp16_t += p_frame[i];
        }
        if (temp16_t == p_frame[frame_len - 3] | p_frame[frame_len - 2]) {
            sframe_body->st_byte = p_frame[0];
            for (i = 0; i < 6; i ++) {
                sframe_body->address_bytes[i] = p_frame[1+i];
    
            }
            sframe_body->mid_st_byte = p_frame[7];
            sframe_body->control_byte = p_frame[8];
            temp16_t = (p_frame[9]<<8) |p_frame[10];
            sframe_body->data_length = temp16_t;
            for (i = 0; i < temp16_t; i ++) {
                sframe_body->user_data[i] = p_frame[11 + i];
            }
            sframe_body->frame_crc_cs = p_frame[frame_len - 3] | p_frame[frame_len - 2];
            sframe_body->end_byte = p_frame[frame_len - 1];
            
            return 1;
        }
        return 0;
    } 
    
    /*
     * 功能:检索一帧数据将值赋给结构体               
     **/
    uint8_t parse_dlt698_frame(char *p_frame, uint16_t frame_len, dlt_698_frame_body* sframe_body) {
        uint16_t temp16_t = 0;//一帧数据的总长度
        uint16_t adr_temp16_t = 0;//地址域的地址长度
        uint16_t i = 0;
    
        //校验
        for (i = 0; i < frame_len - 3; i ++) {
            temp16_t += p_frame[i];
        }
        if (temp16_t == p_frame[frame_len - 3] | p_frame[frame_len - 2]) {
            
            sframe_body->st_byte = p_frame[0];
            temp16_t = ((p_frame[1]<<8) |p_frame[2]) & 0x3FFF;
            sframe_body->data_length = temp16_t;
            sframe_body->control_byte = p_frame[3];
            sframe_body->address_bytes[0] = p_frame[4];//地址域第一个字节
            adr_temp16_t = p_frame[4] & 0x0F;
            for (i = 0; i < adr_temp16_t; i ++) {
                sframe_body->address_bytes[i] = p_frame[5 + i];
            }
            sframe_body->frame_head_hcs = (p_frame[6 + adr_temp16_t - 1] >> 8) | p_frame[6 + adr_temp16_t];
            for (i = 0; i < temp16_t; i ++) {
                sframe_body->user_data[i] = p_frame[adr_temp16_t + 7];
            }
            sframe_body->frame_crc_fcs = p_frame[frame_len - 3] | p_frame[frame_len - 2];
            sframe_body->end_byte = p_frame[frame_len - 1];
            
            
            return 1;
        }
        return 0;
    } 
    
    /*
     * 功能:从缓存区buf中检索dlt645帧数据
     * 将一帧数据读取到frame_buf中     
     * line:缓存区0x68开头的数据
     * out:将捡出来的帧复制到该数组中
     * frame_len:捡出来的帧的长度,
     * line_len:缓存区buf中0x68开头的数据长度
     **/
    frame_result_t find_dlt645_frame(char* line, char* out, uint16_t* frame_len, uint16_t line_len) {
        uint16_t frame_length = 0;//一帧数据的总长度
        uint16_t temp_len = 0;
    
        if (line_len < DLT_645_LEAST_LEN) {
            return UNFINISHED;
        }
    
        //判断第七位
        if (line[7] != 0x68) {
            return ERROR;
        }
    
        frame_length = 9;/*帧起始符+地址域+帧起始符+控制域*/
        temp_len = (line[9]<<8) |line[10];//数据data的长度
        printf("645 data len = %d\n", temp_len);
        frame_length = frame_length + 2 + temp_len;/*2-长度域占的字节*/
        frame_length += 3;/*校验码和结束符*/
        if (frame_length > FRAME_BUFFER_LEN) {
            //超过单包缓存区的最大长度
            return ERROR;
        } else {
            if (frame_length <= line_len) {
                if (line[frame_length - 1] == 0x16) {
                    //检到一帧数据                
                    for (temp_len = 0; temp_len < frame_length; temp_len ++) {
                        out[temp_len] = *line;
                        line++;
                    }
                    *frame_len = frame_length;
                    return OK;
                } else {
                    //不满足此协议的0x16结束符
                    return ERROR;
                }
            } else {
                //数据还没接收完整
                return UNFINISHED;
            }
        }
        
        return UNKNOWN;
    }
    
    /*
     * 功能:从缓存区buf中检索dlt698帧数据
     * 将一帧数据读取到frame_buf中     
     * line:缓存区0x68开头的数据
     * out:将捡出来的帧复制到该数组中
     * frame_len:捡出来的帧的长度,
     * line_len:缓存区buf中0x68开头的数据长度
     **/
    frame_result_t find_dlt698_frame(char* line, char* out, uint16_t* frame_len, uint16_t line_len) {
        uint16_t frame_length = 0;//一帧数据的总长度
        uint16_t temp_len = 0;
    
        if (line_len < DLT_698_LEAST_LEN) {
            return UNFINISHED;
        }
        
        frame_length = 4;/*起始符+长度域+控制域*/
        //地址域
        temp_len = line[4] & 0x0F;
        //printf("698 address len = %d\n", temp_len);    
        frame_length = frame_length + 1 + temp_len;
        //帧头校验
        frame_length += 2;
        //用户数据长度
        temp_len = ((line[1]<<8) |line[2]) & 0x3FFF;
        //printf("698 data len = %d\n", temp_len);
        frame_length += temp_len;//data长度
        //
        frame_length += 3;//帧校验+结束符
        if (frame_length > FRAME_BUFFER_LEN) {
            //超过单包缓存区的最大长度
            return ERROR;
        } else {
            if (frame_length <= line_len) {
                if (line[frame_length - 1] == 0x16) {
                    //检到一帧数据                
                    for (temp_len = 0; temp_len < frame_length; temp_len ++) {
                        out[temp_len] = *line;
                        line++;
                    }
                    *frame_len = frame_length;
                    return OK;
                } else {
                    //不满足此协议的0x16结束符
                    return ERROR;
                }
            } else {
                //数据还没接收完整        
                return UNFINISHED;
            }
        }
    
        return UNKNOWN;
    }
    
    
    /*
     * 功能:协议数据解析
     **/
    void parse_buf (void)
    {
        uint16_t frame_length = 0;//一帧数据的总长度
        uint16_t i = 0, temp_len = 0;
        uint8_t has_content = 0;//buf中是否有数据
        uint8_t frame_error = 0;//缓存区当前的数据对所有协议都不满足
        char* p_buf;
        protocol_type_t protl_type = PROTOCOL_UNKNOWN;
        frame_result_t find_frame_re = UNKNOWN;
    
        //用来保存每个协议解析后的结果 
        //frame_results[0] 保存PROTOCOL_DL_T_645协议解析结果
        //frame_results[1] 保存PROTOCOL_DL_T_698协议解析结果
        frame_result_t frame_results[2] = {UNKNOWN, UNKNOWN}; 
    
        has_content = uart_rcvd_pos > 2;
        while (has_content) {
            p_buf = uart_rcvd_buf;
            printf("p_buf = %#x\n", *p_buf);
            //检索0x68开头的数据
            while (*p_buf != 0x68 && p_buf < uart_rcvd_buf + uart_rcvd_pos) {
                p_buf ++;
            }
            
            if (p_buf == uart_rcvd_buf + uart_rcvd_pos) {
                //检索当前包数据,都不包含,清空
                uart_rcvd_pos = 0;
                break;
            }
    
            //uart_rcvd_buf中剩余的数据长度
            temp_len = uart_rcvd_pos - (p_buf - uart_rcvd_buf);
    
            printf("while start has_content uart_rcvd_pos - (p_buf - uart_rcvd_buf) = %d\n", temp_len);
            
            //以下处理不包含校验
            switch(protl_type) {
                case PROTOCOL_UNKNOWN:
                    memset(frame_buf,0,sizeof(frame_buf));
                    find_frame_re = UNKNOWN;
                    frame_error = 0;
                    frame_length = 0;
                    for (i = 0; i < 3; i ++) {
                        frame_results[i] = UNKNOWN;
                    }
                    
                case PROTOCOL_DL_T_645:
                    find_frame_re = find_dlt645_frame(p_buf, frame_buf, &frame_length, temp_len);
                    frame_results[0] = find_frame_re;
                    if (find_frame_re == OK) {
                        printf("\nfind dlt_645 OK frame_buf = %s, frame_length = %d\n", frame_buf, frame_length);
                        printf("\n");                    
                        memset(&s_dlt_645_frame_body, 0, sizeof(dlt_645_frame_body));                
                        if (parse_dlt645_frame(frame_buf, frame_length, &s_dlt_645_frame_body)) {
                            //解析到一包有效数据
                        }
                        break;
                    }
                    
                case PROTOCOL_DL_T_698:
                    find_frame_re = find_dlt698_frame(p_buf, frame_buf, &frame_length, temp_len);
                    frame_results[1] = find_frame_re;
                    if (find_frame_re == OK) {
                        printf("\nfind dlt_698 OK frame_buf = %s, frame_length = %d\n", frame_buf, frame_length);
                        printf("\n");
                        memset(&s_dlt_698_frame_body, 0, sizeof(dlt_698_frame_body));
    
                        break;
                    }
    
                case PROTOCOL_OTHER:
                    //此处添加其他协议解析
                    //break;
                    
                default :
                    if (frame_results[0] == ERROR && frame_results[1] == ERROR) {
                        //缓存区的数据不满足现有协议的解析
                        //继续找下一个0x68起始符
                        p_buf ++;//跳过当前的0x68
                        //检索0x68开头的数据
                        while (*p_buf != 0x68 && p_buf < uart_rcvd_buf + uart_rcvd_pos) {
                            p_buf ++;
                        }
                        
                        if (p_buf == uart_rcvd_buf + uart_rcvd_pos) {
                            //检索当前包数据,都不包含,清空
                            uart_rcvd_pos = 0;
                            break;
                        }
    
                        //找到下一条0x68开头的数据帧
                        frame_error = 1;
                        
                    }
                    break;
            }
    
    
            //当成功检索到一帧数据或缓存区的数据不满足现有协议的解析
            //buf中剩余的有效数据前移
            if (find_frame_re == OK || frame_error) {
                //uart_rcvd_buf剩余的数据长度
                temp_len = uart_rcvd_pos - (p_buf - uart_rcvd_buf) - frame_length;
                if (temp_len > 0) {
                    //当前uart_rcvd_buf中剩余的数据前移
                    for (i = 0; i < temp_len; i ++) {
                        uart_rcvd_buf[i] = *(p_buf + frame_length + i);
                        *(p_buf + frame_length + i) = 0x00;
                    }
                    has_content = 1;//继续循环解析
                } else {
                    //解析过的位清空
                    for (i = 0; i < (p_buf - uart_rcvd_buf) + frame_length; i ++) {
                        uart_rcvd_buf[i] = 0x00;
                    }
                    has_content = 0;
                }
                uart_rcvd_pos = temp_len;
            } else {
                has_content = 0;
            }
            printf("while end has_content = %d, uart_rcvd_pos = %d\n", has_content, uart_rcvd_pos);
            
        }
    
    }
    
    
    int main(void)
    {
    
        uint16_t timer;
    
        //RCH 24MHz 使用内部时钟
        /*Clk_SwitchTo(ClkRCL);
        Clk_SetRCHFreq(ClkFreq24Mhz);
        Clk_SwitchTo(ClkRCH);
    
        //enable module clk
        M0P_CLOCK->PERI_CLKEN_f.GPIO = 1;  //打开GPIO的clk
        M0P_CLOCK->PERI_CLKEN_f.BASETIM = 1;
        M0P_CLOCK->PERI_CLKEN_f.UART1   = 1;
        M0P_CLOCK->PERI_CLKEN_f.I2C   = 1;
    
        //UART init    
        Gpio_SetFunc_UART1TX_P23();
        Gpio_SetFunc_UART1RX_P24();    
    
        M0P_UART1->SCON_f.DBAUD = 1;    //双倍波特率
        timer = 0x10000-((24000000*2)/(115200*32));  //单倍波特率,定时器配置
        //使用basetimer1作为串口的波特率产生器   
        M0P_BT1->CR_f.GATE_P = 0u;
        M0P_BT1->CR_f.GATE   = 0u;
        M0P_BT1->CR_f.PRS    = 0u;
        M0P_BT1->CR_f.TOG_EN = 0u;
        M0P_BT1->CR_f.CT     = 0u;         //定时器模式
        M0P_BT1->CR_f.MD     = 1u;         //重载模式
        M0P_BT1->ARR_f.ARR = timer;
        M0P_BT1->CNT_f.CNT = timer;
        M0P_BT1->CR_f.TR = TRUE;
    
        M0P_UART1->SCON_f.SM01 = 0x1;     //模式1
        M0P_UART1->SCON_f.SM2  = 0;       //多主机通信disable
    
        EnableNvic(UART1_IRQn, 3u, TRUE);
        M0P_UART1->SCON_f.TIEN = 0;
        M0P_UART1->SCON_f.RIEN = 1;    
        M0P_UART1->ICR_f.RICLR = 0;
        M0P_UART1->ICR_f.TICLR = 0;    
        M0P_UART1->SCON_f.REN = 1;*/
    
        **
    

    “测试代码”;

    **

    char* p_temp;
        uint8_t i = 0;
        char dlt_645_frame_msg[38] = {0x06, 0x06,0x68, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x68,0x03, 
                                                                        0x00,0x04, 0x0D, 0x0D, 0x0D, 0x0D, 0x02, 0x0A, 0x16, 
                                                                        0x68, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x68,0x03, 
                                                                        0x00,0x04, 0x0D, 0x0D, 0x0D, 0x0D, 0x02, 0x0A, 0x16};
    
        char dlt_698_frame_msg[34] = {0x06, 0x06,0x68, 0x00, 0x05, 0x0C, 0x01, 0x0A, 0x00, 0xCC,
                                                                        0x0A, 0x0D, 0x0D, 0x0D, 0x0E, 0x0F, 0xCC, 0x16,
                                                                        0x68, 0x00, 0x05, 0x0C, 0x01, 0x0A, 0x00, 0xCC,
                                                                        0x0A, 0x0D, 0x0D, 0x0D, 0x0E, 0x0F, 0xCC, 0x16 };
        
        char error_frame_msg[20] = {0x06, 0x06,0x68, 0x00, 0x05, 0x0C, 0x01, 0x0A, 0x00, 0xCC, 
                                                    0x16, 0x06,0x68, 0x60, 0x05, 0x01, 0x01, 0x0A, 0x00, 0xCC};
    
    
        char dlt_645_frame_msg_half_st[29] = {0x06, 0x06,0x68, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x68,0x03, 
                                                                        0x00,0x04, 0x0D, 0x0D, 0x0D, 0x0D, 0x02, 0x0A, 0x16, 
                                                                        0x68, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x68,0x03};
    
        char dlt_645_frame_msg_half_end[9] = {0x00,0x04, 0x0D, 0x0D, 0x0D, 0x0D, 0x02, 0x0A, 0x16};
        
        
        p_temp = uart_rcvd_buf;
    
    
    //DLT_645 TEST
    #if 0
    
        printf("\n ****** dlt 645 start ******\n");
    
        //stpcpy(uart_rcvd_buf, dlt_645_frame_msg);
        //strcat(uart_rcvd_buf, end_byte);
        memcpy(uart_rcvd_buf, dlt_645_frame_msg, sizeof(dlt_645_frame_msg));
        uart_rcvd_pos = sizeof(dlt_645_frame_msg);
        printf("main start 645 msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        parse_buf();
        printf("\n ****** dlt 645 end ******\n");
    
    #endif
    
    
    //DLT_698 TEST
    #if 0
        printf("\n ****** dlt 698 start ******\n ");
        memcpy(uart_rcvd_buf, dlt_698_frame_msg, sizeof(dlt_698_frame_msg));
        uart_rcvd_pos = sizeof(dlt_698_frame_msg);
        printf("main start 698 msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        parse_buf();
        printf("\n ****** dlt 698 end ******\n ");
    
    #endif
    
    
    //ALL TEST
    #if 0
    
        printf("\n ****** dlt 698 and 645 start ******\n ");
        memcpy(uart_rcvd_buf + uart_rcvd_pos, dlt_698_frame_msg, sizeof(dlt_698_frame_msg));
        uart_rcvd_pos += sizeof(dlt_698_frame_msg);
        memcpy(uart_rcvd_buf + uart_rcvd_pos, dlt_645_frame_msg, sizeof(dlt_645_frame_msg));
        uart_rcvd_pos += sizeof(dlt_645_frame_msg);
        
        printf("main start 698 and 645 msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        //parse_buf();
        printf("\n ****** dlt 698 and 645 end ******\n ");
    
    #endif
    
    //Error msg TEST
    #if 1
        printf("\n ****** dlt error msg start ******\n ");
        memcpy(uart_rcvd_buf + uart_rcvd_pos, error_frame_msg, sizeof(error_frame_msg));
        uart_rcvd_pos += sizeof(error_frame_msg);
        printf("main start error msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        //parse_buf();
        printf("\n ****** dlt error msg end ******\n ");
    
    #endif
    
    
    //Half test
    #if 1
    
        printf("\n ****** dlt 645 half start ******\n ");
        memcpy(uart_rcvd_buf + uart_rcvd_pos, dlt_645_frame_msg_half_st, sizeof(dlt_645_frame_msg_half_st));
        uart_rcvd_pos += sizeof(dlt_645_frame_msg_half_st);
        parse_buf();
    
        printf("\n ****** dlt 645 half middle +++ ******\n ");
        
        memcpy(uart_rcvd_buf + uart_rcvd_pos, dlt_645_frame_msg_half_end, sizeof(dlt_645_frame_msg_half_end));
        uart_rcvd_pos += sizeof(dlt_645_frame_msg_half_end);
    
        printf("main start 645 half msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        printf("\n ****** dlt 645 half end ******\n ");
    
    #endif
    
    //ALL TEST
    #if 1
    
        printf("\n ****** dlt 698 and 645 start ******\n ");
        memcpy(uart_rcvd_buf + uart_rcvd_pos, dlt_645_frame_msg, sizeof(dlt_645_frame_msg));
        uart_rcvd_pos += sizeof(dlt_645_frame_msg);
        memcpy(uart_rcvd_buf + uart_rcvd_pos, dlt_698_frame_msg, sizeof(dlt_698_frame_msg));
        uart_rcvd_pos += sizeof(dlt_698_frame_msg);
        memcpy(uart_rcvd_buf + uart_rcvd_pos, dlt_645_frame_msg, sizeof(dlt_645_frame_msg));
        uart_rcvd_pos += sizeof(dlt_645_frame_msg);
        
        printf("main start 698 and 645 msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        printf("\n ****** dlt 698 and 645 end ******\n ");
    
    #endif
    
    //Error msg TEST
    #if 1
        printf("\n ****** dlt error msg start ******\n ");
        memcpy(uart_rcvd_buf + uart_rcvd_pos, error_frame_msg, sizeof(error_frame_msg));
        uart_rcvd_pos += sizeof(error_frame_msg);
        printf("main start error msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        //parse_buf();
        printf("\n ****** dlt error msg end ******\n ");
    
    #endif
    
        parse_buf();
    
        printf("main end msg uart_rcvd_buf = %s, uart_rcvd_pos = %d\n", uart_rcvd_buf, uart_rcvd_pos);
        
    }
    
    展开全文
  • 做了一个简单的demo,基本功能是使用串口助手,向stm32f103的串口3发送一个简单的json数据数据包括两个键值对ed0、led1,当led0键值为1时电路板上面LED灯由熄灭变亮(由灭变亮),led1同理 一、何为json? JSON是...

    stm32f103C8T6使用cjson库

    本章文章主要是记录一下最近学习的keil解析cjson数据,如有不对的地方请各位前辈指正。
    做了一个简单的demo,基本功能是使用串口助手,向stm32f103的串口3发送一个简单的json数据,数据包括两个键值对ed0、led1,当led0键值为1时电路板上面LED灯由熄灭变亮(由灭变亮),led1同理
    

    一、何为json?

    JSON是一种基于文本,独立于语言的轻量级数据交换格式,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
    JSON的两种表示结构对象、数组。
    对象结构:
    	以 “{”开始
    	以 “}”结束
    	中间部分由0或多个以”,”分隔的”key(关键字)/value(值)”对构成,关键字和值之间以”:”分隔
    
    {
        key1:value1,
        key2:value2,
        ...
    }
    
    数组结构:
    	以”[”开始
    	以”]”结束
    	中间由0或多个以”,”分隔的值列表组成,
    
    [
        {
            key1:value1,
            key2:value2 
        },
        {
             key3:value3,
             key4:value4   
        }
    ]
    

    二、使用步骤

    1.下载cjson文件

    cjson文件下载

    2.移植库

    1.将cJSON,malloc源文件到工程的根目录下:
    在这里插入图片描述

    2.将cJSON,malloc文件添加至头文件路径、项目文件内:
    在这里插入图片描述
    在这里插入图片描述
    3.修改cJSON.c
    由于这个工程使用正点原子的工程模板,里面定义的有malloc.c、malloc.h,我们需要把cJSON的malloc 和free替换成我们自己的。
    在cJSON.c添加头文件:

    #include "malloc.h"
    

    将cJSON.c文件46、47行修改为:

    static void *(*cJSON_malloc)(size_t sz) = mymalloc;
    static void (*cJSON_free)(void *ptr) = myfree;
    

    4.修改malloc.h
    在这里插入图片描述

    3.cjson解析函数

    void parse_led(const char *JSON)
    {
    	cJSON *json,*led0 , *led1;
    	printf("解析前的数据:%s\r\n",JSON);
    	json = cJSON_Parse(JSON);//解析串口的JSON数据
    	if(json==NULL)
    	{
    		printf("json语法错误:[%s] \r\n",cJSON_GetErrorPtr());//输出语法错误的位置
    	}
    	else
    	{
    		led0 = cJSON_GetObjectItem(json,"led0");
    		led1 = cJSON_GetObjectItem(json,"led1");
    		printf("led0=%d \r\n",led0->valueint);
    		printf("led1=%d \r\n",led1->valueint);
    		if(led0->valueint == 1)LED0=~LED0;
    		if(led1->valueint == 1)LED1=~LED1;
    	}
    	cJSON_Delete(json); // 释放内存
    }
    

    4.串口中断函数

    void USART3_IRQHandler(void)                	//串口1中断服务程序
    	{
    	u8 Res;
    #if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    	OSIntEnter();    
    #endif
    		if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    		{
    			Res = USART_ReceiveData(USART3);
    			USART_RX_BUF[USART_RX_STA++] = Res;  		 
    		}		
    	 if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)  //接收中断(接收到的一帧数据)
    		{		
    			Res =  USART3->SR; //读SR寄存器
    			Res =  USART3->DR; //读DR寄存器  先读SR再度DR目的是清除IDLE中断标志。	
    			USART_RX_STA=0;	//LED0=!LED0;
    			uart3_flag = 1;			
    		}
    //				parse_led((const char *)USART_RX_BUF);
    #if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    	OSIntExit();  											 
    #endif
    } 
    

    5.主函数

    int main()
    {
        uart3_init(115200);
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    	delay_init();
    	LED_Init();
        while(1)
    	{
    		if(uart3_flag==1)
    		{
    			uart3_flag=0;
    			delay_ms(10);
    			parse_led((const char*)USART_RX_BUF);	
    		}
        }
    }
    

    三、工程测试

    打开串口助手,波特率打到115200发送:

    {"led0":1.23,"led1":1}
    

    在这里插入图片描述
    打开串口,以文本发送数据后,可以看到led灯变化,串口返回:

    解析前的数据:{"led0":1.23,"led1":1}}
    led0=1 
    led1=1 
    

    四.测试工程下载

    stm32_test.zip

    展开全文
  • // 存储数据的集合 public void PortDataReceived(object sender, SerialDataReceivedEventArgs e) { if (null == _port || !_port.IsOpen || isClosing) { return; } int n = _port.BytesToRead;//先记录下来,避免...

    `

    帧结构
    根据帧结构,定义状态机为 帧头第一个字节,帧头第二个字节,帧头第三个字节,帧长,帧ID

     private List<byte> bufferZone = new List<byte>(10000);
            public void PortDataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                if (null == _port || !_port.IsOpen || isClosing)
                {
                    return;
                }
                int n = _port.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
                byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
                _port.Read(buf, 0, n);//读取缓存数据;
                bufferZone.AddRange(buf);
                for (int i = 0; i < bufferZone.Count; i++)
                {
                    int rcyByte = bufferZone[i];
                    //Console.WriteLine("接收到的字节" + rcyByte.ToString("X2"));
                    _sb.Append(rcyByte.ToString("X2") + " ");
                    switch (_dataState)
                    {
                        case FrameDataRecvState.HEAD_FRIST:
                            _framByteList.Clear();
                            if (rcyByte == GlobalData.HEAD_FRIST)
                            {
                                //  Console.WriteLine("收到帧头的第一个字节: ");
                                _dataState = FrameDataRecvState.HEAD_SECOND;
                            }
                            break;
                        case FrameDataRecvState.HEAD_SECOND:
                            if (rcyByte == GlobalData.HEAD_SECOND)
                            {
                                //  Console.WriteLine("收到帧头的第二个字节: ");
                                _dataState = FrameDataRecvState.HEAD_THIRD;
                            }
                            else
                            {
                                _dataState = FrameDataRecvState.HEAD_FRIST;
                            }
                            break;
                        case FrameDataRecvState.HEAD_THIRD:
                            if (rcyByte == GlobalData.HEAD_THIRD)
                            {
                                //Console.WriteLine("收到帧头的第三个字节: ");
                                _dataState = FrameDataRecvState.FRAM_LENGTH;
                            }
                            else
                            {
                                _dataState = FrameDataRecvState.HEAD_FRIST;
                            }
                            break;
                        case FrameDataRecvState.FRAM_LENGTH:
                            // 判断帧长
                            _framDataLength = rcyByte & 0x3f;
                            if (_framDataLength > 61)
                            {
                                //帧长不符合协议规范
                                _dataState = FrameDataRecvState.HEAD_FRIST;
                                //Console.WriteLine("帧长大于最大值:  帧长为==========" + _framDataLength);
                            }
                            else
                            {
                                //  Console.WriteLine("收到帧长数据: " + _framDataLength);
                                //帧长符合协议规范
                                _framByteList.Add(Convert.ToByte(rcyByte));
                                _dataState = FrameDataRecvState.FRAM_ID;
                            }
                            break;
                        case FrameDataRecvState.FRAM_ID:
                            // 判断是否正确的帧ID
                            if (_framIdHashSet.Contains(rcyByte))
                            {
                                //  Console.WriteLine("是正确的帧ID: ");
                                // 是正确的帧ID
                                _dataState = FrameDataRecvState.FRAM_DATA;
                                _framByteList.Add(Convert.ToByte(rcyByte));
                            }
                            else
                            {
                                // Console.WriteLine("帧ID错误: " + rcyByte);
                                _dataState = FrameDataRecvState.HEAD_FRIST;
                                _framByteList.Clear();
                            }
                            break;
                        case FrameDataRecvState.FRAM_DATA:
                            // 接收数据,对数据进行校验,校验通过,进行数据解析
                            // 校验不通过,清空解析数据缓冲区                       
                            //   Console.WriteLine("开始接收数据: ");
                            _framByteList.Add(Convert.ToByte(rcyByte));
                            if (_framByteList.Count == _framDataLength)
                            {
                                // 校验数据
                                byte xorByte = GetXor(_framByteList);
                                byte jiaoyan = _framByteList[_framByteList.Count - 1];
                                if ((xorByte ^ jiaoyan) == 0)
                                {
                                    // Console.WriteLine("校验通过,对数据解析: ");
                                    // 另外开线程处理
                                    List<byte> parseList = new List<byte>();
                                    parseList.AddRange(_framByteList);
                                    Thread ParseDataThread = new Thread(new ParameterizedThreadStart(ParseDataThreadMethod));
                                    ParseDataThread.Start(parseList);
                                }
                                _framByteList.Clear();
                                _dataState = FrameDataRecvState.HEAD_FRIST;
                            }
                            break;
                        default:
                            break;
                    }
                }
                bufferZone.RemoveRange(0,n);
            }
    
    
    展开全文
  • 解析串口通信数据

    2017-09-17 14:34:51
    MFC编程中,串口传输的原理,串口数据传输过程及电平转换,RS232的引脚定义,电气特性,传输格式,接收过程,配波形图
  • linux C串口数据解析

    2020-08-31 17:06:01
    @解析串口数据 串口初始化及配置 下面展示一些 串口相关初始化。 /相关初始化/ pthread_t pSerial; static const char *device = "/dev/ttyS1"; static int uartFd = 0; int speed_arr[] = { B921600, B460800, B...
  • vc串口数据解析

    2018-01-22 16:05:26
    串口数据解析,vc读取串口数据,获取完整数据包并解析出其中数据 抱歉,上传时默认了下载所需积分,之后不能编辑,下载了的可以联系我返还部分积分
  • 解析串口通信数据格式DB-9 针连接头(从计算机连出的线的截面,公头)。\ 1 2 3 4 5 /\ 6 7 8 9 /RS-232 针脚的功能:(红色的线是常用的)数据:TXD (pin 3):串口数据输出RXD (pin 2):串口数据输入握手:RTS (pin 7)...
  • 这是解析串口数据的函数 ``` if (listReceive.Count ) return; for (int i = 0; i ; i++) { High2Arr[i] = (listReceive[listReceive.Count - 1 - i] & 0x00) >> 6;//高两位状态 if (High2Arr[i] == 2) ...
  • 串口数据读取解析

    2014-01-17 11:17:37
    c#,通过调用类函数来进行各种串口数据的操作与协议解析,经过大量使用、稳定可靠,希望对串口编写人员有所帮助。
  • 功能:解析串口数据(此程序中以回车符作为解析对象,如需要解析其他字符可以自行参考修改),并将解析后的串口数据通过Wi-Fi透传。 测试过程:使用PC端串口助手软件,通过串口分别按照115200至1382400波特率(实际...
  • 通过标准的OBD II接口和标准的OBD外壳,直接插车上OBD即可获取到相应的车辆信息,然后通过串口的方式输出,方便对OBD诊断不太熟悉,但是又想获取车辆信息的开发者。 可以很方便的对接第三方设备、系统。
  • OBD智能数据解析串口数据手册V3.0

    千次阅读 2019-08-14 10:05:11
    该模块实现一头连接汽车OBD诊断接头,然后另一头将获取到的车辆信息,通过串口的形式输出。方便即使在不了解汽车CNA总线和OBD诊断技术的情况下,也可以实现车辆信息的获取。可以将这个模块等效为一个车辆信息获取的...
  • QT串口数据解析

    2021-02-26 10:50:47
    数据解析 /******************************************************************* * 函数功能:接收遥控器传来的数据并进行解析 * 调用:放在定时器中断服务函数中定时接收 * 时间:2020.12.5 *****************...
  • 串口数据解析总结

    2018-03-27 19:21:00
    在linux下编写串口通讯程序,采用select监听串口的可读事件,一旦可读,调用read。但是我们会发现,read一次得到的数据通常不是完整的一个数据帧。 比如完整数据帧为 但是实际上需要read多次才能完全读到。 ...
  • 首先就想到了使用python脚本来完成数据解析与打包,网上也查了不少资料,最终实现模拟数据来完成代码的调试,脚本主要使用了python的两个模块serial(串口操作)与struct(打包成c语言的字节串)。 serial模块 ...
  • Python串口数据打包发送STM32接收数据解析
  • 本程序vs2013平台用c#开发,包含北斗部分通信应用协议的串口数据解析,其中协议为北斗协议为4.0通用版,大家可放心下载使用。
  • 本程序功能是Arduino R3串口通讯时,解析接收到的数据

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,529
精华内容 611
关键字:

解析串口数据