目录

前言

SPI硬件电路

SPI部分特征 

SPI框图 

SPI数据收发过程 

W25Q64 

技术实现 

接线图 

代码实现 

技术要点 

引脚操作

SPI初始化

SPI起始信号

SPI终止信号

SPI字节交换

宏替换W25Q64操作指令 

W25Q64写使能 

忙等待

读取设备ID号和制造商ID

页写入

数据读取

实验结果

问题记录 


前言

SPI(Serial Peripheral Interface,串行外设接口)是一种同步串行通信接口规范,主要用于短距离通信,广泛应用于嵌入式系统中。它使一个主设备能够与一个或多个从设备进行通信。SPI使用四条主要信号线:MOSI(主机输出/从机输入)、MISO(主机输入/从机输出)、SCK(串行时钟)和SS/CS(从选/片选)来实现数据的双向传输。这种接口方式支持全双工通信,具有传输速率高、延迟低的优点,但相比其他一些接口协议,使用的信号线较多。SPI常用于连接传感器、存储器、ADC(模数转换器)等外围设备。

SPI硬件电路

  • 所有SPI设备的SCK,MISO,MOSI分别连在一起。
  • 主机另外引出多条CS控制线分别连接到各从机的CS引脚。
  • 输出引脚配置为推挽输出,输入引脚配置为浮空输入或上拉输入。

SPI部分特征 

  • 3线(SCK,MISO,MOSI)全双工同步传输
  • 带或不带第三根双向数据线的双线单工同步传输(只使用一根MISO或MOSI进行双向半双工数据传输)
  • 8或16位传输帧格式选择
  • 8个主模式波特率预分频系数(最大为fPCLK/2)
  • 可编程的时钟极性和相位
  • 可编程的数据顺序,MSB在前或LSB在前

SPI框图 

SPI数据收发过程 

硬件SPI通常只使用非连续数据传输方式,时钟速率不需要太快。

 (模式3)SCK被拉低后发送起始信号,要发送的数据被写入SPI_DR寄存器,TXE被清零,表示发送缓冲数据寄存器非空,然后数据从缓冲数据寄存器移入移位寄存器,TXE标志被置位,表示发送数据缓冲器空,因为使用非连续传输方式,暂时不用进行数据写入。然后数据从移位寄存器移出,一个时钟信号移出1位,同时从MISO移入数据接收缓冲寄存器一位,连续8个时钟信号后,一个字节的数据移出,一个字节的数据移入,完成一个字节数据的交换。读取SPI_SR寄存器的RXNE位判断接收数据寄存器内是否接收到数据。读出数据后方可进行下一个字节的写入与接收。

W25Q64 

W25Q64是华邦公司(Winbond)推出的一款基于SPI通信的大容量闪存产品,其存储容量为64Mb(即8MB)。该芯片支持2.7~3.6V的工作电压范围,并且具备至少10万次的擦写周期和长达20年的数据保存时间。W25Q64以其灵活性和出色的性能著称,非常适合用于存储声音、文本和数据等应用。它被组织为32768个可编程页面,每个页面包含256字节的数据。此外,W25Q64还支持多种擦除命令,包括4KB扇区擦除、32KB块擦除、64KB块擦除以及全片擦除,并且兼容标准SPI模式0和模式3,最高支持133MHz的时钟频率。通过SPI接口,W25Q64可以轻松地与各种微控制器进行集成,实现高效的数据读写操作。

W25Q64由8MB的存储容量,存储区域被划分成了128个块,每个块又被划分成了16个扇区,每个扇区又被划分成了 16个页。

W25Q64写入操作时

  •  在写入操作之前,必须先进行写使能。
  • 每个数据为只能有1改写成0,不能由0改写成1。
  • 写入数据之前必须先擦除,擦除后,所有的数据位都变为1。
  • 擦除必须以最小单元擦除(这里最小擦除单元时4kb扇区)。
  • 连续写入多个字节时最多写入一页的数据(256Byte),超过页尾的数据会回到页首覆盖写入。
  • 写入操作完成后,芯片进入忙状态,不响应新的写操作。

W25Q64读操作时:

  • 直接调取读操作时序,无需写使能,无需其他操作,没有页限制,读取操作完成后芯片不会进入忙状态,但是芯片忙状态时不能进行读操作。

技术实现 

原理图

 

接线图 

代码实现 

main.c

/**********************************************************
1.实验名称:硬件SPI读写W25Q64
2.实验环境:STM32F103C8T6最小系统板
3.实验内容:使用SPI外设实现读写W25Q64	
4.作者;abai
5.实验时间:2025-5-7
**********************************************************/
#include "stm32f10x.h"                  // Device header
#include "Delay.h"						//延时函数
#include "OLED.h"
#include "W25Q64.h"

