【SPI协议】

一、SPI介绍

SPI是“全双工”通信,具有单独的发送和接收线,可以同时进行发送和接收,从机不主动发起访问,总是被动执行操作

SPI包含4根逻辑线:
MISO: 主机输入,从机输出
MOSI: 主机输出,从机输入
SCLK: 串行时钟信号,此信号由主机产生。从机不产生时钟信号。
CS: 片选信号,由主机产生,用来控制与哪个从机通信,通常是低电平为选中。

SPI有个时钟极性需要配置,也就是需要配置时钟极性(CPOL)和时钟相位(CPHA),时钟极性和相位共同决定读取数据的方式,也就是说我在什么时候进行取数据。
CPOL: 0 时钟空闲时为低电平
CPOL: 1 时钟空闲时为高电平
CPHA: 0 在时钟信号SCK的第一个跳变沿采样
CPHA: 1 在时钟信号SCK的第二个跳变沿采样

SPI的时钟极性和相位的配置通常称为 SPI模式,遵循以下约定:
在这里插入图片描述
SPI通讯的优势
使SPI作为串行通信接口脱颖而出的原因很多;

全双工串行通信;
高速数据传输速率。
简单的软件配置;
极其灵活的数据传输,不限于8位,它可以是任意大小的字;
非常简单的硬件结构。从站不需要唯一地址(与I2C不同)。从机使用主机时钟,不需要精密时钟振荡器/晶振(与UART不同)。不需要收发器(与CAN不同)。

SPI的缺点
没有硬件从机应答信号(主机可能在不知情的情况下无处发送);
通常仅支持一个主设备;
需要更多的引脚(与I2C不同);
没有定义硬件级别的错误检查协议;
与RS-232和CAN总线相比,只能支持非常短的距离;

二、SPI使用举例

SPI如何实现读写呢?
不同的从机芯片读写方式不同,如下为ADXL345加速度传感器的读写时序,其时序方案按照时钟极性(CPOL)= 1、 时钟相位(CPHA)= 1执行,读写如下如:
在这里插入图片描述
SPI写入寄存器:
ADXL345写寄存器的方式是:如上图写时先发送寄存器地址值随后是寄存器值,则SPI写寄存器的程序如下:

/* SPI向从机寄存器写数据 */
int Single_Write(unsigned char REG_Address,unsigned char REG_data)
{
    int ret = 0;
	uint32_t timeout = 1000;
    uint8_t data[2] = {0}; //构造数据结构,用于发送spi数据
	
	data[0] = REG_Address;
	data[1] = REG_data;
	uint16_t size = sizeof(data);
	
    HAL_GPIO_WritePin(GPIOA, CS_PIN, GPIO_PIN_RESET); //片选拉低,开始通信
    ret = HAL_SPI_Transmit(&hspi1, data, size, timeout); //SPI发送2字节数据
	if (ret != HAL_OK)
	{
		printf("SPI Transmit err ret = %d\n",ret);
		return -1;
	}
    
    HAL_GPIO_WritePin(GPIOA, CS_PIN, GPIO_PIN_SET);	 //片选拉高,通信结束
	return 0;
}

SPI读取寄存器:
ADXL345 读寄存器方式:最高位为1表示读取,所以想要实现读取寄存器,要spi写一个最高位为1的数据(uint8_t txData = REG_Address | 0x80; // 设置读取标志位)。随后ADXL345被动向主机发送寄存器的值数据。SPI读寄存器程序如下:

/*SPI单字节读取*/
unsigned char Single_Read(unsigned char REG_Address)
{   
    int ret = 0;
    uint8_t rxData;
	
    uint8_t txData = REG_Address | 0x80; //构造要发送的数据,MSB位置1
    
	HAL_GPIO_WritePin(GPIOA, CS_PIN, GPIO_PIN_RESET); //片选拉低,开始通信
	ret = HAL_SPI_Transmit(&hspi1, &txData, 1, HAL_MAX_DELAY); //spi发送1字节数据
    if (ret != HAL_OK)
    {
	    printf("SPI Transmit err ret = %d\n",ret);
	    return 0;
    } 
    HAL_SPI_Receive(&hspi1, &rxData, 1, HAL_MAX_DELAY); //SPI读取1字节数据
    HAL_GPIO_WritePin(GPIOA, CS_PIN, GPIO_PIN_SET); //通信完毕,片选拉高
    return rxData;
}

看下读取ADXL345设备ID,示波器抓到的时序:
在这里插入图片描述
注:不同的芯片SPI的读取方式可能不同,例如W25Q16之类存储芯片是通过发送不同的指令来实现读写的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值