STM32的SPI的原理與使用(W25Q128附代碼)


目錄

一、SPI介紹

二、SPI接口框圖

三、SPI優缺點

四、SPI工作原理總結

五、時序圖

六、SPI程序編寫過程

七、W25Q12xx的原理及應用

7.1 分析W25Q128指令

7.2 擦除扇區:

7.3 部分常用設備讀取指令:


一、SPI介紹

SPI 是英語Serial Peripheral interface的縮寫,顧名思義就是串行外圍設備接口。是Motorola首先在其MC68HCXX系列處理器上定義的。SPI,是一種高速的,全雙工,同步的通信總線,並且在芯片的管腳上只佔用四根線,節約了芯片的管腳,同時爲PCB的佈局上節省空間,提供方便,主要應用在 EEPROM,FLASH,實時時鐘,AD轉換器,還有數字信號處理器和數字信號解碼器之間。

正是簡單易用的特性,如NRF24L01、VS1053、SD卡等皆集成了這種通信協議


二、SPI接口框圖


三、SPI優缺點

SPI接口是在CPU和外圍低速器件之間進行同步串行數據傳輸,在主器件的移位脈衝下,數據按位傳輸,低位在前,高位在後,爲全雙工通信,數據傳輸速度總體來說比I2C總線要快,速度可達到幾Mbps。

信號線少,協議簡單,相對數據速率高。

缺點:沒有指定的流控制,沒有應答機制確認是否接收到數據


四、SPI工作原理總結

  • 硬件上爲4根線。
  • 主機和從機都有一個串行移位寄存器,主機通過向它的SPI串行寄存器寫入一個字節來發起一次傳輸。
  • 串行移位寄存器通過MOSI信號線將字節傳送給從機,從機也將自己的串行移位寄存器中的內容通過MISO信號線返回給主機。這樣,兩個移位寄存器中的內容就被交換。
  • 外設的寫操作和讀操作是同步完成的。如果只進行寫操作,主機只需忽略接收到的字節;反之,若主機要讀取從機的一個字節,就必鬚髮送一個空字節來引發從機的傳輸。

多個設備使用SPI的應用舉例


五、時序圖

時序爲 SPI_CR1 寄存器中的 LSBFIRST 位復位時的時序

SPI_CPHA的值將會影響SPI_CPOL的值


六、SPI程序編寫過程

//①使能SPIx和IO口時鐘
RCC_AHBxPeriphClockCmd() / RCC_APBxPeriphClockCmd();

//②初始化IO口爲複用功能
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

//③設置引腳複用映射:
GPIO_PinAFConfig();

//②初始化SPIx,設置SPIx工作模式
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

//③使能SPIx
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

//④SPI傳輸數據
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;

//⑦查看SPI傳輸狀態
SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);
SPI.c:
#include "spi.h"

//以下是SPI模塊的初始化代碼,配置成主機模式 						  
//SPI口初始化
//這裏針是對SPI1的初始化
void SPI1_Init(void)
{	 
  GPIO_InitTypeDef  GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB時鐘
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1時鐘
 
  //GPIOFB3,4,5初始化設置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5複用功能輸出	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//複用功能
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推輓輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3複用爲 SPI1
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4複用爲 SPI1
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5複用爲 SPI1
 
	//這裏只針對SPI口初始化
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//復位SPI1
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止復位SPI1

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //設置SPI單向或者雙向的數據模式:SPI設置爲雙線雙向全雙工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//設置SPI工作模式:設置爲主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//設置SPI的數據大小:SPI發送接收8位幀結構
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步時鐘的空閒狀態爲高電平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步時鐘的第二個跳變沿(上升或下降)數據被採樣
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信號由硬件(NSS管腳)還是軟件(使用SSI位)管理:內部NSS信號有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定義波特率預分頻的值:波特率預分頻值爲256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定數據傳輸從MSB位還是LSB位開始:數據傳輸從MSB位開始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值計算的多項式
	SPI_Init(SPI1, &SPI_InitStructure);  //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器
 
	SPI_Cmd(SPI1, ENABLE); //使能SPI外設

	SPI1_ReadWriteByte(0xff);//啓動傳輸		 
}   
//SPI1速度設置函數
//SPI速度=fAPB2/分頻係數
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256  
//fAPB2時鐘一般爲84Mhz:
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{
  assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判斷有效性
	SPI1->CR1&=0XFFC7;//位3-5清零,用來設置波特率
	SPI1->CR1|=SPI_BaudRatePrescaler;	//設置SPI1速度 
	SPI_Cmd(SPI1,ENABLE); //使能SPI1
} 
//SPI1 讀寫一個字節
//TxData:要寫入的字節
//返回值:讀取到的字節
u8 SPI1_ReadWriteByte(u8 TxData)
{		 			 
 
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待發送區空  
	
	SPI_I2S_SendData(SPI1, TxData); //通過外設SPIx發送一個byte  數據
		
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一個byte  
 
	return SPI_I2S_ReceiveData(SPI1); //返回通過SPIx最近接收的數據	
 		    
}


