ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[学习笔记]STM32F1软件SPI读写W25Qx(寄存器、标准库、HAL库)

2021-07-11 21:33:25  阅读:531  来源: 互联网

标签:MISO HAL PIN MOSI SPI GPIO SOFT STM32F1 define


目录

9. 软件SPI读写W25Qx

0. 博主调侃:

1. 实验内容及步骤:

2. 硬件说明

3. 步骤详细讲解

       3.1 配置GPIO

       3.2 软件SPI读写Byte(模式0或模式3)

       3.3 读取W25Q16的制造商ID和设备ID

       3.4 通过标准SPI对W25Q16擦除-写入-读取     

4. 程序设计(寄存器)

5. 程序设计(标准库)

6. 程序设计(HAL库)

7. 实验结果

8. 源码下载


9. 软件SPI读写W25Qx

0. 博主调侃:

       本实验使用软件模拟标准的SPI读写W25Q16JV,这个W25Qx通常用来存储程序,可在W25Qx内部直接运行程序,无需移动到单片机的内部RAM中,当然用来存储数据也行的。

       这里W25Qx的芯片类型有点多,大体操作都相同,每种类型都有一丢丢区别,建议用哪一块就去找对应的芯片(本人就被坑了一次,啊哈哈哈哈~)。

1. 实验内容及步骤:

       1. 配置GPIO,MOSI(推挽输出)、MISO(浮空输入)、CS(输出)、SCK(输出);

       2. 软件SPI读写Byte(模式0或模式3);

       3. 读取W25Q16的制造商ID和设备ID;

       4. 通过标准SPI对W25Q16擦除-写入-读取;

2. 硬件说明

       CS   ->   PB12

       CLK ->   PB13

       MISO     ->   PB14

       MOSI     ->   PB15

3. 步骤详细讲解

       3.1 配置GPIO

       MOSI(推挽输出)、MISO(浮空输入)、CS(输出)、SCK(输出),详细的代码见源码哈。

       3.2 软件SPI读写Byte(模式0或模式3)

       见基于STM32F1的软件SPI讲解。

       左图为软件SPI模式0的读写Byte,右图为软件SPI模式3的读写Byte

       3.3 读取W25Q16的制造商ID和设备ID

       详细见W25Q16芯片讲解,源码如下所示。

       3.4 通过标准SPI对W25Q16擦除-写入-读取     

       写使能:(在擦除和写入的时候都要进行写使能)

       写使能指令宏定义如下图所示

       写使能操作如下图所示

       擦除:(擦除操作后会清除写使能,并且busy位置1)

       擦除指令宏定义如下图所示

 

       擦除操作如下图所示

       等待忙(BUSY位):

       程序如下所示,读取状态寄存器1的值,并且等待BUSY为清零。

       写入数据:

       注意:W25Qx的写操作只能一次性连续写256个位置,超过256个位置后,就会从1开始重新覆盖,这种写256 Byte操作成为页操作。

       这种页操作不是随便的写256Byte,如从0-255称为一个页,就是你从100开始写也只能写到255,下一个就从0开始;256-511称为下一个页,一次类推。

       写操作程序如下图所示。由于有点长,这里就只截取一点。

       这个程序会判断是否到结尾,并且跳转到另一页。

       普通读操作:

       快速读操作:

4. 程序设计(寄存器)

       在W25Q16芯片的第0x20000位置开始存储,存储15000个数据,并且读取出来进行对比。

/*
    通过标准SPI对W25Q16擦除-写入-读取
输入:
    addr        读取的地址
    len         读数据长度
    writebuf    发送缓冲器
    readbuf     接收缓冲器
*/
void W25Q_test_V2(u32 addr,u32 len,u8* writebuf,u8* readbuf)
{
    u32 i=0;
    u8 j=0;
    u16 ID=0;
    //ID输出
    ID = W25Qx_Read_ID(); 
    printf("制造商ID:0X%0X  设备ID:0X%0X\r\n",(ID>>8)&0xFF,ID&0xFF); 
    printf("寄存器1:0X%0X  寄存器2:0X%0X\r\n",W25Qx_Read_Reg1(),W25Qx_Read_Reg2()); 
    printf("存储起始地址:0X%0X\r\n",addr);    
    for(i=0,j=1;i<len-1;i++,j++)
    {
        if(j==0)j=1;
        writebuf[i]=j;
    }
    writebuf[i]='\0';   
    W25QX_CHIP_ERASE();       //擦除整个芯片(函数内部有等待busy了)
    W25Qx_write_DATA(addr,len,writebuf);    //写入(函数内部有等待busy了)
    W25Qx_Read_DATA(addr,len,readbuf);  //读取数据
    //数据比较
    if(strcmp((char*)writebuf,(char*)readbuf)==0)
        printf("普通读取:存储正确\r\n");
    else
        printf("普通读取:存储出错\r\n");

    W25Qx_Fast_Read_DATA(addr,len,readbuf);	//快速读取
    //数据比较
    if(strcmp((char*)writebuf,(char*)readbuf)==0)
        printf("快速读取:存储正确\r\n");
    else
        printf("快速读取:存储出错\r\n");    
}


