50.读写W25Q128

    按照良许嵌入式的代码引用,需要了解详细请移步良许嵌入式32部分良许嵌入式

引脚定义:

首先是头文件部分声明以及定义

1.1头文件
#ifndef __W25Q128_H
#define __W25Q128_H

#include "sys.h"
//定义片选信号,1为选中,0为未选中
#define W25Q128_CS(X)   do{X? \
                           HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET):\
                           HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);\
                          }while(0)
//下面是W25Q128的指令表,在W25Q128官方手册第八章可以找到
#define FLASH_ManufactDeviceID                  0x90    //查询厂商设备号:16位
#define FLASH_WriteEnable                       0x06    //开启写使能
#define FLASH_ReadStatusReg1                    0x05    //读取SPI状态寄存器1
#define FLASH_ReadData                          0x03    //读取数据
#define FLASH_PageProgram                       0x02    //页
#define FLASH_SectorErase                       0x20    //扇区擦除
#define FLASH_DummyByte                         0xFF    //写入指令

void w25q128_init(void);  //初始化
uint16_t w25q128_read_id(void);  //读取芯片ID
void w25q128_read_data(uint32_t address, uint8_t *data, uint32_t size);  //读取spi接收缓冲区数据
void w25q128_write_page(uint32_t address, uint8_t *data, uint16_t size);  //写页
void w25q128_erase_sector(uint32_t address);  //擦除扇区
#endif
2.1 SPI的初始化(void spi1_init(void))
SPI_HandleTypeDef  SPI_HandleInitStructure={0};  //定义spi句柄并且初始化
void spi1_init(void)
{
    SPI_HandleInitStructure.Instance=SPI1;   //当前模块使用的是spi1
    SPI_HandleInitStructure.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256;   //SPI波特率分频 256
    SPI_HandleInitStructure.Init.CLKPhase=SPI_PHASE_1EDGE;  //奇数边沿触发
    SPI_HandleInitStructure.Init.CLKPolarity=SPI_POLARITY_LOW;  //CPOL,低电平为空闲
    SPI_HandleInitStructure.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE; //关闭crc校验
    SPI_HandleInitStructure.Init.CRCPolynomial=7;  //CRC校验多项式 4+2+1=7,spi默认
    SPI_HandleInitStructure.Init.DataSize=SPI_DATASIZE_8BIT; //8位数据传输模式
    SPI_HandleInitStructure.Init.Direction=SPI_DIRECTION_2LINES;  //双工模式
    SPI_HandleInitStructure.Init.FirstBit=SPI_FIRSTBIT_MSB;  //高位先行
    SPI_HandleInitStructure.Init.NSS=SPI_NSS_SOFT;  //从模式选择,软件
    SPI_HandleInitStructure.Init.Mode=SPI_MODE_MASTER;  //主机模式
    SPI_HandleInitStructure.Init.TIMode=SPI_TIMODE_DISABLE;  //关闭
    
    HAL_SPI_Init(&SPI_HandleInitStructure);
}
2.2 SPI的Msp_Init,这个函数主要作用是配置spi引脚,还有开启时钟,设置中断优先级
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
      if(hspi->Instance == SPI1)  //如果是SPI1
    {
        GPIO_InitTypeDef gpio_initstruct;
        //打开时钟
        __HAL_RCC_GPIOA_CLK_ENABLE();                           // 使能GPIOB时钟
        __HAL_RCC_SPI1_CLK_ENABLE();
        
        //调用GPIO初始化函数
        gpio_initstruct.Pin = W25Q128_CS_PIN;     //片选     
        gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;   //推挽输出        
        gpio_initstruct.Pull = GPIO_PULLUP;            //上拉        
        gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;          
        HAL_GPIO_Init(GPIOA, &gpio_initstruct);
        
        gpio_initstruct.Pin = W25Q128_CLK_PIN | W25Q128_DI_PIN;    //时钟,w25q128数据输入      
        gpio_initstruct.Mode = GPIO_MODE_AF_PP;           
        HAL_GPIO_Init(GPIOA, &gpio_initstruct);
        
        gpio_initstruct.Pin = W25Q128_DO_PIN;   //w25q128数据输出       
        gpio_initstruct.Mode = GPIO_MODE_INPUT;           
        HAL_GPIO_Init(GPIOA, &gpio_initstruct);
    }
    
    
}
2.3 spi交换数据(给spi发送数据,返回spi接收数据后返回的数据)
uint8_t w25q128_spi_swap_byte(uint8_t data)
{
     uint8_t recv_data;
     HAL_SPI_TransmitReceive(&SPI_HandleInitStructure,&data,&recv_data,1,1000);
     return recv_data;
}
2.4 spi 初始化
void w25q128_init(void)
{
    w25q128_spi_init();
}
2.5 w25q128读取设备ID

