stm32入门-----硬件SPI读写W25Q64

 目录

前言        

 一、相关库函数介绍

 1.初始化

 2.写入数据

3.接收数据

 4.获取标志位

二、软件SPI读写W25Q64


前言        

        上一期我们学习了stm32的SPI外设(上一期链接:stm32入门-----硬件SPI外设-CSDN博客),那么我们本期就来通过stm32的SPI外设来去实现之前软件读写W25Q64的功能。(视频:[11-5] 硬件SPI读写W25Q64_哔哩哔哩_bilibili

本期代码我已上传至百度网盘,需要的可以自己下载。

通过百度网盘分享的文件:硬件SPI读写W25Q64(1).rar
链接:https://pan.baidu.com/s/1JZiDtAC9tOKsidcS_BGesA?pwd=0721 
提取码:0721

 一、相关库函数介绍

这里我们点开项目的library库,然后看到下面这两个文件,这两个文件就是存储SPI的底层功能的函数。

下面这些就是关于SPI的相关函数,但是I2S的也是跟SPI弄到一起了,不过我们不需要用到,这里本期要用到的我已经在下面画出来了。 

 1.初始化

这个函数我们已经再熟悉不过了,也就是定义结构体,对结构体进行配置,然后放入到下面这个函数去初始化。

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

下面看一个示例: 

   //SPI结构体初始化
    SPI_InitTypeDef SPI_initstruct;
    SPI_initstruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//波特率预分频器,对SPI总线上的时钟进行分频,这里是SPI1对应的APB2时钟为72MHz
    SPI_initstruct.SPI_CPHA = SPI_CPHA_1Edge;//配置模式,第几个边沿采样(模式0第一个边沿采样)
    SPI_initstruct.SPI_CPOL = SPI_CPOL_Low;//配置模式,SCK默认情况下电平(模式0是低电平)
    SPI_initstruct.SPI_CRCPolynomial = 7;//CRC校验,这里选默认值0x0007就行了
    SPI_initstruct.SPI_DataSize = SPI_DataSize_8b;//配置数据帧,当前选择一个字节为一个数据,8位
    SPI_initstruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//选择工作模式,当前选择双线全双工
    SPI_initstruct.SPI_FirstBit = SPI_FirstBit_MSB;//选择低位先行还是高位先行,这里选择高位先行
    SPI_initstruct.SPI_Mode = SPI_Mode_Master; //选择SPI的模式,当前设备为主机还是从机,这里选择主机
    SPI_initstruct.SPI_NSS = SPI_NSS_Soft; //选择SS SPI设备,这里使用软件NSS模式
    SPI_Init(SPI1, &SPI_initstruct);

 2.写入数据

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

把数据写入到发送数据寄存器DR中。 

3.接收数据

uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);

读取接收数据寄存器DR里面的数据,返回出来。 

 4.获取标志位

FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

 这个函数的参数选择如下,我们可以去通过这个函数来去获取到TEX和RNEX的标志位,从而去判断数据是否能继续写入或者读取操作。

二、软件SPI读写W25Q64

现象:

电路连接图:

工程文件如下,这里我们只需要在软件SPI读写W25Q64的代码进行修改就行了,这里要修改的部分实际上就是底层部分,之前是软件底层,那这里我们只需要改MySPI.c文件的底层即可。

MySPI.c代码如下: 

#include "stm32f10x.h"                  // Device header

//对SS的写入
void SPI_W_SS(uint8_t val) {
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)val);
}


