news 2026/4/14 0:32:05

STM32 SPI读取写入W25Q64JVSSIQ

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32 SPI读取写入W25Q64JVSSIQ

w25q64.h

#ifndef__W25Q64_H#define__W25Q64_H#include"main.h"#include"spi.h"// 引脚定义#defineW25Q64_CS_PINGPIO_PIN_15#defineW25Q64_CS_PORTGPIOA// W25Q64指令集#defineW25Q64_WRITE_ENABLE0x06#defineW25Q64_WRITE_DISABLE0x04#defineW25Q64_READ_STATUS10x05#defineW25Q64_WRITE_STATUS10x01#defineW25Q64_READ_DATA0x03#defineW25Q64_PAGE_PROGRAM0x02#defineW25Q64_SECTOR_ERASE0x20#defineW25Q64_CHIP_ERASE0xC7#defineW25Q64_POWER_DOWN0xB9#defineW25Q64_RELEASE_PD0xAB#defineW25Q64_MANUF_DEVICE_ID0x90#defineW25Q64_JEDEC_ID0x9F// Flash容量参数#defineW25Q64_PAGE_SIZE256#defineW25Q64_SECTOR_SIZE4096#defineW25Q64_TOTAL_SIZE(8*1024*1024)// 8MB// 函数声明voidW25Q64_Init(void);uint8_tW25Q64_ReadByte(uint32_taddr);voidW25Q64_ReadBytes(uint32_taddr,uint8_t*buf,uint32_tlen);voidW25Q64_WriteByte(uint32_taddr,uint8_tdata);voidW25Q64_WriteBytes(uint32_taddr,uint8_t*data,uint32_tlen);voidW25Q64_ModifyByte(uint32_taddr,uint8_tdata);voidW25Q64_EraseSector(uint32_tsector_addr);voidW25Q64_WaitBusy(void);uint32_tW25Q64_ReadID(void);#endif/* __W25Q64_H */

w25q64.c