查看数据手册,先拉低片选,然后发送查询设备ID指令,接着看第二段第三行follow by24 bit address,发送0x00三次。然后就是对spi发送dump_by。先求低位,左移八位,高位补零,然后求高位,并且或上。

uint16_t  w25q128_spi_read_DevId()
{
       uint16_t dev_id;
       W25Q128_CS(0);  //拉低片选,表示被选中
       w25q128_spi_swap_byte(FLASH_ManufactDeviceID);   //发送查询ID指令
       w25q128_spi_swap_byte(0x00);   //根据手册,连续发送三个0x00
       w25q128_spi_swap_byte(0x00);
       w25q128_spi_swap_byte(0x00);
       
       dev_id  = w25q128_spi_swap_byte(FLASH_DummyByte)<<8;  //低八位
       dev_id |= w25q128_spi_swap_byte(FLASH_DummyByte);  //高八位
       W25Q128_CS(1);  //释放片选信号
    
       return dev_id;  //返回设备id号
}
2.6等待忙(w25q128_spi_wait_busy),这是为了往页里面写数据还有擦除扇区做准备
uint8_t w25q128_spi_readSR1(void)
{
    uint8_t recv_data;
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_ReadStatusReg1);  //打开读状态寄存器
    W25Q128_CS(1);  //释放片选信号
    
    return recv_data;
}

void w25q128_spi_wait_busy(void)
{
      while( (w25q128_spi_readSR1()&0x01)==0x01);
}
2.7发送spi地址到w25q128,为读写和擦除数据做准备
//w25q128有24位地址,多以要用uint32_t 传递
void w25q128_spi_sendAddress(uint32_t address)
{
   
    w25q128_spi_swap_byte(address>>16);  //发送最高八位地址
    w25q128_spi_swap_byte(address>>8);  //发送中间八位地址
    w25q128_spi_swap_byte(address);  //发送最低八位地址

}
2.8w25q128读取数据

1.拉低片选 2.发送读数据信号, 3.发送要读取数据在w25q128的地址 4.根据大小循环读取数据(通过往w25q128发送数据,并接收返回的值) 5拉高片选。

//读取保存在w25q128的数据
void w25q128_spi_readData(uint8_t *data,uint32_t address,uint32_t size)
{
    uint32_t i=0;
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_ReadData);  //发送读取数据信号
    w25q128_spi_sendAddress(address);  //发送读取数据信号
    for(i=0;i<size;i++){
       data[i]= w25q128_spi_swap_byte(FLASH_DummyByte);  //发送预设字节
    }
    W25Q128_CS(1);  //释放片选信号
}
 2.9按页往w25q128写入数据

1.开启写使能 2.拉低片选 3.发送写数据信号, 4.发送要写数据在w25q128的地址 5.根据大小循环写入数据  6. 拉高片选 7.等待空闲

void w25q128_spi_writeData(uint8_t *data,uint32_t address,uint16_t size)
{
    uint16_t i=0;
    w25q128_spi_write_enable();  //开启写使能
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_PageProgram);  //发送写入数据信号
    w25q128_spi_sendAddress(address);  //发送写入数据地址
    for(i=0;i<size;i++){
     w25q128_spi_swap_byte(data[i]);  //发送预设字节
    }
    W25Q128_CS(1);  //释放片选信号
    w25q128_spi_wait_busy();  //等待空闲
}
2.10扇区擦除
void w25q128_spi_eraseSector(uint32_t address)
{
    w25q128_spi_write_enable();  //开启写使能
    w25q128_spi_wait_busy();  //等待空闲
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_SectorErase);  //发送读取数据信号
    w25q128_spi_sendAddress(address);  //发送读取数据信号
 
    W25Q128_CS(1);  //释放片选信号
    w25q128_spi_wait_busy();  //等待空闲
}

