SPI通信过程详解以及相关代码实现

1、概述

SPI是Serial Perripheral Interface的简称,是由Motorola公司推出的一种高速、全双工的总线协议。
SPI也是采用主从方式工作,一般由**SCLK(时钟线)、CS(片选信号)、MOSI(主机输出,从机输入),MISO(主机输入,从机输出)**四根线组成,当有多个从机存在时,主机就需要多个CS信号引脚,每个CS引脚信号对应一个从机,主机可以通过相应的CS来选择要控制的从机设备。
如下图所示,SCLK、MOSI,MISO这三根线都是公用的,唯有片选信号线(CS)是和从机一一对应的。
SPI通信主从机接线图

2、四种工作模式

根据SPI时钟极性(CPOL)和时钟相位(CPHA)配置的不同可分为4种模式。
1、CPOL = 1:表示SCLK时钟信号空闲时是高电平;CPHA = 0:表示从第一个跳变沿开始采样;
在这里插入图片描述

2、CPOL = 1:表示SCLK时钟信号空闲时是高电平;CPHA = 1:表示从第二个跳变沿开始采样;
在这里插入图片描述

3、CPOL = 0:表示SCLK时钟信号空闲时是低电平;CPHA = 0:表示从第一个跳变沿开始采样;
在这里插入图片描述
4、CPOL = 0:表示SCLK时钟信号空闲时是低电平;CPHA = 1:表示从第二个跳变沿开始采样;
在这里插入图片描述

3、数据交换

SPI 设备间的数据传输之所以又被称为数据交换,是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 “发送者(Transmitter)” 或者 “接收者(Receiver)”。SPI是全双工通信,所以发送和接收是同时进行的。在每个 Clock 周期内,SPI 设备都会发送并接收一个 bit 大小的数据(不管主设备还是从设备),相当于该设备有一个 bit 大小的数据被交换了。一个 Slave 设备要想能够接收到 Master 发过来的控制信号,必须在此之前能够被 Master 设备进行访问 (Access)。所以,Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上。 在数据传输的过程中,每次接收到的数据必须在下一次数据传输之前被采样。如果之前接收到的数据没有被读取,那么这些已经接收完成的数据将有可能会被丢弃,导致 SPI 物理模块最终失效。因此,在程序中一般都会在 SPI 传输完数据后,去读取 SPI 设备里的数据, 即使这些数据(Dummy Data)在我们的程序里是无用的(虽然发送后紧接着的读取是无意义的,但仍然需要从寄存器中读出来)。
所以一般在SPI通信中,写数据的时候从机一般会返回一个无效数据。读数据的时候,主机也需要向从机发送一个无效数据。

uint8_t SPI_ReadWrite_Byte(uint8_t TxData,uint8_t *RcvMsg)
{	
	uint8_t uState = BSP_OK;
	uint16_t i=0;
	while( !LL_SPI_IsActiveFlag_TXE(SPI1) ) //判断发送缓存器里是否为空。空返回1.
	{
		if(++i>=500)
		{
			uState = BSP_ERR;
			break;
		}
	}
	LL_SPI_TransmitData8(SPI1, TxData);
	i= 0;
	while(!LL_SPI_IsActiveFlag_RXNE(SPI1))   //判断接收寄存器里是否有数据,有数据返回1 
	{
		if(++i>=500)
		{
			uState = BSP_ERR;
			break;
		}
	}
	*RcvMsg = LL_SPI_ReceiveData8(SPI1);
	return uState;
}
写地址调用函数:SPI_ReadWrite_Byte( addrTemp, &date );  //其中返回的data无意义

读数据调用函数:SPI_ReadWrite_Byte( 0xFF, &date );  //其中0xFF为无效数据
  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴为您解答这个问题。以下是针对STM32-24位AD7799驱动手册代码详解的简要说明。 首先,AD7799是一款24位精度的模数转换器,可用于测量各种传感器的输出信号。它可通过SPI接口与微控制器(如STM32通信,以读取和写入寄存器值。 在STM32中,可以采用模拟SPI或硬件SPI与AD7799通信,具体实现方式取决于使用的STM32型号和开发环境。以下是一些可能使用的代码和说明: 1. 模拟SPI方式: ```c // 初始化GPIO口 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化SPI void SPI_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB,&GPIO_InitStructure); } void AD7799_SPI_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); SPI_InitTypeDef SPI_InitStructure; 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_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); } // SPI发送数据 uint8_t AD7799_SPI_Write(uint8_t data) { uint8_t i; for(i = 0; i < 8; i++) { if(data & 0x80) GPIO_SetBits(GPIOB, GPIO_Pin_9); else GPIO_ResetBits(GPIOB, GPIO_Pin_9); data <<= 1; GPIO_ResetBits(GPIOB, GPIO_Pin_10); GPIO_SetBits(GPIOB, GPIO_Pin_10); } return data; } // SPI接收数据 uint8_t AD7799_SPI_Read(void) { uint8_t i, data = 0; for(i = 0; i < 8; i++) { data <<= 1; GPIO_ResetBits(GPIOB, GPIO_Pin_10); if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)) data |= 0x01; GPIO_SetBits(GPIOB, GPIO_Pin_10); } return data; } ``` 2. 硬件SPI方式: ```c // 初始化SPI void AD7799_SPI_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); SPI_InitTypeDef SPI_InitStructure; 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_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); } // SPI发送数据 uint8_t AD7799_SPI_Write(uint8_t data) { while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, data); while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); } ``` 上述代码只是示例,具体实现方式需要根据您的应用场景进行调整。同时,还需要编写读取和写入AD7799寄存器的函数,例如: ```c // AD7799写寄存器函数 void AD7799_WriteReg(uint8_t reg, uint16_t value) { AD7799_SPI_Write(reg << 3); AD7799_SPI_Write(value >> 8); AD7799_SPI_Write(value & 0xFF); } // AD7799读寄存器函数 uint16_t AD7799_ReadReg(uint8_t reg) { uint16_t value = 0; AD7799_SPI_Write((reg << 3) | 0x04); value |= AD7799_SPI_Read() << 8; value |= AD7799_SPI_Read(); return value; } ``` 以上是一个简单的STM32-24位AD7799驱动手册代码详解。希望能帮助到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值