【STM32】SPI接口(非连续传输)

server/2024/9/23 19:49:02/

本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发

目录

前言

SPI简介

IO口初始化 

SPI配置

时钟使能

SPI初始化 

SPI使能 

数据接收与发送 

硬件SPI代码

MySPI.h

MySPI.c


前言

【通信协议】SPI总线-CSDN博客

本篇博客学习使用STM32的SPI硬件收发电路生成SPI时序。SPI协议用模式0,一主多从,非连续传输。

SPI简介

STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担

可配置8位/16位数据帧、高位先行/低位先行

支持多主机模型、主或从操作

可精简为半双工/单工通信

支持DMA

STM32F103C8T6 硬件SPI资源:SPI1、SPI2

IO口初始化 

STM32F103C8T6模式
SCK复用推挽输出,由硬件SPI生成时钟
MOSI复用推挽输出,由硬件SPI生成数据帧
MISO上拉输入
SS推挽输出,不用硬件SPI的NSS,使用GPIO模拟通讯的起始与终止
GND与从机共地

GPIO的其它参数的理解可以阅读下方博客,这里不再赘述。

【STM32】GPIO和AFIO标准库使用框架_gpio afio-CSDN博客

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);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);//推挽输出默认输出低电平MySPI_W_SS(1);//不选择从机,空闲状态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);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);

SPI配置

时钟使能

SPI1在APB2总线上,时钟频率最大72MHz

SPI2、SPI3在APB1总线上,时钟频率最大36MHz

由RCC时钟树,需要使能SPI外设对应的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

SPI初始化 

SPI_Mode

SPI_Mode 描述
SPI_Mode_Master设置为主SPI
SPI_Mode_Slave设置为从 SPI

SPI_ Direction

SPI_ Direction描述
SPI_Direction_2Lines_FullDuplexSPI 设置为双线双向全双工
SPI_Direction_2Lines_RxOnlySPI 设置为双线单向接收
SPI_Direction_1Line_RxSPI 设置为单线双向接收
SPI_Direction_1Line_TxSPI 设置为单线双向发送

SPI_DataSize

SPI_DataSize 描述
SPI_DataSize_16bSPI 发送接收16 位帧结构
SPI_DataSize_8bSPI 发送接收 8 位帧结构

SPI_FirstBit

SPI_FirstBit 指定了数据传输从 MSB 位还是 LSB 位开始

SPI_FirstBit描述
SPI_FisrtBit_MSB数据传输从 MSB 位开始
SPI_FisrtBit_LSB数据传输从 LSB 位开始

SPI_BaudRatePrescale

通讯时钟频率(SCK): fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)

用来定义波特率预分频的值,这个值用以设置发送和接收的 SCK 时钟

注意:通讯时钟由主 SPI 的时钟分频而得,不需要设置从 SPI 的时钟

SPI_CPOL和SPI_CPHA

这两个参数有四种组合,对应四种模式。主机所选择SPI的模式,要与从机一致。

模式对应的参数见本博客前文提供的博客链接

SPI_NSS

本博客代码使用软件模拟来实现片选

SPI_NSS描述
SPI_NSS_HardNSS 由外部管脚管理
SPI_NSS_Soft内部 NSS 信号有 SSI 位控制

