首页 > 编程语言 >基于STM32实现硬件SPI与W25Q128通讯步骤及程序

基于STM32实现硬件SPI与W25Q128通讯步骤及程序

时间:2024-10-17 18:47:58浏览次数:9  
标签:SPI1 SS void STM32 SPI W25Q128 InitStructure GPIO

为了大家更加直接了当的获取信息,我直接上干货

一、硬件原理图:

W25Q128模块图

由上图可以看出,要和W25Q128通讯需要采用单片机上的SPI2

W25Q128引脚连线图

由上图看出:

CS(片选)--------------PB12

SCK--------------PB13

MISO--------------PB14

MOSI--------------PB15

一、标准库函数配置流程

  1. 开启时钟,开启GPIO和SPI的时钟

  2. 初始化GPIO口(其中MOSI和SCK是由硬件外设控制的输出信号,所以配置为复用推挽输出,MISO是硬件外设的输入信号,所以配置为上拉输入,因为输入设备有多个,所以不存在复用输出这东西,最后ss,采用软件控制的输出信号,所以配置为通用推挽输出

  3. 配置SPI外设

  4. 开关控制(使能SPI)

  5. 数据交换

  • 等待TXE为1,发送寄存器为空(一般用while循环来实现等待的过程,当TDR有数据时,它会自动转到移位寄存器开始发送)

  • 软件写入数据至SPI_DR  (将想要发送的数据传入至TDR,之后想要发送的数据将由此转入至移位寄存器,一旦移位寄存器有数据了,将会自动产生时序波形,总动生成之后,想要发送的数据将会通过MOSI一位一位的移出去,在MOSI线上,就会自动产生这个发送的时序波形)

  • 等待RXNE出现(由于选择的是非连续传输,所以,时序产生的这段时间,不必提前将下一个数据放入TDR里,故一位一位移出数据的时间死等就行,直到什么时候结束等待呢?在发送的时候,MISO还会移位接收数据,发送和接收是同步的,故接收移位完成也代表发送移位完成,接收移位完成时,会收到一个字节的数据,这是会置标志位RXNE,故只需等待RXNE出现就行,一般用while循环来实现等待的过程)

  • 读取DR(从RDR里面将交换接收的数据读取出来,)

  • 注意事项:

采用硬件SPI,,必须是发送,同时也接收,要想接收必须得先发送,因为你只有给TDR写东西,才会触发时序的生成

另外,TXE,RXNE不需要再手动清除

二、具体程序

1、配置SPI的程序

配置SPI的程序:
#include "stm32f10x.h"                  // Device header

/**
  * 函    数:SPI写SS引脚电平,SS仍由软件模拟
  * 参    数:BitValue 协议层传入的当前需要写入SS的电平,范围0~1
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SS为低电平,当BitValue为1时,需要置SS为高电平
  */
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);		//根据BitValue,设置SS引脚的电平
}

/**
  * 函    数:SPI初始化
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Init(void)
{
	/*开启时钟*/
	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;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA4引脚初始化为推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA5和PA7引脚初始化为复用推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA6引脚初始化为上拉输入
	
	/*SPI初始化*/
	SPI_InitTypeDef SPI_InitStructure;						//定义结构体变量
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;			//模式,选择为SPI主模式
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;	//方向,选择2线全双工
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//数据宽度,选择为8位
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;		//先行位,选择高位先行
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;	//波特率分频,选择128分频
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;				//SPI极性,选择低极性
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;			//SPI相位,选择第一个时钟边沿采样,极性和相位决定选择SPI模式0
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//NSS,选择由软件控制
	SPI_InitStructure.SPI_CRCPolynomial = 7;				//CRC多项式,暂时用不到,给默认值7
	SPI_Init(SPI1, &SPI_InitStructure);						//将结构体变量交给SPI_Init,配置SPI1
	
	/*SPI使能*/
	SPI_Cmd(SPI1, ENABLE);									//使能SPI1,开始运行
	
	/*设置默认电平*/
	MySPI_W_SS(1);											//SS默认高电平
}

/**
  * 函    数:SPI起始
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Start(void)
{
	MySPI_W_SS(0);				//拉低SS,开始时序
}

/**
  * 函    数:SPI终止
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Stop(void)
{
	MySPI_W_SS(1);				//拉高SS,终止时序
}

/**
  * 函    数:SPI交换传输一个字节,使用SPI模式0
  * 参    数:ByteSend 要发送的一个字节
  * 返 回 值:接收的一个字节
  */
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);	//等待发送数据寄存器空
	
	SPI_I2S_SendData(SPI1, ByteSend);								//写入数据到发送数据寄存器,开始产生时序
	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);	//等待接收数据寄存器非空
	
	return SPI_I2S_ReceiveData(SPI1);								//读取接收到的数据并返回
}