w25q128.c

#include "w25q128.h"

SPI_HandleTypeDef  SPI_HandleInitStructure={0};  //定义spi句柄并且初始化
void spi1_init(void)
{
    SPI_HandleInitStructure.Instance=SPI1;   //当前模块使用的是spi1
    SPI_HandleInitStructure.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256;   //SPI波特率分频 256
    SPI_HandleInitStructure.Init.CLKPhase=SPI_PHASE_1EDGE;  //奇数边沿触发
    SPI_HandleInitStructure.Init.CLKPolarity=SPI_POLARITY_LOW;  //CPOL,低电平为空闲
    SPI_HandleInitStructure.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE; //关闭crc校验
    SPI_HandleInitStructure.Init.CRCPolynomial=7;  //CRC校验多项式 4+2+1=7,spi默认
    SPI_HandleInitStructure.Init.DataSize=SPI_DATASIZE_8BIT; //8位数据传输模式
    SPI_HandleInitStructure.Init.Direction=SPI_DIRECTION_2LINES;  //双工模式
    SPI_HandleInitStructure.Init.FirstBit=SPI_FIRSTBIT_MSB;  //高位先行
    SPI_HandleInitStructure.Init.NSS=SPI_NSS_SOFT;  //从模式选择,软件
    SPI_HandleInitStructure.Init.Mode=SPI_MODE_MASTER;  //主机模式
    SPI_HandleInitStructure.Init.TIMode=SPI_TIMODE_DISABLE;  //关闭
    
    HAL_SPI_Init(&SPI_HandleInitStructure);
}

void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
      if(hspi->Instance == SPI1)  //如果是SPI1
    {
        GPIO_InitTypeDef gpio_initstruct;
        //打开时钟
        __HAL_RCC_GPIOA_CLK_ENABLE();                           // 使能GPIOB时钟
        __HAL_RCC_SPI1_CLK_ENABLE();
        
        //调用GPIO初始化函数
        gpio_initstruct.Pin = W25Q128_CS_PIN;     //片选     
        gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;   //推挽输出        
        gpio_initstruct.Pull = GPIO_PULLUP;            //上拉        
        gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;          
        HAL_GPIO_Init(GPIOA, &gpio_initstruct);
        
        gpio_initstruct.Pin = W25Q128_CLK_PIN | W25Q128_DI_PIN;    //时钟,w25q128数据输入      
        gpio_initstruct.Mode = GPIO_MODE_AF_PP;           
        HAL_GPIO_Init(GPIOA, &gpio_initstruct);
        
        gpio_initstruct.Pin = W25Q128_DO_PIN;   //w25q128数据输出       
        gpio_initstruct.Mode = GPIO_MODE_INPUT;           
        HAL_GPIO_Init(GPIOA, &gpio_initstruct);
    }
    
    
}


void w25q128_spi_init(void)
{
    spi1_init();  //初始化spi1
}
uint8_t w25q128_spi_swap_byte(uint8_t data)
{
     uint8_t recv_data;
     HAL_SPI_TransmitReceive(&SPI_HandleInitStructure,&data,&recv_data,1,1000);
     return recv_data;
}

uint16_t  w25q128_spi_read_DevId(void)
{
       uint16_t dev_id;
       W25Q128_CS(0);  //拉低片选,表示被选中
       w25q128_spi_swap_byte(FLASH_ManufactDeviceID);   //发送查询ID指令
       w25q128_spi_swap_byte(0x00);   //根据手册,连续发送三个0x00
       w25q128_spi_swap_byte(0x00);
       w25q128_spi_swap_byte(0x00);
       
       dev_id  = w25q128_spi_swap_byte(FLASH_DummyByte)<<8;  //低八位
       dev_id |= w25q128_spi_swap_byte(FLASH_DummyByte);  //高八位
       W25Q128_CS(1);  //释放片选信号
    
       return dev_id;  //返回设备id号
}