uint8_t MF;
uint16_t ID;
uint8_t SendArry[] = {0x05,0x06,0x07,0x08};
uint8_t ReceiveArry[4];

int main(void)
{
	/*
		OLED初始化
	*/
	OLED_Init();
	W25Q64_Init();
	
	OLED_ShowString(1,1,"MF:");
	OLED_ShowString(2,1,"ID:");
	OLED_ShowString(3,1,"W:");
	OLED_ShowString(4,1,"R:");
	
	W25Q64_SectorErase(0x000000);												//写入数据之前必须页擦除
	
	W25Q64_PageProgram(0x000000,SendArry,4);
	W25Q64_ReadData(0x000000,ReceiveArry,4);
	
	W25Q64_ReadID(&MF,&ID);
	
	OLED_ShowHexNum(3,3,SendArry[0],2);
	OLED_ShowHexNum(3,5,SendArry[1],2);
	OLED_ShowHexNum(3,7,SendArry[2],2);
	OLED_ShowHexNum(3,9,SendArry[3],2);
	
	OLED_ShowHexNum(4,3,ReceiveArry[0],2);
	OLED_ShowHexNum(4,5,ReceiveArry[1],2);
	OLED_ShowHexNum(4,7,ReceiveArry[2],2);
	OLED_ShowHexNum(4,9,ReceiveArry[3],2);
	
	OLED_ShowHexNum(1,4,MF,2);
	OLED_ShowHexNum(2,4,ID,4);
	while(1)
	{
		
	}
}

MySPI.h 

#ifndef MYSPI_H
#define MYSPI_H

#include "stm32f10x.h"                  // Device header

void MySPI_Init(void);
void MySPI_CS_W(uint8_t BitValue);
void MySPI_SCK_W(uint8_t BitValue);
void MySPI_MOSI_W(uint8_t BitValue);
uint8_t MySPI_MISO_R(void);
void MySPI_Start(void);
void MySPI_Stop(void);
uint8_t MySPI_SwapByte(uint8_t ByteValue);

#endif

 MySPI.c

#include "MySPI.h"

/**
  *@brief  SPI初始化
  *@param  None
  *@retval None
 **/
void MySPI_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	
	//GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_4;
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_Out_PP;								//推挽输出
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	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);
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_6;
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IPU;								//上拉输入
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//SPI
	SPI_InitTypeDef SPI_InitStruct;
	SPI_InitStruct.SPI_BaudRatePrescaler 	= SPI_BaudRatePrescaler_128;			//SPI时钟采用32分频
	SPI_InitStruct.SPI_CPHA 				= SPI_CPHA_1Edge;						//选择第几个上升沿捕获数据
	SPI_InitStruct.SPI_CPOL 				= SPI_CPOL_Low;							//时钟默认为低电平
	SPI_InitStruct.SPI_CRCPolynomial 		= 7;									//CRC校验,这里不使用给一个默认值7
	SPI_InitStruct.SPI_DataSize 			= SPI_DataSize_8b;						//数据字节长度为8
	SPI_InitStruct.SPI_Direction 			= SPI_Direction_2Lines_FullDuplex;		//数据传输采用双向全双工
	SPI_InitStruct.SPI_FirstBit 			= SPI_FirstBit_MSB;						//数据传输采用高位在前
	SPI_InitStruct.SPI_Mode 				= SPI_Mode_Master;						//SPI主模式
	SPI_InitStruct.SPI_NSS 					= SPI_NSS_Soft;							//使用GPIO模拟CS,这里设置为软件控制即可
	
	SPI_Init(SPI1,&SPI_InitStruct);
	
	//使能SPI
	SPI_Cmd(SPI1,ENABLE);
	//默认CS为高电平
	MySPI_CS_W(1);
}

/**
  *@brief  SPI CS控制
  *@param  BitValue 要写入CS的位数据
  *@retval None
 **/
void MySPI_CS_W(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
}

/**
  *@brief  SPI起始信号
  *@param  None
  *@retval None
 **/
void MySPI_Start(void)
{
	MySPI_CS_W(0);																//将片选信号拉低发送起始信号
}

/**
  *@brief  SPI终止信号
  *@param  None
  *@retval None
 **/
void MySPI_Stop(void)
{
	MySPI_CS_W(1);																//将片选信号拉高发送终止信号
}