#include"w25q64.h"// 私有函数声明staticvoidW25Q64_CS_Low(void);staticvoidW25Q64_CS_High(void);staticvoidW25Q64_WriteEnable(void);staticuint8_tW25Q64_ReadStatus(void);// 初始化函数voidW25Q64_Init(void){W25Q64_CS_High();HAL_Delay(10);// 读取ID验证连接uint32_tid=W25Q64_ReadID();if(id==0xEF4017)// W25Q64JV的JEDEC ID{// 初始化成功}}// 读取单个字节uint8_tW25Q64_ReadByte(uint32_taddr){uint8_tcmd[4]={W25Q64_READ_DATA,(addr>>16)&0xFF,(addr>>8)&0xFF,addr&0xFF};uint8_tdata=0;W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,cmd,4,100);HAL_SPI_Receive(&hspi6,&data,1,100);W25Q64_CS_High();returndata;}// 读取多个字节voidW25Q64_ReadBytes(uint32_taddr,uint8_t*buf,uint32_tlen){uint8_tcmd[4]={W25Q64_READ_DATA,(addr>>16)&0xFF,(addr>>8)&0xFF,addr&0xFF};W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,cmd,4,100);HAL_SPI_Receive(&hspi6,buf,len,1000);W25Q64_CS_High();}// 写入单个字节voidW25Q64_WriteByte(uint32_taddr,uint8_tdata){uint8_tcmd[5]={W25Q64_PAGE_PROGRAM,(addr>>16)&0xFF,(addr>>8)&0xFF,addr&0xFF,data};W25Q64_WriteEnable();W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,cmd,5,100);W25Q64_CS_High();W25Q64_WaitBusy();}// 写入多个字节(注意:不能跨页写入)voidW25Q64_WriteBytes(uint32_taddr,uint8_t*data,uint32_tlen){// 确保不跨页写入uint32_tpage_remain=W25Q64_PAGE_SIZE-(addr%W25Q64_PAGE_SIZE);uint32_twrite_len=(len>page_remain)?page_remain:len;uint8_t*cmd=(uint8_t*)malloc(write_len+4);if(cmd==NULL)return;cmd[0]=W25Q64_PAGE_PROGRAM;cmd[1]=(addr>>16)&0xFF;cmd[2]=(addr>>8)&0xFF;cmd[3]=addr&0xFF;memcpy(&cmd[4],data,write_len);W25Q64_WriteEnable();W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,cmd,write_len+4,1000);W25Q64_CS_High();W25Q64_WaitBusy();free(cmd);// 如果还有数据需要写入,递归调用if(len>write_len){W25Q64_WriteBytes(addr+write_len,data+write_len,len-write_len);}}// 修改指定地址的字节(先擦除后写入)voidW25Q64_ModifyByte(uint32_taddr,uint8_tdata){// 计算所在扇区uint32_tsector_addr=addr-(addr%W25Q64_SECTOR_SIZE);uint8_tsector_buffer[W25Q64_SECTOR_SIZE];// 1. 读取整个扇区W25Q64_ReadBytes(sector_addr,sector_buffer,W25Q64_SECTOR_SIZE);// 2. 修改指定字节sector_buffer[addr-sector_addr]=data;// 3. 擦除扇区W25Q64_EraseSector(sector_addr);// 4. 重新写入整个扇区// 分页写入,每次写入一页(256字节)for(uint32_ti=0;i<W25Q64_SECTOR_SIZE;i+=W25Q64_PAGE_SIZE){W25Q64_WriteBytes(sector_addr+i,&sector_buffer[i],W25Q64_PAGE_SIZE);}}// 擦除扇区(4KB)voidW25Q64_EraseSector(uint32_tsector_addr){uint8_tcmd[4]={W25Q64_SECTOR_ERASE,(sector_addr>>16)&0xFF,(sector_addr>>8)&0xFF,sector_addr&0xFF};W25Q64_WriteEnable();W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,cmd,4,100);W25Q64_CS_High();W25Q64_WaitBusy();}// 等待Flash操作完成voidW25Q64_WaitBusy(void){while(W25Q64_ReadStatus()&0x01){HAL_Delay(1);}}// 读取JEDEC IDuint32_tW25Q64_ReadID(void){uint8_tcmd=W25Q64_JEDEC_ID;uint8_tid_data[3];W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,&cmd,1,100);HAL_SPI_Receive(&hspi6,id_data,3,100);W25Q64_CS_High();return(id_data[0]<<16)|(id_data[1]<<8)|id_data[2];}// 私有函数实现staticvoidW25Q64_CS_Low(void){HAL_GPIO_WritePin(W25Q64_CS_PORT,W25Q64_CS_PIN,GPIO_PIN_RESET);}staticvoidW25Q64_CS_High(void){HAL_GPIO_WritePin(W25Q64_CS_PORT,W25Q64_CS_PIN,GPIO_PIN_SET);}staticvoidW25Q64_WriteEnable(void){uint8_tcmd=W25Q64_WRITE_ENABLE;W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,&cmd,1,100);W25Q64_CS_High();}staticuint8_tW25Q64_ReadStatus(void){uint8_tcmd=W25Q64_READ_STATUS1;uint8_tstatus;W25Q64_CS_Low();HAL_SPI_Transmit(&hspi6,&cmd,1,100);HAL_SPI_Receive(&hspi6,&status,1,100);W25Q64_CS_High();returnstatus;}

使用例程