七、W25Q12xx的原理及應用

W25Q128將16M的容量分爲256個塊(Block),每個塊大小爲64K字節,每個塊又分爲16個扇區(Sector),每個扇區4K個字節。W25Q128的最小擦除單位爲一個扇區,也就是每次必須擦除4K個字節。這樣我們需要給W25Q128開闢一個至少4K的緩存區,這樣對SRAM要求比較高,要求芯片必須有4K以上SRAM才能很好的操作。

W25Q128的擦寫週期多達10W次,具有20年的數據保存期限,支持電壓爲2.7~3.6V,W25Q128支持標準的SPI,還支持雙輸出/四輸出的SPI,最大SPI時鐘可以到80Mhz(雙輸出時相當於160Mhz,四輸出時相當於320M),更多的W25Q128的介紹,請參考W25Q128的DATASHEET。

W25Q12xx可根據原理圖查看,使用的是SPI總線通信協議

比如原子的原理圖

7.1 分析W25Q128指令

可參考W25Qxx的數據手冊,這裏列出W25Q128部分指令:

比如讀取設備的ID的指令:0x90000000

7.2 擦除扇區:

7.3 部分常用設備讀取指令:

0x90FFFFFF

讀取廠商ID

0x20xxxxxx

擦除扇區地址 

0x05FFFFFF

  讀取flash狀態   

0x02|addr|data

寫入數據
0x03 讀取數據

每次操作前要使能寫操作,且給一個低電平。結束時要給其爲高電平,再失能寫操作。也就是通過操作片選引腳來確定是否使能或失能。

W25Q12xx.c:
#include "w25qxx.h" 
#include "spi.h"
#include "delay.h"	   
#include "usart.h"	

u16 W25QXX_TYPE=W25Q128;	//默認是W25Q128

//4Kbytes爲一個Sector
//16個扇區爲1個Block
//W25Q128
//容量爲16M字節,共有128個Block,4096個Sector 
													 
//初始化SPI FLASH的IO口
void W25QXX_Init(void)
{ 
  GPIO_InitTypeDef  GPIO_InitStructure;
 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB時鐘
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG時鐘

	  //GPIOB14
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;//PB14
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//輸出
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推輓輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//PG7
  GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
 
	GPIO_SetBits(GPIOG,GPIO_Pin_7);//PG7輸出1,防止NRF干擾SPI FLASH的通信 
	W25QXX_CS=1;			//SPI FLASH不選中
	SPI1_Init();		   			//初始化SPI
	SPI1_SetSpeed(SPI_BaudRatePrescaler_2);		//設置爲42M時鐘,高速模式 
	W25QXX_TYPE=W25QXX_ReadID();	//讀取FLASH ID.
}  

