实验现象:将LED灯的状态保存到Flash里,掉电读取Flash并设置LED。
1,STM32CubeMx 配置
1.1 SPI引脚说明
1.2 参数配置
1.3 GPIO配置
2,程序
2.1 保存LED状态到Flash
发送数据流程为:Flash写使能——擦除扇区——延迟100ms——写使能——页编程——延迟10ms
需要注意的是每一次对Flash进行操作的时候都需要:开启片选NSS——Flash操作——关闭片选NSS
开启或关闭片选NSS:就是对NSS的GPIO引脚输入相应的高低电平。笔者这里NSS的GPIO引脚是PA4。
// 开启片选NSS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
// 关闭片选NSS
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
(1) Flash写使能:从器件工作手册上可以看到,Flash的写使能指令是0x06。
uint8_t WriteEnableCmd[] = {0x06}; // 写使能命令
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 开启片选
HAL_SPI_Transmit(&hspi1,WriteEnableCmd,1,HAL_MAX_DELAY); // 发送命令
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 关闭片选
(2) 擦除扇区:擦除扇区指令为0x20。
uint8_t sectorEraseCmd[] = {0x20,0x00,0x00,0x00}; // 擦除命令和24位擦除地址
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 开启片选
HAL_SPI_Transmit(&hspi1,sectorEraseCmd,4,HAL_MAX_DELAY); // 发送擦除命令
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 关闭片选
(3) 延时100ms:
// 延迟100ms
HAL_Delay(100);
(4) Flash写使能:与上面的一样,写使能指令是0x06。
(5)页编程写入数据: 注意页编程的指令是 0x02 ,擦除扇区的指令是 0x20。
uint8_t pageProgCmd[5]; // 存放页编程命令、24位写入地址、以及写入的数据
pageProgCmd[0]=0x02; // 页编程命令
pageProgCmd[1]=0x00; // 页编程地址
pageProgCmd[2]=0x00;
pageProgCmd[3]=0x00;
pageProgCmd[4]=led_state; // 存放数据——LED状态
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 开启片选
HAL_SPI_Transmit(&hspi1,pageProgCmd,5,HAL_MAX_DELAY); // 页编程
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 关闭片选
(6) 延时10ms:
// 延迟10ms
HAL_Delay(10);
2.2 从Flash读取数据
读取数据流程为:开启片选——Flash发送读命令——读取数据赋值——关闭片选
uint8_t LoadLEDstate(void)
{
uint8_t readEnableCmd[] = {0x03,0x00,0x00,0x00}; // 读命令(0x03)和地址
uint8_t ledState = 0xff; // 存放读取的数据
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 开启片选
HAL_SPI_Transmit(&hspi1,readEnableCmd,4,HAL_MAX_DELAY); // 发送读命令
HAL_SPI_Receive(&hspi1,&ledState,1,HAL_MAX_DELAY); // 接收数据并保存
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 关闭片选
return ledState;
}
2.3 总程序
#include "main.h"
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */
static void SaveLEDstate(uint8_t led_state); // 保存LED状态函数声明
static uint8_t LoadLEDstate(void); // 读取LED状态函数声明
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static void SaveLEDstate(uint8_t led_state) // 保存LED状态函数
{
// 写使能
uint8_t WriteEnableCmd[] = {0x06};
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,WriteEnableCmd,1,HAL_MAX_DELAY);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
// 擦除扇区
uint8_t sectorEraseCmd[] = {0x20,0x00,0x00,0x00};
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,sectorEraseCmd,4,HAL_MAX_DELAY);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
// 延迟100ms
HAL_Delay(100);
// 写使能
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,WriteEnableCmd,1,HAL_MAX_DELAY);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
// 页编程
uint8_t pageProgCmd[5];
pageProgCmd[0]=0x02;
pageProgCmd[1]=0x00;
pageProgCmd[2]=0x00;
pageProgCmd[3]=0x00;
pageProgCmd[4]=led_state;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,pageProgCmd,5,HAL_MAX_DELAY);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
// 延迟10ms
HAL_Delay(10);
}
uint8_t LoadLEDstate(void) // 读取LED状态函数
{
uint8_t readEnableCmd[] = {0x03,0x00,0x00,0x00};
uint8_t ledState = 0xff;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,readEnableCmd,4,HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi1,&ledState,1,HAL_MAX_DELAY);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
return ledState;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void) // 主函数
{
/* USER CODE BEGIN 1 */
/* 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_SPI1_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
uint8_t pre = 1;
uint8_t cur = 1;
uint8_t led_state = 0;
led_state=LoadLEDstate(); // while之前读取Flash
if(led_state == 1)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
}
while (1)
{
pre = cur;
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_SET) // 按钮翻转LED
{
cur=0;
}
else
{
cur=1;
}
if(pre!=cur)
{
if(cur==0){}
else
{
if(led_state == 0)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
led_state = 1;
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
led_state = 0;
}
SaveLEDstate(led_state); // 保存LED状态
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}