精华内容
下载资源
问答
  • 关于遥控器与无人机飞控之间的通信协议有很多种,常见的数据协议如下:1、PWM:需要在接收机上接上全部PWM输出通道,每一个通道就要接一组线,解析程序需要根据每一个通道的PWM高电平时长计算通道数值。2、PPM:按...

    关于遥控器与无人机飞控之间的通信协议有很多种,常见的数据协议如下:

    1、PWM:需要在接收机上接上全部PWM输出通道,每一个通道就要接一组线,解析程序需要根据每一个通道的PWM高电平时长计算通道数值。

    2、PPM:按固定周期发送所有通道PWM脉宽的数据格式,一组接线,一个周期内发送所有通道的PWM值,解析程序需要自行区分每一个通道的PWM时长。

    3、S.BUS:每11个bit位表示一个通道数值的协议,串口通信,但是S.BUS的接收机通常是反向电平,连接到无人机时需要接电平反向器,大部分支持S.BUS的飞行控制板已经集成了反向器,直接将以旧换新机连接到飞行控制器即可。

    4、XBUS:常规通信协议,支持18个通道,数据包较大,串口通信有两种模式,可以在遥控器的配置选项中配置。接收机无需做特殊配置。

    dc0a3afbec01446d4f0e97eea9a5f0d7.png

    一、PWM协议

    PWM信号用于控制单个电调或者单个舵机脉冲宽度调制信号。

    86449f33ac11485255a91aeae5a935f1.png

    电机(电调)上用到PWM信号种类很多,此处对常见的PWM信号特征进行描述:

    1、 PWM信号是一个周期性的方波信号,周期为20ms,也就是50Hz的刷新频率。

    2、 PWM每一周期中的高电平持续时间为1~2ms(1000us~2000us),代表了油门控制量。一般四旋翼中,使用1100~1900us,1100us对应0油门,1900us对应满油门。

    PCM是英文pulse-code modulation的缩写,中文的意思是:脉冲编码调制,又称脉码调制。PPM是英文pulse position modulation的缩写,中文意思是:脉冲位置调制,又称脉位调制,这里顺便提一句,有些航模爱好者误将PPM编码说成是FM,其实这是两个不同的概念。前者指的是信号脉冲的编码方式,后者指的是高频电路的调制方式。比例遥控发射电路的工作原理如图1所示。操作通过操纵发射机上的手柄,将电位器组值的 变化信息送人编码电路。编码电路将其转换成一组脉冲编码信号(PPM或PCM)。这组脉冲编码信号经过高频调制电路(AM或FM)调制后,再经高放电路发送出去。PPM的编解码方式一般是使用积分电路来实现的,而PCM编解码则是用模/数(A/D)和数/模(D/A)转技术实现的。

    目前,比例遥控设备中最常用的两种脉冲编码方式就是PPM和PCM:最常用的两种高频调制方式是FM调频和AM调幅:最常见的组合为PPM/AM脉位调制 编码/调幅、PPM/FM脉位调制编码/调频、PPM/FM脉冲调只编码/调频三种形式。通常的PPM接收解码电路都由通用的数字集成电路组成,如 CD4013,CD4015等。对于这类电路来说,只要输入脉冲的上升沿达到一定的高度,都可以使其翻转。这样,一旦输入脉冲中含有干扰脉冲,就会造成输 出混乱。由于干扰脉冲的数量和位置是随机的,因此在接收机输出端产生的效果就是“抖舵”。除此之外,因电位器接触不好而造成编码波形的畸变等原因,也会影 响接收效果,造成“抖舵”。对于窄小的干扰脉冲,一般的PPM电路可以采用滤波的方式消除;而对于较宽的干扰脉冲,滤波电路就无能为力了。这就是为什么普 通的PPM比例遥控设备,在强干扰的环境下或超出控制范围时会产生误动作的原因。尤其是在有同频干扰的情况下,模型往往会完全失控。

    二、PPM协议

    每一个遥控器通道都需要一个PWM采集器进行采集,但是对于STM32来说不可能使用多个定时器来采集多个通道的PWM,这对于STM32的资源来说十分浪费。因此采用的就是PPM编码。PPM编码是PWM的扩展协议,可以在一个管脚中传输多路PWM信号。

    PPM协议只需要一根线就可以传输,避免了PWM需要多路才能传输多个通道的问题。下面是PPM协议的波形图:

    84d2e2eb35dcd0ba889160941b9dde05.png

    PPM协议最多传输20个通道,使用一个定时器就可以轻松解决了。

    PPM的频率通常是50Hz,周期长度20ms,每一个周期中可以存放最多10路PWM信号,每一路PWM的周期为2ms,如下图所示:

    7cb7073113a3a75f4f8719082c780d95.png

    9bf45752bd5f5bc99bdc11d530e75807.png

    使用STM32的管脚中断配合定时器中的计数可以准确的捕获一个周期内的PPM信号中的高低电平变化,每2ms就是一路PWM信号的周期。每个通道信号脉宽0~2ms,变化范围为1~2ms之间。1帧PPM信号长度为20ms,理论上最多可以有10个通道,但是同步脉冲也需要时间,模型遥控器最多9个通道。

    PPM转PWM示例:

    PPM和PWM的对应关系如下图:

    1efca57709c2c0d8765dbed4740733d4.png

    遥控接收器接收到遥控指令,输出PPM信号,PPM信号经过PPM解码电路输出8路PWM信号。

    f310dfca018d57645b045ce0febc512e.png

    上图为多个通道的PWM信号通过PPM编码电路转化PPM信号输出。

    三、S.BUS协议

    S.BUS本质是一种串口通信协议,使用的是TTL电平的反向电平,即标准TTL中的1取反为0,而0则取反为1,采用100K的波特率,8位数据位,2位停止位,偶校验,即8E2的串口通信。

    S.BUS是一个接收机串行总线输出,通过这根总线,可以获得遥控器上所有zhi通道的数据。目前很多模型及无人机电子设备都支持S.BUS总线的接入。使用SBUS总线获取通道数据,效率高的,而且节省硬件资源,只需要一根线即可获取所有通道的数据。

    值得注意的有三点:

    (一)S.BUS采用负逻辑,所以无论接收还是发送都要进行硬件取反(注意,一定要硬件取反),电路如下(这是网上看资料时看到的电路,实际上可以使用7404电路):

    032a882b2ee557aac8eca957c28b67d3.png

    (二)S.BUS有两种模式:

    a.高速模式:每4ms发送一次;

    b.低速模式:每14ms发送一次。就是说每间隔4或者14ms这个串口就发送25个字节的数据,这25个字节的数据最多可以包含16个信息。

    (三)100K的波特率不是标准波特率,一般串口工具都不能直接读取(所以不要直接用电脑调试,除非你的电脑写好了非标准串口),可以用单片机读取。

    S.BUS具体协议的格式如下:

    [数据头] [第一个字节] [第二个字节] ......[第二十二字节] [标志位] [数据尾];

    数据头、标志位、数据尾不携带信息,而且数据头和数据尾是固定的,数据头=0x0f, 数据尾=0x00;

    数据头(1字节)+数据(22字节)+标志位(1字节)+数据尾(1字节) 。

    解释如下:

    S.BUS一帧数据的长度为25个字节,其中:

    第"0"个字节为帧头:0x0f;

    第24个字节为帧尾:0x00;

    从第1个字节到第22个字节为1-16号比例通道的数据字节;

    第23字节中,第7位为数字开关通道17通道,第6位为数字开关通道18通道;第5位为帧状态标志为(判断是否丢帧),用于控制接收机上的LED的状态,第4位为失控保护激活标志位,此位为1时,表示接收机进入失控保护状态。

    编解码C语言源码:

    编码原理:

    一个信息是二进制的11bit,比如1111 1111 111就可以表示一个信息,一共16个这样的信息,按照顺序将这16个信息依次排成一串,得到一个176bit(11 *16)的数据,也就是22字节(176 / 8 = 22)的数据,再加上数据头数据尾校验位就组成了一个要通过串口传送的信息。每隔4或者14ms就传送一个这样的信息。所以这16个信息每一个所能表示的最大值是2^11 = 2048,也就是它的精度。

    标志位

    标志位的高四位有特殊含义,第四位并没有使用,依照我的理解,第七位和第六位表示两个数字通道(通道17和18)信息(就是只有高低电平的通道,一般用来控制通断或者某个电机简单的启动或者停止,比如1表示启动电机0表示停止电机),第五位表示帧丢失,接收机红色LED亮起,我的理解是,如果这一位为1,表示这一帧信号出问题了,接收机红色LED亮起。第四位表示故障保护激活,意思应该是说如果这一位为1,激活接收方故障保护。

    展开全文
  • 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);
        
    }
    
    展开全文
  • 首先就想到了使用python脚本来完成数据的解析与打包,网上也查了不少资料,最终实现模拟数据来完成代码的调试,脚本主要使用了python的两个模块serial(串口操作)与struct(打包成c语言的字节串)。 serial模块 ...

    概述

    前段时间做一个项目,我们的系统使用串口与MCU进行数据交互,系统侧代码已按照双方约定的数据包协议写好了解析与发送数据的代码,但是MCU侧还未完成代码,我们不能等待他们完成之后在进行代码的调试,这样会耽误项目的进度,网上查阅了相关资料后。最后决定使用python脚本来完成数据的解析与打包进行模拟测试,网上也查了不少资料,最终实现了模拟数据完成了代码的调试,此脚本主要使用了python的两个模块serial(串口操作)与struct(打包成c语言的字节串)。一些简要说明:

    serial模块

    主要用户串口操作,网络上资料也挺多的,这里直接上代码进行注释说明

    class ComThread:
     def __init__(self, Port='COM56'): #打开COM56
      self.l_serial = None 
      self.alive = False
      self.waitEnd = None
      self.port = Port
      self.ID = None
      self.data = None
    
     def waiting(self):
      if not self.waitEnd is None:
       self.waitEnd.wait()
    
     def SetStopEvent(self):
      if not self.waitEnd is None:
       self.waitEnd.set()
      self.alive = False
      self.stop()
    
     def start(self):
      self.l_serial = serial.Serial()
      self.l_serial.port = self.port
      self.l_serial.baudrate = 115200 #串口波特率
      self.l_serial.timeout = 2 #超时时间
      self.l_serial.open()
      if self.l_serial.isOpen():
       self.waitEnd = threading.Event()
       self.alive = True
       self.thread_read = None
       self.thread_read = threading.Thread(target=self.FirstReader)
       self.thread_read.setDaemon(1)
       self.thread_read.start()
       return True
      else:
       return False
    
     def SendDate(self,i_msg,send):
      #lmsg = ''
      isOK = False
      #发送数据到相应的处理组件
      print(i_msg)
      send_buf = nwy_create_send_msg(i_msg, send)
      self.l_serial.write(send_buf)
      print("send success")
      return True
     def FirstReader(self):
      while self.alive:
       time.sleep(0.1)
       data = ''
       data = data.encode('utf-8')
       n = self.l_serial.inWaiting()
       if n:
        data = data + self.l_serial.read(n)
        print(len(data))#打印收到的数据
        print(data.hex()) #按照十六进制打印
    
     def stop(self):
      self.alive = False
      self.thread_read.join()
      if self.l_serial.isOpen():
       self.l_serial.close()
       
    def quit(signum, frame):
     print("Bye Bye!")
     sys.exit(0)
    
    #调用串口,测试串口
    def main():
     rt = ComThread()
     rt.sendport = '**1*80*'
     try:
      if  rt.start():
       signal.signal(signal.SIGINT, quit)
       print(rt.l_serial.name)
       #rt.waiting()
       #print("The data is:%s,The Id is:%s"%(rt.data,rt.ID))
       #t.stop()
      else:
       pass
     except Exception as se:
      print(str(se))
      print ('End OK .')
     return rt
    
    if __name__ == '__main__':
     mSerial = main()
     while True:
      time.sleep(1)
    

    struct模块

    串口数据解析,这里并没有使用unpack进行解析,这里是按照当前的定义进行的解析

    def parse_read_data(data, len):
     print(data)
     print(len)
     #check head
     if 0x0F != data[0]:#判断数据头
      print ("head is not 0x0F data head is " + hex(data[0]))
      return False
     #get msg id 
     msg_id = data[1] << 8 | data[2] #获取消息ID
     msg_len = data[3] << 8 | data[4] #获取数据长度
     data_crc = data[7+msg_len] #获取数据的校验和
     Cal_crc = Calculation_crc(data[1:len-2]) #计算数据的校验和
     if data_crc != Cal_crc: #判断数据的校验和
      print ("crc error ")
      return False
     print ("data is good")
      #do something 
     #处理数据 
     return True
    

    将需要发送的数据打包成固定格式的字节串,具体打包要按照实际的协议打包 ,strcut的详细解释资料太多,这里不再赘述

    def create_send_msg(i_msg, send):
     msg_len = len(send)
     msg_len_2 = ~msg_len
     #下面就类似于c预言的printf 不过可以查查struct中对应的类型
     # !表示大端
     # H unsigned short
     # h singned short 这里用h主要是长度的反码如果有无符号会提示存不下,所以用有符号
     # %ds 这个比较特殊,s为字节串,长度为%d 
     # B byte
     psh = struct.pack('!HHh%ds'%len(send), i_msg, msg_len, msg_len_2,send)
     # 计算crc
     crc = Calculation_crc(psh)
      # c语言的结构体定义如下
     # struct{
     #  unsigned char  header
     #  unsigned short msgid
     #  unsigned short msglen
     #  signed short   unmsglen
     #  char *data
     #  unsigned char   crc
     #  unsigned char   end
     # }
     pshhh = struct.pack('!BHHh%dsBB' %len(send), MSG_HEADER, i_msg, msg_len, msg_len_2,send, crc, MSG_END)
     return pshhh
    

    完整的示例代码如下

    import struct
    import binascii
    import sys
    import signal
    import threading
    import time
    import serial
    import random
    MSG_HEADER=0x0F
    MSG_END=0xF0
    MCU_MSG_ID=0x0001
    
    def create_send_msg(i_msg, send):
     msg_len = len(send)
     msg_len_2 = ~msg_len
     #下面就类似于c预言的printf 不过可以查查struct中对应的类型
     # !表示大端
     # H unsigned short
     # h singned short 这里用h主要是长度的反码如果有无符号会提示存不下,所以用有符号
     # %ds 这个比较特殊,s为字节串,长度为%d 
     # B byte
     psh = struct.pack('!HHh%ds'%len(send), i_msg, msg_len, msg_len_2,send)
     # 计算crc
     crc = Calculation_crc(psh)
      # c语言的结构体定义如下
     # struct{
     #  unsigned char  header
     #  unsigned short msgid
     #  unsigned short msglen
     #  signed short   unmsglen
     #  char *data
     #  unsigned char   crc
     #  unsigned char   end
     # }
     pshhh = struct.pack('!BHHh%dsBB' %len(send), MSG_HEADER, i_msg, msg_len, msg_len_2,send, crc, MSG_END)
     return pshhh
    
    def send_mcu_data(data):
     msg = "FF000000FFECFFD7FC03000000000000"; #模拟的一包数据
     by = binascii.a2b_hex(msg)
     mSerial.SendDate(MCU_MSG_ID, by)
     return
    
    #计算校验和  
    def Calculation_crc(data): 
     crc = 0
     for i in range(len(data)): 
      crc ^= data[i]
     return crc
    
    def parse_read_data(data, len):
     print(data)
     print(len)
     #check head
     if 0x0F != data[0]:#判断数据头
      print ("head is not 0x0F data head is " + hex(data[0]))
      return False
     #get msg id 
     msg_id = data[1] << 8 | data[2] #获取消息ID
     msg_len = data[3] << 8 | data[4] #获取数据长度
     data_crc = data[7+msg_len] #获取数据的校验和
     Cal_crc = Calculation_crc(data[1:len-2]) #计算数据的校验和
     if data_crc != Cal_crc: #判断数据的校验和
      print ("crc error ")
      return False
     print ("data is good")
      #do something 
     #处理数据 
     return True
    class ComThread:
     def __init__(self, Port='COM56'):
      self.l_serial = None
      self.alive = False
      self.waitEnd = None
      self.port = Port
      self.ID = None
      self.data = None
     def waiting(self):
      if not self.waitEnd is None:
       self.waitEnd.wait()
     def SetStopEvent(self):
      if not self.waitEnd is None:
       self.waitEnd.set()
      self.alive = False
      self.stop()
    
     def start(self):
      self.l_serial = serial.Serial()
      self.l_serial.port = self.port
      self.l_serial.baudrate = 230400
      self.l_serial.timeout = 2
      self.l_serial.open()
      if self.l_serial.isOpen():
       self.waitEnd = threading.Event()
       self.alive = True
       self.thread_read = None
       self.thread_read = threading.Thread(target=self.FirstReader)
       self.thread_read.setDaemon(1)
       self.thread_read.start()
       return True
      else:
       return False
     def SendDate(self,i_msg,send):
      send_buf = create_send_msg(i_msg, send)
      self.l_serial.write(send_buf)
      print("send success")
      return True
    
     def FirstReader(self):
      while self.alive:
       time.sleep(0.1)
       data = ''
       data = data.encode('utf-8')
       n = self.l_serial.inWaiting()
       if n:
        data = data + self.l_serial.read(n)
        #print(len(data))
        #print(data.hex())
        parse_read_data(data, len(data))
     def stop(self):
      self.alive = False
      self.thread_read.join()
      if self.l_serial.isOpen():
       self.l_serial.close()
      def quit(signum, frame):
     print("Bye Bye!")
     sys.exit(0)
    #调用串口,测试串口
    def main():
     rt = ComThread()
     rt.sendport = '**1*80*'
     try:
      if  rt.start():
       signal.signal(signal.SIGINT, quit)
       print(rt.l_serial.name)
      else:
       pass
     except Exception as se:
      print(str(se))
      print ('End OK .')
     return rt
    if __name__ == '__main__':
     mSerial = main()
     while True:
      time.sleep(1)
      #发送给系统数据
      send_mcu_data(mSerial)
    
    

    以上就是我的分享,如果有需要探讨的可以加qq 991410485

    展开全文
  • C语言之面向对象

    2020-09-01 12:18:11
    C语言之面向对象_网关 概述 嵌入式设备与外界通信大多是串口,若想通过以太网、WIFI、BLE等通信... 协议解析器; 具体通信行为–> 命令解析器 模块解析 2.1 协议解析器 2.1.1 数据结构 struct ProtocolInte

    C语言之面向对象_网关

    1. 概述
      嵌入式设备与外界通信大多是串口,若想通过以太网、WIFI、BLE等通信,则需要外接对应的模块来实现,但每种通信方式对应的网络协议却不相同,
      为了实现代码复用及减少模块间的耦合,借用面向对象的方式: 只关注通信的属性:接收,处理,发送; 至于具体的通信行为,则由每个通信协议内部实现。
      将上述分为两个模块:通信的属性–> 协议解析器; 具体通信行为–> 命令解析器

    1. 模块解析
      2.1 协议解析器
      2.1.1 数据结构
    			struct ProtocolInterfaceStruct		//协议接口
    			{
    				void (*Protocol_Init) (Protocol_Init_parameters);
    				void (*Protocol_process) (Protocol_process_parameters);
    				void (*Protocol_sender) (Protocol_sender_parameters);
    				void (*Protocol_error) (Protocol_error_parameters);
    			}
    			
    			typedef ProtocolInterfaceStruct *ProtocolInterface;
    			typedef protocol_struct *Protocol;
    			
    			struct protocol_struct			//协议结构
    			{
    				char* protocol_name;
    				E_PROTOCOL_TYPE protocol_type;
    				ProtocolInterface protocol_interface;
    			}
    
    	2.1.2 模块伪代码实现
    		2.1.2.1 协议模块
    			每个协议创建一个.c文件: uart.c, ble.c, tcp.c ```
    			在每个.c 文件中创建上述结构体实例。
    			例如uart.c中:
    
    				static struct ProtocolInterface g_uart_protocol_interface = 
    				{
    					uart_init,
    					uart_process,
    					uart_sender,
    					uart_error
    				};
    				static struct protocol_struct g_uart_protocol = 
    				{
    					"uart_protocol",
    					P_UART,
    					&g_uart_protocol_interface;
    				};
    				//获取protocol的处理函数
    				Protocol Uart_Get_Protocol_Handler(void)
    				{
    					return &g_uart_protocol;
    				}
    
    		2.1.2.2 通用模块
    			在外部通用文件里,例如 protocol.c, 
    
    				Protocol_Init();
    				Protocol_Process();
    				Protocol_Sender();
    				Protocol_error();
    				
    				通过串口号获取对应protocol 的处理函数:
    				Protocol Get_Protocol_Handler(Uart_NUM uart_num)
    				{
    					Protocol protocol = NULL;
    					//check uart_num
    					
    					switch(uart_num)
    					{
    						case uart_usart:
    							protocol = Uart_Get_Protocol_Handler();
    						case ble_usart:
    							protocol = Ble_Get_Protocol_Handler();
    						case tcp_usart:
    							protocol = Tcp_Get_Protocol_Handler();
    						default:
    						break;
    					}
    					return protocol;
    				}
    				协议接口通用函数,例如 初始化:
    				void Protocol_Init(Protocol protocol, Protocol_Init_parameters)
    				{
    					// 检查protocol
    					if( protocol == NULL)
    					{
    						//debug msg
    					}
    					else
    					{
    						protocol->protocol_interface->Protocol_Init(Protocol_Init_parameters);
    					}
    				}
    
    2.2 命令解析器
    	命令解析器:设置一个列表数组,数组索引为协议类型,数组元素包括命令,命令对应的处理函数,最大的命令数等, 初始化时先注册对应的cmd 和 handler, 接收到命令
    	后, 检查命令是否被注册,并调用对应的 cmd_handler , 
    	2.2.1 数据结构
    
    			//命令枚举
    			typedef enum
    			{
    				cmd1,
    				cmd2,
    				cmd3,
    				//```
    			}Protocol_Cmd;
    			//命令处理函数指针
    			typedef Protocol_Return (*Protocol_Handler) (Protocol_Handler_parameters);
    			命令处理结构体
    			struct ProtocolCmdHandler
    			{
    				Protocol_Cmd cmd;				//命令
    				Protocol_Handler handler;		//命令对应的处理函数
    			}
    			typedef struct ProtocolCmdHandler* PROTOCOL_CMD_HANDLER;
    			//命令模块结构体
    			struct Protocol_CMD_Handler_Struct
    			{
    				Uart_NUM uart_num;
    				PROTOCOL_CMD_HANDLER cmd_handler_list;
    				uint16_t max_cmd;
    				bool init_flag;
    			}
    			//命令处理列表
    			static struct Protocol_CMD_Handler_Struct g_protocol_cmd_handler[max_uart_num] = {max_uart_num, NULL, 0, false};
    
    	2.2.2 模块伪代码实现
    		2.2.2.1 通用命令处理函数 protocol_cmd.c
    
    //清空链表
    				Protocol_Command_Handler_Clear();
    				//初始化协议对应列表
    				Protocol_Command_Handler_Init();
    				//协议处理
    				Protocol_Command_Handler_Process();
    				//注册命令处理函数
    				Protocol_Command_Handler_Register();
    				//根据协议获取对应命令的处理函数
    				Protocol_Command_Handler_GetHandle();
    				
    				//初始化
    				void Protocol_Command_Handler_Init(Uart_NUM uart_num, uint16_t max_cmd)
    				{
    					if((uart_num < max_uart_num) &&
    					   (is_protocol_available(uart_num) == true) &&
    					   g_protocol_cmd_handler[uart_num].init_flag == false)
    					{
    						//分配空间
    						g_protocol_cmd_handler[uart_num].uart_num = uart_num;
    						g_protocol_cmd_handler[uart_num].max_cmd_handler = max_cmd;
    						g_protocol_cmd_handler[uart_num].cmd_handler_list = (PROTOCOL_CMD_HANDLER)malloc(max_cmd * sizeof(struct ProtocolCmdHandler));
    
    						if(g_protocol_cmd_handler[uart_num].cmd_handler_list != NULL)
    						{
    							//初始化有链表非空,清空链表
    							Protocol_Command_Handler_Clear(uart_num);
    						}
    
    						g_protocol_cmd_handler[uart_num].init_flag = true;
    					}
    				}
    				//获取命令处理函数
    				PROTOCOL_CMD_HANDLER  Protocol_Command_Handler_GetHandle(Uart_NUM uart_num, Protocol_Cmd command)
    				{
    					PROTOCOL_CMD_HANDLER  handler_p = g_protocol_cmd_handler[uart_num].cmd_handler_list;
    					PROTOCOL_CMD_HANDLER  handler_r = NULL;
    
    					if((uart_num < max_uart_num) &&
    					   (g_product_protocol_cmd_handlers[uart_num].cmd_handler_list != NULL) &&
    					   (is_protocol_available(uart_num) == true))
    					{
    						while (handler_p->command != max_uart_num)
    						{
    							//获取命令对应的处理函数
    							if (handler_p->command == command)
    							{
    								handler_r = handler_p;
    								break;
    							}
    							handler_p++;
    						}
    					}
    					return handler_r;
    				}
    
    		2.2.2.2 协议模块处理
    			uart_cmd_handle.c
    
    				//初始化
    				uart_cmd_handle_init()
    				{
    					//初始化处理列表里usart的结构体
    					Protocol_Command_Handler_Init(uart_usart, usart_max_cmd);
    					
    					//usart 命令注册
    					Protocol_Command_Handler_Register(uart_usart, cmd1, cmd1_handler);
    					Protocol_Command_Handler_Register(uart_usart, cmd2, cmd2_handler);
    				}
    
    3. 数据流
    
    	串口接收任务uart_task,调用 Protocol_Process 接口处理接收到的数据,Protocol_Process 内调用对应的处理函数,如 uart_process, 处理完成后,
    	例如需要将 uart 的数据转发到 tcp ,调用 Protocol_Sender, 内部调用 tcp_sender, 将uart 的数据转发到 tcp 上去
    
    展开全文
  • C语言设计模式——命令模式

    千次阅读 2019-09-03 23:15:29
    C语言设计模式——命令模式 好处:让代码清晰明了,容易添加和删除,易维护。 哪些地方会用到命令模式?...2、协议解析串口,网口,CAN,等等);以串口为例简单说明一下,比如有如下协议:http类型解...
  • c语言编写http服务器

    千次阅读 2018-09-27 10:26:24
    一直想弄一下http服务器,一直没有深入的去看http协议。 昨天研究了一天,查看源码和优化,终于实现了。...需要实现上位机和下位机程序,协议还得自己编写和解析,如果上位机要有界面的话,还得做...
  • C语言高级编程与实例剖析》源码

    热门讨论 2010-09-24 11:39:21
    C语言高级编程与实例剖析》随书源码 第1章 内存管理 1. 1.1 预备知识 1 1.1.1 PC存储器结构 1 1.1.2 CPU地址线宽度 3 1.1.3 内存管理方式 5 1.1.4 内存编译模式 6 1.1.5 堆概念和结构 9 ...
  • 13.5 串口通信机制和实用的串口例程 13.6 练习题 第14章 I2C总线与 EEPROM 14.1 I2C 时序初步认识 14.2 I2C 寻址模式 14.3 EEPROM 的学习 14.3.1 EEPROM 单字节读写操作时序 14.3.2 EEPROM 多字节读写操作...
  • 无人机遥控器控制信号获取   控制无人机首先要考虑的是给无人机下...  sbus解析c语言实现推荐博文   接收过来的接收机信号是遥控器各个通道值,比如大多数航模遥控器遵循通道一到通道四对应着无人机的 roll、pit
  • 数据解包

    千次阅读 2018-01-29 16:20:40
    项目中要使用串口通信,要对数据进行解包,找出...通过程序解析出需要的数据,下位机C语言单片机代码如下: //数据解包 void DataAnalysis() {  u16 i = 0;  if(length ) {//数据长度小于200  for(i = 0
  • 在嵌入式开发中,经常遇到大量传感器数据需要获取,有可能这些传感器都是串口通信,IIC通信,或是485通信,区别仅仅是地址不同,数据量不一样,或是解析方式不同。为了增加程序可扩展性或是调试方便,往往会将有关...
  • 3.3.1 gcc编译流程解析 3.3.2 gcc编译选项分析 3.4 gdb调试器 3.4.1 gdb使用流程 3.4.2 gdb基本命令 3.5 make工程管理器 3.5.1 makefile基本结构 3.5.2 makefile变量 3.5.3 makefile规则 3.5.4 make管理器的使用 3.6...
  • inih:C语言的简单.INI文件解析器,很适合嵌入式系统。 inih:inih的C++版本,只有头文件。 iniparser:INI文件解析器。 libconfig:用于处理结构化配置文件的C、C++库。 libconfuse:C的小型配置文件解析库...
  • 3.3.1 gcc编译流程解析 3.3.2 gcc编译选项分析 3.4 gdb调试器 3.4.1 gdb使用流程 3.4.2 gdb基本命令 3.5 make工程管理器 3.5.1 makefile基本结构 3.5.2 makefile变量 3.5.3 makefile规则 3.5.4 make管理器的使用 3.6...
  • 3.3.1 gcc编译流程解析 3.3.2 gcc编译选项分析 3.4 gdb调试器 3.4.1 gdb使用流程 3.4.2 gdb基本命令 3.5 make工程管理器 3.5.1 makefile基本结构 3.5.2 makefile变量 3.5.3 makefile规则 3.5.4 make管理器的使用 3.6...
  • 3.4.1 Gcc编译流程解析 71 3.4.2 Gcc编译选项分析 74 3.5 Gdb调试器 77 3.5.1 Gdb使用流程 78 3.5.2 Gdb基本命令 81 3.6 Make工程管理器 86 3.6.1 Makefile基本结构 86 3.6.2 Makefile变量 87 3.6.3...
  • linux c应用程序开发教程

    热门讨论 2010-09-06 16:52:48
    3.4.1 Gcc编译流程解析 71 3.4.2 Gcc编译选项分析 74 3.5 Gdb调试器 77 3.5.1 Gdb使用流程 78 3.5.2 Gdb基本命令 81 3.6 Make工程管理器 86 3.6.1 Makefile基本结构 86 3.6.2 Makefile变量 87 3.6.3...
  • 3.4.1 Gcc编译流程解析 71 3.4.2 Gcc编译选项分析 74 3.5 Gdb调试器 77 3.5.1 Gdb使用流程 78 3.5.2 Gdb基本命令 81 3.6 Make工程管理器 86 3.6.1 Makefile基本结构 86 3.6.2 Makefile变量 ...
  • vc源代码合集2244.rar

    2012-06-11 23:15:54
    2012-06-11 22:18 8,280,803 FTP协议解析与实现.rar 2012-06-11 22:36 622,936 QQ资料.rar 2012-06-11 22:25 1,420,820 tcpdump源代码.tar.gz 2012-06-11 22:18 680,188 TCPtoUDPV31CN.rar 2012-06-11 22:40 11,617,...
  • vc程序合集0007.rar

    2012-06-12 00:40:24
    2012-06-11 23:23 10,468,734 TCP+IP协议内核源码分析.pdf 2012-06-12 00:06 228,661,536 TDDOWNLOAD.rar 2012-06-11 23:46 46,080 VC++ mfc ado.doc 2012-06-11 23:54 1,931,226 VC++ MFC 字幕滚动.rar 2012-06-11 ...
  • 阅读本书,需要读者有C语言、数据结构、操作系统和计算机网络的基础知识。 目录: 封面 -25 扉页 -24 内容简介 -23 序 -22 关于本书作者和贡献者 -20 前言 -18 阅读注意 -16 目录 -12 正文 1 第1章 内核上机指导 1...
  • 阅读本书,需要读者有C语言、数据结构、操作系统和计算机网络的基础知识。 目录: 封面 -25 扉页 -24 内容简介 -23 序 -22 关于本书作者和贡献者 -20 前言 -18 阅读注意 -16 目录 -12 正文 1 第1章 内核上机指导 1...
  • 阅读本书,需要读者有C语言、数据结构、操作系统和计算机网络的基础知识。 目录: 封面 -25 扉页 -24 内容简介 -23 序 -22 关于本书作者和贡献者 -20 前言 -18 阅读注意 -16 目录 -12 正文 1 第1章 内核上机指导 1...
  • 阅读本书,需要读者有C语言、数据结构、操作系统和计算机网络的基础知识。 目录: 封面 -25 扉页 -24 内容简介 -23 序 -22 关于本书作者和贡献者 -20 前言 -18 阅读注意 -16 目录 -12 正文 1 第1章 内核上机指导 1...
  • 阅读本书,需要读者有C语言、数据结构、操作系统和计算机网络的基础知识。 目录: 封面 -25 扉页 -24 内容简介 -23 序 -22 关于本书作者和贡献者 -20 前言 -18 阅读注意 -16 目录 -12 正文 1 第1章 内核上机指导 1...

空空如也

空空如也

1 2
收藏数 38
精华内容 15
关键字:

串口协议解析c语言

c语言 订阅