SPI初始化

	/*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模式0SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//NSS,选择由软件控制SPI_InitStructure.SPI_CRCPolynomial = 7;				//CRC多项式,暂时用不到,给默认值7SPI_Init(SPI1, &SPI_InitStructure);						//将结构体变量交给SPI_Init,配置SPI1

SPI使能 

初始化的最后调用即可

SPI_Cmd(SPI1, ENABLE);

数据接收与发送 

先判断发送缓存器中是否有数据,没有?数据就将放在发送缓存区。硬件将数据并行发送到移位寄存器,这时发送缓存器为空(非连续传输模式并没有在这时将下一个要发送的字节写入发送缓存器,而是等待接收到数据后再将数据放发送缓存区),移位寄存器在时钟同步下,将数据发送一位一位发送,对应SPI的模式0的SCL奇数上升沿,数据一位一位接收到移位寄存器,直到一个字节发送完成,也表示一个字节接收完成。移位寄存器的数据会移至接收缓存区,数据接收后及时取走,以免被覆盖。

uint8_t MySPI_SwapByte(uint8_t ByteSend)
{while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);// 在写入发送缓冲器之前,软件必须确认TXE标志为’1’,否则新的数据会覆盖已经在发送缓冲器中的数据SPI_I2S_SendData(SPI1, ByteSend);while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);//发送完成一个字节的同时也接收一个字节,等待接收完成return SPI_I2S_ReceiveData(SPI1);
}

标志位由硬件清除

 

硬件SPI代码

MySPI.h

#ifndef __MYSPI_H
#define __MYSPI_Hvoid MySPI_Init(void);
void MySPI_Start(void);
void MySPI_Stop(void);
uint8_t MySPI_SwapByte(uint8_t ByteSend);#endif

MySPI.c

#include "stm32f10x.h"                  // Device headervoid MySPI_W_SS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}void MySPI_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);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);MySPI_W_SS(1);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);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);SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE);}void MySPI_Start(void)
{MySPI_W_SS(0);
}void MySPI_Stop(void)
{MySPI_W_SS(1);
}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);
}

http://www.ppmy.cn/server/105802.html

相关文章

C语言01 每日一练01

C语言01 每日一练01 习题一 计算两个整数的和并输出。习题二 编写一个C程序,运行时输入 a,b 两个值,输出其中值最大者。习题三 编写一个C程序,运行时输入 a,b,c 三个值,输出其中值最大者。 习题一 计算两个整数的和并输出。 计算两…

Hot100】LeetCode—25. K 个一组翻转链表

目录 1- 思路双指针 start 和 end 链表翻转 2- 实现⭐25. K 个一组翻转链表——题解思路 3- ACM 实现 原题连接:25. K 个一组翻转链表 1- 思路 双指针 start 和 end 链表翻转 实现思路: 1- 通过 pre指针和 end 指针定位, pre 记录需要翻…

设计模式-创建型模式-原型模式

1.原型模式定义 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象; 1.1 原型模式优缺点 优点 当创建一个新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例…

Agent实际落地的应用 未来生活的无形助手

在这个信息爆炸的时代,我们每个人都在追求更高效的生活方式。想象一下,如果有一个无形的助手,能够理解我们的需求,自动处理繁琐的任务,甚至为我们提供个性化的建议,那将是多么美好的体验!这正是…

Flask返回Json格式字符,中文导致unicode乱码问题

一.问题描述 或者直接返回json格式的字符串 从上图可以看出,当flask实现的接口响应中存在中文时,接口返回json字串的中文为unicode乱码。 二.问题解决 百度搜索了很多,原来在创建flask app时使用json格式的字符串,默认是ascii编…

每天一个数据分析题(四百八十九)- 主成分分析与因子分析

关于主成分分析和因子分析的区别,下列描述正确的是( ) A. 主成分分析是一种无监督学习算法,而因子分析是一种有监督学习算法 B. 主成分分析是一种线性变换方法,而因子分析是一种非线性变换方法 C. 主成分分析的结果…

m4a格式音频怎么转成mp3?音频转成mp3的8个方法

在结束关于M4A转MP3格式转换的探讨之际,我们不得不强调这一转换过程对于提升音频文件灵活性和可访问性的重要意义。随着数字媒体的日益普及,音频文件的格式兼容性成为了不可忽视的一环。特别是在一个多元化设备和平台共存的数字时代,确保音频…

搭建自己的GPT

搭建自己的GPT 文章说明核心代码效果展示源码下载 文章说明 目前GPT的使用比较主流,现有开源大模型,可以拉取到本地进行部署,搭建属于自己的GPT对话工具;主要用于熟悉大模型的本地搭建;本文采用开源的Ollama进行服务提…