上篇文章介绍了W25Q16芯片的一些基本信息,这篇主要介绍编程操作。

/*封装读写操作
SPI 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
*/
uint8_t SPI_ReadWriteByte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi2, &TxData, &Rxdata, 1, 1000);
    return Rxdata; //返回收到的数据
}

/*********************************************************************      :  
BIT:   7    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
**********************************************************************/
uint8_t SPI_W25X_ReadSR(void)
{
    uint8_t byte = 0;

W25_CS_L;                               /*enable chip selection*/
    SPI_ReadWriteByte(W25X_ReadStatusReg); /*send read status register command */
    byte = SPI_ReadWriteByte(0Xff);        /*read one byte */
    W25_CS_H;                               /*disable chip selection*/

return byte;
}

void SPI_W25X_Write_SR(uint8_t sr)
{
    W25_CS_L;                                /*enable chip selection*/
    SPI_ReadWriteByte(W25X_WriteStatusReg); /*send write status register command */
    SPI_ReadWriteByte(sr);                  /*write one byte*/
    W25_CS_H;                                /*disable chip selection*/
}

void SPI_W25X_Write_Enable(void)
{
    W25_CS_L;                             /*enable chip selection*/
    SPI_ReadWriteByte(W25X_WriteEnable); /*send write enable*/
    W25_CS_H;                             /*disable chip selection*/
}

uint16_t SPI_W25X_ReadID(void)
{
    uint16_t Temp = 0;

W25_CS_L; /*enable chip selection*/
    SPI_ReadWriteByte(W25X_ManufactDeviceID);
    SPI_ReadWriteByte(0x00);
    SPI_ReadWriteByte(0x00);
    SPI_ReadWriteByte(0x00);
    Temp |= SPI_ReadWriteByte(0xFF) << 8;
    Temp |= SPI_ReadWriteByte(0xFF);
    W25_CS_H;

return Temp;
}

void SPI_W25X_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    uint16_t i;

W25_CS_L;
    SPI_ReadWriteByte(W25X_ReadData);
    SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 16));
    SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 8));
    SPI_ReadWriteByte((uint8_t)ReadAddr);

for (i = 0; i < NumByteToRead; i++)
    {
        pBuffer[i] = SPI_ReadWriteByte(0XFF);
    }
    W25_CS_H;
}

uint8_t SPI_W25X_Read_onebyte(unsigned int ReadAddr)
{

uint8_t tmp;
    W25_CS_L;
    SPI_ReadWriteByte(W25X_ReadData);
    SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 16));
    SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 8));
    SPI_ReadWriteByte((uint8_t)ReadAddr);

tmp = SPI_ReadWriteByte(0XFF);
    W25_CS_H;
    return tmp;
}

//等待空闲
void SPI_W25X_Wait_Busy(void)
{   
        uint16_t uErrTime;
        while ((SPI_W25X_ReadSR() & 0x01) == 0x01) // 等待BUSY位清空
        {
            uErrTime++;
            if(uErrTime > 500)
            {
                break;
            }
        }
}

//-----------------------------------------------------------------------------
//擦除整个芯片
//整片擦除时间:
//W25X16:25s
//W25X32:40s
//W25X64:40s
//等待时间超长...
void SPI_W25X_Erase_Chip(void)
{
    SPI_W25X_Write_Enable(); //SET WEL
    SPI_W25X_Wait_Busy();
    W25_CS_L;                           //使能片选
    SPI_ReadWriteByte(W25X_ChipErase); //发送片擦除命令
    W25_CS_H;                           //关闭片选
    SPI_W25X_Wait_Busy();               //等待芯片擦除结束
}
//-----------------------------------------------------------------------------
//擦除一个扇区
//Dst_Addr:扇区地址 0~511 for w25x16
//擦除一个山区的最少时间:150ms
void SPI_W25X_Erase_Sector(uint32_t Dst_Addr)
{
    Dst_Addr *= 4096;
    SPI_W25X_Write_Enable(); //SET WEL
    SPI_W25X_Wait_Busy();
    W25_CS_L;                                        //使能片选
    SPI_ReadWriteByte(W25X_SectorErase);            //发送扇区擦除指令
    SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 16)); //发送24bit地址
    SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 8));
    SPI_ReadWriteByte((uint8_t)Dst_Addr);
    W25_CS_H;             //关闭片选
    SPI_W25X_Wait_Busy(); //等待擦除完成
}

