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会擦除整个扇区,频繁修改时应考虑缓存机制

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1220028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你的亏损,谁的盛宴?揭秘量化交易在A股的真相

人人都在谈论的“量化”&#xff0c;对你我究竟意味着什么&#xff1f; 量化交易&#xff0c;这个听起来充满科技感的投资策略&#xff0c;常常因其惊人的高回报率而成为市场的焦点。然而&#xff0c;当一种工具被热议时&#xff0c;我们更需要冷静地审视其本质。尽管量化交易…

Java计算机毕设之基于springboot的装修公司家装项目进度及监控安排管理系统(完整前后端代码+说明文档+LW,调试定制等)

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

告别 Java 内卷苦海!Java 程序员转型大模型开发的 “躺赢” 密码,这波血赚!

“AI会取代我的工作吗&#xff1f;” 这大概是当下每个打工人&#xff0c;尤其是程序员&#xff0c;深夜反复思量的问题。 眼看着AI能自动生成代码、秒级定位Bug&#xff0c;甚至参与系统架构设计&#xff0c;不少深耕Java多年的老手也开始慌了&#xff1a;难道苦练十几年的编…

2026年水处理设备厂家最新推荐:工业污水处理设备、废水处理设备厂家、成品玻璃钢化粪池、污水处理一体化设备、混凝土化粪池选择指南

2026年热门水处理设备优质公司推荐榜引言:水处理行业发展现状与痛点据《2026-2030中国污水处理行业市场深度调研及发展前景报告》显示,国内污水处理市场规模预计到2030年将达到1.5万亿元人民币,年复合增长率达8.6%。…

AI写作工具怎么选?模力通覆盖全流程智能办公写作、润色校对与会议纪要生成

时至2026年,AI技术正深度融入政务、企业及事业单位的日常流程。 作为蜜度旗下核心产品,模力通凭借“通用大模型蜜巢文修”多模融合架构,打造了一款集AI公文写作、风格仿写、快速写作、润色校对、会议纪要生成于一体…

2026年AI智能写作校对工具红榜出炉,八大写作工具深度横评与推荐

随着人工智能技术步入深水区,2026年的职场办公模式正经历一场由AIGC驱动的深刻变革。特别是在文档处理领域,单一的文本生成已无法满足需求,集智能写作、润色校对、风格统一、格式合规于一体的全能型AI助手,成为提升…

2026年写作神器推荐!高分AI写作助手模力通的全面功能解析

时光步入2026年,智能化办公已从趋势变为常态。在众多寻求通过AI提升文档处理效率的党政机关、事业单位及大型国有企业中,一款名为“模力通”的AI写作助手正凭借其卓越的实用性和稳定性,获得越来越高的市场评分与用户…

IT行业是不是不行了?程序员还有必要继续学习提升吗?

今年对程序员来说是极不友好的一年&#xff0c;像往年这个时间段一般是程序员跳槽涨薪的黄金期&#xff0c;是很多程序员集体往大厂冲刺的时间段&#xff1b;但由于各大厂纷纷裁员&#xff0c;整得整个互联网行业人心惶惶&#xff0c;纷纷质疑&#xff1a;大厂还值得去吗&#…

【计算机毕业设计案例】基于vue的老年人膳食营养服务网站管理系统(程序+文档+讲解+定制)

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

为什么说Java程序员必须会Netty?

前段时间在Github上看到一条评论&#xff0c;说的是&#xff1a; Java程序员都要会Netty&#xff0c;不会的都是初级或者**这种言论过于偏薄。大家都是学技术的&#xff0c;大部分人进入这一行业都是为了更高的薪资&#xff08;纯纯感兴趣的除外&#xff09;每接触一门新的技术…

【计算机毕业设计案例】基于物联网技术的宠物远程定位与监控系统定位与监控系统设计小程序(程序+文档+讲解+定制)

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

【计算机毕业设计案例】基于springboot的美食分享平台基于java的地方特色美食分享管理系统(程序+文档+讲解+定制)

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

驱动代码39错误怎么办?手把手教你修复设备驱动问题

驱动代码39是Windows设备管理器中常见的硬件错误提示&#xff0c;通常意味着操作系统无法加载某个设备的驱动程序。这个问题可能影响打印机、USB设备、声卡等多种硬件&#xff0c;导致设备无法正常工作。理解这个错误代码的含义并掌握解决方法&#xff0c;对于快速恢复设备功能…

2026Java金三银四面试突击指南!

今年的金三银四也快到了&#xff0c;很多粉丝私信反应说让我总结一份高质量面试题&#xff0c;金三银四之前想要准备准备&#xff0c;于是就有了今天这篇文章~在过去的2025年里&#xff0c;LZ看到很多小伙伴在面试的时候都拿到了自己心仪的Offer&#xff0c;同时也在各大论坛博…

pthread_create函数指针用法:参数传递与线程创建

在Linux多线程编程中&#xff0c;pthread_create函数是创建线程的核心接口&#xff0c;而函数指针作为其关键参数&#xff0c;直接决定了线程执行的内容。正确理解和使用这个函数指针&#xff0c;是多线程编程的基础&#xff0c;也是避免常见线程错误的前提。下面我将结合实际开…

C++单例模式线程安全实现与应用场景详解

单例模式在C中是一种确保一个类只有一个实例&#xff0c;并提供一个全局访问点的设计模式。它在需要严格控制资源或全局状态管理的场景中非常有用&#xff0c;比如配置管理器、日志记录器或线程池。理解其实现细节和潜在陷阱对于编写健壮且高效的C代码至关重要。 单例模式有哪些…

在物理实验中,电子双缝衍射是一个经典的实验,它展示了电子的波动性。今天,我们就用MATLAB的GUI界面来模拟这个实验,通过输入不同的参数,观察衍射图样的变化

基于matlabgui界面下的电子双缝衍射实验的现象模拟&#xff0c;设置的可输入参数有&#xff1a;缝宽a&#xff0c;双缝间距b&#xff0c;加速电压U&#xff0c;缝屏距离D和电子数目n- 首先&#xff0c;我们需要在MATLAB中创建一个GUI界面&#xff0c;这可以通过guide命令来实现…

Python 判断是否为空:字符串、列表等常用方法详解

在Python编程中&#xff0c;判断变量或数据结构是否为空是一项基础但至关重要的操作。它直接关系到程序的健壮性&#xff0c;能有效避免因处理空值而引发的运行时错误。理解不同数据类型&#xff08;如字符串、列表、字典&#xff09;的空值判断方法&#xff0c;是编写可靠代码…

Jetson Orin 回滚保护(Ratcheting)与 RPMB 安全存储:从概念到实战的完整解析

&#x1f4fa; B站视频讲解&#xff08;Bilibili&#xff09;&#xff1a;博主个人介绍 &#x1f4d8; 《Yocto项目实战教程》京东购买链接&#xff1a;Yocto项目实战教程 &#x1f4d8; 加博主微信&#xff0c;进技术交流群&#xff1a; jerrydev Jetson Orin 回滚保护&…

unix shell编程 pdf 教程推荐与学习指南

对于Unix/Linux系统管理员和开发者来说&#xff0c;掌握shell编程是必备技能之一。PDF格式的学习资料因其便于保存、打印和离线阅读的特点&#xff0c;成为许多人系统学习shell编程的首选。通过精心整理的PDF资源&#xff0c;我们可以从基础语法到高级技巧&#xff0c;逐步构建…