您的位置:首页 > 其它

STM32 SPI对外部FLASH的访问(转载)

2015-07-08 12:29 316 查看
本帖最后由 nibutaiguai 于 2012-6-8 11:37 编辑
3.17.1 SPI 简介 SPI 是英语Serial Peripheralinterface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32也有SPI接口。 SPI接口一般使用4条线: MISO 主设备数据输入,从设备数据输出。 MOSI 主设备数据输出,从设备数据输入。 SCLK时钟信号,由主设备产生。 CS从设备片选信号,由主设备控制。 SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。 SPI总线四种工作方式 SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设备时钟相位和极性应该一致。 不同时钟相位下的总线数据传输时序见下图:


图3.17.1.1不同时钟相位下的总线传输时序(CPHA=0/1)
STM32的SPI功能很强大,SPI时钟最多可以到18Mhz,支持DMA,可以配置为SPI协议或者I2S协议。 本节,我们将利用STM32的SPI来读取外部SPIFLASH芯片(W25X16),实现类似上节的功能。这里对SPI我们只简单介绍一下SPI的使用,STM32的SPI详细介绍请参考《STM32参考手册》第422页,22节。然后我们再介绍下SPIFLASH芯片。 这节,我们使用STM32的SPI1的主模式,下面就来看看SPI1部分的设置步骤吧,STM32的主模式配置步骤如下: 1)配置相关引脚的复用功能,使能SPI1时钟。 我们要用SPI1,第一步就要是能SPI1的时钟,SPI1的时钟通过APB2ENR的第12位来设置。其次要设置SPI1的相关引脚为复用输出,这样才会连接到SPI1上否则这些IO口还是默认的状态,也就是标准输入输出口。这里我们使用的是PA5、6、7这3个(SCK.、MISO、MOSI,CS使用软件管理方式),所以设置这三个为复用IO。 2)设置SPI1工作模式。 这一步全部是通过SPI1_CR1来设置,我们设置SPI1为主机模式,设置数据格式为8位,然后通过CPOL和CPHA位来设置SCK时钟极性及采样方式。并设置SPI1的时钟频率(最大18Mhz),以及数据的格式(MSB在前还是LSB在前)。 3)使能SPI1。 这一步通过SPI1_CR1的bit6来设置,以启动SPI1,在启动之后,我们就可以开始SPI通讯了。 SPI1的使用就介绍到这里,接下来介绍一下W25X16。W25X16是华邦公司推出的继W25X10/20/40/80(从1Mb~8Mb)后容量更大的FLASH产品,W25X16的容量为16Mb,还有容量更大的W25X32/64,ALIENTEK所选择的W25X16容量为16Mb,也就是2M字节,同AT45DB161是一样大小的。 W25X16将2M的容量分为32个块(Block),每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K个字节。W25X16的最少擦除单位为一个扇区,也就是每次必须擦除4K个字节。这样我们需要给W25X16开辟一个至少4K的缓存区,这样对SRAM要求比较高(相对于AT45DB161来说),但是它有价格及供货上的优势。 W25X16的差些周期为10000次,具有20年的数据保存期限,支持电压为2.7~3.6V,W25X16支持标准的SPI,还支持双输出的SPI,最大SPI时钟可以到75Mhz(双输出时相当于150Mhz),更多的W25X16的介绍,请参考W25X16的DATASHEET。3.17.2 硬件设计
本节实验功能简介:开机的时候先检测W25X16是否存在,然后在主循环里面用1个按键用来执行写入W25X16的操作,另外一个按键用来执行读出操作,在TFTLCD模块上显示相关信息。同时用DS0提示程序正在运行。 所要用到的硬件资源如下: 1)STM32F103RBT6。 2)DS0(外部LED0)。 3)KEY0和KEY2。 4)TFTLCD液晶模块。 5)W25X16。 前面4部分的资源,我们前面已经介绍了,请大家参考相关章节。这里只介绍W25X16与STM32的连接,板上的W25X16是直接连在STM32F103RBT6上的,连接关系如下图:


