硬件SPI和软件模拟SPI在配置方面的一点区别

一 硬件SPI和软件SPI

顾名思义这种方式是硬件层面的,需要开启并使用单片机里面的SPI外设,IO口要复用到外设,由外设来控制电平翻转;软件模拟就可以随便选择IO口进行配置,需要手动控制电平翻转

硬件接线:

我使用的是外接Flash模块无论是硬件还是软件接线都使用的是相同的IO口

对应关系:

A4-CS

A5-SCK时钟线

A6-MISO-D0

A7-MOSI-D1 接线口诀:主机MOSI接从机DI 主机 MISO接从机DO

二 配置GPIO

配置IO文字描述:

配置GPIO口

把CS SCK MOSI配置为推挽输出

把MISO配置为浮空输入

默认CS高电平抬起不选中状态

硬件版本

void W25Q_SPI_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct;

SPI_InitTypeDef SPI_InitStruct;

// 开启时钟:GPIOA、SPI1(SPI1属于APB2)

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);

// PA5 SCK、PA7 MOSI:复用推挽输出 AF_PP

GPIO_InitStruct.GPIO_Pin = SPI_SCK_PIN | SPI_MOSI_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct);

// PA6 MISO:浮空输入

GPIO_InitStruct.GPIO_Pin = SPI_MISO_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct);

// PA4 CS:普通推挽输出

GPIO_InitStruct.GPIO_Pin = FLASH_CS_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(FLASH_CS_PORT, &GPIO_InitStruct);

FLASH_CS_H(); // 默认片选拉高,不选中Flash

// SPI配置

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; // CPOL=0 空闲SCK低

SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // CPHA=0 第一个边沿采样(Mode0)

SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; // 软件管理片选

SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //72M/4=18M

SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; //高位先发,Flash强制要求

SPI_InitStruct.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStruct); //硬件SPI必须调用SPI_Init

SPI_Cmd(SPI1, ENABLE); //使能SPI外设

}

软件模拟版本

//软件模拟SPI初始化

void W25Q_SPI_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct;

// 只开启GPIOA时钟,删掉SPI1时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

// SCK PA5、MOSI PA7:推挽输出

GPIO_InitStruct.GPIO_Pin = SPI_SCK_PIN | SPI_MOSI_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct);

// MISO PA6:浮空输入

GPIO_InitStruct.GPIO_Pin = SPI_MISO_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct);

// CS PA4:推挽输出

GPIO_InitStruct.GPIO_Pin = FLASH_CS_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(FLASH_CS_PORT, &GPIO_InitStruct);

FLASH_CS_H(); // 默认片选拉高

}

三 收发字节函数的区别

收发字节文字描述:

发送一字节数据

函数有返回值因为是全双工 有发送就有接收

要发送的数据作为函数参数传入

通过循环从最高位开始发送数据

每次都要提取出最高位数据进行发送

然后发送数据左移一位

选择模式0 就是上升沿采样

SCK输出高电平,保持不变

读取MISO电平,进行或操作拼接接收电平数据

SCK输出低电平 停止采样

保持一段时间后,进行下一轮数据的发送和读取

硬件版本

uint8_t SPI_RW_Byte(uint8_t txDat)

{

//等待发送缓冲区为空

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI1, txDat);

//等待接收完成

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

return SPI_I2S_ReceiveData(SPI1);

}

软件模拟版本

uint8_t SPI_RW_Byte(uint8_t txdata)

{

uint8_t i;

uint8_t rxData = 0;

for(i = 0;i<8;i++){

if(txdata & 0x80){

GPIO_SetBits(SPI_GPIO_PORT, SPI_MOSI_PIN);

}else{

GPIO_ResetBits(SPI_GPIO_PORT, SPI_MOSI_PIN);

}

txdata <<= 1;

GPIO_SetBits(SPI_GPIO_PORT, SPI_SCK_PIN);

delay_us(2);//延时函数可以去掉 我加上是为了健壮性

rxData <<= 1;

if(GPIO_ReadInputDataBit(SPI_GPIO_PORT, SPI_MISO_PIN)){

rxData |= 0x01;

}

GPIO_ResetBits(SPI_GPIO_PORT, SPI_SCK_PIN);

delay_us(2);//同理,为了健壮性

}

return rxData;

}

这个SPI手写时序虽然最开始也是参照AI和现成代码写出来的,但是我会一行一行的理解,然后独立参照datasheet写出来,刚开始接触的时候确实感觉很难,但现在感觉好一点了

相关推荐
AUTO_150756759651 小时前
【KT70022】昆腾微 单片音频编解码器
单片机·音频
Logic1011 小时前
C语言/数据结构位运算题解:异或XOR找出英雄队伍中的“独特战斗力“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
LCG元2 小时前
STM32F103 GPIO 翻转方式耗时实测:CRL/CRH 逐位拆解、BSRR 原子写与 ODR 读改写竞态陷阱
stm32·单片机·嵌入式硬件
Zootopia6262 小时前
论文复现|五机编队任务链
c语言·c++·考研·无人机·创业创新·学习方法·高考
搁浅小泽2 小时前
压敏电阻(MOV)选型与设计规范
单片机·嵌入式硬件
一条破秋裤2 小时前
08_GPIO点灯_从J41插针查到复用与寄存器
单片机·嵌入式硬件
Zw-awa13 小时前
传感器是什么:让 STM32 知道车外发生了什么
stm32
女神下凡16 小时前
芯参谋(41):DDR2_电路设计指南
arm开发·单片机·嵌入式硬件·设计规范
Escalating_xu17 小时前
【C 语言】深入理解指针(4):回调函数、qsort、void * 与泛型排序的模拟实现
java·c语言·开发语言