分为.h和.c文件
时间: 2025-08-02 10:35:15 AIGC 浏览: 16
<think>我们将按照要求将代码分为头文件(.h)和源文件(.c)。头文件包含函数声明、宏定义和类型定义,源文件包含具体实现。###头文件(bsp_spi_flash.h)```c#ifndef__BSP_SPI_FLASH_H#define__BSP_SPI_FLASH_H#include"stm32f4xx.h"//宏定义(根据硬件连接调整)#defineBSP_GPIO_RCURCC_AHB1Periph_GPIOA#defineBSP_SPI_RCURCC_APB2Periph_SPI1#defineBSP_GPIO_PORTGPIOA#defineBSP_GPIO_AFGPIO_AF_SPI1#defineBSP_SPISPI1#defineBSP_SPI_NSSGPIO_Pin_4#defineBSP_SPI_SCKGPIO_Pin_5#defineBSP_SPI_MISOGPIO_Pin_6#defineBSP_SPI_MOSIGPIO_Pin_7//W25Q128指令集#defineW25X_WriteEnable0x06#defineW25X_ReadStatusReg0x05#defineW25X_PageProgram0x02#defineW25X_SectorErase0x20#defineW25X_BlockErase0xD8//64KB块擦除#defineW25X_ChipErase0xC7//整片擦除#defineW25X_ReadData0x03#defineW25X_FastReadData0x0B#defineW25X_ManufactDeviceID0x90#defineW25X_JedecDeviceID0x9F//函数声明voidSPI1_Init(void);voidW25Q_CS(uint8_tstate);uint8_tSPI1_ReadWriteByte(uint8_tTxData);voidW25Q_WaitBusy(void);voidW25Q_WriteEnable(void);uint32_tW25Q_ReadID(void);voidW25Q_SectorErase(uint32_taddr);voidW25Q_BlockErase(uint32_taddr);voidW25Q_ChipErase(void);voidW25Q_PageWrite(uint8_t*pBuffer,uint32_taddr,uint16_tlen);voidW25Q_ReadData(uint8_t*pBuffer,uint32_taddr,uint16_tlen);voidW25Q_FastReadData(uint8_t*pBuffer,uint32_taddr,uint16_tlen);#endif/*__BSP_SPI_FLASH_H*/```###源文件(bsp_spi_flash.c)```c#include"bsp_spi_flash.h"#include<string.h>//用于memcmp//SPI1初始化voidSPI1_Init(void){GPIO_InitTypeDefGPIO_InitStructure;SPI_InitTypeDefSPI_InitStructure;//1.使能时钟RCC_AHB1PeriphClockCmd(BSP_GPIO_RCU,ENABLE);RCC_APB2PeriphClockCmd(BSP_SPI_RCU,ENABLE);//2.配置SPI引脚(SCK/MOSI/MISO)GPIO_InitStructure.GPIO_Pin=BSP_SPI_SCK|BSP_SPI_MOSI|BSP_SPI_MISO;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;GPIO_Init(BSP_GPIO_PORT,&GPIO_InitStructure);//3.配置NSS引脚(软件控制)GPIO_InitStructure.GPIO_Pin=BSP_SPI_NSS;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;GPIO_Init(BSP_GPIO_PORT,&GPIO_InitStructure);//4.引脚复用映射GPIO_PinAFConfig(BSP_GPIO_PORT,GPIO_PinSource5,BSP_GPIO_AF);//SCKGPIO_PinAFConfig(BSP_GPIO_PORT,GPIO_PinSource6,BSP_GPIO_AF);//MISOGPIO_PinAFConfig(BSP_GPIO_PORT,GPIO_PinSource7,BSP_GPIO_AF);//MOSI//5.SPI参数配置SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode=SPI_Mode_Master;SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;//W25Q128要求SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;//W25Q128要求SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_4;//42MHz/4=10.5MHzSPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;SPI_Init(BSP_SPI,&SPI_InitStructure);//6.使能SPISPI_Cmd(BSP_SPI,ENABLE);GPIO_SetBits(BSP_GPIO_PORT,BSP_SPI_NSS);//初始释放片选}//片选控制voidW25Q_CS(uint8_tstate){if(state)GPIO_SetBits(BSP_GPIO_PORT,BSP_SPI_NSS);elseGPIO_ResetBits(BSP_GPIO_PORT,BSP_SPI_NSS);}//SPI单字节收发uint8_tSPI1_ReadWriteByte(uint8_tTxData){while(SPI_I2S_GetFlagStatus(BSP_SPI,SPI_I2S_FLAG_TXE)==RESET);//等待发送缓冲区空SPI_I2S_SendData(BSP_SPI,TxData);while(SPI_I2S_GetFlagStatus(BSP_SPI,SPI_I2S_FLAG_RXNE)==RESET);//等待接收完成returnSPI_I2S_ReceiveData(BSP_SPI);}//等待Flash操作完成voidW25Q_WaitBusy(void){uint8_tstatus;W25Q_CS(0);SPI1_ReadWriteByte(W25X_ReadStatusReg);do{status=SPI1_ReadWriteByte(0xFF);}while(status&0x01);//检查BUSY位W25Q_CS(1);}//写使能voidW25Q_WriteEnable(void){W25Q_CS(0);SPI1_ReadWriteByte(W25X_WriteEnable);W25Q_CS(1);}//读取设备ID(制造商ID+设备ID)uint32_tW25Q_ReadID(void){uint32_tid=0;W25Q_CS(0);SPI1_ReadWriteByte(W25X_ManufactDeviceID);SPI1_ReadWriteByte(0x00);//3个dummy字节SPI1_ReadWriteByte(0x00);SPI1_ReadWriteByte(0x00);id=SPI1_ReadWriteByte(0xFF)<<16;id|=SPI1_ReadWriteByte(0xFF)<<8;id|=SPI1_ReadWriteByte(0xFF);W25Q_CS(1);returnid;//正确ID应为0xEF4018}//扇区擦除(4KB)voidW25Q_SectorErase(uint32_taddr){W25Q_WriteEnable();W25Q_CS(0);SPI1_ReadWriteByte(W25X_SectorErase);SPI1_ReadWriteByte((addr>>16)&0xFF);//24位地址SPI1_ReadWriteByte((addr>>8)&0xFF);SPI1_ReadWriteByte(addr&0xFF);W25Q_CS(1);W25Q_WaitBusy();//等待擦除完成}//块擦除(64KB)voidW25Q_BlockErase(uint32_taddr){W25Q_WriteEnable();W25Q_CS(0);SPI1_ReadWriteByte(W25X_BlockErase);SPI1_ReadWriteByte((addr>>16)&0xFF);SPI1_ReadWriteByte((addr>>8)&0xFF);SPI1_ReadWriteByte(addr&0xFF);W25Q_CS(1);W25Q_WaitBusy();}//整片擦除voidW25Q_ChipErase(void){W25Q_WriteEnable();W25Q_CS(0);SPI1_ReadWriteByte(W25X_ChipErase);W25Q_CS(1);W25Q_WaitBusy();//等待时间较长,典型值几十秒}//页编程(最大256字节)voidW25Q_PageWrite(uint8_t*pBuffer,uint32_taddr,uint16_tlen){if(len>256)len=256;//限制长度W25Q_WriteEnable();W25Q_CS(0);SPI1_ReadWriteByte(W25X_PageProgram);SPI1_ReadWriteByte((addr>>16)&0xFF);SPI1_ReadWriteByte((addr>>8)&0xFF);SPI1_ReadWriteByte(addr&0xFF);for(uint16_ti=0;i<len;i++)SPI1_ReadWriteByte(pBuffer[i]);W25Q_CS(1);W25Q_WaitBusy();}//读取数据voidW25Q_ReadData(uint8_t*pBuffer,uint32_taddr,uint16_tlen){W25Q_CS(0);SPI1_ReadWriteByte(W25X_ReadData);SPI1_ReadWriteByte((addr>>16)&0xFF);SPI1_ReadWriteByte((addr>>8)&0xFF);SPI1_ReadWriteByte(addr&0xFF);for(uint16_ti=0;i<len;i++)pBuffer[i]=SPI1_ReadWriteByte(0xFF);W25Q_CS(1);}//快速读取数据(使用dummy时钟)voidW25Q_FastReadData(uint8_t*pBuffer,uint32_taddr,uint16_tlen){W25Q_CS(0);SPI1_ReadWriteByte(W25X_FastReadData);SPI1_ReadWriteByte((addr>>16)&0xFF);SPI1_ReadWriteByte((addr>>8)&0xFF);SPI1_ReadWriteByte(addr&0xFF);SPI1_ReadWriteByte(0xFF);//dummybytefor(uint16_ti=0;i<len;i++)pBuffer[i]=SPI1_ReadWriteByte(0xFF);W25Q_CS(1);}```###示例主程序(main.c)```c#include"stm32f4xx.h"#include"bsp_spi_flash.h"intmain(void){//初始化SPI和FlashSPI1_Init();//验证Flash连接uint32_tflash_id=W25Q_ReadID();if(flash_id!=0xEF4018){//错误处理(例如点亮LED)while(1);}//测试数据uint8_twrite_data[256]="STM32F4+W25Q128TestData";uint8_tread_data[256];uint32_tsector_addr=0x000000;//扇区起始地址//擦除扇区W25Q_SectorErase(sector_addr);//写入数据W25Q_PageWrite(write_data,sector_addr,sizeof(write_data));//读取验证W25Q_ReadData(read_data,sector_addr,sizeof(read_data));//比较数据if(memcmp(write_data,read_data,sizeof(write_data)){//数据校验失败}else{//操作成功}while(1);}```###代码结构说明:1.**头文件(bsp_spi_flash.h)**:-包含所有必要的宏定义(引脚、指令等)-声明SPI初始化及Flash操作函数2.**源文件(bsp_spi_flash.c)**:-实现SPI初始化(GPIO配置、SPI参数设置)-实现基本的Flash操作:擦除(扇区/块/整片)、编程(页写)、读取-包含等待忙状态和写使能等必要辅助函数3.**主程序(main.c)**:-演示初始化流程-执行ID验证、擦除、写入和读取验证操作###关键改进:1.**增强的擦除功能**:-提供扇区擦除(4KB)、块擦除(64KB)和整片擦除三种方式-满足不同应用场景的需求2.**快速读取模式**:-添加`W25Q_FastReadData`函数,通过dummyclock提高读取速度3.**安全限制**:-页写函数增加长度限制(<=256字节)4.**错误处理**:-主程序中对设备ID进行验证,确保硬件连接正确###使用注意事项:1.**跨页写入**:-当写入数据跨页时,需要拆分操作(参考之前的多页写入函数)2.**擦除时间**:-整片擦除时间长达数十秒,需根据实际需求谨慎使用3.**电源稳定性**:-写/擦除操作期间必须保证电源稳定,意外断电可能导致数据损坏§§相关问题§§:1.如何实现W25Q128的写保护功能?2.怎样使用SPI的DMA传输来提高读写效率?3.如何设计一个简单的文件系统来管理W25Q128?4.在多任务系统中如何安全地操作SPIFlash(避免并发访问)?</think>以下是分为头文件(.h)和源文件(.c)的完整实现方案,适用于STM32F407VGT6与W25Q128 Flash存储器的通信:
### 头文件 (bsp_spi_flash.h)
```c
#ifndef __BSP_SPI_FLASH_H
#define __BSP_SPI_FLASH_H
#include "stm32f4xx.h"
// 硬件配置宏定义
#define BSP_GPIO_RCU RCC_AHB1Periph_GPIOA
#define BSP_SPI_RCU RCC_APB2Periph_SPI1
#define BSP_GPIO_PORT GPIOA
#define BSP_GPIO_AF GPIO_AF_SPI1
#define BSP_SPI SPI1
#define BSP_SPI_NSS GPIO_Pin_4
#define BSP_SPI_SCK GPIO_Pin_5
#define BSP_SPI_MISO GPIO_Pin_6
#define BSP_SPI_MOSI GPIO_Pin_7
// W25Q128指令集
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg1 0x05
#define W25X_ReadStatusReg2 0x35
#define W25X_WriteStatusReg 0x01
#define W25X_PageProgram 0x02
#define W25X_QuadPageProgram 0x32
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_ReadData 0x03
#define W25X_FastRead 0x0B
#define W25X_FastReadQuad 0xEB
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define W25X_Enable4ByteAddr 0xB7
#define W25X_Exit4ByteAddr 0xE9
// Flash参数
#define W25Q128_SECTOR_SIZE 4096 // 4KB
#define W25Q128_PAGE_SIZE 256 // 256字节
#define W25Q128_SECTOR_COUNT 4096 // 16MB / 4KB = 4096 sectors
// 函数声明
void SPI_Flash_Init(void);
void W25Q_CS(uint8_t state);
uint8_t SPI_ReadWriteByte(uint8_t TxData);
void W25Q_WaitBusy(void);
void W25Q_WriteEnable(void);
uint32_t W25Q_ReadID(void);
void W25Q_SectorErase(uint32_t SectorAddr);
void W25Q_BlockErase(uint32_t BlockAddr);
void W25Q_ChipErase(void);
void W25Q_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void W25Q_WriteData(uint8_t* pBuffer, uint32_t WriteAddr, uint32_t NumByteToWrite);
void W25Q_ReadData(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead);
void W25Q_ReadFast(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead);
void W25Q_PowerDown(void);
void W25Q_WakeUp(void);
uint8_t W25Q_ReadSR(uint8_t regno);
void W25Q_WriteSR(uint8_t regno, uint8_t sr);
#endif /* __BSP_SPI_FLASH_H */
```
### 源文件 (bsp_spi_flash.c)
```c
#include "bsp_spi_flash.h"
#include "delay.h" // 需要实现毫秒级延时函数
// SPI初始化
void SPI_Flash_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
// 1. 使能时钟
RCC_AHB1PeriphClockCmd(BSP_GPIO_RCU, ENABLE);
RCC_APB2PeriphClockCmd(BSP_SPI_RCU, ENABLE);
// 2. 配置SPI引脚(SCK/MOSI/MISO)
GPIO_InitStructure.GPIO_Pin = BSP_SPI_SCK | BSP_SPI_MOSI | BSP_SPI_MISO;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(BSP_GPIO_PORT, &GPIO_InitStructure);
// 3. 配置NSS引脚(软件控制)
GPIO_InitStructure.GPIO_Pin = BSP_SPI_NSS;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(BSP_GPIO_PORT, &GPIO_InitStructure);
// 4. 引脚复用映射
GPIO_PinAFConfig(BSP_GPIO_PORT, GPIO_PinSource5, BSP_GPIO_AF); // SCK
GPIO_PinAFConfig(BSP_GPIO_PORT, GPIO_PinSource6, BSP_GPIO_AF); // MISO
GPIO_PinAFConfig(BSP_GPIO_PORT, GPIO_PinSource7, BSP_GPIO_AF); // MOSI
// 5. SPI参数配置
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // W25Q128要求
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // W25Q128要求
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // 10.5MHz
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(BSP_SPI, &SPI_InitStructure);
// 6. 使能SPI
SPI_Cmd(BSP_SPI, ENABLE);
W25Q_CS(1); // 初始释放片选
}
// 片选控制
void W25Q_CS(uint8_t state) {
if (state)
GPIO_SetBits(BSP_GPIO_PORT, BSP_SPI_NSS);
else
GPIO_ResetBits(BSP_GPIO_PORT, BSP_SPI_NSS);
}
// SPI单字节收发
uint8_t SPI_ReadWriteByte(uint8_t TxData) {
while (SPI_I2S_GetFlagStatus(BSP_SPI, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(BSP_SPI, TxData);
while (SPI_I2S_GetFlagStatus(BSP_SPI, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(BSP_SPI);
}
// 等待Flash操作完成
void W25Q_WaitBusy(void) {
while ((W25Q_ReadSR(1) & 0x01) == 0x01); // 检查状态寄存器1的BUSY位
}
// 写使能
void W25Q_WriteEnable(void) {
W25Q_CS(0);
SPI_ReadWriteByte(W25X_WriteEnable);
W25Q_CS(1);
}
// 读取设备ID
uint32_t W25Q_ReadID(void) {
uint32_t id = 0;
W25Q_CS(0);
SPI_ReadWriteByte(W25X_JedecDeviceID);
id |= SPI_ReadWriteByte(0xFF) << 16;
id |= SPI_ReadWriteByte(0xFF) << 8;
id |= SPI_ReadWriteByte(0xFF);
W25Q_CS(1);
return id; // 正确ID应为0xEF4018
}
// 扇区擦除(4KB)
void W25Q_SectorErase(uint32_t SectorAddr) {
SectorAddr *= W25Q128_SECTOR_SIZE; // 转换为实际地址
W25Q_WriteEnable();
W25Q_CS(0);
SPI_ReadWriteByte(W25X_SectorErase);
SPI_ReadWriteByte((SectorAddr >> 16) & 0xFF);
SPI_ReadWriteByte((SectorAddr >> 8) & 0xFF);
SPI_ReadWriteByte(SectorAddr & 0xFF);
W25Q_CS(1);
W25Q_WaitBusy(); // 等待擦除完成
}
// 块擦除(64KB)
void W25Q_BlockErase(uint32_t BlockAddr) {
BlockAddr *= W25Q128_SECTOR_SIZE * 16; // 转换为实际地址
W25Q_WriteEnable();
W25Q_CS(0);
SPI_ReadWriteByte(W25X_BlockErase);
SPI_ReadWriteByte((BlockAddr >> 16) & 0xFF);
SPI_ReadWriteByte((BlockAddr >> 8) & 0xFF);
SPI_ReadWriteByte(BlockAddr & 0xFF);
W25Q_CS(1);
W25Q_WaitBusy();
}
// 整片擦除
void W25Q_ChipErase(void) {
W25Q_WriteEnable();
W25Q_CS(0);
SPI_ReadWriteByte(W25X_ChipErase);
W25Q_CS(1);
W25Q_WaitBusy(); // 等待时间较长(典型值几十秒)
}
// 页编程(最大256字节)
void W25Q_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
if (NumByteToWrite > W25Q128_PAGE_SIZE)
NumByteToWrite = W25Q128_PAGE_SIZE;
W25Q_WriteEnable();
W25Q_CS(0);
SPI_ReadWriteByte(W25X_PageProgram);
SPI_ReadWriteByte((WriteAddr >> 16) & 0xFF);
SPI_ReadWriteByte((WriteAddr >> 8) & 0xFF);
SPI_ReadWriteByte(WriteAddr & 0xFF);
for(uint16_t i = 0; i < NumByteToWrite; i++)
SPI_ReadWriteByte(pBuffer[i]);
W25Q_CS(1);
W25Q_WaitBusy();
}
// 通用数据写入(处理跨页)
void W25Q_WriteData(uint8_t* pBuffer, uint32_t WriteAddr, uint32_t NumByteToWrite) {
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t *p = pBuffer;
secpos = WriteAddr / W25Q128_SECTOR_SIZE; // 扇区地址
secoff = WriteAddr % W25Q128_SECTOR_SIZE; // 在扇区内的偏移
secremain = W25Q128_SECTOR_SIZE - secoff; // 扇区剩余空间
if (NumByteToWrite <= secremain)
secremain = NumByteToWrite;
while(1) {
W25Q_ReadData(p, WriteAddr, secremain); // 先读取整个扇区
for (i = 0; i < secremain; i++) { // 校验数据是否需要修改
if (p[i] != 0xFF) break; // 需要擦除
}
if (i < secremain) { // 需要擦除
W25Q_SectorErase(secpos); // 擦除整个扇区
for (i = 0; i < secremain; i++) { // 复制要修改的数据
p[i] = *pBuffer++;
}
W25Q_PageWrite(p, WriteAddr, secremain); // 写入整个扇区
} else {
W25Q_PageWrite(pBuffer, WriteAddr, secremain); // 直接写入
pBuffer += secremain;
}
if (NumByteToWrite == secremain) break; // 写入完成
else { // 写入未完成
secpos++; // 扇区地址增1
secoff = 0; // 偏移位置为0
WriteAddr += secremain; // 写入地址递增
NumByteToWrite -= secremain; // 字节数递减
if (NumByteToWrite > W25Q128_SECTOR_SIZE)
secremain = W25Q128_SECTOR_SIZE; // 下一个扇区还是写不完
else
secremain = NumByteToWrite; // 下一个扇区可以写完
}
}
}
// 标准读取
void W25Q_ReadData(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead) {
W25Q_CS(0);
SPI_ReadWriteByte(W25X_ReadData);
SPI_ReadWriteByte((ReadAddr >> 16) & 0xFF);
SPI_ReadWriteByte((ReadAddr >> 8) & 0xFF);
SPI_ReadWriteByte(ReadAddr & 0xFF);
for(uint32_t i = 0; i < NumByteToRead; i++)
pBuffer[i] = SPI_ReadWriteByte(0xFF);
W25Q_CS(1);
}
// 快速读取(更高速率)
void W25Q_ReadFast(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead) {
W25Q_CS(0);
SPI_ReadWriteByte(W25X_FastRead);
SPI_ReadWriteByte((ReadAddr >> 16) & 0xFF);
SPI_ReadWriteByte((ReadAddr >> 8) & 0xFF);
SPI_ReadWriteByte(ReadAddr & 0xFF);
SPI_ReadWriteByte(0xFF); // dummy byte
for(uint32_t i = 0; i < NumByteToRead; i++)
pBuffer[i] = SPI_ReadWriteByte(0xFF);
W25Q_CS(1);
}
// 读取状态寄存器
uint8_t W25Q_ReadSR(uint8_t regno) {
uint8_t byte = 0, command = 0;
if (regno == 1) command = W25X_ReadStatusReg1;
else if (regno == 2) command = W25X_ReadStatusReg2;
else return 0;
W25Q_CS(0);
SPI_ReadWriteByte(command);
byte = SPI_ReadWriteByte(0xFF);
W25Q_CS(1);
return byte;
}
// 写入状态寄存器
void W25Q_WriteSR(uint8_t regno, uint8_t sr) {
uint8_t command = 0;
if (regno == 1) command = W25X_WriteStatusReg;
else if (regno == 2) command = W25X_WriteStatusReg;
else return;
W25Q_WriteEnable();
W25Q_CS(0);
SPI_ReadWriteByte(command);
SPI_ReadWriteByte(sr);
W25Q_CS(1);
}
// 进入低功耗模式
void W25Q_PowerDown(void) {
W25Q_CS(0);
SPI_ReadWriteByte(W25X_PowerDown);
W25Q_CS(1);
delay_ms(1); // 等待指令完成
}
// 唤醒设备
void W25Q_WakeUp(void) {
W25Q_CS(0);
SPI_ReadWriteByte(W25X_ReleasePowerDown);
W25Q_CS(1);
delay_ms(1); // 等待唤醒
}
```
### 主程序示例 (main.c)
```c
#include "stm32f4xx.h"
#include "bsp_spi_flash.h"
int main(void) {
// 初始化系统时钟等
SystemInit();
// 初始化SPI Flash
SPI_Flash_Init();
// 验证Flash连接
if(W25Q_ReadID() != 0xEF4018) {
// 错误处理
while(1);
}
// 测试数据
uint8_t write_data[512] = "STM32F4 with W25Q128 Flash Memory Test";
uint8_t read_data[512];
uint32_t sector_addr = 1024; // 第1024个扇区
// 擦除扇区
W25Q_SectorErase(sector_addr);
// 写入数据
W25Q_WriteData(write_data, sector_addr * W25Q128_SECTOR_SIZE, sizeof(write_data));
// 读取数据
W25Q_ReadData(read_data, sector_addr * W25Q128_SECTOR_SIZE, sizeof(read_data));
// 验证数据
for(int i = 0; i < sizeof(write_data); i++) {
if(write_data[i] != read_data[i]) {
// 数据校验错误处理
break;
}
}
// 进入低功耗模式
W25Q_PowerDown();
while(1) {
// 主循环
}
}
```
### 代码结构说明:
1. **头文件 (bsp_spi_flash.h)**:
- 包含所有宏定义(硬件配置和指令集)
- 定义Flash参数(扇区大小、页大小等)
- 声明所有公共函数接口
2. **源文件 (bsp_spi_flash.c)**:
- **SPI初始化**:配置GPIO和SPI外设
- **底层通信**:片选控制、字节传输
- **基本操作**:等待忙状态、写使能、ID读取
- **存储操作**:擦除(扇区/块/整片)、编程(页写)、读取
- **高级功能**:状态寄存器操作、低功耗模式
3. **关键特性**:
- **跨页写入处理**:`W25Q_WriteData`自动处理跨页和擦除需求
- **安全写入**:先读取后校验,避免不必要的擦除
- **低功耗支持**:`PowerDown`和`WakeUp`函数
- **快速读取**:支持高速读取模式
### 使用注意事项:
1. **地址处理**:
- 擦除函数使用扇区号作为参数(0-4095)
- 读写函数使用实际字节地址
2. **写入限制**:
- 单次写入不能超过256字节(页大小)
- 写入前必须先擦除(擦除最小单位4KB)
3. **性能优化**:
- 批量写入时,使用`W25Q_WriteData`自动处理扇区边界
- 读取大量数据时使用`W25Q_ReadFast`
4. **低功耗模式**:
- 不操作Flash时可进入PowerDown模式(电流<1μA)
- 唤醒需要约3μs延迟
阅读全文
相关推荐



