void SPI_init() {
    /*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //开启SPI1时钟
    
    /*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//通用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //SS
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; //MOSI和SCK
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //MISO
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //SPI结构体初始化
    SPI_InitTypeDef SPI_initstruct;
    SPI_initstruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//波特率预分频器,对SPI总线上的时钟进行分频,这里是SPI1对应的APB2时钟为72MHz
    SPI_initstruct.SPI_CPHA = SPI_CPHA_1Edge;//配置模式,第几个边沿采样(模式0第一个边沿采样)
    SPI_initstruct.SPI_CPOL = SPI_CPOL_Low;//配置模式,SCK默认情况下电平(模式0是低电平)
    SPI_initstruct.SPI_CRCPolynomial = 7;//CRC校验,这里选默认值0x0007就行了
    SPI_initstruct.SPI_DataSize = SPI_DataSize_8b;//配置数据帧,当前选择一个字节为一个数据,8位
    SPI_initstruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//选择工作模式,当前选择双线全双工
    SPI_initstruct.SPI_FirstBit = SPI_FirstBit_MSB;//选择低位先行还是高位先行,这里选择高位先行
    SPI_initstruct.SPI_Mode = SPI_Mode_Master; //选择SPI的模式,当前设备为主机还是从机,这里选择主机
    SPI_initstruct.SPI_NSS = SPI_NSS_Soft; //选择SS SPI设备,这里使用软件NSS模式
    SPI_Init(SPI1, &SPI_initstruct);

    //使能
    SPI_Cmd(SPI1, ENABLE);
    SPI_W_SS(1);//SS为高电平表示不选中从机,
}

//1.起始
void SPI_Start() {
    //SS置为低电平
    SPI_W_SS(0);
}
// 2.终止
void SPI_Stop() {
    // SS置回高电平
    SPI_W_SS(1);
}


// 交换字节   4步搞定
uint8_t SPI_SwapByte(uint8_t byteSend) {
    //先发送再有接收
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);//等待TXE标志位,表示是否可以写入数据到发送寄存器TDR
    SPI_I2S_SendData(SPI1, byteSend);//写入数据到发送数据寄存器
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);//等待RXNE标志位,表示是否可以从接收数据寄存器RDR读取数据
    return SPI_I2S_ReceiveData(SPI1);//返回读取到的数据
}

main.c文件代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "W25Q64.h"

uint8_t MID;
uint16_t DID;

uint8_t arrWrite[] = { 0x01,0x02,0x03,0x04 };
uint8_t arrRead[4];

int main(void)
{	
	OLED_Init();
	W25Q64_init();
	OLED_ShowString(1, 1, "MID:    DID:");
	OLED_ShowString(2, 1, "W:");
	OLED_ShowString(3, 1, "R:");

	W25Q64_ReadID(&MID, &DID);
	OLED_ShowHexNum(1, 5, MID, 2);
	OLED_ShowHexNum(1, 13, DID, 4);

	W25Q64_SectorErase(0x000000);//扇区的地址取决于前面三位,后面三位无论怎么变都是表示同一个扇区
	W25Q64_PagePro(0x0000FF, arrWrite, 4);//写入
	W25Q64_ReadData(0x0000FF, arrRead, 4);//读取

	// 展示发送的数据
	for (uint8_t i = 0;i < 4;i++) {
		OLED_ShowHexNum(2, 3+3*i, arrWrite[i],2);
	}
	// 展示读取的数据
	for (uint8_t i = 0;i < 4;i++) {
		OLED_ShowHexNum(3, 3+3*i, arrRead[i],2);
	}

	while (1) {
		
	}
}

以上就是本期的全部内容了,我们下次见!

今日壁纸:

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是基于STM32F103C8T6芯片的硬件SPI驱动及W25Q64读写的示例代码,供参考。 SPI驱动: ``` #include "stm32f10x.h" #define SPI_PORT GPIOA #define SPI_SCK GPIO_Pin_5 #define SPI_MOSI GPIO_Pin_7 #define SPI_MISO GPIO_Pin_6 void SPI_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); GPIO_InitStructure.GPIO_Pin = SPI_SCK | SPI_MOSI; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(SPI_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SPI_MISO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(SPI_PORT, &GPIO_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); } uint8_t SPI_SendByte(uint8_t byte) { while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, byte); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); } ``` W25Q64读写: ``` #include "stm32f10x.h" #define W25Q64_CS GPIO_Pin_4 void W25Q64_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = W25Q64_CS; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA, W25Q64_CS); } void W25Q64_WriteEnable(void) { GPIO_ResetBits(GPIOA, W25Q64_CS); SPI_SendByte(0x06); GPIO_SetBits(GPIOA, W25Q64_CS); } void W25Q64_ReadStatus(uint8_t *status) { GPIO_ResetBits(GPIOA, W25Q64_CS); SPI_SendByte(0x05); *status = SPI_SendByte(0xFF); GPIO_SetBits(GPIOA, W25Q64_CS); } void W25Q64_WriteStatus(uint8_t status) { GPIO_ResetBits(GPIOA, W25Q64_CS); SPI_SendByte(0x01); SPI_SendByte(status); GPIO_SetBits(GPIOA, W25Q64_CS); } void W25Q64_EraseChip(void) { W25Q64_WriteEnable(); GPIO_ResetBits(GPIOA, W25Q64_CS); SPI_SendByte(0xC7); GPIO_SetBits(GPIOA, W25Q64_CS); } void W25Q64_EraseSector(uint32_t address) { W25Q64_WriteEnable(); GPIO_ResetBits(GPIOA, W25Q64_CS); SPI_SendByte(0x20); SPI_SendByte((address >> 16) & 0xFF); SPI_SendByte((address >> 8) & 0xFF); SPI_SendByte(address & 0xFF); GPIO_SetBits(GPIOA, W25Q64_CS); } void W25Q64_WritePage(uint32_t address, uint8_t *data, uint32_t length) { uint32_t i; W25Q64_WriteEnable(); GPIO_ResetBits(GPIOA, W25Q64_CS); SPI_SendByte(0x02); SPI_SendByte((address >> 16) & 0xFF); SPI_SendByte((address >> 8) & 0xFF); SPI_SendByte(address & 0xFF); for (i = 0; i < length; i++) { SPI_SendByte(data[i]); } GPIO_SetBits(GPIOA, W25Q64_CS); } void W25Q64_ReadData(uint32_t address, uint8_t *data, uint32_t length) { uint32_t i; GPIO_ResetBits(GPIOA, W25Q64_CS); SPI_SendByte(0x03); SPI_SendByte((address >> 16) & 0xFF); SPI_SendByte((address >> 8) & 0xFF); SPI_SendByte(address & 0xFF); for (i = 0; i < length; i++) { data[i] = SPI_SendByte(0xFF); } GPIO_SetBits(GPIOA, W25Q64_CS); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fitz&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值