//讀取W25QXX的狀態寄存器
//BIT7  6   5   4   3   2   1   0
//SPR   RV  TB BP2 BP1 BP0 WEL BUSY
//SPR:默認0,狀態寄存器保護位,配合WP使用
//TB,BP2,BP1,BP0:FLASH區域寫保護設置
//WEL:寫使能鎖定
//BUSY:忙標記位(1,忙;0,空閒)
//默認:0x00
u8 W25QXX_ReadSR(void)   
{  
	u8 byte=0;   
	W25QXX_CS=0;                            //使能器件   
	SPI1_ReadWriteByte(W25X_ReadStatusReg);    //發送讀取狀態寄存器命令    
	byte=SPI1_ReadWriteByte(0Xff);             //讀取一個字節  
	W25QXX_CS=1;                            //取消片選     
	return byte;   
} 
//寫W25QXX狀態寄存器
//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以寫!!!
void W25QXX_Write_SR(u8 sr)   
{   
	W25QXX_CS=0;                            //使能器件   
	SPI1_ReadWriteByte(W25X_WriteStatusReg);   //發送寫取狀態寄存器命令    
	SPI1_ReadWriteByte(sr);               //寫入一個字節  
	W25QXX_CS=1;                            //取消片選     	      
}   
//W25QXX寫使能	
//將WEL置位   
void W25QXX_Write_Enable(void)   
{
	W25QXX_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_WriteEnable);      //發送寫使能  
	W25QXX_CS=1;                            //取消片選     	      
} 
//W25QXX寫禁止	
//將WEL清零  
void W25QXX_Write_Disable(void)   
{  
	W25QXX_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_WriteDisable);     //發送寫禁止指令    
	W25QXX_CS=1;                            //取消片選     	      
} 		
//讀取芯片ID
//返回值如下:				   
//0XEF13,表示芯片型號爲W25Q80  
//0XEF14,表示芯片型號爲W25Q16    
//0XEF15,表示芯片型號爲W25Q32  
//0XEF16,表示芯片型號爲W25Q64 
//0XEF17,表示芯片型號爲W25Q128 	  
u16 W25QXX_ReadID(void)
{
	u16 Temp = 0;	  
	W25QXX_CS=0;				    
	SPI1_ReadWriteByte(0x90);//發送讀取ID命令	    
	SPI1_ReadWriteByte(0x00); 	    
	SPI1_ReadWriteByte(0x00); 	    
	SPI1_ReadWriteByte(0x00); 	 			   
	Temp|=SPI1_ReadWriteByte(0xFF)<<8;  
	Temp|=SPI1_ReadWriteByte(0xFF);	 
	W25QXX_CS=1;				    
	return Temp;
}   		    
//讀取SPI FLASH  
//在指定地址開始讀取指定長度的數據
//pBuffer:數據存儲區
//ReadAddr:開始讀取的地址(24bit)
//NumByteToRead:要讀取的字節數(最大65535)
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{ 
 	u16 i;   										    
	W25QXX_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<NumByteToRead;i++)
	{ 
        pBuffer[i]=SPI1_ReadWriteByte(0XFF);   //循環讀數  
    }
	W25QXX_CS=1;  				    	      
}  
//SPI在一頁(0~65535)內寫入少於256個字節的數據
//在指定地址開始寫入最大256字節的數據
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的字節數(最大256),該數不應該超過該頁的剩餘字節數!!!	 
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
 	u16 i;  
    W25QXX_Write_Enable();                  //SET WEL 
	W25QXX_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<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循環寫數  
	W25QXX_CS=1;                            //取消片選 
	W25QXX_Wait_Busy();					   //等待寫入結束
} 
//無檢驗寫SPI FLASH 
//必須確保所寫的地址範圍內的數據全部爲0XFF,否則在非0XFF處寫入的數據將失敗!
//具有自動換頁功能 
//在指定地址開始寫入指定長度的數據,但是要確保地址不越界!
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的字節數(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 			 		 
	u16 pageremain;	   
	pageremain=256-WriteAddr%256; //單頁剩餘的字節數		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大於256個字節
	while(1)
	{	   
		W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)break;//寫入結束了
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;	

			NumByteToWrite-=pageremain;			  //減去已經寫入了的字節數
			if(NumByteToWrite>256)pageremain=256; //一次可以寫入256個字節
			else pageremain=NumByteToWrite; 	  //不夠256個字節了
		}
	};	    
} 
//寫SPI FLASH  
//在指定地址開始寫入指定長度的數據
//該函數帶擦除操作!
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)						
//NumByteToWrite:要寫入的字節數(最大65535)   
u8 W25QXX_BUFFER[4096];		 
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 
	u32 secpos;
	u16 secoff;
	u16 secremain;	   
 	u16 i;    
	u8 * W25QXX_BUF;	  
   	W25QXX_BUF=W25QXX_BUFFER;	     
 	secpos=WriteAddr/4096;//扇區地址  
	secoff=WriteAddr%4096;//在扇區內的偏移
	secremain=4096-secoff;//扇區剩餘空間大小   
 	//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//測試用
 	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大於4096個字節
	while(1) 
	{	
		W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//讀出整個扇區的內容
		for(i=0;i<secremain;i++)//校驗數據
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除  	  
		}
		if(i<secremain)//需要擦除
		{
			W25QXX_Erase_Sector(secpos);//擦除這個扇區
			for(i=0;i<secremain;i++)	   //複製
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];	  
			}
			W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//寫入整個扇區  

		}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//寫已經擦除了的,直接寫入扇區剩餘區間. 				   
		if(NumByteToWrite==secremain)break;//寫入結束了
		else//寫入未結束
		{
			secpos++;//扇區地址增1
			secoff=0;//偏移位置爲0 	 

		   	pBuffer+=secremain;  //指針偏移
			WriteAddr+=secremain;//寫地址偏移	   
		   	NumByteToWrite-=secremain;				//字節數遞減
			if(NumByteToWrite>4096)secremain=4096;	//下一個扇區還是寫不完
			else secremain=NumByteToWrite;			//下一個扇區可以寫完了
		}	 
	};	 
}
//擦除整個芯片		  
//等待時間超長...
void W25QXX_Erase_Chip(void)   
{                                   
    W25QXX_Write_Enable();                  //SET WEL 
    W25QXX_Wait_Busy();   
  	W25QXX_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_ChipErase);        //發送片擦除命令  
	W25QXX_CS=1;                            //取消片選     	      
	W25QXX_Wait_Busy();   				   //等待芯片擦除結束
}   
//擦除一個扇區
//Dst_Addr:扇區地址 根據實際容量設置
//擦除一個山區的最少時間:150ms
void W25QXX_Erase_Sector(u32 Dst_Addr)   
{  
	//監視falsh擦除情況,測試用   
 	printf("fe:%x\r\n",Dst_Addr);	  
 	Dst_Addr*=4096;
    W25QXX_Write_Enable();                  //SET WEL 	 
    W25QXX_Wait_Busy();   
  	W25QXX_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_SectorErase);      //發送扇區擦除指令 
    SPI1_ReadWriteByte((u8)((Dst_Addr)>>16));  //發送24bit地址    
    SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));   
    SPI1_ReadWriteByte((u8)Dst_Addr);  
	W25QXX_CS=1;                            //取消片選     	      
    W25QXX_Wait_Busy();   				   //等待擦除完成
}  
//等待空閒
void W25QXX_Wait_Busy(void)   
{   
	while((W25QXX_ReadSR()&0x01)==0x01);   // 等待BUSY位清空
}  
//進入掉電模式
void W25QXX_PowerDown(void)   
{ 
  	W25QXX_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_PowerDown);        //發送掉電命令  
	W25QXX_CS=1;                            //取消片選     	      
    delay_us(3);                               //等待TPD  
}   
//喚醒
void W25QXX_WAKEUP(void)   
{  
  	W25QXX_CS=0;                            //使能器件   
    SPI1_ReadWriteByte(W25X_ReleasePowerDown);   //  send W25X_PowerDown command 0xAB    
	W25QXX_CS=1;                            //取消片選     	      
    delay_us(3);                               //等待TRES1
}   

