本帖最后由 王昱顺 于 2024-8-30 15:13 编辑
快速搭建简单的串口分包通讯
在近距离通讯中(20cm内),串口通讯也是一个很不错的选择。 虽然已经拥有了ModBus这种广为人知协议,但是从头适配起来往往有些麻烦。所以,这里给出一种快速的(10分钟内可从头写完)的串口传输协议。
协议分成三部分:包头,数据,校验和。 包头固定为0x55,校验和为ADD8(即定义一个unsigned char变量,然后将所有数据(包括0x55包头)加起来,溢出部分不管)。
发送十分简单,并不需要考虑延时分包问题,直接在需要的时候发送数据就可以了(不过这个并没有数据重发功能,发送受到干扰也会造成数据丢失)
这里主要讲一下接收部分的实现:
- u8 uart_set[10] = {0};//串口操作缓冲区
- u8 uart_cnt = 0;//串口指针
- u8 crc_add = 0, crc_cnt = 0;
- void Uart2_Isr(void) interrupt 8
- {
- //发送中断部分,略
- if(S2CON & 0x01) // 检测串口2接收中断
- {
- S2CON&= ~0x01; // 清除串口2接收中断请求位
- if(uart_cnt != 0)
- {
- uart_set[uart_cnt]= S2BUF;
- uart_cnt++;
- if(uart_cnt == 10)
- {
- uart_cnt= 0;
- crc_add= 0;
- for(crc_cnt = 0; crc_cnt < 9; crc_cnt++)
- {
- crc_add+= uart_set[crc_cnt];
- }
- if(crc_add == uart_set[9])
- {
- //数据解析
- uart_dat_out1= (int)(uart_set[1] << 8 | uart_set[2]);
- uart_dat_out2= (int)(uart_set[3] << 8 | uart_set[4]);
- uart_dat_diff1= (int)(uart_set[5] << 8 | uart_set[6]);
- uart_dat_diff2= (int)(uart_set[7] << 8 | uart_set[8]);
- }
- }
- }
- if(S2BUF == 0x55 && uart_cnt == 0)
- {
- uart_set[uart_cnt]= S2BUF;
- uart_cnt++;
- }
- }
- }
复制代码
首先是包头同步功能,检测到串口接收中断的数据为包头数据,并且当前串口数据指针为包头时,将数据存入缓冲区,并且开始串口数据指针自加,否则就继续等待。 这样,就算数据丢失造成错位,但是crc校验不过,仍然会在下一次的等待同步过程中继续同步。
然后就是数据帧阶段,这部分会根据串口数据指针存入缓冲区,直到最后一个数据的时候进行crc校验比较,成功后则将缓冲区内容取出,然后赋值给所需变量。 这个部分中,数据的长度应该是确定的。这个协议要求收发双方发送了同样的指定长度数据,并不能支持不定长数据传输。好处就是不需要延迟分包,连一块发也是可以的。
这个代码经过实际测试,效果良好,没有传入错误的数据,且性能损耗小,计算简单。
|