STC89C52是经典的C51单片机,该芯片不自带硬件SPI接口,正好有手上一块W25Q32的存储模块(某宝上买的2.2元),试着使用89C52模拟SPI接口驱动W25Q32,在驱动的过程中遇到了几个问题,首先的问题是电平不匹配,其次是对芯片datasheet资料的解读,关于W25Qx的资料基本上是全英文的资料,笔者英文水平有限解读起来有一定的困难,只能一点点去解读;其次网络上关于使用C51驱动W25Qx的相关资料有限,很大部分都是使用stm32芯片驱动的案例,结合stm32案例实现W25Qx的驱动,以下内容为个人学习过程小结,由于笔者水平有限,难免有错误,敬请谅解。

一、电路搭建(解决芯片IO电平匹配):

依据W25Qx芯片资料,该芯片支持电平范围为2.7V-3.6V,过电平可能造成损坏芯片,而89C52的IO电平为5V。解决办法是加一块3.3V转5V的电平转换模块(TXS-0108E),电路的连接如下图:

另外网络上也有采用电阻限流的方案,由于元件较多,焊接有点麻烦,笔者未验证,提供下图,仅供学习参考。

二、编写软SPI驱动:

SPI接口一般使用 4 条线通信:

DO 主设备数据输入,从设备数据输出。

DI 主设备数据输出,从设备数据输入。

SCK 时钟信号,由主设备产生。

CS 从设备片选信号,由主设备控制。

SPI 主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。

以下是SPI传送时序,SPI传送时序有4种方式,方式0-方式3。

方式0(0,0),方式1(0,1),方式2(1,0),方式3(1,1)

SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;SPI主模块和与之通信的外设时钟相位和极性应该一致。CPOL是用来决定SCK时钟信号空闲时的电平,CPOL=0,空闲电平为低电平,CPOL=1时,空闲电平为高电平。CPHA是用来决定采样时刻的,CPHA=0,在每个周期的第一个时钟沿采样,CPHA=1,在每个周期的第二个时钟沿采样。

小结下上述内容:CPOL=0时起始电平为低电平,CPOL=1时起始电平为高电平。CPHA=0时,CLK的第一个上升沿为采样(写W25Qx), CLK的第一个下降沿为输出(读W25Qx),CPHA=1时,CLK的第一个下降沿为采样(写W25Qx), CLK的第一个上升沿为输出(读W25Qx)。

W25Qx的SPI传输支持方式0和方式3,即方式0(CPOL=0,CPHA=0),方式3(CPOL=1,CPHA=1)。

为了方便起见,笔者以方式0为基础,编写一个SPI的传输函数,该函数发送以MSB(高位优先传输)。

//SPI传输函数,发送与接收一个字节

unsignedchar SPI_Byte(unsigned char dat)

{

unsigned charread=0,i=0;

for(i=0;i<8;i++)

{

W25_DI=dat&0x80;

W25_CLK=1;

dat<<=1;

read<<=1;

read|=W25_DO;

W25_CLK=0;

}

return read;

}

三、编写函数测试获取芯片的Flash ID号(JEDEC ID):

当电路搭建完成后,SPI通信基础函数编写完成后,下一步需要获取芯片返回一个值,测试电路与基础函数成功与否。

依据资料文件,获取ID之前有两点需要注意,第一点是MSB高位优先传输,第二点是获取操作时CS必须拉低。

当获取成功后W25Q32对应的16位的码值为0x4016,下面依据芯片资料提供的时序。

依据上图小结如下信息。

1、获取时CS必须为低电平,高位优先传输。

2、获取JEDEC ID的指令为0x90。

3、接收到信息三个字节,第一个字节为ManufacturerID(制造商ID)固定值为0xEF,第二个字节为MemoryType(内存类型),第三个字节为Capacity(容量)。

编写代码如下:

unsignedlong W25x_read_ID()

{

unsigned long re,t1,t2,t3;

W25_CS=0;

W25_CLK=0;

SPI_Byte(0x9F);

t3=SPI_Byte(0xff);

t2=SPI_Byte(0xff);

t1=SPI_Byte(0xff);

W25_CS=1;

re=(t3<<16)|(t2<<8)|t1;

return re;

}

测试结果:

四、芯片写使能与忙状态等待。

1、写使能:

写使能的操作与读ID的操作类似,其操作指令为0x06,写使能成功后Status Register1的S1位WSL置1,即允许写操作与擦除操作。

//写使能

voidW25x_write_Enable()

{

W25_CS=0;

W25_CLK=0;

SPI_Byte(0x06);

W25_CS=1;

}

2、忙状态等待函数:

