帮我写一下代码,并且每段代码对应的注释说明,让我可以明白实现的功能,我想实现stm32f407单片机可以从串口读取{"start":"1","input1":"68","input2":150,"input3":20,"end":"OK"}这种被发送到串口的数据包,其中"start":"1"为帧头,"end":"OK"为帧尾,当帧头和帧尾正确则开始读取并存储input1,input2,input3的数值,这三个变量有可能是字符串也有可能是数值类型,存储完后把三个数值打印到串口上,检测是否存储正确,
时间: 2025-05-24 16:19:06 浏览: 18
### STM32F407串口接收JSON格式数据包并解析
为了实现STM32F407单片机通过串口接收特定格式的数据包,解析其中的`input1`、`input2`和`input3`数值,并将其存储后再回传至串口以验证正确性,可以按照以下方法设计程序。
#### 数据包结构
假设数据包采用如下格式:
- **帧头**:固定为 `0xFE`
- **帧尾**:固定为 `0xFF`
- **数据部分**:包含 JSON 格式的字符串,例如 `"{"input1":1,"input2":2,"input3":3}"`
当接收到完整的数据包后,需检测其有效性(如校验帧头/帧尾是否匹配),然后解析 JSON 字符串提取所需字段值。
---
#### 接收与处理逻辑
以下是基于中断方式的代码示例:
```c
#include "stm32f4xx.h"
#include <string.h>
#include <stdio.h>
#define MAX_BUF_LEN 256 // 缓冲区最大长度
uint8_t rxd_buf[MAX_BUF_LEN]; // 接收缓冲区
volatile uint8_t recv_state = 0; // 接收状态
volatile uint16_t rxd_index = 0; // 当前接收索引
volatile uint8_t rxd_flag = 0; // 完整数据包接收完成标志
// 初始化串口函数
void USART1_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// 配置 PA9 作为 TX, PA10 作为 RX
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
// 配置 USART 参数
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_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_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 启用接收中断
}
// 中断服务程序
void USART1_IRQHandler(void) {
uint8_t recv_dat;
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { // 接收中断
recv_dat = USART_ReceiveData(USART1); // 获取接收到的数据
switch (recv_state) {
case 0: // 等待帧头
if (recv_dat == 0xFE) { // 检测到帧头
recv_state = 1; // 切换到接收数据状态
rxd_index = 0; // 清空索引
}
break;
case 1: // 接收数据阶段
if (rxd_index >= sizeof(rxd_buf)) {
recv_state = 0; // 超过缓存大小则丢弃当前包
break;
}
rxd_buf[rxd_index++] = recv_dat; // 将数据写入缓冲区
if (recv_dat == '}') { // 如果遇到 '}' 表明可能结束
recv_state = 2; // 进入等待帧尾状态
}
break;
case 2: // 等待帧尾
if (recv_dat == 0xFF) { // 检测到帧尾
rxd_flag = 1; // 设置接收完成标志
recv_state = 0; // 返回初始状态
} else {
recv_state = 0; // 若未检测到帧尾,则重置状态
}
break;
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE); // 清除中断标志位
}
}
```
---
#### 解析JSON数据
在主循环中,当检测到 `rxd_flag == 1` 时,表示已成功接收到一整个数据包。此时可调用库函数(如 cJSON 或手动解析)来提取所需的 `input1`、`input2` 和 `input3` 数值。
##### 手动解析示例
如果不想引入额外库文件,可以通过简单的字符串操作解析 JSON 数据:
```c
int parse_json(uint8_t *buf, int buf_len, int *input1, int *input2, int *input3) {
char key_input1[] = "\"input1\":";
char key_input2[] = "\"input2\":";
char key_input3[] = "\"input3\":";
char value_str[16];
memset(value_str, 0, sizeof(value_str));
// 查找 input1 的值
const char *pos = strstr((char *)buf, key_input1);
if (!pos || sscanf(pos + strlen(key_input1), "%d", input1) != 1) return -1;
// 查找 input2 的值
pos = strstr((char *)buf, key_input2);
if (!pos || sscanf(pos + strlen(key_input2), "%d", input2) != 1) return -1;
// 查找 input3 的值
pos = strstr((char *)buf, key_input3);
if (!pos || sscanf(pos + strlen(key_input3), "%d", input3) != 1) return -1;
return 0;
}
```
---
#### 主循环中的处理流程
```c
int main(void) {
USART1_Init(); // 初始化串口
while (1) {
if (rxd_flag) { // 检查是否有新数据包到达
rxd_flag = 0; // 清除标志
int input1, input2, input3;
if (parse_json(rxd_buf, rxd_index, &input1, &input2, &input3) == 0) {
printf("Received Data:\n");
printf("Input1: %d\n", input1);
printf("Input2: %d\n", input2);
printf("Input3: %d\n", input3);
// 发送回传数据
char send_buf[64];
snprintf(send_buf, sizeof(send_buf), "{\"output1\":%d,\"output2\":%d,\"output3\":%d}", input1, input2, input3);
for (size_t i = 0; i < strlen(send_buf); ++i) {
USART_SendData(USART1, send_buf[i]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
} else {
printf("Invalid data packet.\n");
}
}
}
}
```
---
### 总结
以上代码实现了 STM32F407 单片机通过串口接收带有帧头 (`0xFE`) 和帧尾 (`0xFF`) 的 JSON 数据包的功能[^1]。它能够解析出指定键值对的内容,并将结果重新打包成 JSON 格式发送回去以确认接收无误。此方案适用于实时性和可靠性较高的应用场景。
---
阅读全文