当前位置: 首页 > news >正文

嵌入式-SPI的IO引脚初始化、模块初始化、数据的收发-Day16

目录

一、IO引脚的初始化

1.SPI模块简介

2.W25Q64简介

​3.定位SPI的引脚位置

4.选择IO引脚的模式

5.选择IO的最大输出速度

6.代码实现IO引脚的初始化

二、模块初始化

1.SPI模块的基本工作原理

2.选择数据通信方向

3.数据宽度、极性、相位和比特位传输顺序

​4.设置波特率

5.NSS的配置方式

6.SPl Init

7.初始化的代码

三、数据的收发

1.SPI数据收发的特点(全双工一定是收发'同时'的)

2.声明数据收发的编程接口

3.SPI数据收发过程简介(核心:收发同时)

4.代码编写


一、IO引脚的初始化

1.SPI模块简介

  


2.W25Q64简介

  • Flash 芯片:一种非易失性存储器,就像小U盘,掉电后数据也不会丢,用来存程序、固件、配置等。

  • Flash:指的就是这种存储技术,常见在单片机、路由器、手机里。

  • W25Q64:是 华邦(Winbond) 出的一款 串行Flash存储芯片,容量是 64Mbit(8MB),通过 SPI接口 和单片机通信,常用来存放程序代码或数据。

👉 总结一句:
Flash 就是掉电不丢的存储器(硬盘),W25Q64 是一款常见的 8MB 大小的 SPI Flash 芯片。


3.定位SPI的引脚位置

同理,在操作手册里面的引脚章节存储着这个引脚的位置以及重映射的位置


4.选择IO引脚的模式


5.选择IO的最大输出速度

根据官方的操作手册来说,最大高达80MHz,这里实际因为接的是面包板,不稳定,所以选择2MHz就行。 

6.代码实现IO引脚的初始化

这里想随便选择一个IO引脚,结果选择了PA15,结果正好这个PA15比较特殊,其默认的功能是不是PA15,所以这里可以换一个其他普通引脚,或者像下面一样使用重映射,将引脚映射到PA15