/**
  *@brief  SPI交换字节
  *@param  None
  *@retval 交换的字节
 **/
uint8_t MySPI_SwapByte(uint8_t ByteValue)
{
	while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
	SPI_I2S_SendData(SPI1,ByteValue);
	while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE));
	
	return SPI_I2S_ReceiveData(SPI1);
}

W25Q64_Ins.h 

#ifndef W25Q64_INS_H
#define W25Q64_INS_H

#define W25Q64_WRITEENABLE 				0x06
#define W25Q64_READSTATUSREGISTER1 		0x05
#define W25Q64_PAGEPROGRAM 				0x02
#define W25Q64_SECTORERASE4KB 			0x20
#define W25Q64_JEDECID 					0X9F
#define W25Q64_READDATA 				0x03
#define W25Q64_DUMMY_BYTE 				0xFF

#endif

W25Q64.h 

#ifndef W25Q64_H
#define W25Q64_H

#include "stm32f10x.h"                  // Device header
#include "MySPI.h"

void W25Q64_Init(void);
void W25Q64_ReadID(uint8_t* MF, uint16_t*ID);
void W25Q64_WriteEnable(void);
void W25Q64_WaitBusy(void);
void W25Q64_PageProgram(uint32_t Address, uint8_t* DataArry, uint16_t Count);
void W25Q64_SectorErase(uint32_t Address);
void W25Q64_ReadData(uint32_t Address,uint8_t* DataArry, uint32_t Count);

#endif

W25Q64.c 

#include "W25Q64.h"
#include "W25Q64_Ins.h"

/**
  *@brief  W25Q64初始化
  *@param  None
  *@retval None
 **/
void W25Q64_Init(void)
{
	MySPI_Init();
}

/**
  *@brief  W25Q64ID读取
  *@param  None
  *@retval None
 **/
void W25Q64_ReadID(uint8_t* MF, uint16_t*ID)
{
	MySPI_Start();
	//发送读取ID指令
	MySPI_SwapByte(W25Q64_JEDECID);
	//发送空指令交换数据
	*MF = MySPI_SwapByte(W25Q64_DUMMY_BYTE);													//随便发送一个数据用于与从机交换数据,一般使用0xFF或0x00
	*ID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	*ID <<= 8;
	*ID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	MySPI_Stop();
}

/**
  *@brief  W25Q64ID写使能
  *@param  None
  *@retval None
 **/
void W25Q64_WriteEnable(void)
{
	MySPI_Start();
	//发送写使能指令
	MySPI_SwapByte(W25Q64_WRITEENABLE);
	MySPI_Stop();
}

/**
  *@brief  W25Q64ID忙等待
  *@param  None
  *@retval None
 **/
void W25Q64_WaitBusy(void)
{
	MySPI_Start();
	//发送读状态寄存器指令
	MySPI_SwapByte(W25Q64_READSTATUSREGISTER1);
	//等待BUSY位清零,则从设备退出忙状态
	while((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0X01) == 0X01);
	MySPI_Stop();
}

/**
  *@brief  W25Q64ID页写入
  *@param  None
  *@retval None
 **/
void W25Q64_PageProgram(uint32_t Address, uint8_t* DataArry, uint16_t Count)
{
	uint16_t i;
	
	W25Q64_WriteEnable();														//写使能
	MySPI_Start();
	MySPI_SwapByte(W25Q64_PAGEPROGRAM);
	//发送24位地址
	MySPI_SwapByte(Address>>16);
	MySPI_SwapByte(Address>>8);
	MySPI_SwapByte(Address);
	//发送指定数量的数据
	for(i=0;i<Count;i++)
	{
		MySPI_SwapByte(DataArry[i]);
	}
	MySPI_Stop();
	W25Q64_WaitBusy();															//事后等待忙状态
}

/**
  *@brief  W25Q64ID指定扇区擦除
  *@param  None
  *@retval None
 **/
void W25Q64_SectorErase(uint32_t Address)
{			
	W25Q64_WriteEnable();
	MySPI_Start();
	MySPI_SwapByte(W25Q64_SECTORERASE4KB);
	//发送24位地址
	MySPI_SwapByte(Address>>16);
	MySPI_SwapByte(Address>>8);
	MySPI_SwapByte(Address);
	MySPI_Stop();
	W25Q64_WaitBusy();
}

/**
  *@brief  W25Q64ID读取数据
  *@param  None
  *@retval None
  *@note   数据接收的数量也要指定,不然无法停止数据读取操作
 **/
