2026/2/18 12:41:38
网站建设
项目流程
如何发布网站,购物网站的建设思维导图,邢台市的做网站制作公司,ppt免费下载雷锋网站1. SPI通信基础与STM32硬件配置
SPI#xff08;Serial Peripheral Interface#xff09;是一种高速全双工同步串行通信协议#xff0c;由摩托罗拉公司设计#xff0c;广泛应用于嵌入式系统中。它只需要四根信号线就能实现主从设备之间的数据交换#xff0c;非常适合连接Fl…1. SPI通信基础与STM32硬件配置SPISerial Peripheral Interface是一种高速全双工同步串行通信协议由摩托罗拉公司设计广泛应用于嵌入式系统中。它只需要四根信号线就能实现主从设备之间的数据交换非常适合连接Flash存储器、传感器等外设。SPI的四根信号线分别是SCKSerial Clock时钟信号由主设备产生MOSIMaster Output Slave Input主设备输出从设备输入MISOMaster Input Slave Output主设备输入从设备输出SSSlave Select从设备片选信号在STM32中配置SPI外设时我们需要重点关注几个关键参数时钟极性CPOL决定SCK空闲时的电平状态时钟相位CPHA决定数据在时钟的哪个边沿采样波特率分频设置SPI通信速率数据帧格式8位或16位数据以STM32F1系列为例硬件SPI1的引脚通常对应PA4SS软件控制PA5SCKPA6MISOPA7MOSI2. W25Q64闪存芯片特性解析W25Q64是Winbond公司推出的64M-bit串行Flash存储器采用SPI接口通信具有以下特点支持标准SPI模式0和模式3最高支持104MHz时钟频率支持扇区擦除4KB、块擦除32KB/64KB和整片擦除页编程操作每页256字节写保护功能和保持/暂停功能实际项目中我发现W25Q64对时序要求比较严格。有一次调试时发现写入失败最后发现是SPI时钟相位配置错误。正确的配置应该是CPOL0空闲时低电平CPHA0第一个边沿采样3. STM32 SPI外设初始化实战下面是一个完整的SPI初始化代码示例采用STM32标准外设库void SPI1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; // 1. 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); // 2. 配置GPIO // SCK和MOSI配置为复用推挽输出 GPIO_InitStruct.GPIO_Pin GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStruct); // MISO配置为上拉输入 GPIO_InitStruct.GPIO_Pin GPIO_Pin_6; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IPU; GPIO_Init(GPIOA, GPIO_InitStruct); // SS配置为普通推挽输出 GPIO_InitStruct.GPIO_Pin GPIO_Pin_4; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_Init(GPIOA, GPIO_InitStruct); GPIO_SetBits(GPIOA, GPIO_Pin_4); // 默认不选中 // 3. 配置SPI参数 SPI_InitStruct.SPI_Direction SPI_Direction_2Lines_FullDuplex; SPI_InitStruct.SPI_Mode SPI_Mode_Master; SPI_InitStruct.SPI_DataSize SPI_DataSize_8b; SPI_InitStruct.SPI_CPOL SPI_CPOL_Low; // 模式0 SPI_InitStruct.SPI_CPHA SPI_CPHA_1Edge; // 模式0 SPI_InitStruct.SPI_NSS SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_4; // 18MHz 72MHz PCLK SPI_InitStruct.SPI_FirstBit SPI_FirstBit_MSB; SPI_InitStruct.SPI_CRCPolynomial 7; SPI_Init(SPI1, SPI_InitStruct); // 4. 使能SPI SPI_Cmd(SPI1, ENABLE); }调试时有个小技巧如果SPI通信不正常可以先用逻辑分析仪抓取SCK、MOSI和MISO的波形确认时序是否符合预期。我曾经遇到过因为GPIO速度配置过低导致波形畸变的问题将GPIO_Speed提高到50MHz后解决。4. W25Q64驱动开发与功能实现4.1 基本读写函数封装首先需要封装几个基础函数// 片选控制 void W25Q64_CS(uint8_t state) { GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)state); } // 发送一个字节并接收返回值 uint8_t SPI1_ReadWriteByte(uint8_t data) { while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) RESET); SPI_I2S_SendData(SPI1, data); while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) RESET); return SPI_I2S_ReceiveData(SPI1); } // 读取设备ID用于检测芯片是否正常 uint32_t W25Q64_ReadID(void) { uint32_t id 0; W25Q64_CS(0); SPI1_ReadWriteByte(0x9F); // JEDEC ID指令 id | SPI1_ReadWriteByte(0xFF) 16; id | SPI1_ReadWriteByte(0xFF) 8; id | SPI1_ReadWriteByte(0xFF); W25Q64_CS(1); return id; }4.2 闪存操作指令实现W25Q64的操作都需要通过特定指令实现常见指令如下#define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_PageProgram 0x02 #define W25X_SectorErase 0x20实现写使能和等待写入完成函数void W25Q64_WriteEnable(void) { W25Q64_CS(0); SPI1_ReadWriteByte(W25X_WriteEnable); W25Q64_CS(1); } void W25Q64_WaitBusy(void) { W25Q64_CS(0); SPI1_ReadWriteByte(W25X_ReadStatusReg); while((SPI1_ReadWriteByte(0xFF) 0x01) 0x01); W25Q64_CS(1); }4.3 扇区擦除与页编程Flash存储器必须先擦除才能写入擦除的最小单位是扇区4KBvoid W25Q64_SectorErase(uint32_t addr) { W25Q64_WriteEnable(); W25Q64_CS(0); SPI1_ReadWriteByte(W25X_SectorErase); SPI1_ReadWriteByte((addr 16) 0xFF); SPI1_ReadWriteByte((addr 8) 0xFF); SPI1_ReadWriteByte(addr 0xFF); W25Q64_CS(1); W25Q64_WaitBusy(); }页编程函数最多写入256字节void W25Q64_PageProgram(uint32_t addr, uint8_t *data, uint16_t len) { W25Q64_WriteEnable(); W25Q64_CS(0); SPI1_ReadWriteByte(W25X_PageProgram); SPI1_ReadWriteByte((addr 16) 0xFF); SPI1_ReadWriteByte((addr 8) 0xFF); SPI1_ReadWriteByte(addr 0xFF); for(uint16_t i0; ilen; i) { SPI1_ReadWriteByte(data[i]); } W25Q64_CS(1); W25Q64_WaitBusy(); }5. 实际应用中的注意事项时序问题W25Q64对指令时序有严格要求每个指令后需要适当延时写保护写入前必须发送Write Enable指令且WP引脚需接高电平跨页写入单次写入不能跨页256字节边界擦除时间扇区擦除需要较长时间典型值100ms电源稳定性在写入和擦除操作期间必须保证电源稳定一个完整的读写流程示例读取设备ID确认通信正常擦除目标扇区等待擦除完成写入数据读取回校验uint8_t buf[256], rbuf[256]; memset(buf, 0xAA, 256); // 擦除第一个扇区 W25Q64_SectorErase(0x000000); // 写入数据 W25Q64_PageProgram(0x000000, buf, 256); // 读取验证 W25Q64_ReadData(0x000000, rbuf, 256); if(memcmp(buf, rbuf, 256) 0) { printf(Verify OK!\n); }在项目开发中建议将W25Q64的操作封装成独立的驱动模块便于移植和维护。对于需要频繁读写的场景可以考虑实现缓存机制来减少擦写次数延长Flash寿命。