当芯片正在执行擦除、写操作时,不允许其它操作,此时必须进入等待状态,直到执行完成后Status Register1的S0位BUSY重新置0后才允许后续操作,函数必须不断的读取状态寄存器,从中提取S0的数据,从而确定相应操作的状态。Status Register1读取指令为0x05,读取方式为MSB那么S0位对应与操作位为0x01,操作方式与读ID的操作类似,依据下图资料的时序,编写函数如下。

//等待擦除或写入操作,直到操作完成结束。

voidW25x_wait_BusyEnd()

{

unsigned char i=0,temp;

W25_CS=0;

W25_CLK=0;

SPI_Byte(0x05);

temp=SPI_Byte(0xff);

while((temp&0x01)==1)

{

temp=SPI_Byte(0xff);

}

W25_CS=1;

}

五、编写擦除指令:

W25Q32为非易失性存储器,写数据之前必须先执行擦除操作,这里我们先编写一个芯片擦除函数。

小结上图芯片资料信息:

1、所谓的芯片擦除是往存储单元字节中填充0xFF即为擦除。

2、芯片擦除操作前必须开启Write Enable(写使能)之前有介绍。

3、芯片擦除操作的指令0x07或0x60,当然CS也必须低电平。

4、芯片擦除完成后需要等待一段时间(读忙状态),之前有介绍。

5、其它与读取ID操作类似。

//芯片擦除操作函数

voidW25x_chipErase()

{

W25x_write_Enable();//开使能

W25_CS=0;

W25_CLK=0;

SPI_Byte(0xC7);

W25_CS=1;

W25x_wait_BusyEnd();//等待擦除操作完成结束

}

六、页写入操作:

W25Qx最大写入单位为页(Page),每页最多写入256B,超过256B必须另写一页,每16页组成一个扇区(Sector),每16个扇区组成一个块(Block)。W25x32为4MB的容量,共有64个块,1024个扇区,16384个页。地址范围为(0x000000-0x2FFFFF),理论上地址每一位对应一个字节,实际在连续写入大数据的过程中还需考虑页、扇区、块的容量问题。注意写之前必须确保是擦除操作过的,最小的擦除单位不是页而是扇区。下面的例子仅考虑页写,理想的起始地址为页的起始位置,内容小于256B。

1块=16扇区,1扇区=16页,1页=256字节

小结上图芯片资料如下:

1、页写操作与擦除操作类似,需要CS低电平、写使能、忙等待。

2、页写操作指令为0x02,接下来是24位地址(页的每页的起始地址为:0xXXXX00,页结束地址为0xXXXXFF其中X为16进制任意数)。

3、写入地址完成后,再次写入不大于256B的数据内容

页写代码如下:

//页写操作,*buf为内容,addr为地址,PageSize为写入字节数必//须小于256个

voidW25x_write_Page(unsigned char *buf,unsigned long addr,unsigned int Pagesize)

{

W25x_write_Enable();

W25_CS=0;

W25_CLK=0;

SPI_Byte(0x02);

SPI_Byte(addr>>16&0xff);

SPI_Byte(addr>>8&0xff);

SPI_Byte(addr&0xff);

if(Pagesize>256)

{

Pagesize=256;

}

while(Pagesize--)

{

SPI_Byte(*buf++);

}

W25_CS=1;

W25x_wait_BusyEnd();

}

七、读操作:

读操作相对于写操作比较简单,不用考虑页、扇区、块,仅使用24位地址即可读。

小结上图芯片资料如下:

1、读操作与读ID操作类似,需要CS低电平。

2、读操作指令为0x03,接下来是24位地址。

3、写入地址完成后直接读出数据内容。

//读操作,*buf为内容,addr为地址,PageSize为读出的字节数

voidW25x_read_Page(unsigned char *buf,unsigned long addr,unsigned int Pagesize)

{

W25_CS=0;

W25_CLK=0;

SPI_Byte(0x03);

SPI_Byte(addr>>16&0xff);

SPI_Byte(addr>>8&0xff);

SPI_Byte(addr&0xff);

while(Pagesize--)

{

*buf=SPI_Byte(0xff);

buf++;

}

W25_CS=1;

}

八、读写测试

数组a为写入内容,数据b为读出数据,i为芯片ID信息,所有信息通过串口发送至电脑。

voidmain()

{

unsigned long i;

unsigned chara[]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13};//写入内容

unsigned char b[15];//读出内容

char j;

uart_init(); //串口初始化

i=W25x_read_ID();//读ID

uart_sendbyte(i/256/256);

uart_sendbyte(i/256);

uart_sendbyte(i%256);

W25x_chipErase();//芯片擦除

W25x_write_Page(a,0x000002,15);//从02位置开始写入

W25x_read_Page(b,0x000000,15);//从00位置开始读信息

for(j=0;j<15;j++)

{

uart_sendbyte(b[j]);//输出所读内容

}

while(1);

}

输出结果:

实物展示:

