ToB企服应用市场:ToB评测及商务社交产业平台

标题: STM32 SPI Flash读写实验手册 [打印本页]

作者: 温锦文欧普厨电及净水器总代理    时间: 2025-2-21 12:47
标题: STM32 SPI Flash读写实验手册
实验名称

基于SPI Flash的断电状态保存系统

实验目标


硬件要求


硬件毗连

SPI Flash引脚STM32引脚CLKSPI_SCK (PA5)DISPI_MISO (PA7)DOSPI_MOSI (PA6)CSNSS(PA4)VCC3.3VGNDGND 按键毗连:




软件配置(STM32CubeMX)
















按钮及其灯亮代码实现

  1. uint8_t pre = 1;//按钮按下的前标志
  2. uint8_t cur = 1;//按钮按下的后标志
  3. uint8_t ledState = 0;//板载LED的状态标志
  4. //读取flsh数据并进行判断,函数实现在fish读数据实现
  5. ledState = LoadledState();
  6.        
  7.         if(ledState == 1){
  8.                 HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
  9.         }else{
  10.                 HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
  11.         }
  12.   while (1)
  13.   {
  14.                 pre = cur;将前后标志重置为1,既按钮未被按下的状态
  15.                
  16.                 if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_SET){//获取按钮引脚电平
  17.                         cur = 1;//引脚高电平
  18.                 }else{
  19.                         cur = 0;//引脚低电平
  20.                 }
  21.                
  22.                 if(pre !=  cur){//按钮有动作
  23.                         HAL_Delay(10);//延迟消抖
  24.                         if(cur == 0){//按下按钮(图2)
  25.                        
  26.                         }else{//按钮弹起(图3)
  27.                                 if(ledState == 1){
  28.                                         HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);//板载LED熄灭
  29.                                         ledState = 0;//设置LED灯状态为0
  30.                                 }else{
  31.                                         HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);//板载LED点亮
  32.                                         ledState = 1;//设置LED灯状态为1
  33.                                 }
  34.                     SaveLEDState(ledState);//flsh写入数据的方法在后面实现
  35.                         }
  36.                 }
复制代码
未按下

                                                          图1

按钮按下 

                                                          图2

 按钮弹起

                                                           图3

SPI Flash读写原理

读写函数


TypeDef HAL_SPI_Transmit

HAL_SPI_Transmit函数通过SPI接口以阻塞(轮询)模式发送指定长度的数据。
  1. HAL_StatusTypeDef HAL_SPI_Transmit(
  2.     SPI_HandleTypeDef *hspi,
  3.     uint8_t *pData,
  4.     uint16_t Size,
  5.     uint32_t Timeout
  6. );
复制代码
参数阐明
参数类型阐明hspiSPI_HandleTypeDef*指向SPI外设句柄的指针,包含SPI配置信息(如SPI1、SPI2等)pDatauint8_t*待发送数据的缓冲区指针Sizeuint16_t待发送数据的字节数Timeoutuint32_t超时时间(单位:毫秒),若超时,函数返回HAL_TIMEOUT 返回值
返回值阐明HAL_OK传输成功完成HAL_ERROR发生错误(如SPI未初始化、DMA错误等)HAL_BUSYSPI外设正忙(上一次传输未完成)HAL_TIMEOUT传输超时(未在指定时间内完成)


HAL_SPI_Receive

HAL_SPI_Receive通过SPI接口以阻塞(轮询)模式接收指定长度的数据。
  1. HAL_StatusTypeDef HAL_SPI_Receive(
  2.     SPI_HandleTypeDef *hspi,
  3.     uint8_t *pData,
  4.     uint16_t Size,
  5.     uint32_t Timeout
  6. );
复制代码
参数阐明
参数类型阐明hspiSPI_HandleTypeDef*指向SPI外设句柄的指针,包含SPI配置信息(如SPI1、SPI2等)pDatauint8_t*接收数据的缓冲区指针(用于存储从设备返回的数据)Sizeuint16_t待接收数据的字节数Timeoutuint32_t超时时间(单位:毫秒),若超时,函数返回HAL_TIMEOUT 返回值
返回值阐明HAL_OK接收成功完成HAL_ERROR发生错误(如SPI未初始化、DMA错误等)HAL_BUSYSPI外设正忙(上一次传输未完成)HAL_TIMEOUT接收超时(未在指定时间内完成)


HAL_SPI_TransmitReceive

全双工同步通讯:在发送数据的同时接收数据,每个发送字节对应一个接收字节。高效数据互换,适用于须要高速双向数据互换的场景(如传感器数据读取、通讯协议交互)。
  1. HAL_StatusTypeDef HAL_SPI_TransmitReceive(
  2.     SPI_HandleTypeDef *hspi,
  3.     uint8_t *pTxData,
  4.     uint8_t *pRxData,
  5.     uint16_t Size,
  6.     uint32_t Timeout
  7. );