W25Q12xx.h:

#ifndef __W25QXX_H
#define __W25QXX_H			    
#include "sys.h"  

//W25X系列/Q系列芯片列表	   
//W25Q80  ID  0XEF13
//W25Q16  ID  0XEF14
//W25Q32  ID  0XEF15
//W25Q64  ID  0XEF16	
//W25Q128 ID  0XEF17	
#define W25Q80 	0XEF13 	
#define W25Q16 	0XEF14
#define W25Q32 	0XEF15
#define W25Q64 	0XEF16
#define W25Q128	0XEF17

extern u16 W25QXX_TYPE;					//定義W25QXX芯片型號		   

#define	W25QXX_CS 		PBout(14)  		//W25QXX的片選信號
////////////////////////////////////////////////////////////////////////////////// 
//指令表
#define W25X_WriteEnable		0x06 
#define W25X_WriteDisable		0x04 
#define W25X_ReadStatusReg		0x05 
#define W25X_WriteStatusReg		0x01 
#define W25X_ReadData			0x03 
#define W25X_FastReadData		0x0B 
#define W25X_FastReadDual		0x3B 
#define W25X_PageProgram		0x02 
#define W25X_BlockErase			0xD8 
#define W25X_SectorErase		0x20 
#define W25X_ChipErase			0xC7 
#define W25X_PowerDown			0xB9 
#define W25X_ReleasePowerDown	0xAB 
#define W25X_DeviceID			0xAB 
#define W25X_ManufactDeviceID	0x90 
#define W25X_JedecDeviceID		0x9F 