STC89C52驱动W25Q32测试笔记相关推荐

  1. Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)

    Windows驱动开发学习笔记(四)-- 3环与0环通信(常规方式) 设备对象 创建设备对象 设置数据交互方式 创建符号链接 IRP与派遣函数 IRP的类型 其它类型的IRP 派遣函数 派遣函数注册位 ...

  2. Windows驱动开发学习笔记(一)—— 环境配置第一个驱动程序

    Windows驱动开发学习笔记(一)-- 环境配置&第一个驱动程序 环境配置 第一个驱动程序 环境配置 安装VS2010:https://pan.baidu.com/s/1uZWWxCtB60 ...

  3. 软件质量保证与测试笔记——江湖救急版

    软件质量保证与测试笔记--江湖救急版 Powered by DZY 以下部分图片来源于老师课件,仅供学习交流使用,侵权致删! Ch1 软件质量与测试概念 软件质量的定义 软件质量是"反映实体 ...

  4. Windows驱动开发学习笔记(七)—— 多核同步内核重载

    Windows驱动开发学习笔记(七)-- 多核同步 基础知识 并发与同步 分析 InterlockedIncrement 原子操作相关API 内核文件 多核同步 临界区 示例一:错误的临界区 示例二: ...

  5. Windows驱动开发学习笔记(六)—— Inline HOOK

    Windows驱动开发学习笔记(六)-- Inline HOOK SSDT HOOK Inline Hook 挂钩 执行流程 脱钩 实验一:3环 Inline Hook 实验二:0环 Inline H ...

  6. Windows驱动开发学习笔记(五)—— SSDT HOOK

    Windows驱动开发学习笔记(五)-- SSDT HOOK 系统服务表 系统服务描述符表 实验一:通过代码获取SSDT表地址 通过页表基址修改页属性 方法1:修改页属性 方法2:修改CR0寄存器 实 ...

  7. Windows驱动开发学习笔记(三)—— 内核空间内核模块

    Windows驱动开发学习笔记(三)-- 内核空间&内核模块 内核空间 实验 第一步:编译如下代码 第二步:将 .sys 文件拷贝到虚拟机中 第三步:部署 .sys 文件并运行 第四步:创建一 ...

  8. Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础

    Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...

  9. 基于fpga的dds函数信号发生器的设计_超声信号功率放大器驱动压电陶瓷测试

    压电陶瓷片是一种电子发音元件,以锆钛酸铅压电陶瓷材料制成.基于压电效应原理,当在两片电极上面接通交流音频信号时,压电片会根据信号的大小频率发生震动而产生相应的声音来. 压电陶瓷驱动电源的性能直接关系着 ...

最新文章

  1. oracle enterprise linux 5.7,Red Hat Enterprise Linux 5.7 安装Oracle数据库
  2. (五)springmvc+mybatis+dubbo+zookeeper分布式架构 整合 - maven构建根项目
  3. ubuntu 16.04修复固件刷新失败的LimeSDR-USB V1.4
  4. mailmessage html编码,C#MailMessage顯示HTML標記的AlternateViews
  5. 使用级联SFU改善媒体质量和规模
  6. mapreduce阶段出现pending的原因及解决
  7. SSO之CAS单点登录实例演示
  8. 云南省最好的计算机学校排名,云南学校排名
  9. ⽤户去输⼊⼀个⼈民币⾦额,然后程序会计算如何去⽤20元纸币,10元纸币,5元纸币和⼀元纸币去表⽰这个⼈民币⾦额。要求使⽤最⼩数⽬的纸币。
  10. React + Springboot + Quartz,从0实现Excel报表自动化
  11. latex的段落间距设置
  12. java统计字数_JAVA 仿 MS word 字数统计
  13. 信息与网络安全复习(四)——无线网络安全与DES算法
  14. 编程语言只是一个工具
  15. 细数人工智能这几年的悲与喜
  16. 手机软件开发环境种类介绍(转)
  17. 02.Python网络爬虫第二弹(http和https协议)
  18. mysql数据报错:Packet for query is too large (1348754 1048576)
  19. 变量泵-变量马达静液压行走 Variable pump-variable motor in Drive system
  20. 鼠标点一下就行 玩转CPU软件超频

热门文章

  1. 用关键词搜索店铺列表详情
  2. 编辑器下运行exe或bat run exe or bat in editor
  3. android10全面屏手势 操作图,丨系统设计丨ZUI 10加入更多全面屏手势
  4. syntactic与semantic
  5. Syntactic sugar Syntactic salt
  6. MAC软件推荐(Java方向)
  7. [Kaggle实战] Titanic 逃生预测 (1) - 项目起步
  8. 《易经》 数中以9最为奇妙
  9. 华为确定发布鸿蒙的时间了吗,Mate40系列首发,华为鸿蒙OS手机版发布时间确定...
  10. PyTorch语音识别框架,将语音转成文本格式