图3.17.2.1STM32F103RBT6与W25X16连接电路图
3.17.3 软件设计 打开上一节的工程,首先在HARDWARE文件夹下新建一个FLASH的文件夹和SPI的文件夹。然后新建一个flash.c和flash.h的文件保存在FLASH文件夹下,新建spi.c和spi.h的文件,保存在SPI文件夹下,并将这两个文件夹加入头文件包含路径。 打开spi.c文件,输入如下代码: //这里针是对SPI1的初始化 voidSPIx_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设备使能      SPIx_ReadWriteByte(0xff);//启动传输                }    //SPI 速度设置函数 //SpeedSet: //SPI_SPEED_2   2分频   (SPI 36M@sys 72M) //SPI_SPEED_8   8分频   (SPI 9M@sys 72M) //SPI_SPEED_16  16分频  (SPI 4.5M@sys 72M) //SPI_SPEED_256256分频 (SPI281.25K@sys 72M) voidSPIx_SetSpeed(u8 SpeedSet) {      SPI1->CR1&=0XFFC7;//Fsck=Fcpu/256      if(SpeedSet==SPI_SPEED_2)//二分频      {                  SPI1->CR1|=0<<3;//Fsck=Fpclk/2=36Mhz                 }else if(SpeedSet==SPI_SPEED_8)//八分频      {                  SPI1->CR1|=2<<3;//Fsck=Fpclk/8=9Mhz      }else if(SpeedSet==SPI_SPEED_16)//十六分频      {                  SPI1->CR1|=3<<3;//Fsck=Fpclk/16=4.5Mhz      }else                                         //256分频      {                  SPI1->CR1|=7<<3;//Fsck=Fpclk/256=281.25Khz 低速模式      }      SPI1->CR1|=1<<6; //SPI设备使能          } //SPIx读写一个字节 //TxData:要写入的字节 //返回值:读取到的字节 u8SPIx_ReadWriteByte(u8 TxData) {     u8 retry=0;                                                  while((SPI1->SR&1<<1)==0)//等待发送区空            {  retry++;                  if(retry>200)return 0;      }                                          SPI1->DR=TxData;                     //发送一个byte      retry=0;      while((SPI1->SR&1<<0)==0) //等待接收完一个byte        {      retry++;                 if(retry>200)return 0;      }                                                                                            return SPI1->DR;          //返回收到的数据                                                   } 此部分代码主要初始化SPI,这里我们选择的是SPI1,所以在SPIx_Init函数里面,其相关的操作都是针对SPI1的,其初始化步骤和我们上面介绍的一样。在初始化之后,我们就可以开始使用SPI1了,在SPIx_Init函数里面,把SPI1的波特率设置成了最低(281.25Khz)。在外部函数里面,我们通过SPIx_SetSpeed来设置SPI1的速度,而我们的数据发送和接收则是通过SPIx_ReadWriteByte函数来实现的。、 保存spi.c,并把该文件加入RDWARE组下面,然后我们打开spi.h在里面输入如下代码: #ifndef __SPI_H #define __SPI_H #include "sys.h" //Mini STM32开发板 //SPI 驱动 V1.1 //正点原子@ALIENTEK //2010/6/13 // SPI总线速度设置 #define SPI_SPEED_2   0 #define SPI_SPEED_8   1 #define SPI_SPEED_16  2 #define SPI_SPEED_256 3   void SPIx_Init(void);                                  //初始化SPI口 void SPIx_SetSpeed(u8 SpeedSet); //设置SPI速度    u8 SPIx_ReadWriteByte(u8 TxData);//SPI总线读写一个字节 #endif      此部分代码我们就不多介绍了,保存spi.h,然后我们打开flash.c,在里面输入如下代码: #include "flash.h" #include "spi.h" #include "delay.h"    //Mini STM32开发板 //W25X16 驱动函数 //正点原子@ALIENTEK //2010/6/13 //V1.0 //4Kbytes为一个Sector //16个扇区为1个Block //W25X16 //容量为2M字节,共有32个Block,512个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上拉      SPIx_Init();                      //初始化SPI }  
//读取SPI_FLASH的状态寄存器 //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 SPI_Flash_ReadSR(void)    {        u8byte=0;         SPI_FLASH_CS=0;                            //使能器件         SPIx_ReadWriteByte(W25X_ReadStatusReg);    //发送读取状态寄存器命令         byte=SPIx_ReadWriteByte(0Xff);             //读取一个字节        SPI_FLASH_CS=1;                            //取消片选           returnbyte;    } //写SPI_FLASH状态寄存器 //只有SPR,TB,BP2,BP1,BP0(bit7,5,4,3,2)可以写!!! void SPI_FLASH_Write_SR(u8 sr)    {   SPI_FLASH_CS=0;                            //使能器件         SPIx_ReadWriteByte(W25X_WriteStatusReg);   //发送写取状态寄存器命令         SPIx_ReadWriteByte(sr);               //写入一个字节        SPI_FLASH_CS=1;                            //取消片选                  }   //SPI_FLASH写使能          //将WEL置位    void SPI_FLASH_Write_Enable(void)    {      SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_WriteEnable);      //发送写使能        SPI_FLASH_CS=1;                            //取消片选                  } //SPI_FLASH写禁止          //将WEL清零   void SPI_FLASH_Write_Disable(void)    { SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_WriteDisable);     //发送写禁止指令         SPI_FLASH_CS=1;                            //取消片选                  }                               //读取芯片ID W25X16的ID:0XEF14 u16 SPI_Flash_ReadID(void) {u16Temp = 0;           SPI_FLASH_CS=0;                                                     SPIx_ReadWriteByte(0x90);//发送读取ID命令            SPIx_ReadWriteByte(0x00);                 SPIx_ReadWriteByte(0x00);                 SPIx_ReadWriteByte(0x00);                                                   Temp|=SPIx_ReadWriteByte(0xFF)<<8;        Temp|=SPIx_ReadWriteByte(0xFF);               SPI_FLASH_CS=1;                                                     returnTemp; }                               //读取SPI FLASH   //在指定地址开始读取指定长度的数据 //pBuffer:数据存储区 //ReadAddr:开始读取的地址
11a60
(24bit) //NumByteToRead:要读取的字节数(最大65535) void SPI_Flash_Read(u8* pBuffer,u32ReadAddr,u16 NumByteToRead)    {  u16 i;                                                                                                                                                         SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_ReadData);         //发送读取命令       SPIx_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址       SPIx_ReadWriteByte((u8)((ReadAddr)>>8));       SPIx_ReadWriteByte((u8)ReadAddr);      for(i=0;i<NumByteToRead;i++)      {        pBuffer=SPIx_ReadWriteByte(0XFF);  //循环读数      }      SPI_FLASH_CS=1;                            //取消片选                  }   //SPI在一页(0~65535)内写入少于256个字节的数据 //在指定地址开始写入最大256字节的数据 //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!             void SPI_Flash_Write_Page(u8* pBuffer,u32WriteAddr,u16 NumByteToWrite) {      u16 i;    SPI_FLASH_Write_Enable();                  //SET WEL      SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_PageProgram);      //发送写页命令       SPIx_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址       SPIx_ReadWriteByte((u8)((WriteAddr)>>8));       SPIx_ReadWriteByte((u8)WriteAddr);      for(i=0;i<NumByteToWrite;i++)SPIx_ReadWriteByte(pBuffer);//循环写数        SPI_FLASH_CS=1;                            //取消片选      SPI_Flash_Wait_Busy();                                                    //等待写入结束 } //无检验写SPI FLASH //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败! //具有自动换页功能 //在指定地址开始写入指定长度的数据,但是要确保地址不越界! //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大65535) //CHECK OK void SPI_Flash_Write_NoCheck(u8*pBuffer,u32 WriteAddr,u16 NumByteToWrite)   {                                                         u16pageremain;         pageremain=256-WriteAddr%256;//单页剩余的字节数                                    if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节      while(1)      {                              SPI_Flash_Write_Page(pBuffer,WriteAddr,pageremain);                  if(NumByteToWrite==pageremain)break;//写入结束了                  else//NumByteToWrite>pageremain                  {                              pBuffer+=pageremain;                              WriteAddr+=pageremain;            
                             NumByteToWrite-=pageremain;                             //减去已经写入了的字节数                              if(NumByteToWrite>256)pageremain=256;//一次可以写入256个字节                              elsepageremain=NumByteToWrite;            //不够256个字节了                  }      };             } //写SPI FLASH   //在指定地址开始写入指定长度的数据 //该函数带擦除操作! //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大65535)                      u8 SPI_FLASH_BUF[4096]; void SPI_Flash_Write(u8* pBuffer,u32WriteAddr,u16 NumByteToWrite)    {      u32secpos;      u16secoff;      u16secremain;            u16 i;         secpos=WriteAddr/4096;//扇区地址0~511 for w25x16      secoff=WriteAddr%4096;//在扇区内的偏移      secremain=4096-secoff;//扇区剩余空间大小         if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节      while(1)      {                           SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容                  for(i=0;i<secremain;i++)//校验数据                  {                              if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除                     }                  if(i<secremain)//需要擦除                  {                              SPI_Flash_Erase_Sector(secpos);//擦除这个扇区                              for(i=0;i<secremain;i++)    //复制                              {                                          SPI_FLASH_BUF[i+secoff]=pBuffer;                                 }                              SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区  
                 }elseSPI_Flash_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;          //下一个扇区还是写不完                              elsesecremain=NumByteToWrite;                                    //下一个扇区可以写完了                  }               };                      } //擦除整个芯片 //整片擦除时间: //W25X16:25s //W25X32:40s //W25X64:40s //等待时间超长... void SPI_Flash_Erase_Chip(void)    {                                                 SPI_FLASH_Write_Enable();                  //SET WEL    SPI_Flash_Wait_Busy();         SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令        SPI_FLASH_CS=1;                            //取消片选                       SPI_Flash_Wait_Busy();                                                    //等待芯片擦除结束 }   //擦除一个扇区 //Dst_Addr:扇区地址0~511 for w25x16 //擦除一个山区的最少时间:150ms void SPI_Flash_Erase_Sector(u32Dst_Addr)    {        Dst_Addr*=4096;    SPI_FLASH_Write_Enable();                 //SET WEL             SPI_Flash_Wait_Busy();         SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_SectorErase);      //发送扇区擦除指令    SPIx_ReadWriteByte((u8)((Dst_Addr)>>16));  //发送24bit地址       SPIx_ReadWriteByte((u8)((Dst_Addr)>>8));       SPIx_ReadWriteByte((u8)Dst_Addr);      SPI_FLASH_CS=1;                            //取消片选                     SPI_Flash_Wait_Busy();                                                     //等待擦除完成 }   //等待空闲 void SPI_Flash_Wait_Busy(void)    {        while((SPI_Flash_ReadSR()&0x01)==0x01);  // 等待BUSY位清空 }   //进入掉电模式 void SPI_Flash_PowerDown(void)    {      SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_PowerDown);        //发送掉电命令        SPI_FLASH_CS=1;                            //取消片选                     delay_us(3);                               //等待TPD   }   //唤醒 void SPI_Flash_WAKEUP(void)    {        SPI_FLASH_CS=0;                            //使能器件       SPIx_ReadWriteByte(W25X_ReleasePowerDown);   // send W25X_PowerDown command 0xAB         SPI_FLASH_CS=1;                            //取消片选                     delay_us(3);                               //等待TRES1 } 此部分代码里面一个最关键的函数就是voidSPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite),该函数可以在W25X16的任意地址开始写入任意长度(必须不超过W25X16的容量)的数据。我们这里简单介绍一下思路:先获得首地址(WriteAddr)所在的扇区,并计算在扇区内的偏移,然后判断要写入的数据长度是否超过本扇区所剩下的长度,如果不超过,再先看看是否要删除,如果不要,则直接写入数据即可,如果要则读出整个扇区,在偏移处开始写入指定长度的数据,然后擦除这个扇区,再一次性写入。当所需要写入的数据长度超过一个扇区的长度的时候,我们先按照前面的步骤把扇区剩余部分写完,再在新扇区内执行同样的操作,如此循环,直到写入结束。 其他的代码就比较简单了,我们这里不介绍了。保存falsh.c,然后加入到HARDWARE组下面,再打开flahs.h,在该文件里面输入如下代码: #ifndef __FLASH_H #define __FLASH_H                                       #include "sys.h" //Mini STM32开发板 //W25X16 驱动函数 //正点原子@ALIENTEK //2010/6/13 //V1.0 #define       SPI_FLASH_CSPAout(2)  //选中FLASH                                                            //////////////////////////////////////////////////////////////////////////// //W25X16读写 #define FLASH_ID 0XEF14 //指令表 #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 SPI_Flash_Init(void); u16 SPI_Flash_ReadID(void);             //读取FLASH ID u8  SPI_Flash_ReadSR(void);        //读取状态寄存器 void SPI_FLASH_Write_SR(u8 sr);              //写状态寄存器 void SPI_FLASH_Write_Enable(void);  //写使能 void SPI_FLASH_Write_Disable(void);        //写保护 void SPI_Flash_Read(u8* pBuffer,u32ReadAddr,u16 NumByteToRead);   //读取flash void SPI_Flash_Write(u8* pBuffer,u32WriteAddr,u16 NumByteToWrite);//写入flash void SPI_Flash_Erase_Chip(void);                  //整片擦除 void SPI_Flash_Erase_Sector(u32Dst_Addr);//扇区擦除 void SPI_Flash_Wait_Busy(void);           //等待空闲 void SPI_Flash_PowerDown(void);           //进入掉电模式 void SPI_Flash_WAKEUP(void);                               //唤醒 #endif 这里面就定义了一些与W25X16操作相关的命令,这些命令在W25X16的数据手册上都有详细的介绍,感兴趣的大家可以参考该数据手册,其他的就没啥好说的了。保存此部分代码。 最后,我们在test.c里面,修改main函数如下: //要写入到W25X16的字符串数组 const u8 TEXT_Buffer[]={"MiniSTM32SPI TEST"}; #define SIZE sizeof(TEXT_Buffer)    int main(void) {                     u8key;      u16i=0;      u8datatemp[SIZE];
     Stm32_Clock_Init(9);//系统时钟设置      delay_init(72);               //延时初始化      uart_init(72,9600);//串口1初始化         LED_Init();                               //LED初始化      KEY_Init();                               //按键初始化      LCD_Init();                   //TFTLCD液晶初始化      SPI_Flash_Init();   //SPI FLASH 初始化
     POINT_COLOR=RED;//设置字体为蓝色                    LCD_ShowString(60,50,"MiniSTM32");      LCD_ShowString(60,70,"SPITEST");           LCD_ShowString(60,90,"ATOM@ALIENTEK");      LCD_ShowString(60,110,"2010/6/11");   
     while(SPI_Flash_ReadID()!=FLASH_ID)//检测不到W25X16      {                              i=SPI_Flash_ReadID();                  printf("ID:%d",i);                  LCD_ShowString(60,130,"W25X16Check Failed!");                  delay_ms(500);                  LCD_ShowString(60,130,"   Please Check!    ");                  delay_ms(500);                  LED0=!LED0;//DS0闪烁      }      LCD_ShowString(60,130,"W25X16Ready!");      //显示提示信息      LCD_ShowString(60,150,"KEY0:WriteKEY2:Read");
     POINT_COLOR=BLUE;//设置字体为蓝色                 while(1)      {                  key=KEY_Scan();                  if(key==1)//KEY0按下,写入SPIFLASH                  {                              LCD_Fill(0,170,239,319,WHITE);//清除半屏                                 LCD_ShowString(60,170,"StartWrite W25X16....");                              SPI_Flash_Write((u8*)TEXT_Buffer,1000,SIZE);//从1000字节处开始,写入SIZE长度的数据                              LCD_ShowString(60,170,"W25X16Write Finished!");//提示传送完成                  }                  if(key==3)//KEY1按下,读取写入的字符传字符串并显示                  {                              LCD_ShowString(60,170,"StartRead W25X16.... ");                              SPI_Flash_Read(datatemp,1000,SIZE);//从1000地址处开始,读出SIZE个字节                              LCD_ShowString(60,170,"TheData Readed Is:  ");//提示传送完成                              LCD_ShowString(60,190,datatemp);//显示读到的字符串                  }                  i++;                  delay_ms(1);                  if(i==200)                  {                              LED0=!LED0;//提示系统正在运行                                       i=0;                  }                              } } 这部分代码和IIC实验那部分代码大同小异,我们就不多说了,实现的功能就和IIC差不多,不过此次写入和读出的是SPIFLASH,而不是EEPROM。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: