STM32L0中使用HAL_FLASH_Program写入内部Flash的疑问
如何在STM32L0的Flash中写入字符串类字节数据
我来帮你理清这个问题——STM32L0的Flash编程确实有最小单元的要求,但HAL库已经帮我们封装了不同粒度的编程接口,你要写入char*这类字节流,核心是选对编程类型并做好Flash的前置操作(解锁、擦除)。
先给你拆解UM1749里19.2.7章节的疑惑:那个章节讲的是字编程(32位),这是Flash编程的一种方式,但STM32L0支持字节、半字、字三种编程粒度,你要写入单个字节的char数据,只需要在HAL_FLASH_Program里指定FLASH_TYPEPROGRAM_BYTE作为编程类型即可,不用局限于字编程的内容。
下面是完整的可运行代码示例,包含你提到的ScratchWrite函数实现,以及关键步骤的说明:
完整代码实现
#include "stm32l0xx_hal.h" // 注意:请根据你的STM32L0型号选择合适的空闲扇区地址和对应扇区编号 // 以STM32L053为例,扇区7的地址范围是0x0800F000 ~ 0x0800FFFF,这里选起始地址作为写入起点 #define FLASH_SCRATCH_START 0x0800F000 #define FLASH_SCRATCH_SECTOR FLASH_SECTOR_7 uint32_t ScratchWrite(uint32_t startAddr, const char* data) { HAL_StatusTypeDef status = HAL_OK; FLASH_EraseInitTypeDef eraseInitConfig = {0}; uint32_t eraseErrorAddr = 0; // 第一步:解锁Flash,否则无法进行编程/擦除操作 status = HAL_FLASH_Unlock(); if (status != HAL_OK) { return status; } // 第二步:擦除目标扇区——Flash只能从1写为0,写入前必须擦除对应扇区(全变为0xFF) eraseInitConfig.TypeErase = FLASH_TYPEERASE_SECTORS; eraseInitConfig.VoltageRange = FLASH_VOLTAGE_RANGE_1; // STM32L0供电范围1.65-3.6V,选RANGE_1 eraseInitConfig.Sector = FLASH_SCRATCH_SECTOR; eraseInitConfig.NbSectors = 1; // 只擦除我们要使用的扇区 status = HAL_FLASHEx_Erase(&eraseInitConfig, &eraseErrorAddr); if (status != HAL_OK) { HAL_FLASH_Lock(); // 擦除失败也要上锁,保护Flash return status; } // 第三步:逐个字节写入字符串,包括终止符'\0'(否则读取时会越界) const char* dataPtr = data; uint32_t currentAddr = startAddr; // 先写入字符串的每个字符 while (*dataPtr != '\0') { status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, currentAddr, (uint32_t)*dataPtr); if (status != HAL_OK) { HAL_FLASH_Lock(); return status; } dataPtr++; currentAddr++; } // 最后写入字符串终止符,保证读取时能正确识别字符串结束 status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, currentAddr, (uint32_t)'\0'); if (status != HAL_OK) { HAL_FLASH_Lock(); return status; } // 第四步:操作完成后上锁Flash,防止误操作 HAL_FLASH_Lock(); return HAL_OK; } // 主函数调用示例 int main(void) { HAL_Init(); // 这里添加时钟初始化、外设初始化等代码... char* demo = "nucleo"; uint32_t writeResult = ScratchWrite(FLASH_SCRATCH_START, demo); if (writeResult == HAL_OK) { // 写入成功,可以读取验证 char readBuffer[20] = {0}; // 直接从Flash地址拷贝数据到缓冲区 memcpy(readBuffer, (const char*)FLASH_SCRATCH_START, sizeof(readBuffer) - 1); // 可以通过串口打印readBuffer来验证写入结果 } while (1) { // 主循环代码 } }
关键注意事项
- Flash解锁与上锁:这是必须的操作,解锁才能修改Flash,操作完成后必须上锁,避免后续误操作损坏Flash内容。
- 扇区擦除:Flash不支持单个字节擦除,只能按扇区擦除,所以写入前一定要擦除目标地址所在的扇区,否则写入会失败。
- 编程类型选择:
FLASH_TYPEPROGRAM_BYTE对应字节编程,刚好匹配char类型的1字节数据,如果你要写入半字(2字节)或字(4字节),可以选择FLASH_TYPEPROGRAM_HALFWORD或FLASH_TYPEPROGRAM_WORD。 - 字符串终止符:一定要写入
'\0',否则读取字符串时会超出有效数据范围,导致不可预料的行为。 - 地址合法性:
FLASH_SCRATCH_START必须是芯片Flash范围内的有效地址,且对应扇区要未被程序代码占用,具体地址和扇区对应关系请参考你的STM32L0型号的数据手册。
内容的提问来源于stack exchange,提问作者SamForiYana
相关产品推荐
相关产品推荐