2、使用W25Q128的程序

#include "stm32f10x.h"
#include "w25q128.h"
#include "SPI.h"
void W25Q128_Init(void)
{
	SPI_int();
}

void read_W25Q128(uint8_t *MF,uint16_t *ID)
{
	spi_start();
	Swap_bytes(0X9F);
	*MF=Swap_bytes(0XFF);
	*ID=Swap_bytes(0XFF);
	*ID<<=8;
	*ID|=Swap_bytes(0XFF);
	spi_stop();	
}

标签:SPI1,SS,void,STM32,SPI,W25Q128,InitStructure,GPIO
From: https://blog.csdn.net/qq_56883486/article/details/143025886

相关文章

  • 一、STM32F103C8T6--GPIO
    STM32f103c8t632位Cortex-M3内核RISC处理器,最高主频72MHZ,Flash:64KB,SRAM:20KB片上外设:I/O端口:多达37个GPIO引脚(支持复用功能)。GPIO端口支持输入、输出、上拉/下拉功能。定时器:3个16位通用定时器(支持PWM输出)。********1个高级定时器(支持多通道PWM)。通信接口:......
  • Spingboot 定时任务与过滤器,拦截器
     在boot环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用Spring自带的定时任务处理器@Scheduled注解,另一种就是使用第三方框架Quartz,SpringBoot源自Spring+SpringMVC,因此天然具备这两个Spring中的定时任务实现策略,当然也支持Quartz1.定时任务@Sched......
  • 《安富莱嵌入式周报》第344期:开源手表一年的误差不到1秒,开源32路IMU传感器矩阵,STM32L4
    周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 本周更新视频DSP视频教程第13期:汇编浮点库qfplib性能媲美TI的IQmath和硬件FPU,强于C库的math和ARMDSP库,适用于M0和M3(2024-10-12)https://www.armbbs.cn/forum.php?mod=view......
  • 单片机项目|基于STM32实现具有室内定位功能的智能手环的设计
    作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验,被多个学校常年聘为校外企业导师,指导学生毕业设计并参与学生毕业答辩指导,有较为丰富的相关经验。期待与各位高校教师、企业......
  • 基于IO模拟IIC与SPI驱动实现
        最近项目上,由于一些变更问题,导致硬件设计上未考虑到相关GPIO是否支持硬件驱动,考虑到这两个驱动的应用场景并不普遍,基本上只有在下电与Boot升级时才可以会被应用(相信有经验的朋友以及猜出来是什么功能了),具体功能就不详说了,我们直接讲解关于IIC与SPI的模拟驱动吧。1......
  • STM32F103+Air780 OTA升级测试说明
     测试1,单片机通过串口1和GPRS模块通信; 单片机PA8引脚作为复位模组使用;串口2做日志打印(115200)(单片机)PA9  ----  (Air780 )RX;(单片机)PA10  ----  (Air780 )TX;(单片机)PA8  ----  (Air780 )RST2,打开这节例程3,可以使用下载器先下载Bo......
  • STM32学习笔记—USART串口
    USART串口协议通信接口通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统通信协议:制定通信的规则,通信双方按照协议规则进行数据收发全双工:通信双方能够同时进行双向通信。全双工有两根通信线。半双工:数据可以沿两个方向传送,但同一时刻一个信道只允许单方向传送。I......
  • 2-STM32F103+ML307(中移4G Cat1)OTA升级篇(自建物联网平台)-STM32通过ML307使用http或
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/ZLIOTB/ML307/myota.html"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p>  说明前面......
  • 1-STM32F103+ML307(中移4G Cat1)OTA升级篇(自建物联网平台)-STM32通过ML307使用http或
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/ZLIOTB/ML307/myota.html"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p>  说明这节......
  • STM32开发————定时器的基本配置
    一、将定时器相关的.c和.h添加到新建的工程中添加文件路径:二、对.c和.h文件进行代码编写打开timer.h文件,写一下防止重复包含的宏定义#ifndef__TIMER_H#define__TIMER_H#endif打开timer.c文件,包含一下STM32的头文件:“右键单机”--->Insert'#includefi......