//主函数
int main(void)
{
  SET_NVIC_GROUP(NVIC_PriorityGroup_4); //中断组4
  Systick_Config(); 
  USART1_Config(115200);      //串口1配置115200
  W25Qx_GPIO_Config();  //W25Qx初始化
    W25Q_test_V2(0x020000,15000,W25Q_write,W25Q_read);
  while (1)
  {
  }
}

5. 程序设计(标准库)

       软件SPI的标准库,除了GPIO配置、时钟配置与寄存器不同,其它部分都与寄存器一致。

       源码:(GPIO配置部分)


//CS
#define SOFT_CS_PIN_NUM      12
#define SOFT_CS_PIN          GPIO_Pin_12
#define SOFT_CS_Mode         GPIO_Mode_Out_PP   
#define SOFT_CS_RCC_CLK      RCC_APB2Periph_GPIOB
#define SOFT_CS_GPIOX        GPIOB
#define SOFT_CS_OUT          BPB_OUT(SOFT_CS_PIN_NUM)
#define SOFT_CS_IN           BPB_IN(SOFT_CS_PIN_NUM)

//SCK
#define SOFT_SCK_PIN_NUM     13
#define SOFT_SCK_PIN         GPIO_Pin_13
#define SOFT_SCK_Mode        GPIO_Mode_Out_PP 
#define SOFT_SCK_RCC_CLK     RCC_APB2Periph_GPIOB
#define SOFT_SCK_GPIOX       GPIOB
#define SOFT_SCK_OUT         BPB_OUT(SOFT_SCK_PIN_NUM)
#define SOFT_SCK_IN          BPB_IN(SOFT_SCK_PIN_NUM)

//MISO
#define SOFT_MISO_PIN_NUM      14
#define SOFT_MISO_PIN          GPIO_Pin_14
#define SOFT_MISO_Mode         GPIO_Mode_IN_FLOATING 
#define SOFT_MISO_RCC_CLK      RCC_APB2Periph_GPIOB
#define SOFT_MISO_GPIOX        GPIOB
#define SOFT_MISO_OUT          BPB_OUT(SOFT_MISO_PIN_NUM)
#define SOFT_MISO_IN           BPB_IN(SOFT_MISO_PIN_NUM)
#define SOFT_MISO_MODE_OUT()        GPIOX_PIN_Mode_Turn(SOFT_MISO_GPIOX,SOFT_MISO_PIN_NUM,GPIOX_MODE_OUT);   //配置MISO为输出模式
#define SOFT_MISO_MODE_IN()         GPIOX_PIN_Mode_Turn(SOFT_MISO_GPIOX,SOFT_MISO_PIN_NUM,GPIOX_MODE_IN);   //配置MISO为输入模式

//MOSI
#define SOFT_MOSI_PIN_NUM      15
#define SOFT_MOSI_PIN          GPIO_Pin_15
#define SOFT_MOSI_Mode         GPIO_Mode_Out_PP
#define SOFT_MOSI_RCC_CLK      RCC_APB2Periph_GPIOB
#define SOFT_MOSI_GPIOX        GPIOB
#define SOFT_MOSI_OUT          BPB_OUT(SOFT_MOSI_PIN_NUM)
#define SOFT_MOSI_IN           BPB_IN(SOFT_MOSI_PIN_NUM)
#define SOFT_MOSI_MODE_OUT()        GPIOX_PIN_Mode_Turn(SOFT_MOSI_GPIOX,SOFT_MOSI_PIN_NUM,GPIOX_MODE_OUT);   //配置MOSI为输出模式
#define SOFT_MOSI_MODE_IN()         GPIOX_PIN_Mode_Turn(SOFT_MOSI_GPIOX,SOFT_MOSI_PIN_NUM,GPIOX_MODE_IN);   //配置MOSI为输入模式


