欢迎来到泰骏兴电子,大家有问题可以直接联系管理员QQ:233619809单片机 QQ群:59194556 各位游客也可以注册玩玩,享受更多权益。温馨提示:本网站仅提供平台学习以及渠道,一切后果自行承担,还望广大用户提高自我意识,请不要轻易相信他人,请不要轻易相信他人,请不要轻易相信他人。为了更好的管理论坛工作,所以现在使用邮箱注册,如果以前的邮箱不能修改的,请联系管理员代为修改

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 47|回复: 0

STM32F1驱动W25Qxx程序代码

[复制链接]
发表于 2023-8-22 14:51:19 | 显示全部楼层 |阅读模式
本程序是使用STM32F1驱动W25Qxx系列FLASH存储的驱动代码:


注意配置一下此函数






.H文件
  1. #ifndef __FLASH_H
  2. #define __FLASH_H                            
  3. #include "sys.h"
  4.           
  5. //W25X系列/Q系列芯片列表          
  6. //W25Q80  ID  0XEF13
  7. //W25Q16  ID  0XEF14
  8. //W25Q32  ID  0XEF15
  9. //W25Q64  ID  0XEF16       
  10. //W25Q128 ID  0XEF17       
  11. #define W25Q80         0XEF13        
  12. #define W25Q16         0XEF14
  13. #define W25Q32         0XEF15
  14. #define W25Q64         0XEF16
  15. #define W25Q128        0XEF17

  16. extern u16 W25QXX_TYPE;                                        //定义W25QXX芯片型号                  

  17. #define        W25QXX_CS                 PCout(5)                  //W25QXX的片选信号        ADC1
  18. //配置SPI信息
  19. #define W25Qxx_ReadWriteByte                SPI1_ReadWriteByte
  20. #define W25Qxx_SPI_init                                SPI1_Init                               
  21. #define W25Qxx_SPI_SetSpeed                        SPI1_SetSpeed
  22.                                  
  23. ////////////////////////////////////////////////////////////////////////////

  24. //指令表
  25. #define W25X_WriteEnable                0x06
  26. #define W25X_WriteDisable                0x04
  27. #define W25X_ReadStatusReg                0x05
  28. #define W25X_WriteStatusReg                0x01
  29. #define W25X_ReadData                        0x03
  30. #define W25X_FastReadData                0x0B
  31. #define W25X_FastReadDual                0x3B
  32. #define W25X_PageProgram                0x02
  33. #define W25X_BlockErase                        0xD8
  34. #define W25X_SectorErase                0x20
  35. #define W25X_ChipErase                        0xC7
  36. #define W25X_PowerDown                        0xB9
  37. #define W25X_ReleasePowerDown        0xAB
  38. #define W25X_DeviceID                        0xAB
  39. #define W25X_ManufactDeviceID        0x90
  40. #define W25X_JedecDeviceID                0x9F

  41. u16  W25QXX_Init(void);
  42. u16  W25QXX_ReadID(void);                              //读取FLASH ID
  43. u8         W25QXX_ReadSR(void);                        //读取状态寄存器
  44. void W25QXX_Write_SR(u8 sr);                          //写状态寄存器
  45. void W25QXX_Write_Enable(void);                  //写使能
  46. void W25QXX_Write_Disable(void);                //写保护
  47. void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
  48. void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //读取flash
  49. void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash
  50. void W25QXX_Erase_Chip(void);                      //整片擦除
  51. void W25QXX_Erase_Sector(u32 Dst_Addr);        //扇区擦除
  52. void W25QXX_Wait_Busy(void);                   //等待空闲
  53. void W25QXX_PowerDown(void);                //进入掉电模式
  54. void W25QXX_WAKEUP(void);                                //唤醒
  55. #endif
















