STM32之W25Qxx(Flash)掉电保存

简单说一下W25Qxx芯片:W25Qxx芯片为Flash芯片,可以实现数据保存,且掉电不丢失。

部分AT24Cxx的容量如图,该芯片通过 SPI 总线与 STM32 连接

                                        STM32之W25Qxx(Flash)掉电保存_第1张图片

电路如下(原子的):

                            STM32之W25Qxx(Flash)掉电保存_第2张图片

讲实现之前,简单介绍一下SPI:

SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI 是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32F1 也有 SPI 接口。

SPI 接口一般使用 4 条线通信:
MISO 主设备数据输入,从设备数据输出。
MOSI 主设备数据输出,从设备数据输入。
SCLK 时钟信号,由主设备产生。
CS 从设备片选信号,由主设备控制。

SPI 主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。SPI 总线四种工作方式 SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI 主模块和与之通信的外设备时钟相位和极性应该一致。

SPI  总线时序图

                  STM32之W25Qxx(Flash)掉电保存_第3张图片

 STM32F1 的 SPI 功能很强大,SPI 时钟最高可以到 18Mhz,支持 DMA,可以配置为 SPI协议或者 I2S 协议。

代码实现:

稍微讲一下代码以及使用 :

W25Q128写数据:

//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	 
void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
 	u16 i;  
    SPI_FLASH_Write_Enable();                  //SET WEL 
	SPI_FLASH_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_PageProgram);      //发送写页命令   
    SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址    
    SPI1_ReadWriteByte((u8)((WriteAddr)>>8));   
    SPI1_ReadWriteByte((u8)WriteAddr);   
    for(i=0;i

W25Q128 读数据

//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{ 
 	u16 i;    												    
	SPI_FLASH_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_ReadData);         //发送读取命令   
    SPI1_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址    
    SPI1_ReadWriteByte((u8)((ReadAddr)>>8));   
    SPI1_ReadWriteByte((u8)ReadAddr);   
    for(i=0;i

初始化代码之后,可以往W25Q128(Flash),写入字符、字符串、数字等,

断电之后,数据还保存在W25Q128里面,只要使用读函数,就可以将数据读出来

示例:

const u8 TEXT_Buffer[]={12,2,34,54};

          //TEXT_Buffer[]={"dafeacaeceawa"}; 可以是字符串

#define SIZE sizeof(TEXT_Buffer)                                                                                        

W25QXX_Write((u8*)TEXT_Buffer,        FLASH_SIZE-100,        SIZE);            //从倒数第100个地址处开始,写入SIZE长度的数据

       // (u8*)TEXT_Buffer, :数据 ,要写入的数据,这里是数组

        //FLASH_SIZE-100  开始写入的地址

       //  SIZE:写入的字节数,就是数组的大小

W25QXX_Read(datatemp,          FLASH_SIZE-100,          SIZE);                    //从倒数第100个地址处开始,读出SIZE个字节

       // (u8*)TEXT_Buffer, :数据 ,要读出的数据,这里是数组

        //FLASH_SIZE-100  开始读的地址

       //  SIZE:读出的字节数,就是数组的大小

开始写入的数据为TEXT_Buffer[]={12,2,34,54};;  

因此读出时,datatemp []={12,2,34,54};  要什么数据直接对数组操作就行  

W25Q 128 初始化


//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q64
//容量为8M字节,共有128个Block,2048个Sector 

//初始化SPI FLASH的IO口
void SPI_Flash_Init(void)
{
	RCC->APB2ENR|=1<<2;       	//PORTA时钟使能  
	GPIOA->CRL&=0XFFF000FF; 
	GPIOA->CRL|=0X00033300;		//PA2.3.4 推挽 	    
	GPIOA->ODR|=0X7<<2;    		//PA2.3.4上拉
	SPI1_Init();		   		//初始化SPI1
	SPI1_SetSpeed(SPI_SPEED_4);	//设置为18M时钟,高速模式
	SPI_FLASH_TYPE=SPI_Flash_ReadID();//读取FLASH ID.
}

 

接下来这部分的代码主要是SPI的初始化以及一些驱动,就粘贴出来,不作详细的介绍了

//这里针是对SPI1的初始化
void SPI1_Init(void)
{	 
	RCC->APB2ENR|=1<<2;       //PORTA时钟使能 	 
	RCC->APB2ENR|=1<<12;      //SPI1时钟使能 
		   
	//这里只针对SPI口初始化
	GPIOA->CRL&=0X000FFFFF; 
	GPIOA->CRL|=0XBBB00000;//PA5.6.7复用 	    
	GPIOA->ODR|=0X7<<5;    //PA5.6.7上拉
		
	SPI1->CR1|=0<<10;//全双工模式	
	SPI1->CR1|=1<<9; //软件nss管理
	SPI1->CR1|=1<<8;  

	SPI1->CR1|=1<<2; //SPI主机
	SPI1->CR1|=0<<11;//8bit数据格式	
	SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
	SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1  
	SPI1->CR1|=7<<3; //Fsck=Fcpu/256
	SPI1->CR1|=0<<7; //MSBfirst   
	SPI1->CR1|=1<<6; //SPI设备使能
	SPI1_ReadWriteByte(0xff);//启动传输(主要作用:维持MOSI为高)		 
}   
//SPI1 速度设置函数
//SpeedSet:0~7
//SPI速度=fAPB2/2^(SpeedSet+1)
//APB2时钟一般为72Mhz
void SPI1_SetSpeed(u8 SpeedSet)
{
	SpeedSet&=0X07;			//限制范围
	SPI1->CR1&=0XFFC7; 
	SPI1->CR1|=SpeedSet<<3;	//设置SPI1速度  
	SPI1->CR1|=1<<6; 		//SPI设备使能 
} 
//SPI1 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{		
	u16 retry=0;				 
	while((SPI1->SR&1<<1)==0)//等待发送区空	
	{
		retry++;
		if(retry>0XFFFE)return 0;
	}			  
	SPI1->DR=TxData;	 	  //发送一个byte 
	retry=0;
	while((SPI1->SR&1<<0)==0) //等待接收完一个byte  
	{
		retry++;
		if(retry>0XFFFE)return 0;
	}	  						    
	return SPI1->DR;          //返回收到的数据				    
}

总结:

1、STM32 与 W25Q128 通信方式为IIC通信;

2、W25Q128 为Flash 芯片,可以实现数据的掉电保存

3、往W25Q128 写入和读出数据只需要对W25Q128的地址写入和读出就行

4、读出的数据,可以保存在数组里面,操作只需要对数组进行操作

 

 

 

 

 

 

你可能感兴趣的:(STM32基础知识)