stm32-硬件SPI

简介

软件SPI灵活可变;硬件SPI高性能,可以减轻软件负担

SPI1在APB2 总线,APB2外设时钟频率=72MHZ;SPI2在APB1 总线,APB1总线外设时钟频率=36MHZ。SPI的时钟就来源于外设时钟分频,可以是2~256分频。

I2S协议是一种音频协议,和SPI很相似。

结构

SPI中接收寄存器RDR 和发送寄存器TDR 在软件里是同一个地址,表现为一个DR 。硬件上分成TDR和RDR;写入数据到TDR中,如果移位寄存器中此时没有数据,TDR中的数据会马上进入移位寄存器进行移位发送,此时会置TXE标志位;

SPI全双工,发送的同时也在接收,发送完毕时接收也完成了,移位寄存器里接收的数据会进入RDR,同时置标志位RXNE ,此时需要尽快读出数据,不然后面的数据进入RDR会导致数据覆盖

LSBFIRST 位控制高位先行还是低位先行。寄存器里的BR0、BR1、BR2一起控制时钟分频选择。看MOSI,MISO交叉的地方,当芯片作为主机时,数据通过MOSI发送,通过MISO接收;作为从机时就要交叉过来了,数据通过MISO发送,MOSI接收。

流程

数据传输

全双工连续传输

使用全双工连续传输,效率很高,但同时操作也很复杂,程序不好封装。

开始传输时,在TDR写入数据0xf1,这是第一个数据,所以会马上进入移位寄存器,置TXE标志位了,所以就要继续在TDR写入第二个数据0xf2等待进入移位寄存器;0xf1发送完毕同时也就接收到了第一个数据0xa1,置RXNE标志位了,需要尽快读取出来。

之后0xf2进入移位寄存器了,置TXE就要写入发送的第三个数据0xf3到TDR等待移位;0xf2发送完毕同时收到了第二个数据0xa2,置RXNE需要尽快读出数据。随后最后一个数据0xf3开始移位,置TXE标志位但不写入数据了,最后接收第三个数据0xa3。

整体流程是:写第一个数据------>写第二个数据------>收第一个数据------>写第三个数据------>收第二个数据------>收第三个数据。是交错的,所以软件实施不太友好,比较复杂,但配合得好就能实现连续的数据,效率很高。

非连续传输

操作简单易封装,但效率会低一些。是最常用的。

如图是发送数据的过程。开始在TDR写入第一个数据之后会马上进入移位寄存器,TXE置1了,此时和连续传输时的操作不同,连续传输时一旦TXE置1了就马上写入第二个数据,

但在非连续传输这里不会马上写入,而是等待,等RXNE置1即收到了第一个数据,读出数据之后才继续写入第二个数据,第二个数据进入移位寄存器后也不马上写入第三个数据,同样要等读出第二个数据后才写入第三个数据。

整体流程是:写入第一个数据------>收到第一个数据------>写入第二个数据------>收到第二个数据------>写入第三个数据------>收到第三个数据。

这样就不会出现交叉,软件的执行步骤也可以封装起来:等待TXE置1,写入数据,等待RXNE置1,读取数据。循环下去就行了。但由于等待,就会产生间隙,在SPI时钟频率低的时候间隙没什么影响,但在时钟频率很高的时候,间隙影响就比较大了,比如在二分频时频率很高,间隙的时间是一次数据传输所用时间的好几倍,效率大大降低。所以不追求效率时可以使用非连续传输。

非连续传输代码

MYSPI.c文件

cs 复制代码
#include "stm32f10x.h"                  // Device header
void MYSPI_W_SS(uint8_t bitvalue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)bitvalue);//改变SS
}

void MYSPI_init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitSturcture;
	GPIO_InitSturcture.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitSturcture.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_7;//SCK,MOSI输出引脚为复用推挽输出
	GPIO_InitSturcture.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitSturcture);
	
	GPIO_InitSturcture.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitSturcture.GPIO_Pin=GPIO_Pin_4;//SS输出引脚为推挽输出,依旧使用GPIO口模拟SS
	GPIO_InitSturcture.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitSturcture);
	
	GPIO_InitSturcture.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitSturcture.GPIO_Pin=GPIO_Pin_6;//MISO输出引脚为上拉输入
	GPIO_InitSturcture.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitSturcture);
	
	SPI_InitTypeDef SPI_InitStructure;
	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_128;//分频
	SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;//时钟第一个边沿采样
	SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;//默认低电平,结合起来就是模式0
	SPI_InitStructure.SPI_CRCPolynomial=7;//CRC校验,7是默认值
	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//8位数据
	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//双线全双工
	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;//高位先行
	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//主模式
	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;//软件模拟SS
	SPI_Init(SPI1,&SPI_InitStructure);
	
	SPI_Cmd(SPI1,ENABLE);//使能
	MYSPI_W_SS(1);//SS默认高电平
	
}

void MYSPI_start(void)//开始
{
	MYSPI_W_SS(0);
}

void MYSPI_stop(void)//结束
{
	MYSPI_W_SS(1);
}

uint8_t MYSPI_byte(uint8_t byte)//交换一个字节
{
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);//等待标志位TXE置1,好写入数据
	
	SPI_I2S_SendData(SPI1,byte);//写入数据
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);//等标志位RXNE置1,好读出数据
	
	return SPI_I2S_ReceiveData(SPI1);//读出数据
}

其余和软件SPI代码一样。

相关推荐
我是一棵无人问荆的小草2 小时前
stm32f103单片机的NVIC分组2介绍
stm32·单片机·嵌入式硬件
紫幽3 小时前
从 0 用 Vue 做屏并生成 LVGL 单片机代码(完整源码备忘)
前端·单片机
智者知已应修善业3 小时前
【51单片机数码管逐位显示1-8余位不亮】2024-10-23
c语言·经验分享·笔记·嵌入式硬件·51单片机
Be for thing4 小时前
【嵌入式成长3】STC89C51外部中断|中断原理、寄存器、中断服务函数
单片机·嵌入式硬件·学习
科芯创展6 小时前
1A,5.5VIN,同步升降压恒流芯片,XZ3442
单片机
恒锐丰-罗生6 小时前
率能半导体 SS6840 单通道 H 桥电机驱动芯片深度解析
驱动开发·嵌入式硬件·硬件工程
9稳7 小时前
基于PLC的小车运料装卸控制系统设计
开发语言·网络·数据库·单片机·嵌入式硬件
拾知_H8 小时前
STM32+FreeRTOS基础配置
stm32·嵌入式硬件·freertos
智购科技自动贩卖机8 小时前
自动售货机硬件主控方案选型实战:单片机、树莓派、ESP32怎么选?
人工智能·单片机·嵌入式硬件·物联网·网络协议·yolo·架构
LCG元9 小时前
STM32 多通道 ADC + DMA 采集实战:数据错位、读数跳动的根因与滤波选型
stm32·单片机·嵌入式硬件