复制代码
参数阐明
参数类型阐明hspiSPI_HandleTypeDef*指向SPI外设句柄的指针pTxDatauint8_t*发送数据缓冲区指针(需发送的数据)pRxDatauint8_t*接收数据缓冲区指针(用于存储接收的数据)Sizeuint16_t发送/接收数据的字节数(需确保发送和接收数据长度一致)Timeoutuint32_t超时时间(单位:毫秒) 返回值
返回值阐明HAL_OK全双工传输成功完成HAL_ERROR参数错误或SPI初始化失败HAL_BUSYSPI外设正忙(上一次操纵未完成)HAL_TIMEOUT超时未完成传输


flsh布局

存储单位大小操纵特性页(Page)256字节最小编程单位扇区(Sector)4KB最小擦除单位块(Block)64KB大容量擦除单位整片(Chip)8MB(64Mbit)全片擦除操纵 存储特性


flsh写入数据过程


根据数据写入过程函数设计如下
  1. static void SaveLEDState(uint8_t ledState){
  2.     //写使能
  3.     //扇区删除
  4.     HAL_Delay(100)
  5.     //写使能
  6.     //扇区删除
  7.     HAL_Delay(10)
  8. }
复制代码
写使能

  1. 操作时序:
  2. CS拉低 → 发送0x06 → CS拉高
  3. 作用:开启写操作许可(每次写操作前必须执行)
复制代码

实当代码
  1. uint8_t writeEnableCmd[] = {0x06};
  2. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  3. HAL_SPI_Transmit(&hspil,writeEnableCmd,1,HAL_MAX_DELAY);
  4. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
复制代码
扇区擦除

  1. 操作时序:
  2. CS拉低 →
  3. 发送0x20 →
  4. 发送24位地址(仅使用高16位确定扇区)→
  5. CS拉高
  6. 擦除时间:典型值400ms
复制代码

实当代码
  1. uint8_t sectorEraseCmd[] = {0x20,0x00,0x00,0x00};
  2. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  3. HAL_SPI_Transmit(&hspil1,sectorEraseCmd,4,HAL_MAX_DELAY);
  4. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
复制代码
页编程

  1. 操作时序:
  2. CS拉低 →
  3. 发送0x02 →
  4. 发送24位地址(A23-A0)→
  5. 发送数据(最多256字节)→
  6. CS拉高
  7. 注意:地址必须页对齐(如0x000000, 0x000100等)
复制代码

实当代码
  1. uint8_t pageProgCmd[5];
  2. pageProgCmd[0] = 0x02;
  3. pageProgCmd[1] = 0;
  4. pageProgCmd[2] = 0;
  5. pageProgCmd[3] = 0;
  6. pageProgCmd[4] = ledState;
  7. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  8. HAL_SPI_Transmit(&hspi1,pageProgCmd,5,HAL_MAX_DELAY);
  9. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
复制代码
实当代码

  1. static void SaveLEDState(uint8_t ledState){
  2. //写使能
  3.         uint8_t writeEnableCmd[] = {0x06};
  4.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  5.         HAL_SPI_Transmit(&hspi1,writeEnableCmd,1,HAL_MAX_DELAY);
  6.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
  7. //扇区擦除
  8.         uint8_t sectorEraseCmd[] = {0x20,0x00,0x00,0x00};
  9.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  10.         HAL_SPI_Transmit(&hspi1,sectorEraseCmd,4,HAL_MAX_DELAY);
  11.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
  12. //延迟
  13.         HAL_Delay(100);
  14. //写使能
  15.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  16.         HAL_SPI_Transmit(&hspi1,writeEnableCmd,1,HAL_MAX_DELAY);
  17.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
  18. //页编程
  19.         uint8_t pageProgCmd[5];
  20.         pageProgCmd[0] = 0x02;
  21.         pageProgCmd[1] = 0x00;
  22.         pageProgCmd[2] = 0x00;
  23.         pageProgCmd[3] = 0x00;
  24.         pageProgCmd[4] = ledState;
  25.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  26.         HAL_SPI_Transmit(&hspi1,pageProgCmd,5,HAL_MAX_DELAY);
  27.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
  28. //延迟
  29.         HAL_Delay(10);
  30. }
复制代码
上述方法加到判断按钮状态的if语句中去。
flsh读数据

  1. 操作时序:
  2. CS拉低 →
  3. 发送0x03 →
  4. 发送24位地址 →
  5. 连续读取数据 →
  6. CS拉高
  7. 特点:支持跨页连续读取
复制代码

实当代码
  1. static uint8_t LoadledState(){
  2.     uint8_t readDateCmd[] = {0x03,0x00,0x00,0x00};
  3.     uint8_t ledState = 0xff;
  4.     HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  5.     HAL_SPI_Transmit(&hspi1,readDateCmd,4,HAL_MAX_DELAY);
  6.     HAL_SPI_Receive(&hspi1,&ledState ,1,HAL_MAX_DELAY);
  7.     HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
  8.     return ledState ;
  9. }
复制代码
读取flsh内容函数要在程序加载前执行并对返回的数据进行判断并进行亮灯或没灯操纵。

实验步骤



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4