STM32笔记--SPI通信
相对于上次说的IIC,这次我们来回忆一下SPI,之前并没有过多深入了解SPI协议,所以这次再来记录一下,首先附上资料里的SPI定义:
SPI,是英语 Serial Peripheral Interface 的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
SPI 是一个环形总线结构,由 ss(cs)、sck、sdi、sdo 构成,其时序其实很简单,主要是在 sck 的控制下,两个双向移位寄存器进行数据交换。
上升沿发送、下降沿接收、高位先发送。
上升沿到来的时候,sdo 上的电平将被发送到从设备的寄存器中。
下降沿到来的时候,sdi 上的电平将被接收到主设备的寄存器中。
SPI 总线是 Motorola 公司推出的三线同步接口,同步串行 3 线方式进行通信:一条时钟线 SCK,一条数据输入线 MOSI,一条数据输出线 MISO;用于 CPU 与各种外围器件进行全双工、同步串行通讯。SPI 主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。
SPI 总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是 SPI0 和 SPI3 方式。
SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。 SPI 主模块和与之通信的外设音时钟相位和极性应该一致。
SPI 时序图详解---SPI 接口在模式 0 下输出第一位数据的时刻
SPI 接口有四种不同的数据传输时序,取决于 CPOL 和 CPHL 这两位的组合。图 1 中表现了这四种时序,时序与 CPOL、CPHL 的关系也可以从图中看出。
CPOL 是用来决定 SCK 时钟信号空闲时的电平,CPOL=0,空闲电平为低电平,CPOL=1 时,空闲电平为高电平。CPHA 是用来决定采样时刻的,CPHA=0,在每个周期的第一个时钟沿采样,CPHA=1,在每个周期的第二个时钟沿采样。
由于我使用的器件工作在模式 0 这种时序(CPOL=0,CPHA=0),所以将图 1 简化为图 2,只关注模式 0 的时序。
SPI的四种模式:
笔者个人还是认为IIC更加简单方便,SPI的通信比较复杂(个人认为,我也看到其他人说IIC比较复杂),且使用引脚比较多,但是SPI的数据传输速率还是更快一点,所以各有利弊,在实际工程中还要斟酌。
在代码方面,驱动还是得了解一下,结合时序可以更加清楚通信过程,下面附上驱动文件代码,比较多,大家选择查看:
void SPI_FLASH_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SPI1 and GPIO clocks */
/*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO,
SPI_FLASH_SPI_MISO_GPIO, SPI_FLASH_SPI_DETECT_GPIO
and SPI_FLASH_SPI_SCK_GPIO Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);
/*!< SPI_FLASH_SPI Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/*!< Configure SPI_FLASH_SPI pins: SCK */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*!< Configure SPI_FLASH_SPI pins: MISO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*!< Configure SPI_FLASH_SPI pins: MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*!< Configure SPI_FLASH_SPI_CS_PIN pin: SPI_FLASH Card CS pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH();
/* SPI1 configuration */
// W25X16: data input on the DIO pin is sampled on the rising edge of the CLK.
// Data on the DO and DIO pins are clocked out on the falling edge of CLK.
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/* Enable SPI1 */
SPI_Cmd(SPI1, ENABLE);
}
#define SPI_FLASH_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4)
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_SPI_ALL_PERIPH(SPIx));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
/* Enable the selected SPI peripheral */
SPIx->CR1 |= CR1_SPE_Set;
}
else
{
/* Disable the selected SPI peripheral */
SPIx->CR1 &= CR1_SPE_Reset;
}
}
上一篇: 【STM32F103笔记】5、串口通信——你好呀~
下一篇: STM32学习笔记——串口通信