擦除内部flash导致的串口接收数据异常

在STM32H743开发中,程序在执行擦除内部Flash操作时,关闭了串口3的接收,导致后续数据丢失。通过调整中断管理和使用DMA接收,发现是擦除操作引起的问题。解决方案是在擦除前关闭并恢复串口接收,然后进行写入操作。

问题描述:

stm32h743程序运行过程中,有指令保存数据到内部flash,在执行操作的时候,影响到了另一个串口接收数据。

在存内部flash的过程中,有关闭中断,挂起其他任务的操作。但是均没有解决问题。

打印发现,另一个任务的DMA接收只能接收一个字节,接收的第一个字节是正确的,后面的字节丢失。

eae408029e90a44e626d358c8d2819f2.png

串口3的接收使用的是全局变量,将全局变量改成局部变量依旧没有解决问题。

检查写入程序,写入程序只做了擦除和写入操作,一条条注释发现是擦除操作导致的问题。

擦除内部flash的时候影响到了串口3的接收,在擦除之前使用HAL_UART_AbortReceive(&huart3);关闭串口三的串口接收,在写入完毕 使用HAL_UART_Receive_DMA(&huart3,...,...),解决问题。

如果串口数据丢失一次不是很影响可以这么做,很重要就不建议了,后来改到存储数据到外部flash了

 

### STM32F103 串口接收数据并写入内部 Flash 的实现 #### 实现概述 STM32F103 支持通过 UART 接收外部数据,并将其存储到片内 FLASH 中。由于 FLASH 只能按半字(16 位)或字(32 位)进行写入[^2],因此需要对接收到的数据进行适当处理后再执行写入操作。 以下是具体的实现过程: --- #### 硬件连接 根据硬件实训部分描述,USB-to-TTL 模块与 STM32F103C8T6 开发板的连接如下: - **3V3 → 3V3** - **GND → GND** - **RXD (模块) → PA9 (STM32)** - **TXD (模块) → PA10 (STM32)** 注意:BOOT0 和 BOOT1 配置应分别为 `0` 和 `0`,以便正常运行用户程序[^3]。 --- #### 软件设计 ##### 1. 初始化 UART 外设 初始化 USART1 并设置波特率、停止位等参数。以下是一个典型的初始化代码片段: ```c void UART_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; USART_InitTypeDef USART_InitStruct = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); // 配置PA9为USART1_TX, PA10为USART1_RX GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // 配置USART1 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); } ``` ##### 2. 数据接收缓冲区管理 为了高效接收数据,可以启用 DMA 或轮询模式。这里以简单轮询为例: ```c uint8_t RxBuffer[128]; // 假设最大接收长度为128字节 uint8_t RxIndex = 0; void UART_ReadData(uint8_t *pData, uint16_t Length) { while (RxIndex < Length && USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { pData[RxIndex++] = USART_ReceiveData(USART1); // 逐字节读取 } } ``` ##### 3. 将接收到的数据写入 FLASH FLASH 写入前需先解锁 FLASH 控制寄存器,并确保目标地址未被锁定。以下是一段示例代码: ```c #include "flash.h" #define WRITE_ADDRESS ((uint32_t)0x0800F000) // 自定义写入起始地址 void WriteToFlash(uint8_t *data, uint16_t length) { HAL_FLASH_Unlock(); // 解锁FLASH for (int i = 0; i < length / 2; i++) { // 半字写入 uint16_t half_word = *(uint16_t *)(data + i * 2); FLASH_ProgramHalfWord(WRITE_ADDRESS + i * 2, half_word); } if (length % 2 != 0) { // 如果有剩余单字节,则填充高位为零 uint16_t last_half_word = (*(uint8_t *)(data + length - 1)) << 8; FLASH_ProgramHalfWord(WRITE_ADDRESS + length - 1, last_half_word); } HAL_FLASH_Lock(); // 锁定FLASH } ``` 上述代码中调用了 `FLASH_ProgramHalfWord` 函数,该函数用于向指定地址写入半字数据。 ##### 4. 主循环逻辑 主循环负责等待数据到达并通过串口中断触发后续操作: ```c int main(void) { UART_Init(); SystemInit(); while (1) { if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { uint8_t receivedByte = USART_ReceiveData(USART1); RxBuffer[RxIndex++] = receivedByte; if (receivedByte == '\n' || RxIndex >= sizeof(RxBuffer)) { // 结束标志检测 WriteToFlash(RxBuffer, RxIndex); RxIndex = 0; // 清空缓冲区 } } } } ``` --- #### 注意事项 1. **FLASH 寿命**:频繁擦除和写入可能降低 FLASH 使用寿命,建议合理规划写入频率。 2. **校验机制**:在实际应用中加入 CRC 校验或其他错误检测手段,防止误码影响数据完整性。 3. **电源稳定性**:确保供电稳定,避免因电压波动导致写入失败或损坏 FLASH。 --- ### 示例总结 以上代码展示了如何利用 STM32F103 的 UART 功能接收数据,并将这些数据安全地写入内部 FLASH 存储区域。整个过程中涉及外设初始化、数据缓存管理和 FLASH 编程等多个环节[^4]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值