串口协议包的接收及解析处理

串口是单片机应用中应用最多的外设之一。很多电子硬件都会提供串口,如蓝牙模块、WIFI模块、串口屏等。如果我们想开发基于串口通信的产品或使用基于串口通信的电子硬件时,都避不开通信协议

通信协议

通信协议听起来很抽象,实际他就是两个通信设备之间交流的纽带。例如我们两个人互相对话,这就是一个通信的过程,为什么我们可以听懂对方的话,因为我们说的都是汉语,汉语就是我们之间的通信协议。

通信协议一般分为物理层协议层。对于物理层我这里就不介绍了,大家可以根据自己的情况翻阅其他资料,这里主要介绍基于串口的应用层协议。

串口应用层协议

串口应用层协议以下简称为串口协议。在大家购买的各类串口通信的产品时,官方都会提供一份通信协议。总的来说这些协议五花八门,下面我列举几个我见到的通信协议:

DWIN DGUS串口屏 读取内存地址值的指令:

        | Example 5A A5 06 83 20 01 01 78 01 ……|          / /  |  |   \ /   |  \     \|        Header |  |    |    |   \_____\_ DATA (Words!)|     DatagramLen  /  VPAdr  ||           Command          DataLen (in Words) 

某指纹模块使其进入休眠模式的指令:

        | Example F5 2C 00 00 00 00 01 F5|         /  |  |  |  |   |  |  \     |   Header  /   |  |  |   |   \  Tailer|     Command   P1 P2 P3  |    CheckSum|                         Alawys 0

3D打印机的G代码指令:

        |                (X,Y,Z Command)|                / | \   |              /   |   \|            |     |     || Example G1 X10.0 Y10.0 Z10.0 ;注释|         /      \    |    /   |      |   Command        \  |  /     Comment|                 (Distance)                        

某平衡小车控制指令:

 | Example $0,0,0,0,1,1,AP23.54,AD85.45,VP10.78,VI0.26#|        / | \ \ | / /  |  |    |  |    |  |    | |   \     |  Header /    \\|//    |  data |  data |  data | data Tailer|  move cmd  other cmd  angel P angle D speed P speed I 

以上通信协议前两种属于十六进制格式的通信协议,后面两种属于字符串格式的通信协议。就实际应用而言,十六进制的通信协议格式应用更加广泛。字符串格式的通信协议更倾向于对于字符串的格式有明确标准的场合,如gcode代码。

实际上无论是十六进制格式的通信协议还是字符串格式的通信协议,只是使用过程中给人的直观感受不同而已(勾选16进制发送,不勾选十六进制发送),对于串口硬件传输而言都是一样的:数据一个字节一个字节的传输,这一个字节的数据我们既可以当做十六进制数据处理也可以当做字符数据处理。

对于通信协议我们一般都会包含一些包头、包尾、包长、校验码等必要的信息,以便于解析协议。没有这些标识信息我们怎么知道发过来的数据到底对还是不对,发过来的数据到底是什么含义。

串口数据的接收及协议解析处理

对于串口接收问题前面之前有文章介绍过串口缓存机制的应用。当然这里不应用缓存机制也是完全可行的。这里我们讲解基于不带串口缓存机制的处理。对于串口接收我们最常用的方式就是在串口中断中接收数据。

利用串口接收数据包信息大致分为下面三种情况:

  1. 接收一帧数据,对帧数据进行处理(可以利用串口接收非空中断和串口空闲中断实现)
  2. 中断中边接收边处理存储,并将有效数据存储起来,再对有效数据进行解析。
  3. 将接收到的数据全部存入缓存,从缓存中提取数据并做处理。

1. 接收帧数据

利用串口和ESP8266WIFI模块通信(可参考野火例程)

2. 边接收边处理存储

以对上面平衡小车协议解析为例:

  • 串口数据接收
