I2C能够通过软件模拟,同样的,SPI通讯也可以通过软件模拟,具体需要掌握SPI的收发时序。但在本节,我们着重讲解STM32的硬件SPI外设。
我们知道SPI有以下几个特点
1、时钟频率:Fpclk /2,4,8,16,32,64,128,256 (Fpclk是时钟分频 ,APH2的Fpclk是72MHZ ,APB1的Fpclk是36MHZ)
2、支持多主机模型、主或从操作
3、可精简为半双工/单工通信
4、支持DMA
5、兼容I2S协议 (I2S是一种数字音频信号传输协议)
在STM32F103C8T6中,分别有 SPI1 、SPI2 硬件外设
SPI1挂载载APB2总线上,pclk是72MHZ(高速总线)
SPI2挂载载APB1总线上,pclk是36MHZ(低速总线)
相对于UART(串口),SPI和I2C是高位先行
比如要发送一个0x34
在SPI和I2C的波形上是 0011 0100 →
但在UART中, 波形是 0010 1100 ←
在SPI通讯中,不像I2C,需要发送和接收数据。在SPI中,数据是通过“交换”来实现通讯的。
通过MOSI(主出从入)和MISO(主入从出)两条数据线来传输数据的,如图。
在SPI通信中,TXE位和RXNE位是非常重要的两个标志位,TXE是数据传送完毕标志位,RXNE是数据接收完毕标志位。后面我们使用硬件SPI通讯时,需要通过这两个位来确定通讯进度。
先说说怎么准备去使用SPI通讯吧
/*-------------------------------------启动硬件SPI---------------------------------------*/
在硬件SPI中,完成代码只需要以下几个步骤
第一步:
开启时钟,开启GPIO和SPI的时钟
第二步:
初始化GPIO口,
SCK ,MOSI配置成复用推挽输出(硬件外设的输出信号,跟I2C一样要配置成复用推挽输出)
MISO配置成上拉输入(输入设备可能有多个)
SS,实验中是软件控制的输出信号,配置为通用推挽输出
第三步:
配置SPI外设,使用结构体配置即可
第四步:
开关控制,SPI_CMD使能
以下是常用的库函数,待会我们写代码需要用到这些
/*-------------------------------------SPI库函数---------------------------------------*/ //库函数主要使用到这些 SPI_I2S_DeInit();//恢复出厂配置 SPI_Init();//SPI初始化 I2S_Init();//I2S初始化 SPI_StructInit();//SPI结构体变量初始化 I2S_StructInit();//I2S结构体变量初始化 SPI_CMD();//SPI外设使能 SPI_I2S_ITConfig();//中断使能 SPI_I2S_CMD();//DMA使能 SPI_I2S_SendData();//写 DR数据寄存器 SPI_I2S_ReceiveData();//读 DR数据寄存器 SPI_I2S_GetFlagStatus();//获取标志位 ---主要用于获取TXE 和RXNE 标志位 SPI_I2S_ClearFalg();//清除标志位 SPI_I2S_GetITStatus();//获取中断标志位 SPI_I2S_ClearITPendingBit();//清除中断标志位
/*-------------------------------------硬件SPI代码---------------------------------------*/ void SPI_GPIO_Init() { RCC_APB2PeriphClockCmd(RCC_APB1Periph_SPI1 ,ENABLE);//开启SPI1外设的时钟 RCC_APB2PeriphClockCmd(RCC_APB1Periph_GPIOA ,ENABLE);//开启GPIOA外设的时钟 GPIO_TypeDef GPIO_InitStructure ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽模式 GPIO_InitStructure.GPIO_Pin =GPIO_PIN_5|GPIO_PIN_7;//pin5和pin7作为SPI通讯的SCK 和MOSI引脚 GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHZ;//50MHZ GPIO(GPIO_A ,&GPIO_InitStructure); GPIO_TypeDef GPIO_InitStructure ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;//推挽输出 GPIO_InitStructure.GPIO_Pin =GPIO_PIN_4;//pin4用于模拟SS引脚 GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHZ;//50MHZ GPIO(GPIO_A ,&GPIO_InitStructure); GPIO_TypeDef GPIO_InitStructure ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//Input Pull UP上拉输出模式 GPIO_InitStructure.GPIO_Pin =GPIO_PIN_6;//pin6作为SPI通讯的MISO引脚 GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHZ;//50MHZ GPIO(GPIO_A ,&GPIO_InitStructure); SPI_TypeDef SPI_InitStructure; SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主机还是从机, Master是主机 , Slave则是从机 SPI_InitStructure.SPI_Direction =SPI_Direction_2Lines_FullDuplex ;//SPI工作模式 :标准模式 -双线全双工 SPI_InitStructure.SPI_DataSize =SPI_DataSize_8b ;//数字帧长度: 8Bit ,16Bit SPI_InitStructure.SPI_FirstBit =SPI_FirstBit_MSB ;//高位先行 SPI_InitStructure.SPI_BaudRatePrescalar = SPI_BaudRatePrescalar_128;//SPI波特率预分频器:2,4,8,16,.....256 SPI_InitStructure.SPI_CPOL =SPI_CPOL_LOW ;//时钟极性:High就是1 ,Low是0 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟相位:1Edge第一个边沿(下降沿)触发 ,2Edge第二个边沿(上升沿)触发 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS引脚设置:Hard硬件NSS模式,Soft软件NSS模式 SPI_InitStructure.SPI_CRCPolynomialS =7 ;//CRC校验的多项式:默认值7 SPI_Init(SPI1 , &SPI_InitStructure); SPI_Cmd(SPI1,ENABLE);//SPI开关控制 MySPI_W_SS(1);//默认给SS输出高电平,默认不选择从机 } uint8_t SPI_SwapByte (uint8_t ByteSend)//交换字节函数 { while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FALG_TXE) !=SET);//检测TXE //在写入DR数据寄存器的时候,TXE标志位会自动清零 SPI_I2S_SendData(SPI1 ,ByteSend );//发送一个字节数据 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FALG_RXNE) !=SET);//检测RXNE return SPI_I2S_ReceiveData(SPI1);//接受数据 }
以上是STM32-SPI通讯的代码,欢迎纠错指正。
标签:---,SPI1,I2S,STM32,SPI,InitStructure,Mode,GPIO From: https://www.cnblogs.com/xuegaogao/p/17790216.html