//软件SPI GPIO配置
void soft_spi_gpio_config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    //时钟
    RCC_APB2PeriphClockCmd(SOFT_CS_RCC_CLK,ENABLE);     //CS时钟
    RCC_APB2PeriphClockCmd(SOFT_SCK_RCC_CLK,ENABLE);    //SCK时钟   
    RCC_APB2PeriphClockCmd(SOFT_MISO_RCC_CLK,ENABLE);   //MISO时钟
    RCC_APB2PeriphClockCmd(SOFT_MOSI_RCC_CLK,ENABLE);   //MOSI时钟
    
    //CS(推挽输出、速度10MHz)
    GPIO_InitStruct.GPIO_Mode   =   SOFT_CS_Mode;
    GPIO_InitStruct.GPIO_Pin    =   SOFT_CS_PIN;
    GPIO_InitStruct.GPIO_Speed  =   GPIO_Speed_10MHz;
    GPIO_Init(SOFT_CS_GPIOX,&GPIO_InitStruct);        
    //SCK(推挽输出、速度10MHz)
    GPIO_InitStruct.GPIO_Mode   =   SOFT_SCK_Mode;
    GPIO_InitStruct.GPIO_Pin    =   SOFT_SCK_PIN;
    GPIO_InitStruct.GPIO_Speed  =   GPIO_Speed_10MHz;
    GPIO_Init(SOFT_SCK_GPIOX,&GPIO_InitStruct);     
    //MISO(输入 浮空模式)
    GPIO_InitStruct.GPIO_Mode   =   SOFT_MISO_Mode;
    GPIO_InitStruct.GPIO_Pin    =   SOFT_MISO_PIN;
    GPIO_Init(SOFT_MISO_GPIOX,&GPIO_InitStruct);     
    //MOSI(推挽输出、速度10MHz)
    GPIO_InitStruct.GPIO_Mode   =   SOFT_MOSI_Mode;
    GPIO_InitStruct.GPIO_Pin    =   SOFT_MOSI_PIN;
    GPIO_InitStruct.GPIO_Speed  =   GPIO_Speed_10MHz;
    GPIO_Init(SOFT_MOSI_GPIOX,&GPIO_InitStruct);     
}

6. 程序设计(HAL库)

       软件SPI的HAL库,除了GPIO配置、时钟配置与寄存器不同,其它部分都与寄存器一致。

       源码:(GPIO配置部分)

/*============================================= SPI宏定义 ================================================*/
//CS
#define SOFT_CS_CLK_ENABLE   __HAL_RCC_GPIOB_CLK_ENABLE
#define SOFT_CS_PIN_NUM      12
#define SOFT_CS_PIN          GPIO_PIN_12
#define SOFT_CS_Mode         GPIO_MODE_OUTPUT_PP   
#define SOFT_CS_RCC_CLK      RCC_APB2Periph_GPIOB
#define SOFT_CS_GPIOX        GPIOB
#define SOFT_CS_OUT          BPB_OUT(SOFT_CS_PIN_NUM)
#define SOFT_CS_IN           BPB_IN(SOFT_CS_PIN_NUM)

//SCK
#define SOFT_SCK_CLK_ENABLE   __HAL_RCC_GPIOB_CLK_ENABLE
#define SOFT_SCK_PIN_NUM     13
#define SOFT_SCK_PIN         GPIO_PIN_13
#define SOFT_SCK_Mode        GPIO_MODE_OUTPUT_PP 
#define SOFT_SCK_RCC_CLK     RCC_APB2Periph_GPIOB
#define SOFT_SCK_GPIOX       GPIOB
#define SOFT_SCK_OUT         BPB_OUT(SOFT_SCK_PIN_NUM)
#define SOFT_SCK_IN          BPB_IN(SOFT_SCK_PIN_NUM)