//-----------------------------------------------------------------------------
//在一页(0~65535)内写入少于256个字节的数据
//从指定地址开始写入最大256字节的数据
//pBuffer:数据存储区地址
//WriteAddr:写入区首地址
//NumByteToWrite:待写入的字节数(最大256,且不得超过本页的剩余字节数)
void SPI_W25X_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t i;

SPI_W25X_Write_Enable(); //使能片选
    W25_CS_L;
    SPI_ReadWriteByte(W25X_PageProgram);
    SPI_ReadWriteByte((uint8_t)((WriteAddr) >> 16));
    SPI_ReadWriteByte((uint8_t)((WriteAddr) >> 8));
    SPI_ReadWriteByte((uint8_t)WriteAddr);

for (i = 0; i < NumByteToWrite; i++)
    {
        SPI_ReadWriteByte(pBuffer[i]);
    }

W25_CS_H;             //关闭片选
    SPI_W25X_Wait_Busy(); //等待写入结束
}

//-----------------------------------------------------------------------------
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void SPI_W25X_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t pageremain;

pageremain = 256 - WriteAddr % 256;
    if (NumByteToWrite <= pageremain)
        pageremain = NumByteToWrite; //不大于256字节
    while (1)
    {
        SPI_W25X_Write_Page(pBuffer, WriteAddr, pageremain);
        if (NumByteToWrite == pageremain)
            break; //写入结束
        else
        {
            pBuffer += pageremain;
            WriteAddr += pageremain;

NumByteToWrite -= pageremain; //减去已经写入的字节
            if (NumByteToWrite > 256)
                pageremain = 256;
            else
                pageremain = NumByteToWrite; //不够256个字节
        }
    }
}

//-----------------------------------------------------------------------------
//写W25X
//在指定地址开始写入指定长度的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
uint8_t W25X_BUF[4096];
void SPI_W25X_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;

secpos = WriteAddr / 4096; //扇区地址
    secoff = WriteAddr % 4096; //在扇区内的偏移
    secremain = 4096 - secoff; //扇区剩余空间

