写一个STM32L051C8T6的代码,使用HAL库,使用内部EEPROM存储,要求上电发送进入地址设置指令,进入地址设定状态,保证7个RGBLED灭,然后在对应地址放入瓶子,轮询三次,相应的RGBLED闪三下,LED闪三下一样的绿色则最后显示绿灯,LED闪三下不同的(绿色或红色)则最后显示红灯,显示绿灯则串口1显示正确的地址,显示红灯则不显,当地址设定正确后,地址设定状态结束,进入工作状态,运行其他工作代码,完成后请解析代码
时间: 2023-09-28 17:13:37 浏览: 107
以下是代码实现:
```c
#include "stm32l0xx_hal.h"
#include <string.h>
#define EEPROM_ADDR 0x08080000 // 内部EEPROM起始地址
#define LED_NUM 7 // RGBLED数量
#define LED_GREEN GPIO_PIN_13 // 绿色LED引脚
#define LED_RED GPIO_PIN_14 // 红色LED引脚
// 进入地址设定状态
void enterAddressSettingMode(void) {
// 发送进入地址设置指令
uint8_t cmd[5] = {0x7F, 0x7F, 0x7F, 0x7F, 0x7F};
HAL_UART_Transmit(&huart1, cmd, 5, 1000);
// 延时等待进入地址设定状态
HAL_Delay(2000);
// 关闭所有RGBLED
for (int i = 0; i < LED_NUM; i++) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6, GPIO_PIN_RESET);
}
}
// 存储瓶子到EEPROM
void storeBottleToEEPROM(uint32_t address, uint8_t* data, uint16_t size) {
HAL_FLASH_Unlock();
FLASH_Erase_Sector(FLASH_SECTOR_2, FLASH_VOLTAGE_RANGE_3);
for (int i = 0; i < size; i++) {
uint8_t byte = data[i];
HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address + i, byte);
}
HAL_FLASH_Lock();
}
// 从EEPROM读取瓶子数据
void readBottleFromEEPROM(uint32_t address, uint8_t* data, uint16_t size) {
memcpy(data, (void*)address, size);
}
int main(void) {
HAL_Init();
// 初始化GPIO
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | LED_GREEN | LED_RED;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始化UART
__HAL_RCC_USART1_CLK_ENABLE();
UART_HandleTypeDef huart1;
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
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;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);
enterAddressSettingMode(); // 进入地址设定状态
uint8_t address[4] = {0x01, 0x23, 0x45, 0x67};
storeBottleToEEPROM(EEPROM_ADDR, address, 4); // 存储瓶子到EEPROM
uint8_t read_address[4];
for (int i = 0; i < 3; i++) { // 轮询三次
readBottleFromEEPROM(EEPROM_ADDR, read_address, 4); // 从EEPROM读取瓶子数据
if (memcmp(address, read_address, 4) == 0) { // 地址设定正确
HAL_GPIO_WritePin(LED_GREEN, GPIO_PIN_SET); // 点亮绿色LED
HAL_UART_Transmit(&huart1, address, 4, 1000); // 串口1显示正确的地址
} else { // 地址设定错误
HAL_GPIO_WritePin(LED_RED, GPIO_PIN_SET); // 点亮红色LED
}
HAL_Delay(1000);
// 关闭所有RGBLED
for (int j = 0; j < LED_NUM; j++) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6, GPIO_PIN_RESET);
}
HAL_Delay(1000);
}
if (HAL_GPIO_ReadPin(LED_GREEN) == GPIO_PIN_SET && HAL_GPIO_ReadPin(LED_RED) == GPIO_PIN_RESET) { // 显示绿灯
HAL_GPIO_WritePin(LED_GREEN, GPIO_PIN_SET);
} else { // 显示红灯
HAL_GPIO_WritePin(LED_RED, GPIO_PIN_SET);
}
// 进入工作状态,运行其他工作代码
while (1) {}
}
```
代码实现步骤:
1. 初始化GPIO和UART。
2. 进入地址设定状态,发送进入地址设置指令,并延时等待进入地址设定状态。
3. 将要存储的瓶子地址存储到EEPROM中。
4. 轮询三次,从EEPROM中读取瓶子数据并与存储的地址进行比较,如果地址正确则点亮绿色LED并通过串口1显示地址,否则点亮红色LED。
5. 根据LED状态显示绿灯或红灯。
6. 进入工作状态,运行其他工作代码。
需要注意的是,STM32L051C8T6的内部EEPROM起始地址为0x08080000,存储时需要先解锁FLASH并擦除对应扇区,存储操作完成后需要重新锁定FLASH。从EEPROM中读取数据可以直接使用memcpy函数,因为内部EEPROM的地址是线性的,可以当做普通的内存使用。
阅读全文