通讯协议3-SPI通讯
注意:本文章需要配合无际单片机编程-硬件基础2.0教程视频学习。
注意:本文章需要配合无际单片机编程-硬件基础2.0教程视频学习。
一、SPI的介绍:
SPI中文名称是:串行外设接口(Serial Peripheral Interface)。
SPI一般用于芯片之间的数据交互,在单片机开发中比较常见。
是一种高速、全双工、同步通信总线。SPI有主、从两种模式,通常由一个主模块和一个或多个从模块组成(SPI不支持多主机)之间的通讯。
二、SPI硬件连接接口
SPI硬件连接比较简单,需要4根线(通讯设备需要共地):
- MOSI(Master Output Slave Input):主设备数据输出,从设备数据输入;
- MISO( Master Input Slave Output):主设备数据输入,从设备数据输出;
- SCLK(Serial Clock):时钟信号,由主设备产生;
- CS/SS(Chip Select/Slave Select)(片选):从设备使能信号,由主设备控制,一主多从时,CS/SS是从芯片是否被主芯片选中的控制信号,只有片选信号为预先规定的使能信号时(高电位或低电位),主芯片对此从芯片的操作才有效。
问题:MOSI 和MOSI连接?还是MOSI和MISO连接?
在产品开发中,我们经常会碰到这个疑问,MOSI和MISO连接,还是和MOSI连接呢?和串口工作的原理类似,理论上是MOSI 和MISO 连接,MISO和MOSI连接的。
如果是两个单片机通过SPI通讯,需要按照:MOSI-MISO、MISO-MOSI连接。 但如果是单片机和只能做从机的设备连接,是MOSI-MOSI、MISO-MOSI 连接。因为从机的丝印标志的是需要连接主机的端口。 其从机内部MISO脚的功能是MOSI,或MOSI的功能是MISO;
三、通讯协议:
SPI是一种全双工、高速的、同步的通信总线. SPI的通讯相比UART、IIC更加简单,没有起始位、结束位;数据按照时钟直接发送和接收;
1. SPI通讯时序图举例:
①举例1:
主机发送数据(0x65)给从机:
从机发送数据(0xA9)给主机:
时序图说明: SPI和IIC、Uart 相比,通讯更简单,没有起始位,停止位。
关于的时序图,有几个问题:
- 一个时钟周期怎么确定?
- 发送/接收数据 固定高字节在前面?
- 数据在哪里更改?哪里采集?
2.数据通讯原理
①时钟速率
SPI总线上的主设备必须在通信开始时候配置并生成相应的时钟信号。从理论上讲,只要实际可行,时钟速率就可以是你想要的任何速率,当然这个速率受限于每个系统能提供多大的系统时钟频率,以及最大的SPI传输速率。
②数据格式
SPI发送数据在对应的规格书中都有规定的,如下图,支持的是MSB(Most Significant Bit) 最高有效位在前,当然也可以配置成LSB(Least Significant Bit)最低有效位在前;
SPI程序开发,这个参数也是可以配置的:
③时钟极性(CPOL或CKP)
时钟极性,一般用CPOL或CKP 来表示,其作用是用来规定,SPI空闲状态下CLK的电平的:
- CPOL = 0: CLK空闲状态是 低电平;
- CPOL = 1: CLK空闲状态是 高电平;
④时钟相位
时钟相位,一般用CKE或CPHA来表示;其作用是用来规定,采集数据是在那个时钟信号的位置;
- CPHA = 0:在时钟信号SCK的第一个跳变沿采样;
- CPHA = 1:在时钟信号SCK的第二个跳变沿采样。
⑤SPI的四种通讯模式:
按照时钟极性和时钟相位不同的组合,SPI共有4种通讯模式,具体如下:
- 模式0: CPOL = 0 CPHA = 0
- 模式1: CPOL = 0 CPHA =1
- 模式2: CPOL = 1 CPHA = 0
- 模式3: CPOL = 1 CPHA =1
⑥SPI的通讯内部工作结构(了解)
这部分内容,建议大家有个了解即可,不需要花太多时间。
SPI通讯,主设备和从设备接口内部,都有一个串行移位寄存器,主设备通过向它的SPI串行寄存器写入一个字节来发起一次传输。 所以在主机发送数据的同时,也接收到了新的数据。
注意:SPI 有主模式和从模式之分,但没有读和写的区别,写操作和读操作是同步完成的。
如果SPI写操作时,主机需要忽略接收到的数据;同理,SPI主机读取从机数据的时候,就必须发送一个空字节来引发从机数据的传输。即:发一个数据必然会收到一个数据;要收一个数据必须也要先发一个数据。
四、 单片机SPI参数程序代码配置:
1.单片机内部硬件SPI接口参数配置
这里以STM32单片机为例:
①硬件连接图
②SPI参数配置-代码
从机25Q64连接的是STM32单片机的硬件SPI2 接口。
单片机内部集成的SPI,可以自动的发送和接收数据,在程序开发的时候,我们只需要按照单片机官方的要求配置相关参数即可,如下:
/* SPI2 configuration */
// #define SPI_Direction_2Lines_FullDuplex ((uint16_t)0x0000)
// #define SPI_Direction_2Lines_RxOnly ((uint16_t)0x0400)
// #define SPI_Direction_1Line_Rx ((uint16_t)0x8000)
// #define SPI_Direction_1Line_Tx ((uint16_t)0xC000)
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI1设置为两线全双工
// #define SPI_Mode_Master ((uint16_t)0x0104) //主机
// #define SPI_Mode_Slave ((uint16_t)0x0000) //从机
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI1为主模式
// #define SPI_DataSize_16b ((uint16_t)0x0800)
// #define SPI_DataSize_8b ((uint16_t)0x0000)
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
// #define SPI_CPOL_Low ((uint16_t)0x0000)
// #define SPI_CPOL_High ((uint16_t)0x0002)
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行时钟在不操作时,时钟为高电平
// #define SPI_CPHA_1Edge ((uint16_t)0x0000)
// #define SPI_CPHA_2Edge ((uint16_t)0x0001)
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //第二个时钟沿开始采样数据
// #define SPI_NSS_Soft ((uint16_t)0x0200)
// #define SPI_NSS_Hard ((uint16_t)0x0000)
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件(使用SSI位)管理
// #define SPI_BaudRatePrescaler_2 ((uint16_t)0x0000)
// #define SPI_BaudRatePrescaler_4 ((uint16_t)0x0008)
// #define SPI_BaudRatePrescaler_8 ((uint16_t)0x0010)
// #define SPI_BaudRatePrescaler_16 ((uint16_t)0x0018)
// #define SPI_BaudRatePrescaler_32 ((uint16_t)0x0020)
// #define SPI_BaudRatePrescaler_64 ((uint16_t)0x0028)
// #define SPI_BaudRatePrescaler_128 ((uint16_t)0x0030)
// #define SPI_BaudRatePrescaler_256 ((uint16_t)0x0038)
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8
//#define SPI_FirstBit_MSB ((uint16_t)0x0000)
//#define SPI_FirstBit_LSB ((uint16_t)0x0080)
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
这里只给大家提供了SPI参数的配置,关于相关GPIO口的配置和读写在这里就给大家不讲解了,大家后续做实际项目的时候再进一步去学习和理解。本节课的重点是要理解SPI通讯协议即可。
2. 模拟SPI通讯参数配置
① 硬件连接
主机: STM8L103
从机: SX1278
通过规格书知悉:数据高位在前 CPOL = 0 CPHA = 0;
②代码
//输入 MISO
#define MISO_PORT GPIOB
#define MISO_PIN GPIO_Pin_7
#define MISO_DATABIT GPIO_ReadInputDataBit(MISO_PORT,MISO_PIN)
//输出 MOSI
#define MOSI_PORT GPIOB
#define MOSI_PIN GPIO_Pin_6
#define MOSI_HIGH GPIO_SetBits(MOSI_PORT,MOSI_PIN)
#define MOSI_LOW GPIO_ResetBits(MOSI_PORT,MOSI_PIN)
#define SCK_PORT GPIOB
#define SCK_PIN GPIO_Pin_5
#define SCK_HIGH GPIO_SetBits(SCK_PORT,SCK_PIN)
#define SCK_LOW GPIO_ResetBits(SCK_PORT,SCK_PIN)
//CS
#define CS_PORT GPIOB
#define CS_PIN GPIO_Pin_4
#define CS_HIGH GPIO_SetBits(CS_PORT,CS_PIN)
#define CS_LOW GPIO_ResetBits(CS_PORT,CS_PIN)
//输入
#define RF_IRQ_DIO0_PORT GPIOB
#define RF_IRQ_DIO0_PIN GPIO_Pin_3
#define RF_IRQ_DIO0_DATABIT GPIO_ReadInputDataBit(RF_IRQ_DIO0_PORT,RF_IRQ_DIO0_PIN)
///通讯GPIO口初始化
static void Sx1278_GpioInt()
{
//***** SPI_SCK
GPIO_Init(SCK_PORT,SCK_PIN , GPIO_Mode_Out_PP_Low_Slow);
//*****SPI_MISO
GPIO_Init(MISO_PORT,MISO_PIN , GPIO_Mode_In_PU_No_IT);
//*****SPI_MOSI
GPIO_Init(MOSI_PORT,MOSI_PIN , GPIO_Mode_Out_PP_Low_Slow);
CS_HIGH;
RF_RST_HIGH;
}
/**********************************************************
**Name: SPI_SentDate
**Function: SPI Write one byte
**Input: WrPara
**Output: none
**note: use for burst mode
**********************************************************/
void SPI_SentDate(u8 WrPara)
{//CPOL = 0 CPHA = 0;
u8 bitcnt;
CS_LOW;
SCK_LOW;
for(bitcnt=8; bitcnt!=0; bitcnt–)
{
SCK_LOW;
if(WrPara&0x80)
{///高位在前 1
MOSI_HIGH;
}
else
{
MOSI_LOW;
}
asm(“nop”);
asm(“nop”);
SCK_HIGH;
asm(“nop”);
WrPara <<= 1;
}
SCK_LOW;
MOSI_HIGH;
}
/**********************************************************
**Name: SPI_ReadByte
**Function: SPI Read one byte
**Input: None
**Output: result byte
**Note: use for burst mode
**********************************************************/
u8 SPI_ReadByte(void)
{
u8 RdPara = 0;
u8 bitcnt;
CS_LOW;
MOSI_HIGH;
for(bitcnt=8; bitcnt!=0; bitcnt–)
{///高位在前
SCK_LOW;
asm(“nop”);
asm(“nop”);
RdPara <<= 1;
SCK_HIGH;
if(MISO_DATABIT)
{
RdPara |= 0x01;
}
else
{
RdPara |= 0x00;
}
asm(“nop”);
asm(“nop”);
}
SCK_LOW;
return(RdPara);
}
五、SPI优缺点
1.优点
- 无起始位和停止位、校验位,数据可以连续高效传输;
- 数据传输速率比串口、IIC 速率更高
- 全双工,支持同时发送和接收数据;
- 数据位长度没有限制,比较常用的是8bit、16bit
2.缺点
- 通讯线比串口、IIC更多,需要四根信号线 CS CLK MOSI MISO
- 没有校验位/应答位,无法确认是否已成功接收数据
<结束>
关于SPI 相关的知识点,大家可以看以下两篇文章。