目录
一、什么是SPI
1、SPI总线概念
SPI 是 Motorola(摩托罗拉) 公司推出的一种同步串行接口技术,是一种高速、全双工的同步通信总线, SPI 时钟频率相比 I2C 要高很多,I2C的速度上限是400Khz,而SPI的速度为40Mhz。
2、硬件连接图

说明:
SPI通信也可以挂载多个从器件,通过片选线选中具体从器件。SPI一般为4线也可以是3线。
常见的为四线模式,分别是下面四根线
| CS/NSS |
片选信号线,选择需要进行通信的从设备;拉低有效。 |
| SCK |
串行时钟信号线,为SPI提供时钟(主机发出) |
| MOSI/SDO |
主出从入信号线,主机向从机发送数据 |
| MISO/SDI |
主入从出信号线,从机向主机发送数据 |
3、数据帧传输
片选低 +数据位(8/16) +片选高
4、SPI配置方式
①用IO口模拟SPI的时序
②直接配置SPI控制器的寄存器
二、如何配置SPI
1、SPI通信IO口模拟
1.1 工作模式
时钟极性:
空闲时候时钟线电平状态 高 低
时钟相位:
时钟线在第一个跳变沿时,数据线可以读
时钟线在第二个跳变沿时,数据线可以读
具体模式如下:
①时钟极性为0(SCL_L),时钟相位为0(时钟线在第一个跳变沿数据线可以读)

空闲:
SCL_L
规则:
先发高位
时钟线上升沿,数据线稳定,可以读数据
时钟线为下降沿,数据线可以改变
②时钟极性为0(SCL_L),时钟相位为1(时钟线在第二个跳变沿数据线可以读)

空闲:
SCL_L
规则:
先发高位
时钟线为下降沿,数据线稳定,可以读数据
时钟线为上升沿,数据线可以改变
③时钟极性为1(SCL_H),时钟相位为0(时钟线在第一个跳变沿数据线可以读)

空闲:
SCL_H
规则:
先传输高位
时钟线为下降沿,数据线稳定; (要想读数据,时钟线拉低)
第一位数据时钟线为高电平,数据线可以改变;(要想写数据,时钟线要拉高)
其他的数据时钟线为上升沿,数据线可以改变(要想写数据,时钟线要拉高)
④时钟极性为1(SCL_H),时钟相位为1(时钟线在第二个跳变沿数据线可以读)

空闲;
SCL_H
规则:
先传输高位
时钟线为上升沿,数据线可读
时钟线为下降沿,数据线可写
说明:
如果用IO口模拟SPI时序,IO口要用通用模式
本篇主要针对于0,0模式展开学习,其它模式同样操作
1.2 数据传输规矩
SPI 设备间的数据传输之所以又被称为数据交换,是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 “发送者(Transmitter)” 或者 “接收者(Receiver)”。SPI是全双工通信,所以发送和接收是同时进行的。在每个 Clock 周期内,SPI 设备都会发送并接收一个 bit 大小的数据(不管主设备还是从设备),相当于该设备有一个 bit 大小的数据被交换了。一个 Slave 设备要想能够接收到 Master 发过来的控制信号,必须在此之前能够被 Master 设备进行访问。所以,Master 设备必须首先通过 NSS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上。 在数据传输的过程中,每次接收到的数据必须在下一次数据传输之前被采样。如果之前接收到的数据没有被读取,那么这些已经接收完成的数据将有可能会被丢弃,导致 SPI 物理模块最终失效。因此,在程序中一般都会在 SPI 传输完数据后,去读取 SPI 设备里的数据, 即使这些数据在我们的程序里是无用的(虽然发送后紧接着的读取是无意义的,但仍然需要从寄存器中读出来)。
所以一般在SPI通信中,写数据的时候从机一般会返回一个无效数据。读数据的时候,主机也需要向从机发送一个无效数据
1.3 程序设计
SPI初始化函数
{
时钟线所用到的IO通用推挽输出
MOSI线所用到的IO通用推挽输出
MISO线所用到的IO通用输入
}
具体程序:
/***************************************
*函数名 :spi_io_init
*函数功能 :spi所用IO口初始化配置函数
*函数参数 :无
*函数返回值 :无
*函数描述 :SCK------PA5 通用推挽输出
MOSI-----PA7 通用推挽输出
MISO-----PA6 通用输入
****************************************/
void spi_io_init(void)
{
//端口时钟使能
RCC->AHB1ENR |= (1 << 0);
//端口模式
GPIOA->MODER &= ~((3 << 10) | (3 << 14) | (3 << 12));
GPIOA->MODER |= ((1 << 10) | (1 << 14));
//输出类型
GPIOA->OTYPER &= ~((1 << 5) | (1 << 7));
//输出速率 50M
GPIOA->OSPEEDR &= ~((3 << 10) | (3 << 14));
GPIOA->OSPEEDR |= ((2 << 10) | (2 << 14));
//上下拉
GPIOA->PUPDR &= ~((3 << 10) | (3 << 14) | (3 << 12));
//空闲
GPIOA->ODR &= ~(1 << 5);
}
SPI发送数据和接收数据的规则
发送一位数据一定会接收到一位数据
接收一位数据之前一定要发送一位数据
所以,发送函数和接收函数要写成一个函数.
收发一体函数:
u8 SPI收发一字节函数(u8)
{

最低0.47元/天 解锁文章
2466

被折叠的 条评论
为什么被折叠?