void W25Q64_ReadData(uint32_t Address,uint8_t* DataArry, uint32_t Count)
{
	uint32_t i;

	MySPI_Start();
	MySPI_SwapByte(W25Q64_READDATA);
	//发送24位地址
	MySPI_SwapByte(Address>>16);
	MySPI_SwapByte(Address>>8);
	MySPI_SwapByte(Address);
	
	for(i=0;i<Count;i++)
	{
		DataArry[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	}
	MySPI_Stop();
}

 OLED部分代码参照文章《STM32基础教程——OLED显示》

技术要点 

引脚操作

/**
  *@brief  SPI CS控制
  *@param  BitValue 要写入CS的位数据
  *@retval None
 **/
void MySPI_CS_W(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
}

对单个引脚的操作进行封装,用于模拟SPI引脚电平翻转用于控制CS信号。 

SPI初始化

/**
  *@brief  SPI初始化
  *@param  None
  *@retval None
 **/
void MySPI_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	
	//GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_4;
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_Out_PP;								//推挽输出
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	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);
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_6;
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IPU;								//上拉输入
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//SPI
	SPI_InitTypeDef SPI_InitStruct;
	SPI_InitStruct.SPI_BaudRatePrescaler 	= SPI_BaudRatePrescaler_128;			//SPI时钟采用128分频
	SPI_InitStruct.SPI_CPHA 				= SPI_CPHA_1Edge;						//选择第几个上升沿捕获数据
	SPI_InitStruct.SPI_CPOL 				= SPI_CPOL_Low;							//时钟默认为低电平
	SPI_InitStruct.SPI_CRCPolynomial 		= 7;									//CRC校验,这里不使用给一个默认值7
	SPI_InitStruct.SPI_DataSize 			= SPI_DataSize_8b;						//数据字节长度为8
	SPI_InitStruct.SPI_Direction 			= SPI_Direction_2Lines_FullDuplex;		//数据传输采用双向全双工
	SPI_InitStruct.SPI_FirstBit 			= SPI_FirstBit_MSB;						//数据传输采用高位在前
	SPI_InitStruct.SPI_Mode 				= SPI_Mode_Master;						//SPI主模式
	SPI_InitStruct.SPI_NSS 					= SPI_NSS_Soft;							//使用GPIO模拟CS,这里设置为软件控制即可
	
	SPI_Init(SPI1,&SPI_InitStruct);
	
	//使能SPI
	SPI_Cmd(SPI1,ENABLE);
	//默认CS为高电平
	MySPI_CS_W(1);
}

SPI初始化,先初始化GPIO,PA4作为软件发送CS信号的引脚,应初始化为推挽输出。PA5和PA7作为外设SPI的SCK和MOSI引脚,应初始化为复用推挽输出,PA6引脚作为MISO引脚,用于接收数据输入,初始化为上拉输入。

SPI1初始化,时钟分频选择128分频,SPI1为APB2外设,系统时钟为72MHz,经分频后时钟频率为562.5kHz。设置第一个边沿数据移入,且默认时钟为低电平。将SPI设置为主模式下双向全双工模式,数据长度设置为8位,数据传输高位在前。其余杂项CRC校验设为默认值,NSS在本实验不使用,设置为软件控制。将片选信号初始化为高电平。

SPI起始信号

SPI的起始时序是CS(SS)从高电平切换为低电平 。

/**
  *@brief  SPI起始信号
  *@param  None
  *@retval None
 **/
void MySPI_Start(void)
{
	MySPI_CS_W(0);																//将片选信号拉低发送起始信号
}

SPI终止信号
 

 SPI的终止时序是CS(SS)从低电平切换为高电平 。

/**
  *@brief  SPI终止信号
  *@param  None
  *@retval None
 **/
void MySPI_Stop(void)
{
	MySPI_CS_W(1);																//将片选信号拉高发送终止信号
}

SPI字节交换

SPI为同步全双工通信,每一次通信都会进行数据交换。

/**
  *@brief  SPI交换字节
  *@param  None
  *@retval 交换的字节
 **/
uint8_t MySPI_SwapByte(uint8_t ByteValue)
{
	while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE));
	SPI_I2S_SendData(SPI1,ByteValue);
	while(!SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE));
	
	return SPI_I2S_ReceiveData(SPI1);
}

硬件SPI交换字节数据,先等待TXE标志位置位,表示发送数据缓冲寄存器为空,方可向发送数据缓冲寄存器写入数据,硬件SPI会在数据写入发送数据寄存器后自动完成数据发送,无需手动操作。然后只需等待数据接收寄存器的标志位RXNE被置位即可,当RXNE被置位后,说明数据接收寄存器已接收到从机发来的数据,此时将数据读出即可。