void W25QXX_Init(void);
u16  W25QXX_ReadID(void);  	    		//讀取FLASH ID
u8	 W25QXX_ReadSR(void);        		//讀取狀態寄存器 
void W25QXX_Write_SR(u8 sr);  			//寫狀態寄存器
void W25QXX_Write_Enable(void);  		//寫使能 
void W25QXX_Write_Disable(void);		//寫保護
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //讀取flash
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//寫入flash
void W25QXX_Erase_Chip(void);    	  	//整片擦除
void W25QXX_Erase_Sector(u32 Dst_Addr);	//扇區擦除
void W25QXX_Wait_Busy(void);           	//等待空閒
void W25QXX_PowerDown(void);        	//進入掉電模式
void W25QXX_WAKEUP(void);				//喚醒

#endif

main.c:

main.c:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "spi.h"
#include "w25qxx.h"
#include "key.h"    

//要寫入到W25Q16的字符串數組
const u8 TEXT_Buffer[]={"Explorer STM32F4 SPI TEST"};
#define SIZE sizeof(TEXT_Buffer)	 
	
int main(void)
{ 
	u8 key;
	u16 i=0;
	u8 datatemp[SIZE];	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2
	delay_init(168);    //初始化延時函數
	uart_init(115200);	//初始化串口波特率爲115200
	LED_Init();					//初始化LED 
	KEY_Init(); 				//按鍵初始化  
	W25QXX_Init();			//W25QXX初始化 
 			
 	while(W25QXX_ReadID()!=W25Q128)	//檢測不到W25Q128
	{
		printf("W25Q128 Check Failed!");
		delay_ms(500);
		printf("Please Check!      ");
		delay_ms(500);
		LED0=!LED0;		//DS0閃爍
	}
	
	while(1)
	{
		key=KEY_Scan(0);
		if(key==KEY1_PRES)//KEY1按下,寫入24C02
		{
			printf("Start Write W25Q128...."); 
                        //從倒數第100個地址處開始,寫入SIZE長度的數據  
			W25QXX_Write((u8*)TEXT_Buffer,FLASH_SIZE-100,SIZE);
			printf("W25Q128 Write Finished!");  //提示傳送完成
		}
		if(key==KEY0_PRES)//KEY0按下,讀取字符串並顯示
		{
                        printf("Start Read W25Q128.... ");
                        //從倒數第100個地址處開始,讀出SIZE個字節
			W25QXX_Read(datatemp,FLASH_SIZE-100,SIZE);					
			printf("The Data Readed Is: \r\n ");//提示傳送完成
			printf("%s\r\n ",datatemp);
		}	   
	} 	    
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章