目录
一、EEPROM
(1)板载 EEPROM
EEPROM(Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器,掉电后数据不丢失,使用方便,可重复擦写,电擦除。
STM32L071 系列提供了高达6千字节的 EEPROM,对 EEPROM 进行编程时采用在按字、半字或字节,可以页执行擦除操作。

(2)接口函数
?EEPROM 解锁函数
HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Unlock(void)
解锁数据存储器和 FLASH_PECR 寄存器访问;
- 启用数据EEPROM访问和闪存程序擦除控制寄存器访问;
- 在读写 EEPROM 之前都需要调用该函数;
?EEPROM 锁定函数
HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Lock(void)
锁定数据存储器和 FLASH_PECR 寄存器访问;
- 禁用数据 EEPROM 访问和闪存程序擦除控制寄存器访问;
- 推荐在读写操作后使用以保护 DATA_EEPROM 免受可能的意外操作;
?EEPROM 写函数
HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data)
参数说明:
- TypeProgram:用于区分要写入的数据类型,取值有:
- FLASH_TYPEPROGRAMDATA_BYTE (字节:8位)
- FLASH_TYPEPROGRAMDATA_HALFWORD(字节:16位)
- FLASH_TYPEPROGRAMDATA_WORD(字节:32位)
- Address:用于设置要写入数据 FLASHEx_DATAEEPROM地址;
- Data:写入的数据;
(3)STM32CubeMX 软件配置
?“工程建立、时钟树配置、Debug 串行线配置、代码生成配置” 在【蓝桥杯——物联网设计与开发】基础模块1- GPIO输出 一文中有讲解,这里不再赘述❗️
1️⃣点击引脚 PC15 → 选择 GPIO_Output 模式(此处默认为推挽输出);

2️⃣点击 "GPIO" → 点击引脚 PC15 → 将 "GPIO output level" 栏修改为 "High",即将 PC15 引脚初始化为高电平;
⚠️此处修改不是必须的,应当根据题意要求进行配置,这里默认为上电熄灭;

3️⃣点击左侧 "Connectivity" → 选择 "USART2" → 模式选择 "Asynchronous" (异步通信模式),不使能硬件流控制;

4️⃣在 "Parameter Settings" 中对串口参数进行修改(具体请根据题目要求修改);
- 波特率9600Bit/s
- 8位数据位
- 无奇偶校验
- 1位停止位
- 使能接收和发送
- 16倍过采样

5️⃣生成代码即可;
(4)代码编写
?️main 函数
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- uint32_t count[3] = {0}; // 定义一个数组用于存储读取的地址
- uint32_t *whole_addr; // 定义地址指针
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART2_UART_Init();
- /* USER CODE BEGIN 2 */
- /* EEPROM 读部分 */
- HAL_FLASHEx_DATAEEPROM_Unlock(); // 解锁
- whole_addr = (uint32_t *)(DATA_EEPROM_BASE + 8); //DATA_EEPROM_BASE(0x08080000UL)是FLASHEx_DATAEEPROM的起始地址
- *count = *whole_addr;
- HAL_FLASHEx_DATAEEPROM_Lock(); //锁定
- count[0]++;
- /* EEPROM 写部分 */
- HAL_FLASHEx_DATAEEPROM_Unlock(); // 解锁
- HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, DATA_EEPROM_BASE + 8, count[0]);
- printf("count[0] = %d\r\n", count[0]);
- while(count[0]--)
- {
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET);
- HAL_Delay(500);
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET);
- HAL_Delay(500);
- }
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
?“串口重定向” 在【蓝桥杯——物联网设计与开发】基础模块4 - 串行通信 一文中有讲解,这里不再赘述❗️
- 在初始化时,在 EEPROM 地址8中读出一个字的数据存入 count,并将该数据 +1 后写会该地址;
- 通过串口将该数据打印出来;
- 并且根据数值闪烁 LD5;
⚠️注意:DATA_EEPROM_BASE(0x08080000UL) 是FLASHEx_DATAEEPROM的起始地址,所以我们写入 EEPROM 的地址需要添加该基地址❗️
由于库函数中没有提供专用的读函数,这次采用指针的方式,读取目标地址上的值即可;
(5)实验现象

- 每一次板子上电后,串口打印出 EEPROM 中的值,并将该值进行 +1 处理;
- LD5 根据数值进行间隔 1s 的亮灭闪烁;
二、EEPROM 接口函数封装
?️EEPROM 写函数
- /**
- * @brief EEPROM Write Function EEPROM写函数
- * @param addr EEPROM 地址
- @arg 地址范围为0-512,地址必须是4的整数倍,因为主函数中是按照'字'写入的
- buf 写入数据的地址
- len 写入数据长度
- * @retval None
- */
- void EEPROM_Write(uint32_t addr, uint32_t *buf, uint32_t len)
- {
- uint32_t whole_addr; // 定义地址指针
- HAL_FLASHEx_DATAEEPROM_Unlock(); // 解锁
- whole_addr = (addr + DATA_EEPROM_BASE);
- //DATA_EEPROM_BASE(0x08080000UL)是FLASHEx_DATAEEPROM的起始地址
- while(len--)
- {
- HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, whole_addr, *buf++);
- whole_addr += 4;
- }
- HAL_FLASHEx_DATAEEPROM_Lock(); //锁定
- }
?️EEPROM 读函数
- /**
- * @brief EEPROM Read Function EEPROM读函数
- * @param addr EEPROM 地址
- @arg 地址范围为0-512,地址必须是4的整数倍,因为主函数中是按照'字'写入的
- buf 写入地址
- len 读取数据长度
- * @retval None
- */
- void EEPROM_Read(uint32_t addr, uint32_t *buf, uint32_t len)
- {
- uint32_t *whole_addr; // 定义地址指针
- HAL_FLASHEx_DATAEEPROM_Unlock(); // 解锁
- whole_addr = (uint32_t *)(addr + DATA_EEPROM_BASE);
- //DATA_EEPROM_BASE(0x08080000UL)是FLASHEx_DATAEEPROM的起始地址
- while(len--)
- {
- *buf++ = *whole_addr++;
- }
- HAL_FLASHEx_DATAEEPROM_Lock(); //锁定
- }
?EEPROM 接口函数调用实例
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- uint32_t count[3] = {0}; // 定义一个数组用于存储读取的地址
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART2_UART_Init();
- /* USER CODE BEGIN 2 */
- EEPROM_Read(8, count, 2); // 在EEPROM地址4上读取数据
- count[0]++;
- count[1]++;
- EEPROM_Write(8, count, 2);
- printf("count[0] = %d\r\n", count[0]);
- printf("count[1] = %d\r\n", count[1]);
- while(count[0]--)
- {
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET);
- HAL_Delay(500);
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET);
- HAL_Delay(500);
- }
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
此处测试写两个数据,实验现象正常;
三、踩坑日记
?写函数中地址参数需为4的整数倍,因为主函数中是按照'字'写入的,否则系统会卡死在 HAL_FLASHEx_DATAEEPROM_Program 函数中;
⭐在多数据写入时,传入函数 HAL_FLASHEx_DATAEEPROM_Program 的地址参数应该➕4;

评论记录:
回复评论: