头文件

#ifndef W25QXX__H
#define W25QXX__H
#include "sys.h"#define W25Q80    0XEF13
#define W25Q16  0XEF14
#define W25Q32  0XEF15
#define W25Q64  0XEF16
#define W25Q128 0XEF17
#define W25Q256 0XEF18#define W25QXX_CS PAout(4)//指令表
#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          0x09
#define W25X_Enable_Rest                0x66
#define W25X_Rest_Device                0x99
#define W25X_Enter_4_Addres         0xb7
#define W25X_Read_4_Addres      0x13
#define W25X_Write_4_Addres     0x02
#define W25X_Exit_4_Addres      0xe9
void W25QXX_Init(void);
u16  W25QXX_ReadID(void);               //读取FLASH ID
u8   W25QXX_Read_SR(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,u32 NumByteToWrite);
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u32 NumByteToRead);   //读取flash
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u32 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);               //唤醒
void W25XX_Reset_With_Soft(void);//软件复位W25qXX
#endif

访问W25Q256的所有地址(32MB)需要使用4字节地址,使用3字节地址只能访问16MB的空间,根据需要开启

.c文件

#include "spi.h"
#include "w25qxx.h"
u16 W25QXX_TYPE=W25Q256;   //默认是W25Q32#define ENABLE_W25Q258 1//要使用W25Q256的32MB空间时,设置1,否则为0//软件复位W25qXX
void W25XX_Reset_With_Soft(void){W25QXX_CS=0;                             //使能器件SPI1_ReadWriteByte(W25X_Enable_Rest);   //发送允许复位命令W25QXX_CS=1;                            //取消片选   W25QXX_CS=0;                             //使能器件SPI1_ReadWriteByte(W25X_Rest_Device);   //发送允许复位命令W25QXX_CS=1;                             //取消片选
}#if  ENABLE_W25Q258                   //进入4字节地址模式
void W25QXX_Enter_4Byte(){W25QXX_CS=0;SPI1_ReadWriteByte(W25X_Enter_4_Addres);  W25QXX_CS=1;
}//退出4字节地址模式
void W25QXX_Exit_4Byte(){W25QXX_CS=0;SPI1_ReadWriteByte(W25X_Exit_4_Addres);  W25QXX_CS=1;
}#endifvoid W25QXX_Init(void)
{//管脚初始化GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);W25QXX_CS=1;SPI1_Init();SPI1_SetSpeed(SPI_BaudRatePrescaler_2);
//进入4字节模式#if    ENABLE_W25Q258W25QXX_Enter_4Byte();#endifW25QXX_TYPE=W25QXX_ReadID();
}/********************************************************************************//读取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
//0XEF18,表示芯片型号为W25Q256
*******************************************************************************/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)(W25Q256为(32bit))
//NumByteToRead:要读取的字节数(最大65535)*******************************************************************************/void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u32 NumByteToRead)
{ u32 i;                                            W25QXX_CS=0;                            //使能器件   //    SPI1_ReadWriteByte(W25X_ReadData);  #if ENABLE_W25Q258SPI1_ReadWriteByte(W25X_ReadData);         //发送4字节地址读取命令   SPI1_ReadWriteByte((u8)((ReadAddr)>>24)); //发送32bit地址#elseSPI1_ReadWriteByte(W25X_ReadData);             //发送普通读指令#endifSPI1_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)(W25Q256为(32bit))
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!  *******************************************************************************/void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u32 NumByteToWrite)
{u32 i;  W25QXX_Write_Enable();                  //SET WEL W25QXX_CS=0;                            //使能器件   SPI1_ReadWriteByte(W25X_PageProgram);      //发送写页命令  #if ENABLE_W25Q258        //发送读取命令   SPI1_ReadWriteByte((u8)((WriteAddr)>>24)); //发送32bit地址#endifSPI1_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)(W25Q256为(32bit))
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK*******************************************************************************/void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u32 NumByteToWrite)
{                    u32 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)(W25Q256为(32bit))
//NumByteToWrite:要写入的字节数(最大65535) *******************************************************************************/u8 W25QXX_BUFFER[4096];       void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u32 NumByteToWrite)
{ u32 secpos;u32 secoff;u32 secremain;     u32 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++;//扇区地址增1secoff=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);      //发送扇区擦除指令 #if ENABLE_W25Q258        //发送读取命令   SPI1_ReadWriteByte((u8)((Dst_Addr)>>24)); #endifSPI1_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)
{ u16 Time_i=0xffff;W25QXX_CS=0;                            //使能器件   SPI1_ReadWriteByte(W25X_PowerDown);        //发送掉电命令  W25QXX_CS=1;                            //取消片选               while(Time_i--);                               //等待TPD
}  /********************************************************************************//唤醒*******************************************************************************/void W25QXX_WAKEUP(void)
{  u16 Time_i=0xffff;W25QXX_CS=0;                            //使能器件   SPI1_ReadWriteByte(W25X_ReleasePowerDown);   //  send W25X_PowerDown command 0xAB    W25QXX_CS=1;                            //取消片选              while(Time_i--);                               //等待TRES1
}   

对于4字节读取时,根据芯片手册,使用Read_Data(03h)也可以访问4字节地址,测试后也确实可以

当然 也可以使用专门的4地址读指令Read_Date_with_4_Byte_Address(13h)

这里我使用的是Read_Date_with_4_Byte_Address(13h)

void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u32 NumByteToRead)
{ u32 i;                                            W25QXX_CS=0;                            //使能器件   //    SPI1_ReadWriteByte(W25X_ReadData);  #if ENABLE_W25Q258SPI1_ReadWriteByte(W25X_ReadData);         //发送4字节地址读取命令   SPI1_ReadWriteByte((u8)((ReadAddr)>>24)); //发送32bit地址#elseSPI1_ReadWriteByte(W25X_ReadData);             //发送普通读指令#endifSPI1_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;
} 