/* 变量说明 */
#define BUFFER_SIZE 4    //最多缓存4包数据
#define MAX_CMD_SIZE 80  //每包最多包含80个字节的数据bool g_bStartBitFlag = 0; //开始接收数据包的标志位
char cmdBuffer[BUFFER_SIZE][MAX_CMD_SIZE]; 缓存数组int bufindr = 0; //数据包的读取索引int bufindw = 0; //数据包的写入索引int buflen  = 0; //缓存中数据包的个数
int serial_count = 0; //每包数据中的计数变量/*** @brief  USART3串口中断服务函数* @param  none* @retval none*/
void USART3_IRQHandler(void)
{uint8_t rec;if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断{rec = USART_ReceiveData(USART3);//(USART1->DR); //读取接收到的数据if(rec == '$')  //判断接收到的数据是否为包头信息{g_bStartBitFlag = 1; //数据包开始标志位serial_count = 0;    //计数变量}if(g_bStartBitFlag == 1){cmdBuffer[bufindw][serial_count++] = rec; //命令缓存}if(g_bStartBitFlag == 1 && rec == '#') //接收到包尾数据,接收完成{g_bStartBitFlag = 0;bufindw = (bufindw + 1) & (BUFFER_SIZE - 1);buflen += 1;}if(serial_count >= 80) //接收长度溢出,重新接收{g_bStartBitFlag = 0;serial_count = 0;}}
} 
  • 数据包解析:
void protocol_process(void)
{if(buflen){switch(cmdBuffer[bufindr][1]){case '0'://...break;case '1'://...break;}/* 协议中其他数据的处理 */buflen -= 1; //该包数据已分析完缓存中数据包数减1bufindr = (bufindr + 1) & (BUFFER_SIZE - 1); //移到下一读取索引位置}
}

3. 先缓存后处理

以上面串口屏的协议为例:(该段代码来自于marlin固件)

/* 定义包头及指令信息 */
#define HEADER1 0x5A
#define HEADER2 0xA5
#define CMD_READVAR  0x83
#define CMD_WRITEVAR 0x82/* 枚举读取数据报文的状态 */
typedef enum
{IDLE,SEEN_HEADER1,SEEN_HEADER2,DATA
}rx_datagram_state_t;/* 定义数据包接收状态的变量,并初始化为空闲状态 */
rx_datagram_state_t rx_datagram_state = IDLE;/* 协议数据处理函数 */
void processRx()
{uint8_t receivedbyte;while(serial_available())  //缓存中有数据{switch(rx_datagram_state){case IDLE:receivedbyte = serial_read();if(HEADER1 == receivebyte){rx_datagram_state = SEEN_HEADER1;}break;case SEEN_HEADER1:receivedbyte = serial_read();rx_datagram_state = (HEADER2 == receivebyte) ? IDLE : SEEN_HEADER2break;case SEEN_HEADER2:rx_dategram_len = serial_read(); //数据包的长度rx_datagram_state = DATA;break;case DATA:if(serial_available() < rx_datagram_len) return;uint8_t command = serial_read();uint8_t readlen = rx_datagram_len - 1; //command is part of lenuint8_t tmp[rx_datagram_len - 1];unsigned char *ptmp = tmp;while(readlen--){receivedbyte = serial_read();*ptmp++ = receivedbyte;}// mostly we'll get this: 5A A5 03 82 4F 4B -- ACK on 0x82,so discard it.if(command == CMD_WRITEVAR && 'O' == tmp[0] && 'K' == tmp[1]){rx_datagram_state = IDLE;break;}/* AutoUpload, (and answer to) Command 0x83 :|      tmp[0  1  2  3  4 ... ]| Example 5A A5 06 83 20 01 01 78 01 ……|          / /  |  |   \ /   |  \     \|        Header |  |    |    |   \_____\_ DATA (Words!)|     DatagramLen  /  VPAdr  ||           Command          DataLen (in Words) */if(command == CMD_READVAR){const uint16_t vp = tmp[0] << 8 | tmp[1];const uint8_t dlen = tmp[2] << 1; //Convert to Bytes.(Display works with words)/* 数据处理 */rx_datagram_state = IDLE;break;}//discard anything elserx_datagram_state = IDLE;}}
}

串口协议包的接收及解析处理相关推荐

  1. FPGA解析串口协议帧3.0版本,增加了错误重发功能,提供仿真文件以及源码

    FPGA解析串口协议帧已经发布2个版本了,分别如下: 版本1:点击查看版本1 版本1详细介绍了串口协议帧的帧组成和设计思想,但设计粗糙,注释不详细: 版本1:点击查看版本2 版本2优化了代码,添加了详 ...

  2. 关于STM32串口3的使用,接收并解析一帧数据

    关于STM32串口3的使用,接收并解析一帧数据 当stm32的串口1被使用时,我们可以使用其他串口来使用. 步骤: 串口3定义.初始化: 串口3中断服务函数(接收的一帧数据并判断是否正确): 主函数使 ...

  3. 串口通信,接收并解析数据的方式

    串口通信,接收并解析数据的方式 (点击链接阅读原文)

  4. java pop3 接收邮件_JavaMail使用POP3协议接收并解析电子邮件

    JavaMail使用POP3协议接收并解析电子邮件 代码片段:public static void main(String[] args) throws Exception { receive(); ...

  5. Python实现IMAP协议接收并解析邮件内容

    Python实现IMAP协议接收并解析邮件内容 **前言:**昨天接到这个任务,然后搜索了很多资料和博客去看,这些资料链接我会放在本文后面 一.开通IMAP服务 我以网页邮箱(163邮箱为例) 1.登 ...

  6. stm32f103c8t6串口数据包收发

    硬件资源: 使用stm32f103c8t6单片机作为主控,CH340USB转串口模块进行串口数据收发,0.96寸支持IIC协议的显示屏进行效果显示. 接线图: 项目思路: ①:什么是串口数据包? 用来 ...

  7. 六、Dubbo协议模块原理源码解析

    课程概要: RPC协议基本组成 RPC协议报文编码与实现详解 Dubbo中所支持RPC协议与使用 RPC协议基本组成 RPC 协议名词解释 在一个典型RPC的使用场景中,包含了服务发现.负载.容错.网 ...

  8. STM32使用串口1配合DMA接收不定长数据,大大减轻CPU载荷。

    最近经常看见坛友在论坛上问串口接收的问题,我之前刚好由于项目需要用到PLC的PPI协议,需要不停地利用串口接收数据,一开始的时候采用单字节中断的方式接收判断.但是用来做通信的时候需要不停的产生串口接收 ...

  9. STM32使用串口1配合DMA接收不定长数据,大大减轻CPU载荷

    摘自:http://www.openedv.com/thread-63849-1-1.html 参考:https://blog.csdn.net/heda3/article/details/80602 ...

  10. STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷

    STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷 http://www.openedv.com/thread-63849-1-1.html 实现思路:采 用STM32F103的串口1,并配 ...

最新文章

  1. 转,大佬关于虚拟内存与物理内存关系讲解。
  2. 第一阶段_第一部分_工具介绍
  3. 一个大屏监控380个泵房,13000个设备,智能水务是怎么实现的?
  4. python 爬取网页内容 snmp_python通过SNMP协议收集服务器监控信息
  5. ndnsim r语言 ubuntu_Ubuntu14.04下配置ndnSIM-nom-rapid-car2car
  6. org.eclipse.e4.core.di.InjectionException:org.eclipse.swt.SWTException: Widget is disposed
  7. 怎么调整矩形边框宽度_PPT内容太少,怎么做才不会单调?
  8. 桂电在linux、Mac OS环境下使用出校器(支持2.14)
  9. 软件工程实践_Task2_sudoku
  10. python 增量备份mysql_Python 生产环境MySQL数据库增量备份脚本
  11. 关于输入法的弹出和隐藏
  12. 博客样式-bbsmax4风格V0.2
  13. 继电保护原理5-变压器保护
  14. ATX电源接口, 服务器插拔电源接口
  15. OKR组织敏捷目标和绩效管理第二课 O、KR和案例讲解
  16. win10打开软件显示c盘服务器,【解决】win10 打开本地磁盘 提示找不到应用程序...
  17. Android使用SharedPreferences存储数据
  18. python运维必备知识
  19. 什么是features(特征)
  20. 十二个“一”的假想人物设定

热门文章

  1. 计算机记笔记软件是什么,电脑记笔记软件哪个好(适合学生做笔记的软件)
  2. chapter 1 JS简介,核心语法,变量
  3. python步态识别算法_步态识别
  4. 用printf 输出各种数据格式(包含示例代码)
  5. 安卓逆向入门----Andriod smail 与 Java 代码
  6. 主流手机游戏引擎介绍
  7. 撒花!苹果iOS迅雷手机版终于上架App Store
  8. Python 音频生成器
  9. 23 - OAI NSA gNB搭建 - 博一
  10. 微信聊天功能软件测试用例,软件测试用例实例之常见功能测试点