USART串口数据包

HEX数据包

首先数据包的作用,把一个个单独的数据给封装起来,方便进行对字节的数据通信。

在HEX数据包里面,数据都是以原始的字节数据本身呈现。

两种数据包格式:

  • 固定包长,含包头包尾:每个数据包的长度都固定不变,数据包前面是包头,后面是包尾。
  • 可变包长,含包头包尾:每个数据包的长度可以不一样,可以根据需求,进行规定。

文本数据包

以@字符作为包头,\r\n作为包尾,在载荷数据中间可以出现除了包头包尾的任意字符,所以很灵活,当接收到数据之后,得到的就是一个字符串,在软件中再对字符串进行操作和判断,就可以实现各种指令控制的功能了。

两种数据包格式的对比

HEX数据包

  • 优点:传输直接,解析数据非常简单,适用于模块发送原始数据。
  • 确定:灵活性不足,载荷容易和包头包尾重复。

文本数据包

  • 优点:数据非常直观容易理解,灵活性很高,适用于输入指令的人机交互的场合。
  • 缺点:解析效率较低。

HEX数据包接收

格式为固定包长

  1. 每收到一个字节,程序都会进一遍中断,在中断函数里可以拿到这个字节,随即要退出中断,所以每次拿数据都是独立的过程,而数据包具有前后关联性。
  2. 对此需要设计能记住不同状态的机制,在不同状态执行不同的操作,同时还要进行状态的合理转移
  3. 因此如图所示,定义三个状态,第一个是等待包头、第二个是接收数据、第三个是等待包尾,每个状态分别用一个变量进行标志。

文本数据包接收

格式为可变包长

同理也是定义三个状态:

  1. 第一个等待包头,判断收到的是否为规定的字符,如果收到,将进入下一状态。
  2. 第二状态依次接收数据,判断是否为\r,如果不是,正常接收;如果是,则不接收,同时跳到下一状态等待包尾\n 同时,此状态还应该要兼具等待包尾的功能(因为格式为可变包长,接收数据时,需要时刻监视,是否收到包尾
  3. 如果包尾只有一个字符,出现包尾后可直接回到初始状态。
### USART串口发送和接收文本数据包 在嵌入式开发中,STM32 微控制器常用于通过 USART 实现串口通信。以下是关于如何通过 STM32USART 模块实现文本数据包发送与接收的具体方法。 #### 1. 初始化 USART 配置 为了使能 USART 功能并设置波特率、字长、停止位等参数,需完成初始化操作。以下是一个典型的 USART 初始化函数: ```c void USART_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; USART_InitTypeDef USART_InitStruct = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); // 配置 TX 和 RX 引脚 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // PA9(TX), PA10(RX) GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // 配置 USART 参数 USART_InitStruct.USART_BaudRate = 115200; // 波特率为 115200 bps USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长为 8 位 USART_InitStruct.USART_StopBits = USART_StopBits_1; // 停止位为 1 USART_InitStruct.USART_Parity = USART_Parity_No; // 无校验 USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStruct); USART_Cmd(USART1, ENABLE); // 启用 USART } ``` 上述代码实现了 USART 的基本配置[^1]。 --- #### 2. 发送文本数据包 对于文本数据包发送,通常会将字符串转换为字符数组形式逐字节发送串口缓冲区。下面提供了一个简单的发送函数示例: ```c void USART_SendString(const char *str) { while (*str != '\0') { USART_SendData(USART1, (uint16_t)(*str)); // 将当前字符写入发送寄存器 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送缓存为空 str++; } USART_SendData(USART1, '\r'); // 添加回车符 USART_SendData(USART1, '\n'); // 添加换行符 while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // 等待传输结束 } ``` 此函数能够连续发送一整条字符串,并自动附加 `\r\n` 结束标志。 --- #### 3. 接收文本数据包 接收部分可以通过中断方式捕获接收到的数据,并存储到指定缓冲区中以便后续处理。以下是一段基于中断机制的接收代码: ```c volatile uint8_t RxBuffer[256]; // 定义全局变量作为接收缓冲区 volatile uint8_t RxIndex = 0; // 当前索引位置 // 中断服务程序 void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { // 判断是否有新数据到达 RxBuffer[RxIndex++] = USART_ReceiveData(USART1); // 存储接收到的数据 if (RxBuffer[RxIndex - 1] == '\n' || RxIndex >= sizeof(RxBuffer)) { RxBuffer[--RxIndex] = '\0'; // 终止字符串 ProcessReceivedPacket(); // 调用解析函数 RxIndex = 0; // 清空缓冲区指针 } } } // 解析接收到的数据包 void ProcessReceivedPacket() { printf("Received Packet: %s\r\n", RxBuffer); // 打印接收到的内容 } ``` 该代码片段展示了如何利用中断来实时获取输入流中的每一帧数据,并判断其是否构成完整的消息体[^2]。 --- #### 4. 协议设计注意事项 实际应用中可能涉及更复杂的协议定义,比如加入起始标记 (`STX`)、终止标记 (`ETX`) 或者长度字段以增强鲁棒性和兼容性。例如,一种常见的简单封装如下所示: - 数据结构:`<STX><LEN><DATA><CHKSUM><ETX>` - `STX`: 开头固定值(如 ASCII 'S') - `LEN`: 表明有效载荷大小的一个字节数值 - `DATA`: 用户自定义的有效负载区域 - `CHKSUM`: 校验码计算结果 - `ETX`: 结尾固定值(如 ASCII 'E') 这种格式有助于区分不同类型的命令以及验证数据完整性[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

¥sunrise

来自大牛的认可,是我梦寐以求的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值