宏替换W25Q64操作指令 

#ifndef W25Q64_INS_H
#define W25Q64_INS_H

#define W25Q64_WRITEENABLE 				0x06
#define W25Q64_READSTATUSREGISTER1 		0x05
#define W25Q64_PAGEPROGRAM 				0x02
#define W25Q64_SECTORERASE4KB 			0x20
#define W25Q64_JEDECID 					0X9F
#define W25Q64_READDATA 				0x03
#define W25Q64_DUMMY_BYTE 				0xFF

#endif

将对W25Q64操作的命令使用宏代替, 提高代码的便捷性和可读性。

W25Q64写使能 

/**
  *@brief  W25Q64ID写使能
  *@param  None
  *@retval None
 **/
void W25Q64_WriteEnable(void)
{
	MySPI_Start();
	//发送写使能指令
	MySPI_SwapByte(W25Q64_WRITEENABLE);
	MySPI_Stop();
}

将写使能操作封装,方便使用。主机与从机交换数据,发送写使能命令,对从机进行写使能操作。

忙等待

/**
  *@brief  W25Q64ID忙等待
  *@param  None
  *@retval None
 **/
void W25Q64_WaitBusy(void)
{
	MySPI_Start();
	//发送读状态寄存器指令
	MySPI_SwapByte(W25Q64_READSTATUSREGISTER1);
	//等待BUSY位清零,则从设备退出忙状态
	while((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0X01) == 0X01);
	MySPI_Stop();
}

 发送读取状态寄存器1的命令,判断BUSY位的状态,使用while循环等待芯片退出忙状态将BUSY位清零。

读取设备ID号和制造商ID

/**
  *@brief  W25Q64ID读取
  *@param  None
  *@retval None
 **/
void W25Q64_ReadID(uint8_t* MF, uint16_t*ID)
{
	MySPI_Start();
	//发送读取ID指令
	MySPI_SwapByte(W25Q64_JEDECID);
	//发送空指令交换数据
	*MF = MySPI_SwapByte(W25Q64_DUMMY_BYTE);													//随便发送一个数据用于与从机交换数据,一般使用0xFF或0x00
	*ID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	*ID <<= 8;
	*ID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	MySPI_Stop();
}

 主机发送读取JEDEC ID的命令,从机向主机发送数据,数据格式为第一个字节为制造商ID,第二个和第三个字节为设备ID。这里使用指针进行数据操作。

页写入

/**
  *@brief  W25Q64ID页写入
  *@param  None
  *@retval None
 **/
void W25Q64_PageProgram(uint32_t Address, uint8_t* DataArry, uint16_t Count)
{
	uint16_t i;
	
	W25Q64_WriteEnable();														//写使能
	MySPI_Start();
	MySPI_SwapByte(W25Q64_PAGEPROGRAM);
	//发送24位地址
	MySPI_SwapByte(Address>>16);
	MySPI_SwapByte(Address>>8);
	MySPI_SwapByte(Address);
	//发送指定数量的数据
	for(i=0;i<Count;i++)
	{
		MySPI_SwapByte(DataArry[i]);
	}
	MySPI_Stop();
	W25Q64_WaitBusy();															//事后等待忙状态
}

页写入操作,先进行写使能,然后发送起始信号,发送页写入命令。然后发送24位地址,高16位为页地址,低八位为字节地址。使用for循环写入指定数量的数据,数据的数量不应超过256字节。最后发送停止信号,然后进行芯片忙等待操作(忙等待如果加在函数开始,那读取操作也要加忙等待函数调用,这样会使操作更复杂。)。所有写操作函数与本函数类似,不再赘述。

数据读取

/**
  *@brief  W25Q64ID读取数据
  *@param  None
  *@retval None
  *@note   数据接收的数量也要指定,不然无法停止数据读取操作
 **/
void W25Q64_ReadData(uint32_t Address,uint8_t* DataArry, uint32_t Count)
{
	uint32_t i;

	MySPI_Start();
	MySPI_SwapByte(W25Q64_READDATA);
	//发送24位地址
	MySPI_SwapByte(Address>>16);
	MySPI_SwapByte(Address>>8);
	MySPI_SwapByte(Address);
	
	for(i=0;i<Count;i++)
	{
		DataArry[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	}
	MySPI_Stop();
}

数据读取操作无需写使能,无需进行其他操作。发送读数据命令,然后发送24位地址,同样高16位地址为页地址,低八位为字节地址。读取操作不受页限制。

实验结果

问题记录 

暂无

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