复制代码
.C文件

  1. #include "w25qxx.h"
  2. #include "spi.h"
  3. #include "delay.h"   
  4. u16 W25QXX_TYPE;//默认就是25Q64
  5. //4Kbytes为一个Sector
  6. //16个扇区为1个Block
  7. //W25X16
  8. //容量为2M字节,共有32个Block,512个Sector

  9. //初始化SPI FLASH的IO口
  10. u16 W25QXX_Init(void)
  11. {

  12.                         GPIO_InitTypeDef GPIO_InitStructure;

  13.                         RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOC, ENABLE );

  14.                         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  //SPI CS
  15.                         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //复用推挽输出
  16.                         GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  17.                         GPIO_Init(GPIOC, &GPIO_InitStructure);
  18.                         GPIO_SetBits(GPIOC,GPIO_Pin_5);
  19.                         W25Qxx_SPI_init();                   //初始化SPI
  20.                         W25Qxx_SPI_SetSpeed(SPI_BaudRatePrescaler_4);        //设置为18M时钟,高速模式
  21.                         W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.
  22.                         return W25QXX_TYPE;
  23. }  

  24. //读取SPI_FLASH的状态寄存器
  25. //BIT7  6   5   4   3   2   1   0
  26. //SPR   RV  TB BP2 BP1 BP0 WEL BUSY
  27. //SPR:默认0,状态寄存器保护位,配合WP使用
  28. //TB,BP2,BP1,BP0:FLASH区域写保护设置
  29. //WEL:写使能锁定
  30. //BUSY:忙标记位(1,忙;0,空闲)
  31. //默认:0x00
  32. u8 W25QXX_ReadSR(void)   
  33. {  
  34.                         u8 byte=0;   
  35.                         W25QXX_CS=0;                            //使能器件   
  36.                         W25Qxx_ReadWriteByte(W25X_ReadStatusReg);    //发送读取状态寄存器命令   
  37.                         byte=W25Qxx_ReadWriteByte(0Xff);             //读取一个字节  
  38.                         W25QXX_CS=1;                            //取消片选     
  39.                         return byte;   
  40. }
  41. //写SPI_FLASH状态寄存器
  42. //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
  43. void W25QXX_Write_SR(u8 sr)   
  44. {   
  45.                         W25QXX_CS=0;                            //使能器件   
  46.                         W25Qxx_ReadWriteByte(W25X_WriteStatusReg);   //发送写取状态寄存器命令   
  47.                         W25Qxx_ReadWriteByte(sr);               //写入一个字节  
  48.                         W25QXX_CS=1;                            //取消片选                  
  49. }   
  50. //SPI_FLASH写使能       
  51. //将WEL置位   
  52. void W25QXX_Write_Enable(void)   
  53. {
  54.                         W25QXX_CS=0;                            //使能器件   
  55.                         W25Qxx_ReadWriteByte(W25X_WriteEnable);      //发送写使能  
  56.                         W25QXX_CS=1;                            //取消片选                  
  57. }
  58. //SPI_FLASH写禁止       
  59. //将WEL清零  
  60. void W25QXX_Write_Disable(void)   
  61. {  
  62.                         W25QXX_CS=0;                            //使能器件   
  63.                         W25Qxx_ReadWriteByte(W25X_WriteDisable);     //发送写禁止指令   
  64.                         W25QXX_CS=1;                            //取消片选                  
  65. }                             
  66. //读取芯片ID W25X16的ID:0XEF14
  67. u16 W25QXX_ReadID(void)
  68. {
  69.                         u16 Temp = 0;          
  70.                         W25QXX_CS=0;                                    
  71.                         W25Qxx_ReadWriteByte(0x90);//发送读取ID命令            
  72.                         W25Qxx_ReadWriteByte(0x00);             
  73.                         W25Qxx_ReadWriteByte(0x00);             
  74.                         W25Qxx_ReadWriteByte(0x00);                                    
  75.                         Temp|=W25Qxx_ReadWriteByte(0xFF)<<8;  
  76.                         Temp|=W25Qxx_ReadWriteByte(0xFF);         
  77.                         W25QXX_CS=1;                                    
  78.                         return Temp;
  79. }                       
  80. //读取SPI FLASH  
  81. //在指定地址开始读取指定长度的数据
  82. //pBuffer:数据存储区
  83. //ReadAddr:开始读取的地址(24bit)
  84. //NumByteToRead:要读取的字节数(最大65535)
  85. void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
  86. {
  87.                         u16 i;                                                                                                        
  88.                         W25QXX_CS=0;                            //使能器件   
  89.                         W25Qxx_ReadWriteByte(W25X_ReadData);         //发送读取命令   
  90.                         W25Qxx_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址   
  91.                         W25Qxx_ReadWriteByte((u8)((ReadAddr)>>8));   
  92.                         W25Qxx_ReadWriteByte((u8)ReadAddr);   
  93.                         for(i=0;i<NumByteToRead;i++)
  94.         {
  95.                         pBuffer[i]=W25Qxx_ReadWriteByte(0XFF);   //循环读数  
  96.         }
  97.                         W25QXX_CS=1;                            //取消片选                  
  98. }  
  99. //SPI在一页(0~65535)内写入少于256个字节的数据
  100. //在指定地址开始写入最大256字节的数据
  101. //pBuffer:数据存储区
  102. //WriteAddr:开始写入的地址(24bit)
  103. //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!         
  104. void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
  105. {
  106.                         u16 i;  
  107.                         W25QXX_Write_Enable();                  //SET WEL
  108.                         W25QXX_CS=0;                            //使能器件   
  109.                         W25Qxx_ReadWriteByte(W25X_PageProgram);      //发送写页命令   
  110.                         W25Qxx_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址   
  111.                         W25Qxx_ReadWriteByte((u8)((WriteAddr)>>8));   
  112.                         W25Qxx_ReadWriteByte((u8)WriteAddr);   
  113.                         for(i=0;i<NumByteToWrite;i++)W25Qxx_ReadWriteByte(pBuffer[i]);//循环写数  
  114.                         W25QXX_CS=1;                            //取消片选
  115.                         W25QXX_Wait_Busy();                                           //等待写入结束
  116. }
  117. //无检验写SPI FLASH
  118. //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
  119. //具有自动换页功能
  120. //在指定地址开始写入指定长度的数据,但是要确保地址不越界!
  121. //pBuffer:数据存储区
  122. //WriteAddr:开始写入的地址(24bit)
  123. //NumByteToWrite:要写入的字节数(最大65535)
  124. //CHECK OK
  125. void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
  126. {                                           
  127.                         u16 pageremain;          
  128.                         pageremain=256-WriteAddr%256; //单页剩余的字节数                             
  129.                         if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
  130.                         while(1)
  131.         {          
  132.                         W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
  133.                         if(NumByteToWrite==pageremain)break;//写入结束了
  134.                         else //NumByteToWrite>pageremain
  135.                 {
  136.                         pBuffer+=pageremain;
  137.                         WriteAddr+=pageremain;       

  138.                         NumByteToWrite-=pageremain;                          //减去已经写入了的字节数
  139.                         if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
  140.                         else pageremain=NumByteToWrite;           //不够256个字节了
  141.                 }
  142.         }            
  143. }
  144. //写SPI FLASH  
  145. //在指定地址开始写入指定长度的数据
  146. //该函数带擦除操作!
  147. //pBuffer:数据存储区
  148. //WriteAddr:开始写入的地址(24bit)
  149. //NumByteToWrite:要写入的字节数(最大65535)                    
  150. u8 SPI_FLASH_BUF[4096];
  151. void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
  152. {
  153.                         u32 secpos;
  154.                         u16 secoff;
  155.                         u16 secremain;          
  156.                         u16 i;   

  157.                         secpos=WriteAddr/4096;//扇区地址 0~511 for w25x16
  158.                         secoff=WriteAddr%4096;//在扇区内的偏移
  159.                         secremain=4096-secoff;//扇区剩余空间大小   

  160.                         if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
  161.                         while(1)
  162.         {       
  163.                         W25QXX_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
  164.                         for(i=0;i<secremain;i++)//校验数据
  165.                 {
  166.                         if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除            
  167.                 }
  168.                         if(i<secremain)//需要擦除
  169.                 {
  170.                         W25QXX_Erase_Sector(secpos);//擦除这个扇区
  171.                         for(i=0;i<secremain;i++)           //复制
  172.                         {
  173.                         SPI_FLASH_BUF[i+secoff]=pBuffer[i];          
  174.                         }
  175.                         W25QXX_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区  

  176.                 }
  177.                         else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                   
  178.                        
  179.                         if(NumByteToWrite==secremain)break;//写入结束了
  180.                         else//写入未结束
  181.                 {
  182.                         secpos++;//扇区地址增1
  183.                         secoff=0;//偏移位置为0          

  184.                         pBuffer+=secremain;  //指针偏移
  185.                         WriteAddr+=secremain;//写地址偏移          
  186.                         NumByteToWrite-=secremain;                                //字节数递减
  187.                         if(NumByteToWrite>4096)secremain=4096;        //下一个扇区还是写不完
  188.                         else secremain=NumByteToWrite;                        //下一个扇区可以写完了
  189.                 }         
  190.         }                  
  191. }
  192. //擦除整个芯片
  193. //整片擦除时间:
  194. //W25X16:25s
  195. //W25X32:40s
  196. //W25X64:40s
  197. //等待时间超长...
  198. void W25QXX_Erase_Chip(void)   
  199. {                                             
  200.                         W25QXX_Write_Enable();                  //SET WEL
  201.                         W25QXX_Wait_Busy();   
  202.                         W25QXX_CS=0;                            //使能器件   
  203.                         W25Qxx_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  
  204.                         W25QXX_CS=1;                            //取消片选                  
  205.                         W25QXX_Wait_Busy();                                      //等待芯片擦除结束
  206. }   
  207. //擦除一个扇区
  208. //Dst_Addr:扇区地址 0~511 for w25x16
  209. //擦除一个山区的最少时间:150ms
  210. void W25QXX_Erase_Sector(u32 Dst_Addr)   
  211. {   
  212.                         Dst_Addr*=4096;
  213.                         W25QXX_Write_Enable();                  //SET WEL          
  214.                         W25QXX_Wait_Busy();   
  215.                         W25QXX_CS=0;                            //使能器件   
  216.                         W25Qxx_ReadWriteByte(W25X_SectorErase);      //发送扇区擦除指令
  217.                         W25Qxx_ReadWriteByte((u8)((Dst_Addr)>>16));  //发送24bit地址   
  218.                         W25Qxx_ReadWriteByte((u8)((Dst_Addr)>>8));   
  219.                         W25Qxx_ReadWriteByte((u8)Dst_Addr);  
  220.                         W25QXX_CS=1;                            //取消片选                  
  221.                         W25QXX_Wait_Busy();                                      //等待擦除完成
  222. }  
  223. //等待空闲
  224. void W25QXX_Wait_Busy(void)   
  225. {   
  226.                         while ((W25QXX_ReadSR()&0x01)==0x01);   // 等待BUSY位清空
  227. }  
  228. //进入掉电模式
  229. void W25QXX_PowerDown(void)   
  230. {
  231.                         W25QXX_CS=0;                            //使能器件   
  232.                         W25Qxx_ReadWriteByte(W25X_PowerDown);        //发送掉电命令  
  233.                         W25QXX_CS=1;                            //取消片选                  
  234.                         delay_us(3);                               //等待TPD  
  235. }   
  236. //唤醒
  237. void W25QXX_WAKEUP(void)   
  238. {  
  239.                         W25QXX_CS=0;                            //使能器件   
  240.                         W25Qxx_ReadWriteByte(W25X_ReleasePowerDown);   //  send W25X_PowerDown command 0xAB   
  241.                         W25QXX_CS=1;                            //取消片选                  
  242.                         delay_us(3);                               //等待TRES1
  243. }   


























复制代码







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
高级模式
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|泰骏兴电子科技有限公司 ( 粤ICP备2023060260号-1 ) 单片机爱好者

GMT+8, 2025-10-31 17:19

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表