if (NumByteToWrite <= secremain)
        secremain = NumByteToWrite; //不大于4096字节
    while (1)
    {
        SPI_W25X_Read(W25X_BUF, secpos * 4096, 4096); //读该扇区
        for (i = 0; i < secremain; i++)               //校验
        {
            if (W25X_BUF[secoff + i] != 0XFF)
                break; //需要擦除
        }

if (i < secremain) //需要擦除
        {
            SPI_W25X_Erase_Sector(secpos);  //擦除该扇区
            for (i = 0; i < secremain; i++) //复制
            {
                W25X_BUF[i + secoff] = pBuffer[i];
            }
            SPI_W25X_Write_NoCheck(W25X_BUF, secpos * 4096, 4096); //写扇区
        }
        else
            SPI_W25X_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 SPI_W25X_PowerDown(void)
{
    W25_CS_L;                           //使能片选
    SPI_ReadWriteByte(W25X_PowerDown); //发送掉电命令
    W25_CS_H;                           //关闭片选
    Delay_ms(3);                       //等待TPD
}
//-----------------------------------------------------------------------------
//唤醒
void SPI_W25X_WAKEUP(void)
{
    W25_CS_L;                                  //使能片选
    SPI_ReadWriteByte(W25X_ReleasePowerDown); //  send W25X_PowerDown command 0xAB
    W25_CS_H;                                  //关闭片选
    Delay_ms(3);                              //等待TRES1
}

以下链接为STM32Cube 配置测试完的完成工程文档,芯片为STM32F030  硬件SPI读写W25Q16,使用HAL库编写,有需要的朋友可点击链接下载!

(43条消息) 基于STM32CubeMX-STM32F030HAL库对W25Q16读写操作-C文档类资源-CSDN文库

STM32F030 HAL库硬件SPI操作W25Q16存储芯片(二)相关推荐

  1. STM32F030 HAL库硬件SPI操作W25Q16存储芯片(一)

    芯片:华邦W25Q16JV W25Q16JV (16m位)串行闪存为有限空间.引脚和电源的系统提供了存储解决方案.25Q系列提供了超越普通串行闪存设备的灵活性和性能.它们非常适合代码跟踪到RAM,直接 ...

  2. STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片

    STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片 STM32基础工程生成 首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到7 ...

  3. 单片机:STM32F4x HAL库软硬SPI驱动ST7735s 1.8寸LCD屏幕

    单片机:STM32F4x HAL库软硬SPI驱动ST7735s 1.8寸LCD屏幕 说明:此篇为学习记录.可能存在错误或者不足.如有问题请指出. 硬件环境 主控芯片:STM32F411CEU6 主控开 ...

  4. LSM6DS3TR-C姿态传感器的使用(二)---HAL库硬件IIC和官方例程

    上篇记录了,利用模拟IIC读取LSM6DS3TR数据,这篇记录利用硬件IIC和LSM6DS3TR官方例程,读取加速计.陀螺仪.温度数据,并利用加速计数据装换成角度. 官网例程写的很好,有兴趣的网友可以 ...

  5. 简单的记录一下使用HAL库的SPI外挂W25Q32

    简单的记录一下使用HAL库的SPI外挂W25Q32 抽筋了,想记录一下. cubeMX配置SPI CS脚 spi.h 里添加 #define FLASH_ID 0XEF14//指令表#define W ...

  6. HAL库硬件IIC_MPU6050_DMP移植

    HAL库硬件IIC_MPU6050_DMP移植 一.CUBEMX基本配置 ​ 本篇博客只介绍如何在HAL库进行移植代码,所以只开启了一些必要的端口:I2C1,USART1,另外介绍一下本文基于芯片ST ...

  7. STM32 HAL库 STM32CubeMX -- SPI

    文章目录 一.SPI 协议简介 SPI 物理层 SPI 协议层 二.SPI 的架构 三.通讯过程 四.STM32Cube MX配置 五.SPI HAL库函数 一.SPI 协议简介 SPI (Seria ...

  8. STM8L151 使用硬件SPI驱动W25Q16 Flash

    SPI:有四根线的串行通信协议,允许与其他设备以半.全双工.同步.串行方式通信. MISO:主模式输入.从模式输出线 MOSI:主模式输出.从模式输入线 CLK:时钟线 NSS:从设备选择引脚,主设备 ...

  9. STM32 (基于HAL库) 硬件IIC读写任意AT24CXX芯片

    HAL任意AT24Cxx芯片读写: 原理我就不讲了,直接实操: 一.配置 1.使用STM32CUBEMX进行引脚配置,IIC配置如下: 2.利用串口进行数据查看,串口配置如下: 3.时钟我们选择最高7 ...

最新文章

  1. iOS-仿膜拜贴纸滚动(物理仿真)
  2. js 阻断网页选中和右键
  3. 数据库系统概论:第七章 数据库设计
  4. SpringCloud入门之Maven系统安装及配置
  5. Python+matplotlib绘制函数曲线查找函数极值
  6. Python爬虫之Cookie和Session(转载)
  7. netbeans使用教程
  8. Ubuntu上安装visual studio code
  9. MapReduce环境准备
  10. 刘宇凡:一棵树给我的真理
  11. 无限循环小数四则运算_无限循环小数不能进行四则运算
  12. 电子技术基础(三)__电感的感抗_无功功率和电容的容抗_无功功率
  13. 输出所有3位数的水仙花数,例:153=1的3次方+5的3次方+3的3次方 谭浩强《c语言程序设计》第五章第八题
  14. 【模型】【课程笔记】01+02+03 金融风险管理导论
  15. 第一章:计算机硬件知识
  16. C++定义结构体大小根堆的方法
  17. 移动聊天工具Kakao要开网络银行 牌照有望下月到手
  18. 做程序员,就是修自己的佛,渡众生的苦--看看散文缓缓心情吧
  19. etry error, curr request is null
  20. 手机QQ安卓版下载【正式版】

热门文章

  1. 《Using OpenRefine》翻译~12
  2. ProcessingJoy —— 简单的 3D 文字【JAVA】
  3. 如何优雅的获取 Mac OS 系统 IP 地址?
  4. 宝塔 开启xdebug_Xdebug 使用说明
  5. 捕获OutputDebugString
  6. android实现自定义DigLog
  7. Bug产生原因的深入分析
  8. Android捕捉崩溃日志并输出日志文件
  9. 学习笔记 - 小常识
  10. 我用HTML写的新学期课程表