void w25q128_spi_write_enable(void)
{
       W25Q128_CS(0);  //拉低片选,表示被选中
       w25q128_spi_swap_byte(FLASH_WriteEnable);  //打开写使能
       W25Q128_CS(1);  //释放片选信号
}

uint8_t w25q128_spi_readSR1(void)
{
    uint8_t recv_data=0;
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_ReadStatusReg1);  //打开写使能
    recv_data=w25q128_spi_swap_byte(FLASH_DummyByte);  //发送dummy byte
    W25Q128_CS(1);  //释放片选信号
    
    return recv_data;
}

void w25q128_spi_wait_busy(void)
{
      while( (w25q128_spi_readSR1()&0x01)==0x01);
}
//w25q128有24位地址,多以要用uint32_t 传递
void w25q128_spi_sendAddress(uint32_t address)
{
   
    w25q128_spi_swap_byte(address>>16);  //发送最高八位地址
    w25q128_spi_swap_byte(address>>8);  //发送中间八位地址
    w25q128_spi_swap_byte(address);  //发送最低八位地址

}

//读取保存在w25q128的数据
void w25q128_spi_readData(uint8_t *data,uint32_t address,uint32_t size)
{
    uint32_t i=0;
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_ReadData);  //发送读取数据信号
    w25q128_spi_sendAddress(address);  //发送地址信号
    for(i=0;i<size;i++){
       data[i]= w25q128_spi_swap_byte(FLASH_DummyByte);  //发送预设字节
    }
    W25Q128_CS(1);  //释放片选信号
}

//按页往w25q128写入数据
void w25q128_spi_writeData(uint8_t *data,uint32_t address,uint16_t size)
{
    uint16_t i=0;
    w25q128_spi_write_enable();  //开启写使能
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_PageProgram);  //页
    w25q128_spi_sendAddress(address);  //发送地址信号
    for(i=0;i<size;i++){
     w25q128_spi_swap_byte(data[i]);  //发送预设字节
    }
    W25Q128_CS(1);  //释放片选信号
    w25q128_spi_wait_busy();  //等待空闲
}

void w25q128_spi_eraseSector(uint32_t address)
{
    w25q128_spi_write_enable();  //开启写使能
    w25q128_spi_wait_busy();  //等待空闲
    W25Q128_CS(0);  //拉低片选,表示被选中
    w25q128_spi_swap_byte(FLASH_SectorErase);  //发送读取数据信号
    w25q128_spi_sendAddress(address);  //发送读取数据信号
 
    W25Q128_CS(1);  //释放片选信号
    w25q128_spi_wait_busy();  //等待空闲
}

main.c

#include "sys.h"
#include <string.h>
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "w25q128.h"
int main(void)
{
    uint8_t data_temp[100];
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* 初始化LED灯 */
    uart1_init(115200);
    w25q128_spi_init();
    printf("SPI 读取实验!\r\n");
   
    uint16_t dev_id=w25q128_spi_read_DevId();
    printf("W25Q128 DEV_ID:%X\r\n",dev_id);
    printf("往SPI写入数据!\r\n");
    sprintf( (char*)data_temp,"这是写入芯片的数据,真的应该这次没有乱码了吧放假哦i我就佛i今晚i哦飞机哦");
    w25q128_spi_eraseSector(0x000000);
    w25q128_spi_writeData(data_temp,0x000000,100);
    
    memset(data_temp,0,100);  //清空w25q128的数组
    w25q128_spi_readData(data_temp,0x000000,100);  //从w25q128再次读取
    printf("读取出的数据:%s.\r\n",data_temp);
    while(1)
    { 
        led1_on();
        led2_off();
        delay_ms(500);
        led1_off();
        led2_on();
        delay_ms(500);
    }
}

个人使用不足请指正。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值