stm32 W25QXX系列驱动 W25Q80 W25Q16 W25Q32 W25Q64 W25Q128 W25Q256相关推荐

  1. 华邦存储器W25Q80, W25Q16, W25Q32系列的spi通讯

    华邦存储器W25Q80, W25Q16, W25Q32系列与stm32f1系列单片机的spi通讯 2020.4.9 spi通讯在配置好之后一定要开启spi使能,和串口的配置是一样的 2020.4.13 ...

  2. 关于W25QXX系列以及AT24CXX系列容量大小

    一.W25QXX系列容量大小 在使用SPI对W25Q64进行存取数据进行驱动编写时,不知道W25Q64的容量是多少,偶尔会Byte和bit给混淆了 1Byte=8bit (1个字节为8位!!) 以下为 ...

  3. STM32 基础系列教程 45 - FSMC_LCD_Touch

    前言 上一节我们完成了用 STM32F4的 FSMC接口来控制 TFTLCD的显示的操作,其实正点原子的探索者F4开发板带的屏幕支持触摸操作,笔者用的是4.3寸的电容触摸屏,本节我们继续实验,来完成基 ...

  4. STM32 基础系列教程 44 - FSMC_LCD

    前言 TFT-LCD 即薄膜晶体管液晶显示器.其英文全称为: Thin Film Transistor-Liquid Crystal Display. TFT-LCD 与无源 TN-LCD. STN- ...

  5. STM32 基础系列教程 19 – WWDG

    前言 学习stm32 窗口看门狗(WWDG)接口使用,学会用STM32内部窗口看门狗(WWDG)接口实现程序异常时自复位功能.WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序.窗口看门狗由从 ...

  6. STM32 基础系列教程 18 – IWDG

    前言 学习stm32 独立看门狗(IWDG)接口使用,学会用STM32内部独立看门狗(IWDG)实现程序异常时自复位功能. STM32F10xxx内置两个看门狗,提供了更高的安全性.时间的精确性和使用 ...

  7. STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例)

    STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例) 目录 STM32CubeMX | STM32 F1系列HAL库低功耗 ...

  8. 12. STM32——硬件IIC驱动OLED屏幕显示

    STM32--硬件IIC驱动OLED屏幕显示 OLED屏幕 OLED屏幕特点 OLED屏幕接线说明 OLED屏幕显存 OLED屏幕原理 OLED屏幕常用指令 OLED屏幕字模软件的使用 写命令 写数据 ...

  9. 【STM32学习】(29)STM32实现595驱动三个数码管(标准库和HAL库实现)

    我选用的单片机型号为:STM32F103系列 74LS595是一个串转并行输出的芯片,它能为单片机节省很多的IO口,应用场景广泛. 现要求三个数码管动态显示,常规设计都是并行实现,需要8个IO数据口, ...

  10. 嵌入式开发-STM32硬件SPI驱动TFT屏

    嵌入式开发-STM32硬件SPI驱动TFT屏 这次用到的TFT屏 CubeMX设置 代码编写 增加的内容 需要注意问题 代码下载 这次用到的TFT屏 现在的TFT屏幕已经很便宜了,65536色屏幕,2 ...

最新文章

  1. 如何定制一款12306抢票浏览器——启动“人”线程
  2. 科大星云诗社动态20211130
  3. Python——分布式监控项目
  4. window中搭建jenkins_为容器化的 Go 程序搭建 CI
  5. 【leetcode】Permutations
  6. [everydayNote] 今天脑子不好使
  7. 《HFSS 电磁仿真设计 从入门到精通》笔记 HFSS入门实例
  8. python做客户端监控程序(python 监控程序)
  9. 还不错,字母成熟了些!
  10. python 控制键盘鼠标库pynput详解
  11. 输出电阻与反馈网络的关系以及计算
  12. 关于学校计算机的情景剧剧本,校园剧本校园情景剧
  13. Q:python编码
  14. 一节前端课:html+css+js做个计算器
  15. 一切未晚——七公主后花园的成立
  16. 微信php第三方登录接口,ThinkPHP实现微信三方登录
  17. ffmpeg 如何配置编译
  18. scanpy和umap版本不匹配问题总结
  19. 机械优化黄金分割法c语言编程,黄金分割法_机械优化设计_C语言程序.doc
  20. mxGraph进阶(一)mxGraph教程-开发入门指南

热门文章

  1. 微信支付v2升级v3注意事项
  2. Highcharts 将默认文字更改为中文
  3. DOS命令窗口基本操作
  4. 编译华硕路由器ACRH17源代码小记
  5. 说说自己,向前看远些,路还要走下去的
  6. 微信公众平台二次开发技术文档
  7. 新疆计算机二级vb 试题,2020年9月新疆维吾尔自治区计算机二级易考套餐:二级VB考试题库+教材...
  8. Django 3.0实战: 仿链家二手房信息查询网(附GitHub源码)
  9. 如何在水经注会员中心购买流量下载地图
  10. 2021-05-24