【STM32-HAL】 SPI通信与Flash数据写入实战

文章目录

  • 1.参考教程
  • [2. 4种时间模式](#2. 4种时间模式)
  • [3. 3个编程接口](#3. 3个编程接口)
    • [3.1 `HAL_StatusTypeDef HAL_SPI_Transmit(...)` :](#3.1 HAL_StatusTypeDef HAL_SPI_Transmit(...) :)
      • [3.1.1 参数说明](#3.1.1 参数说明)
      • [3.1.2 例子](#3.1.2 例子)
    • [3.2 `HAL_StatusTypeDef HAL_SPI_Receive(...)` :](#3.2 HAL_StatusTypeDef HAL_SPI_Receive(...) :)
    • [3.3 `HAL_StatusTypeDef HAL_SPI_TransmitReceive(...)` :](#3.3 HAL_StatusTypeDef HAL_SPI_TransmitReceive(...) :)
      • [3.3.1 参数说明](#3.3.1 参数说明)
      • [3.3.2 例子](#3.3.2 例子)
  • [4. spi应用-flash数据写入](#4. spi应用-flash数据写入)
    • [4.1 flash数据写入过程](#4.1 flash数据写入过程)
    • [4.2 流程](#4.2 流程)
    • [5. 流程实现](#5. 流程实现)
      • [5.1 写使能](#5.1 写使能)
      • [5.2 扇区擦除](#5.2 扇区擦除)
      • [5.3 页编程](#5.3 页编程)
    • [6. 代码实现](#6. 代码实现)
  • [5. spi应用-flash数据加载](#5. spi应用-flash数据加载)
    • [5.1 流程](#5.1 流程)
    • [5.2 代码实现](#5.2 代码实现)

1.参考教程

[STM32 HAL库][SPI]外部flash实验
[STM32 HAL库][SPI]外部flash数据存取

2. 4种时间模式

3. 3个编程接口

3.1 HAL_StatusTypeDef HAL_SPI_Transmit(...)

用于通过 SPI 总线发送数据,返回 HAL_StatusTypeDef 类型状态值 ,作用为"发送"。

c 复制代码
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi,
                                    uint8_t *pData,
                                    uint16_t Size,
                                    uint32_t Timeout)

3.1.1 参数说明

参数名 说明
hspi 填写 SPI 句柄的指针
pData 填写要发送的数据
Size 填写要发送的数据的数量,以字节为单位
Timeout 超时时间,单位是 ms;HAL_MAX_DELAY 表示无限长的超时时间

3.1.2 例子

  • 通信场景 :主机(单片机)向从机1发送数据 0x5a, 0x33
  • 硬件连接 :涉及主机与从机的 MOSI(主机输出从机输入)、MISO(主机输入从机输出 ,从机1此处未动作 )、SCK(时钟 )、NSS(从机选择 ,NSS1 选中从机1 )引脚
  • 代码逻辑
    • 定义发送数据数组 uint8_t dataToSend[] = {0x5a, 0x33};
    • 通过 HAL_GPIO_WritePin 函数拉低引脚选中从机1
    • 调用 HAL_SPI_Transmit 函数发送数据
    • 数据发送后,通过 HAL_GPIO_WritePin 函数拉高引脚取消选中从机1

3.2 HAL_StatusTypeDef HAL_SPI_Receive(...)

用于通过 SPI 总线接收数据,返回 HAL_StatusTypeDef 类型状态值 ,作用为"接收"。

c 复制代码
HAL_StatusTypeDef HAL_SPI_Receive(&hspi1, uint8_t *pData, uint16_t Size, uint32_t Timeout)

3.2.1参数说明

参数名 说明
参数hspi 填写SPI句柄的指针
参数pData 填写接收缓冲区
参数Size 填写要发送的数据的数量,以字节为单位
参数Timeout 超时时间,单位是ms;HAL_MAX_DELAY表示无限长的超时时间

3.2.2 例子

  1. 功能描述:从从机1接收2个字节的数据
  2. 硬件连接:主机(单片机)与从机1通过MOSI、MISO、SCK、NSS1引脚连接,从机还有从机2、从机3,引脚连接逻辑同从机1
  3. 代码逻辑
    • 定义接收缓冲区 uint8_t dataRcvd[] = {0xff, 0xff};
    • 通过 HAL_GPIO_WritePin(..., GPIO_PIN_RESET); 函数拉低引脚选中从机1
    • 调用 HAL_SPI_Receive(&hspi1, dataRcvd, 2, HAL_MAX_DELAY); 函数,参数含SPI句柄 &hspi1、接收缓冲区 dataRcvd、数据长度 2(字节)、超时时间 HAL_MAX_DELAY(无限超时 )
    • 数据接收后,通过 HAL_GPIO_WritePin(..., GPIO_PIN_SET); 函数拉高引脚取消选中从机1
  4. 时序图 :展示NSS1(低电平选中 )、SCK(时钟信号 )、MOSI(发送 0xff0xff 波形 )、MISO(接收 0x1f0x27 波形 )的时序关系 ,呈现SPI接收数据时各信号的变化 。

3.3 HAL_StatusTypeDef HAL_SPI_TransmitReceive(...)

用于通过 SPI 总线同时进行发送和接收数据操作,返回 HAL_StatusTypeDef 类型状态值 ,作用为"发送同时接收"。

c 复制代码
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, 
                                           uint8_t *pTxData, 
                                           uint8_t *pRxData, 
                                           uint16_t Size, 
                                           uint32_t Timeout)

发送数据的同时接收数据

3.3.1 参数说明

参数名 说明
参数hspi 填写SPI句柄的指针
参数pTxData 填写要发送的数据
参数pRxData 填写接收数据缓冲区
参数Size 发送数据的数量=接收数据的数量,以字节为单位
参数Timeout 超时时间,单位是ms

3.3.2 例子

  1. 功能描述 :发送 {0x5a, 0x33} ,同时接收 2 个字节数据
  2. 硬件连接 :主机(单片机)与从机 1 通过 MOSI(主机输出从机输入 )、MISO(主机输入从机输出 )、SCK(时钟 )、NSS1(从机选择 )引脚连接,从机还有从机 2、从机 3 ,引脚连接逻辑同从机 1
  3. 代码逻辑
    • 定义发送数据数组 uint8_t txData[] = {0x5a, 0x33};
    • 定义接收缓冲区 uint8_t rxData[2];
    • 通过 HAL_GPIO_WritePin(..., GPIO_PIN_RESET); 函数拉低引脚选中从机 1
    • 调用 HAL_SPI_TransmitReceive(&hspi1, txData, rxData, 2, HAL_MAX_DELAY); 函数,参数含 SPI 句柄 &hspi1、发送数据数组 txData、接收缓冲区 rxData、数据长度 2(字节)、超时时间 HAL_MAX_DELAY(无限超时 )
    • 数据收发后,通过 HAL_GPIO_WritePin(..., GPIO_PIN_SET); 函数拉高引脚取消选中从机 1
  4. 时序图 :展示 NSS1(低电平选中 )、SCK(时钟信号 )、MOSI(发送 0x5a0x33 波形 )、MISO(接收 0x1f0x27 波形 )的时序关系 ,呈现 SPI 同时收发数据时各信号的变化 。

4. spi应用-flash数据写入

4.1 flash数据写入过程

4.2 流程

5. 流程实现

5.1 写使能

抽水机的写使能是发送0x06

5.2 扇区擦除

扇区擦除的指令码是0x20,所以首先发送0x20,后面接着24位的扇区首地址

5.3 页编程

页编程指令码是0x02,后面跟着24位地址(往哪里写地址就发谁的地址),再后面是发要写入的数据,一次性可以写多个数据

6. 代码实现

c 复制代码
static void SaveLEDState(uint8_t ledState)
{
    // #1. 写使能
    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. 扇区擦除
	uint8_t sectorErase[] = {0x20, 0x00, 0x00, 0x00};
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, sectorErase, 4, HAL_MAX_DELAY);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    HAL_Delay(100);

    // #3. 写使能
    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);

    // #4. 页编程
	uint8_t pageProgCmd[5];//要发送5个字节
	pageProgCmd[0] = 0x02; //页编程指令码是0x02
	pageProgCmd[1] = 0x00; //地址
	pageProgCmd[2] = 0x00; //地址
	pageProgCmd[3] = 0x00; //地址
	pageProgCmd[4] = ledState; //要发送的数据
	
	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); 
	
	HAL_Delay(10); 
  
}

在主函数写上 SaveLEDState( ledState);就可以保存灯的状态数据。

5. spi应用-flash数据加载

5.1 流程

读取数据的指令码是0x03,先发0x03,后面跟24位地址,再往后从总线上读取数据。

首先声明数组,用于存放要发送的数据。先发送读取命令,然后接收数据。最后返回读取的数据。

5.2 代码实现

c 复制代码
// 函数:读取LED状态(从Flash等存储设备)
// 功能:通过SPI总线发送读命令,接收并返回存储的LED状态数据
static uint8_t LoadLEDState(void)
{
    // 读命令及地址:0x03为读数据指令,后三个0x00为起始地址
    uint8_t readDataCmd[] = {0x03, 0x00, 0x00, 0x00}; 
    uint8_t ledState; // 用于存储读取到的LED状态数据

    // 选通从设备:拉低GPIOA_PIN_4(SPI从设备片选信号)
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); 

    // 通过SPI发送读命令:向从设备发送读数据指令及地址,长度4字节,无限超时等待
    HAL_SPI_Transmit(&hspi1, readDataCmd, 4, HAL_MAX_DELAY); 

    // 通过SPI接收数据:从从设备接收1字节数据(LED状态),存入ledState,无限超时等待
    HAL_SPI_Receive(&hspi1, &ledState, 1, HAL_MAX_DELAY); 

    // 取消选通:拉高GPIOA_PIN_4,释放从设备片选
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); 

    return ledState; // 返回读取到的LED状态
}
相关推荐
Yuroo zhou4 小时前
无人机在复杂气流中,IMU 如何精准捕捉姿态变化以维持稳定?
单片机·嵌入式硬件·算法·机器人·无人机
李永奉12 小时前
STM32-USART串口实现接收数据三种方法(1.根据\r\n标志符、2.空闲帧中断、3.根据定时器辅助接收)
stm32·单片机·嵌入式硬件
嵌入式×边缘AI:打怪升级日志12 小时前
【7】串口编程三种模式(查询/中断/DMA)韦东山老师学习笔记(课程听不懂的话试着来看看我的学习笔记吧)
单片机·嵌入式硬件
jghhh0112 小时前
stm32的PID控制算法
stm32·单片机·嵌入式硬件
你好!蒋韦杰-(烟雨平生)13 小时前
扫雷游戏C++
c++·单片机·游戏
来点光吧17 小时前
STM32F1 Flash的操作
stm32·单片机·嵌入式硬件
Cyrus_柯18 小时前
硬件电路设计(基本元器件)
嵌入式硬件·元器件·电路基础
扣篮发型不乱19 小时前
STM32 按键输入检测 轮询和中断
stm32·单片机
四谎真好看20 小时前
第六章第一节 TIM 定时中断
stm32·单片机·嵌入式硬件·tim·江科大
扣篮发型不乱20 小时前
STM32 外部中断 和 定时器中断
stm32·单片机·嵌入式硬件