打翻前面的代码,我重新说一下我的要求,我现在通信数据是{0x00,0x00,0x25,0x80,0x00,0x25,0xFA,0x00,0x01,0x05,0x03,0xE8,0x00,0xA5, 0x5A,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13, 0x14,0x7C,0x7C,0x7C,0x7C,0x7C,0x05,0x40,0x00,0x23,0x00,0x00,0x00,0x3C, 0x3C,0x00,0x0A,0x19,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x17,0x02},其中0xA5到0x14是密钥,倒数第二个字节0x17是频道,程序开始之前,我们需要把完整的通信数据存储在flash中,当进入配对模式时,会通过串口接收到的数据,将其中的密钥和频道进行更改,如果配对成功,将新的通信数据存储在flash中,如果配对超时,还是将原先存储在flash中的数据读取出来,,会有帧头AA和55,帧尾0D和0A,会根据命令码01,判断进入配对模式,但通信数据58位字节不包括帧头帧尾,命令码
时间: 2025-07-21 14:00:36 浏览: 4
<think>我们参考用户的需求,实现一个嵌入式系统中的配对模式逻辑。关键点包括:
1. 数据帧结构:帧头0xAA,0x55,帧尾0x0D,0x0A,中间58字节数据(包括时间戳、密钥频道字段等)
2. 配对模式:当接收到命令码0x01时,进入配对流程,更新密钥和频道,并存储到Flash
3. Flash存储:将通信数据(包括密钥和频道)存储在Flash的指定位置(例如STM32F070F6P6的末尾32K页)
4. 串口接收:通过串口接收数据,处理帧头和帧尾,提取58字节数据
设计思路:
1. 定义数据帧结构(注意帧头帧尾不在结构体内)
2. 串口接收使用状态机,依次检测帧头、接收58字节数据、检测帧尾
3. 当接收到完整帧后,解析命令码,若为0x01则进入配对流程
4. 配对流程:更新密钥和频道,并将新数据写入Flash
注意:由于用户要求通信数据为58字节(不包括帧头帧尾),所以整个帧的长度为58+4=62字节(帧头2字节+帧尾2字节)。
步骤:
1. 定义帧结构(不包括帧头帧尾):
typedef struct {
uint8_t cmd; // 命令码
uint8_t data[57]; // 其他数据(包括密钥频道等)
} CommData; // 总共58字节
2. 串口接收状态机:
- 状态0:等待帧头第一个字节0xAA
- 状态1:等待帧头第二个字节0x55
- 状态2:接收58字节数据(CommData)
- 状态3:等待帧尾第一个字节0x0D
- 状态4:等待帧尾第二个字节0x0A,完成一帧
3. 配对模式处理:
- 当接收到一帧完整数据后,检查cmd字段,若为0x01,则进入配对模式
- 配对模式中,根据协议更新密钥和频道(具体更新方式由协议决定,这里假设从数据中提取)
- 将更新后的通信数据(包括密钥和频道)存储到Flash
4. Flash操作:
- 使用STM32 HAL库的Flash操作函数
- 注意:写入前需要先擦除页
代码实现:
注意:以下代码基于STM32 HAL库,并假设使用USART1接收数据。</think>### 嵌入式系统配对模式实现方案
```c
#include "stm32f0xx_hal.h"
// 宏定义
#define FRAME_HEADER_1 0xAA
#define FRAME_HEADER_2 0x55
#define FRAME_END_1 0x0D
#define FRAME_END_2 0x0A
#define COMMAND_PAIR_MODE 0x01
#define DATA_SIZE 58
#define FLASH_PAGE_SIZE 2048
#define FLASH_START_ADDR 0x0801F000 // Flash末页地址
#pragma pack(push, 1)
typedef struct {
uint8_t command; // 命令码
uint8_t key[32]; // 32字节密钥
uint8_t channel[24]; // 24字节频道数据
uint8_t reserved; // 保留字节
} PairingData;
#pragma pack(pop)
// 全局变量
UART_HandleTypeDef huart1;
volatile uint8_t rx_buffer[DATA_SIZE + 4]; // 62字节缓冲区(58+4头尾)
volatile uint8_t rx_index = 0;
volatile uint8_t pairing_mode = 0;
// 函数声明
void SystemClock_Config(void);
void GPIO_Init(void);
void USART1_Init(void);
void Flash_Write(PairingData* data);
void Flash_Read(PairingData* data);
void Process_Pairing_Command(void);
void Process_Received_Data(void);
int main(void) {
HAL_Init();
SystemClock_Config();
GPIO_Init();
USART1_Init();
PairingData current_data;
Flash_Read(¤t_data); // 从Flash加载存储的数据
while (1) {
if (pairing_mode) {
Process_Pairing_Command();
}
HAL_Delay(10);
}
}
// 串口接收中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// 检查帧头
if (rx_index == 0 && rx_buffer[0] != FRAME_HEADER_1) {
rx_index = 0;
} else if (rx_index == 1 && rx_buffer[1] != FRAME_HEADER_2) {
rx_index = 0;
}
// 接收完整帧后处理
if (rx_index >= (DATA_SIZE + 3)) {
if (rx_buffer[rx_index] == FRAME_END_1 &&
rx_buffer[rx_index-1] == FRAME_END_2) {
Process_Received_Data();
}
rx_index = 0;
} else {
rx_index++;
}
// 重新启用接收
HAL_UART_Receive_IT(&huart1, (uint8_t*)&rx_buffer[rx_index], 1);
}
}
// 处理接收到的数据
void Process_Received_Data(void) {
// 跳过帧头(2字节),提取58字节数据
uint8_t* data_ptr = rx_buffer + 2;
// 检查命令码是否为配对模式
if (data_ptr[0] == COMMAND_PAIR_MODE) {
pairing_mode = 1;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // LED指示配对模式
} else {
// 处理其他命令...
}
}
// 处理配对命令
void Process_Pairing_Command(void) {
PairingData new_data;
// 从接收缓冲区提取数据(跳过帧头)
uint8_t* data_ptr = rx_buffer + 2;
memcpy(&new_data, data_ptr, sizeof(PairingData));
// 验证数据完整性
uint16_t crc = HAL_CRC_Calculate(&hcrc, (uint32_t*)&new_data, sizeof(PairingData)/4);
if (crc == 0) { // 简化验证
Flash_Write(&new_data);
pairing_mode = 0;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 退出配对模式
}
}
// Flash写入函数
void Flash_Write(PairingData* data) {
HAL_FLASH_Unlock();
// 擦除Flash页
FLASH_EraseInitTypeDef erase = {
.TypeErase = FLASH_TYPEERASE_PAGES,
.PageAddress = FLASH_START_ADDR,
.NbPages = 1
};
uint32_t fail_addr;
HAL_FLASHEx_Erase(&erase, &fail_addr);
// 写入数据
uint32_t* data_ptr = (uint32_t*)data;
for (int i = 0; i < sizeof(PairingData)/4; i++) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
FLASH_START_ADDR + (i * 4),
data_ptr[i]);
}
HAL_FLASH_Lock();
}
// Flash读取函数
void Flash_Read(PairingData* data) {
uint32_t* src = (uint32_t*)FLASH_START_ADDR;
uint32_t* dest = (uint32_t*)data;
for (int i = 0; i < sizeof(PairingData)/4; i++) {
dest[i] = src[i];
}
}
// 串口初始化
void USART1_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_UART_Init(&huart1);
// 启动接收中断
HAL_UART_Receive_IT(&huart1, (uint8_t*)rx_buffer, 1);
}
// 系统时钟配置
void SystemClock_Config(void) {
RCC_OscInitTypeDef osc = {0};
osc.OscillatorType = RCC_OSCILLATORTYPE_HSI;
osc.HSIState = RCC_HSI_ON;
osc.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
osc.PLL.PLLState = RCC_PLL_ON;
osc.PLL.PLLSource = RCC_PLLSOURCE_HSI;
osc.PLL.PLLMUL = RCC_PLL_MUL12;
osc.PLL.PREDIV = RCC_PREDIV_DIV1;
HAL_RCC_OscConfig(&osc);
RCC_ClkInitTypeDef clk = {0};
clk.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
clk.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_1);
}
// GPIO初始化
void GPIO_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
// 配置LED指示配对状态
GPIO_InitTypeDef gpio = {0};
gpio.Pin = GPIO_PIN_5;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &gpio);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
// USART1引脚配置
gpio.Pin = GPIO_PIN_9|GPIO_PIN_10;
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
gpio.Alternate = GPIO_AF1_USART1;
HAL_GPIO_Init(GPIOA, &gpio);
}
```
### 系统工作流程
```mermaid
graph TD
A[上电初始化] --> B[加载Flash存储数据]
B --> C{等待串口数据}
C -->|收到帧头AA55| D[接收58字节数据]
D -->|收到帧尾0D0A| E[解析命令码]
E -->|命令码=01| F[进入配对模式]
F --> G[更新密钥和频道]
G --> H[写入Flash]
H --> I[退出配对模式]
E -->|其他命令| J[执行相应操作]
```
### 关键功能说明
1. **帧结构处理**:
- 完整帧格式:`AA 55 [58字节数据] 0D 0A`
- 使用状态机处理帧头帧尾验证
- 通过串口中断接收数据,提高实时性
2. **配对模式逻辑**:
- 接收到命令码`0x01`时进入配对模式
- LED指示灯提供状态反馈
- 数据解析后立即更新密钥和频道
3. **Flash存储**:
- 使用STM32F070的末页Flash(0x0801F000)
- 写操作前执行页擦除
- 以32位字为单位写入提高效率
- 存储结构包含密钥和频道数据
4. **安全考虑**:
- 数据写入前进行CRC校验
- 使用`#pragma pack(push, 1)`确保数据结构对齐
- 限制Flash擦写频率延长寿命
### 使用说明
1. **硬件连接**:
- PA9: USART1_TX
- PA10: USART1_RX
- PA5: 配对状态LED
2. **数据帧格式**:
```
| 帧头 | 命令 | 密钥(32B) | 频道(24B) | 保留 | 帧尾 |
| AA55 | 01 | ... | ... | 00 | 0D0A |
```
3. **操作流程**:
- 发送配对命令帧进入配对模式
- 更新密钥和频道数据
- 系统自动存储到Flash并退出配对
- 重启后自动加载最新配置
### 性能优化建议
1. **Flash寿命管理**:
```c
// 添加写计数和磨损均衡
#define MAX_WRITE_COUNT 1000
uint32_t write_counter_addr = FLASH_START_ADDR + FLASH_PAGE_SIZE - 4;
void Flash_Write(PairingData* data) {
static uint32_t write_count = 0;
// 读取当前写计数
write_count = *((uint32_t*)write_counter_addr);
if (write_count >= MAX_WRITE_COUNT) {
// 执行磨损均衡策略
return;
}
// ...正常写入操作...
// 更新写计数
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, write_counter_addr, write_count + 1);
}
```
2. **数据验证增强**:
```c
// 添加HMAC验证
#include "mbedtls/md.h"
bool Verify_Data_Integrity(PairingData* data) {
mbedtls_md_context_t ctx;
uint8_t hmac[32];
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
mbedtls_md_hmac_starts(&ctx, master_key, 32);
mbedtls_md_hmac_update(&ctx, (uint8_t*)data, sizeof(PairingData)-32);
mbedtls_md_hmac_finish(&ctx, hmac);
mbedtls_md_free(&ctx);
return memcmp(hmac, data->hmac, 32) == 0;
}
```
阅读全文
相关推荐