#include"w25q64.h"// 测试函数voidmain(void){uint8_tread_data;uint8_twrite_data=0xAA;uint32_ttest_addr=0x000000;// 测试地址// 1. 初始化W25Q64_Init();// 2. 写入单个字节W25Q64_WriteByte(test_addr,write_data);HAL_Delay(10);// 3. 读取单个字节read_data=W25Q64_ReadByte(test_addr);if(read_data==write_data){// 写入成功}// 4. 批量写入测试uint8_twrite_buffer[256];uint8_tread_buffer[256];for(inti=0;i<256;i++){write_buffer[i]=i;}W25Q64_WriteBytes(0x1000,write_buffer,256);HAL_Delay(10);// 5. 批量读取测试W25Q64_ReadBytes(0x1000,read_buffer,256);// 6. 修改指定地址的数据W25Q64_ModifyByte(0x2000,0x55);// 7. 擦除扇区测试W25Q64_EraseSector(0x3000);}

CubeMX配置要点

  1. SPI6配置:
    · Mode: Full-Duplex Master
    · Hardware NSS Signal: Disable
    · Prescaler: 根据HCLK频率调整(建议≤50MHz)
  2. GPIO配置:
    · PA15: GPIO_Output(CS引脚)
    · PB3: SPI6_SCK
    · PB4: SPI6_MISO
    · PB5: SPI6_MOSI
  3. 时钟配置:
    · 确保SPI时钟不超过W25Q64的最大频率(104MHz)

注意事项

  1. 写操作前必须擦除:Flash只能从1变为0,所以写前需要擦除(变为0xFF)
  2. 擦除最小单位:4KB扇区
  3. 写操作跨页处理:页大小为256字节,跨页时需要分页写入
  4. 修改函数效率:W25Q64_ModifyByte会擦除整个扇区,频繁修改时应考虑缓存机制

这个驱动提供了基本的读写和修改功能,可以根据需要扩展更多功能(如整片擦除、快速读取等)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 20:57:32

Java毕设选题推荐:基于springboot的装修公司房屋装修管理系统基于springboot的装修公司家装项目管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/9 21:49:43

FT32F072RBAT7/CBAT7/KBBT7/KBBU7/KBCW7 32位MCU单片机解析

当智能硬件走向“高算力低功耗丰富外设”时代&#xff0c;8位机常常力不从心&#xff0c;而主流32位MCU又面临成本敏感、封装庞大、开发复杂等痛点。辉芒微推出的 FT32F072xx 系列&#xff08;含 RBAT7/CBAT7/KBBT7/KBBU7/KBCW7 等子型号&#xff09;恰逢其时&#xff1a;Corte…

作者头像 李华
网站建设 2026/4/6 0:40:26

Java毕设项目推荐-基于springboot饮食分享平台、美食菜谱分享管理系统基于springboot的美食分享平台管理系统【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/3/27 16:18:47

Java双向链表实现教程:插入操作与节点结构详解

双向链表是数据结构中链表的一种重要形式&#xff0c;它在每个节点中除了存储数据外&#xff0c;还包含两个引用分别指向前一个节点和后一个节点。这种结构相比单向链表&#xff0c;能够实现双向遍历&#xff0c;为某些特定场景下的数据操作提供了更高的效率。在Java中实现双向…

作者头像 李华
网站建设 2026/4/12 4:29:19

什么是TextStream流处理?它如何实现实时数据分析

TextStream作为一种新兴的数据处理范式&#xff0c;正在重塑我们处理信息的方式。其核心在于将信息视为持续的、不间断的字符流&#xff0c;从而实现实时的分析、转换与响应。这区别于传统批处理模式&#xff0c;更适应如今高速产生、需要即时洞察的数据环境&#xff0c;例如金…

作者头像 李华
网站建设 2026/4/3 4:43:45

vss2026客户端安装步骤与条件详解

vss2026客户端是企业级版本控制的重要工具&#xff0c;正确安装是保证团队协作效率的基础。本文将详细介绍安装前的准备工作、具体安装步骤以及常见问题的解决方法&#xff0c;帮助您顺利完成部署。 vss2026 客户端安装需要什么条件 在开始安装前&#xff0c;请确保您的计算机满…

作者头像 李华