#include "stm32f10x.h"
#include "Delay.h"
void My_SPI_IOInit(void);int main(void)
{My_SPI_IOInit();while(1){}
}
void My_SPI_IOInit(void){//首先IO引脚,这里选择的是重映射的RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);//PA15的重映射GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//IO引脚初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct1={0};GPIO_InitStruct1.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_5;GPIO_InitStruct1.GPIO_Speed=GPIO_Speed_2MHz;GPIO_InitStruct1.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_Init(GPIOB,&GPIO_InitStruct1);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStruct2={0};GPIO_InitStruct2.GPIO_Pin=GPIO_Pin_15;GPIO_InitStruct2.GPIO_Speed=GPIO_Speed_2MHz;GPIO_InitStruct2.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Init(GPIOA,&GPIO_InitStruct2);//这里很容易忘记,因为这个是要发往从机的NSS,所以需要默认给高电压GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct3={0};GPIO_InitStruct3.GPIO_Pin=GPIO_Pin_4;GPIO_InitStruct3.GPIO_Mode=GPIO_Mode_IPU;GPIO_Init(GPIOB,&GPIO_InitStruct3);}

二、模块初始化

1.SPI模块的基本工作原理

从上往下看,上面最右边的就是状态寄存器,Tx的发送,RX的接收状态寄存器,ORV后面再说

之后就是左边的发送数据需要的发送寄存器和移位寄存器。之后就是接收数据的同理。

再下来就是时钟信号的传输,首先总开关,之后经过一个分频器,通过该分频器可以得到想要的波特率,在右边的时钟控制电路里面还有两极性和相位。

之后在下面就是模块通信方向的选择,是选择主/从,以及通信的模式

最后就是NSS,一般单片机作为主机是基本不使用NSS的。虽然不使用,但是会设置默认的为其连接默认的高电压(硬件)或者(软件)为其写1,使其高电压(因为NSS如果低电压了说明自己被当别人的从机了,所以需要设置一个默认的高电压,来恒定自己的主机身份)

在模块初始化的时候一般进行配置参数的时候,也要考虑从机的配置(配置手册)从而配置合适的参数


 


2.选择数据通信方向

3.数据宽度、极性、相位和比特位传输顺序

发现这些配置都有多种,而具体选择哪种,需要去连接的设备的操作手册选择合适的模式

从手册发现。W25Q64支持8b,低极性的1相位,MSB的下的配置,注意不支持高级性和2相位


4.设置波特率


5.NSS的配置方式

6.SPl Init

7.初始化的代码

#include "stm32f10x.h"
#include "Delay.h"
void My_SPI_IOInit(void);int main(void)
{My_SPI_IOInit();while(1){}
}
void My_SPI_IOInit(void){//首先IO引脚,这里选择的是重映射的RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);//PA15的重映射GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//IO引脚初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct1={0};GPIO_InitStruct1.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_5;GPIO_InitStruct1.GPIO_Speed=GPIO_Speed_2MHz;GPIO_InitStruct1.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_Init(GPIOB,&GPIO_InitStruct1);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStruct2={0};GPIO_InitStruct2.GPIO_Pin=GPIO_Pin_15;GPIO_InitStruct2.GPIO_Speed=GPIO_Speed_2MHz;GPIO_InitStruct2.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Init(GPIOA,&GPIO_InitStruct2);//这里很容易忘记,因为这个是要发往从机的NSS,所以需要默认给高电压GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct3={0};GPIO_InitStruct3.GPIO_Pin=GPIO_Pin_4;GPIO_InitStruct3.GPIO_Mode=GPIO_Mode_IPU;GPIO_Init(GPIOB,&GPIO_InitStruct3);//SPI模块的初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);SPI_InitTypeDef SPI_InitStruct={0};SPI_InitStruct.SPI_Direction=SPI_Direction_2Lines_FullDuplex;SPI_InitStruct.SPI_Mode=SPI_Mode_Master;SPI_InitStruct.SPI_DataSize=SPI_DataSize_8b;SPI_InitStruct.SPI_CPOL=SPI_CPOL_Low;SPI_InitStruct.SPI_CPHA=SPI_CPHA_1Edge;SPI_InitStruct.SPI_FirstBit=SPI_FirstBit_MSB;SPI_InitStruct.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_64;SPI_InitStruct.SPI_NSS=SPI_NSS_Soft;SPI_Init(SPI1,&SPI_InitStruct);//设置软件的NSS的高电压模式SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);}

三、数据的收发

1.SPI数据收发的特点(全双工一定是收发'同时'的)


2.声明数据收发的编程接口


3.SPI数据收发过程简介(核心:收发同时)

首先,闭合总开关

之后,先向发送数据寄存器写入一个字节;

之后开始Size-1次的循环,因为首先是发了一个字节,当发送寄存器空了,就开始传入下一个要发送的字节,而在移位寄存器里面的前一个字节一位位发送的时候,相应的也是在接收数据的移位寄存器里面也是在一位位比特位的接收,因为是收发同时的。

最后接收最后一个字节然后断开开关


4.代码编写

这里自带的SPI_I2S_SendData()的I2S是涉及音频相关的,因为和SPI的内容逻辑差不多就写为同一个方法

#include "stm32f10x.h"
#include "Delay.h"
void My_SPI_IOInit(void);
void App_SPI_MasterTransmitReceiv(SPI_TypeDef *SPIx,const uint8_t *pDataTx,uint8_t *pDataRx,uint16_t Size);
int main(void)
{My_SPI_IOInit();uint8_t pDataTx[]={0,1,2,3};uint8_t pDataRx[100];App_SPI_MasterTransmitReceiv(SPI1,pDataTx,pDataRx,4);while(1){}
}
void My_SPI_IOInit(void){//首先IO引脚,这里选择的是重映射的RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);//PA15的重映射GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//IO引脚初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct1={0};GPIO_InitStruct1.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_5;GPIO_InitStruct1.GPIO_Speed=GPIO_Speed_2MHz;GPIO_InitStruct1.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_Init(GPIOB,&GPIO_InitStruct1);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStruct2={0};GPIO_InitStruct2.GPIO_Pin=GPIO_Pin_15;GPIO_InitStruct2.GPIO_Speed=GPIO_Speed_2MHz;GPIO_InitStruct2.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Init(GPIOA,&GPIO_InitStruct2);//这里很容易忘记,因为这个是要发往从机的NSS,所以需要默认给高电压GPIO_WriteBit(GPIOA,GPIO_Pin_15,Bit_SET);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct3={0};GPIO_InitStruct3.GPIO_Pin=GPIO_Pin_4;GPIO_InitStruct3.GPIO_Mode=GPIO_Mode_IPU;GPIO_Init(GPIOB,&GPIO_InitStruct3);//SPI模块的初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);SPI_InitTypeDef SPI_InitStruct={0};SPI_InitStruct.SPI_Direction=SPI_Direction_2Lines_FullDuplex;SPI_InitStruct.SPI_Mode=SPI_Mode_Master;SPI_InitStruct.SPI_DataSize=SPI_DataSize_8b;SPI_InitStruct.SPI_CPOL=SPI_CPOL_Low;SPI_InitStruct.SPI_CPHA=SPI_CPHA_1Edge;SPI_InitStruct.SPI_FirstBit=SPI_FirstBit_MSB;SPI_InitStruct.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_64;SPI_InitStruct.SPI_NSS=SPI_NSS_Soft;SPI_Init(SPI1,&SPI_InitStruct);//设置软件的NSS的高电压模式SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);}void App_SPI_MasterTransmitReceiv(SPI_TypeDef *SPIx,const uint8_t *pDataTx,uint8_t *pDataRx,uint16_t Size){SPI_Cmd(SPIx,ENABLE);//发送第一个数据SPI_I2S_SendData(SPIx,pDataTx[0]);//开始发送Size-1个数据for(int i=0;i<Size-1;i++){while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE)==RESET);SPI_I2S_SendData(SPIx,pDataTx[i+1]);while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE)==RESET);pDataRx[i]=SPI_I2S_ReceiveData(SPIx);}//接收最后一个数据while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE)==RESET);pDataRx[Size-1]=SPI_I2S_ReceiveData(SPIx);SPI_Cmd(SPIx,DISABLE);}

http://www.dtcms.com/a/340094.html

相关文章:

  • Codeforces 盒装苹果
  • vLLM加载lora
  • CF266E More Queries to Array... Solution
  • GPFS不同存储方式的优劣
  • 2943. 最大化网格图中正方形空洞的面积
  • Manus AI 与多语言手写识别技术深度剖析
  • 不同的 Text2sql 方式优缺点探究
  • 智慧校园中IPTV融合对讲:构建高效沟通新生态
  • Unity常用工具及默认快捷键
  • PowerBI登录出错解决过程
  • YOLO多模态改进系列 | YOLOFuse:多模态融合的 Slim-Neck 改进
  • java面试——多线程
  • C++高频知识点(二十九)
  • HarmonyOS 中的 泛型类和泛型接口
  • 51单片机拼接板(开发板积木)
  • 爬小红书搜索详情软件:根据关键词采集笔记详情,包含正文内容、发布时间、转评赞藏等
  • C++开发基础之:队列用法与生产者消费者模型实战和可直接复用的线程安全的队列
  • 疏老师-python训练营-Day50预训练模型+CBAM注意力
  • 会话技术之<Cookie>和<Session>的区别联系
  • “数据权限”的道和术
  • 从 SGD 到梯度累积:Epoch、Batch、Step 的关系全解析
  • 使用redis读写锁实现抢券功能
  • Hive 存储管理测试用例设计指南
  • 力扣(最小栈)
  • Android逆向工程:Smali语法解析完整指南
  • [ Maven 开发工具 ] 环境搭建及配置
  • DRM驱动架构浅析-上(DRM基础概要与U-Boot阶段驱动解析)
  • 基于 OpenMV 的矩形识别与 STM32 串口通信(电子设计大赛实用教程)
  • k8s运维实践:高可用Redis Cluster(三主三从)与Proxy部署方案
  • 使用 Docker 安装长安链管理平台 + 部署区块链与示例合约