//MISO
#define SOFT_MISO_CLK_ENABLE   __HAL_RCC_GPIOB_CLK_ENABLE
#define SOFT_MISO_PIN_NUM      14
#define SOFT_MISO_PIN          GPIO_PIN_14
#define SOFT_MISO_Mode         GPIO_MODE_INPUT 
#define SOFT_MISO_RCC_CLK      RCC_APB2Periph_GPIOB
#define SOFT_MISO_GPIOX        GPIOB
#define SOFT_MISO_OUT          BPB_OUT(SOFT_MISO_PIN_NUM)
#define SOFT_MISO_IN           BPB_IN(SOFT_MISO_PIN_NUM)
#define SOFT_MISO_MODE_OUT()        GPIOX_PIN_Mode_Turn(SOFT_MISO_GPIOX,SOFT_MISO_PIN_NUM,GPIOX_MODE_OUT);   //配置MISO为输出模式
#define SOFT_MISO_MODE_IN()         GPIOX_PIN_Mode_Turn(SOFT_MISO_GPIOX,SOFT_MISO_PIN_NUM,GPIOX_MODE_IN);   //配置MISO为输入模式

//MOSI
#define SOFT_MOSI_CLK_ENABLE   __HAL_RCC_GPIOB_CLK_ENABLE
#define SOFT_MOSI_PIN_NUM      15
#define SOFT_MOSI_PIN          GPIO_PIN_15
#define SOFT_MOSI_Mode         GPIO_MODE_OUTPUT_PP
#define SOFT_MOSI_RCC_CLK      RCC_APB2Periph_GPIOB
#define SOFT_MOSI_GPIOX        GPIOB
#define SOFT_MOSI_OUT          BPB_OUT(SOFT_MOSI_PIN_NUM)
#define SOFT_MOSI_IN           BPB_IN(SOFT_MOSI_PIN_NUM)
#define SOFT_MOSI_MODE_OUT()        GPIOX_PIN_Mode_Turn(SOFT_MOSI_GPIOX,SOFT_MOSI_PIN_NUM,GPIOX_MODE_OUT);   //配置MOSI为输出模式
#define SOFT_MOSI_MODE_IN()         GPIOX_PIN_Mode_Turn(SOFT_MOSI_GPIOX,SOFT_MOSI_PIN_NUM,GPIOX_MODE_IN);   //配置MOSI为输入模式

//软件SPI GPIO配置
void soft_spi_gpio_config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    //时钟
    SOFT_CS_CLK_ENABLE();     //CS时钟
    SOFT_SCK_CLK_ENABLE();    //SCK时钟   
    SOFT_MISO_CLK_ENABLE();   //MISO时钟
    SOFT_MOSI_CLK_ENABLE();   //MOSI时钟
    
    //CS(推挽输出、速度10MHz)
    GPIO_InitStruct.Mode    =   SOFT_CS_Mode;
    GPIO_InitStruct.Pin     =   SOFT_CS_PIN;
    GPIO_InitStruct.Speed   =   GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(SOFT_CS_GPIOX,&GPIO_InitStruct);      
    //SCK(推挽输出、速度10MHz)
    GPIO_InitStruct.Mode    =   SOFT_SCK_Mode;
    GPIO_InitStruct.Pin     =   SOFT_SCK_PIN;
    GPIO_InitStruct.Speed   =   GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(SOFT_SCK_GPIOX,&GPIO_InitStruct);    
    //MISO(输入 浮空模式)
    GPIO_InitStruct.Mode    =   SOFT_MISO_Mode;
    GPIO_InitStruct.Pin     =   SOFT_MISO_PIN;
    GPIO_InitStruct.Pull    =   GPIO_NOPULL;
    HAL_GPIO_Init(SOFT_MOSI_GPIOX,&GPIO_InitStruct);      
    //MOSI(推挽输出、速度10MHz)
    GPIO_InitStruct.Mode    =   SOFT_MOSI_Mode;
    GPIO_InitStruct.Pin     =   SOFT_MOSI_PIN;
    GPIO_InitStruct.Speed   =   GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(SOFT_MOSI_GPIOX,&GPIO_InitStruct);    
}

7. 实验结果

       可以看出,写入的起始地址为0x20000,最后通过普通读取和快速读取,分别读出写入的数据,并对比。结果都为存储正确。

       HAL,标准库源码运行结果:

8. 源码下载

        源码下载

标签:MISO,HAL,PIN,MOSI,SPI,GPIO,SOFT,STM32F1,define
来源: https://blog.csdn.net/m0_48376567/article/details/118659852

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有