STM32F407使用SPI协议读取ADXL345三轴加速度注意事项

关于ADXL345三轴加速度模块网上有很多都是关于I2C协议的,关于SPI的很少且对于新手没多少参考价值。于是我拿到模块想用SPI协议来读取信息,我们先来看一下这个模块。

 这个模块一共有10个引脚,在连开发板时,需要用到6个引脚(包括3V3 和 GND),关于引脚的连线我们先看一下官方提供的资料手册。

在一开始,模块默认的SPI协议就是4线,根据手册,我们进行实物连接。

根据实物图进行连接

PB12---CS                 <-------------------->        CS

PB13---SCK               <-------------------->        SCL        

PB14---MISO             <-------------------->        SDO

PB15---MOSI             <-------------------->        SDA

注意不要接反了,3V3,GDN正常接3V3/5V 和 GND就行

 我们这里要仔细阅读ADXL345的手册关于SPI的那一章

我们先来分析这段话

大体意思就是

  1. SPI通信有两种接线方式:SPI是一种常见的通信协议,用于微控制器和传感器之间的数据交换。SPI可以以3线或4线模式工作。3线模式指的是只使用时钟线(SCLK)、数据线(SDI/SDO)和芯片选择线(CS)。4线模式则额外增加了一个数据线(SDO/SDI),专门用于从传感器到微控制器的数据传输。

  2. 通过寄存器设置通信模式:ADXL345内部有一个叫做DATA_FORMAT的寄存器,地址是0x31。通过修改这个寄存器里的一个位(位D6),可以选择是使用3线还是4线SPI模式。如果把位D6清零,就表示使用4线模式;如果把位D6设为1,则表示使用3线模式。

  3. 通信速度和时序:SPI通信的速度由时钟速度决定。这里提到,如果负载电容不超过100皮法拉(pF),SPI的最大时钟速度可以达到5MHz。时钟极性(CPOL)和时钟相位(CPHA)的设置决定了数据在时钟的哪个边缘被采样。这里提到的时钟极性为1、时钟相位为1,意味着数据在时钟的上升沿被采样。

  4. CS引脚的处理:在SPI通信开始之前,需要确保CS(芯片选择)引脚处于高电平。这样做是为了确保在设置好时钟极性和相位之后,传感器处于正确的初始状态。

  5. 3线SPI的特别建议:如果你使用的是3线SPI模式,建议将SDO引脚通过一个10千欧姆(kΩ)的电阻下拉到地,或者直接接到VDD I/O(电源电压)。这是为了确保在通信时,SDO引脚的电平状态是确定的


 大体意思就是

  1. CS线的作用:CS是“Chip Select”的缩写,意为“芯片选择”。在SPI通信中,CS线用于告诉SPI从设备(在这个例子中是ADXL345传感器)“嘿,现在轮到你了,我们开始通信吧”。这根线在开始传输数据之前要设置为低电平,告诉从设备“现在开始传输数据”;传输结束之后,CS线要设置回高电平,表示“传输结束,你可以休息了”。

  2. SCLK线的控制:SCLK代表“Serial Clock”,即串行时钟。这个时钟信号是由SPI主设备(比如STM32微控制器)提供的,它用来同步数据的发送和接收。当没有数据传输发生时,SCLK保持在高电平状态,等待下一次数据传输的开始。

  3. SDI和SDO线:SDI是“Serial Data Input”的缩写,意为串行数据输入;SDO是“Serial Data Output”的缩写,意为串行数据输出。在SPI通信中,SDI线用于从主设备向从设备发送数据,而SDO线则用于从从设备向主设备发送数据。

  4. 数据更新和采样:在SPI通信中,数据在SCLK的下降沿(即时钟信号从高变低的时刻)更新,这意味着在这一刻,主设备和从设备会改变它们发送的数据。而在SCLK的上升沿(即时钟信号从低变高的时刻),主设备会采样从设备发送过来的数据。

  5. 多字节传输:如果你需要一次性发送或接收多个数据字节,就需要使用多字节位(MB)。在第一个字节传输之后,接下来的每个8个时钟脉冲会使得ADXL345自动切换到下一个寄存器进行读取或写入,无需额外的命令。

  6. 传输结束和CS失效:一旦停止发送时钟脉冲,数据传输就会停止,这时CS信号也就失效,表示当前的通信已经结束。

  7. 访问不同的寄存器:如果你需要读取或写入ADXL345中不连续的寄存器,那么在两次传输之间,CS信号必须先失效,然后再激活,以便开始新的传输。

大体意思就是

  1. 时序图的作用:时序图是一种图表,用来展示在SPI通信中,各种信号(比如CS、SCLK、SDI、SDO)随时间变化的状态。图38是针对3线式SPI的读取或写入操作的时序图,而图36和图37则是4线式SPI的读取和写入操作的时序图。这些图帮助我们理解在数据传输过程中,信号应该如何正确地变化。

  2. 逻辑阈值和时序参数:在SPI通信中,有一些关键的参数需要遵守,比如信号的高低电平阈值,以及信号变化的时间点。这些参数确保了数据能够正确无误地被发送和接收。表9和表10中列出了必须满足的逻辑阈值和时序参数,以保证SPI通信的正确性。

  3. 通信速率与输出数据速率(ODR)的匹配:SPI通信速率(也就是SPI时钟的速度)和输出数据速率(ODR,即传感器输出数据的频率)需要相互匹配。如果SPI通信速率很快(2MHz或更高),那么推荐使用较高的ODR,比如3200Hz或1600Hz。如果通信速率慢一些(至少400kHz),那么推荐使用800Hz的ODR。这样做是为了确保数据能够被正确地采样,不会因为速率不匹配而丢失数据或产生噪声。

  4. 速率设置不当的后果:如果你设置的ODR高于推荐的值,那么可能会因为SPI通信速率跟不上而导致数据采样出现问题,比如数据丢失或额外噪声。这就好比一个人试图在很短的时间内读完一本书,结果可能会漏掉一些内容或者读错字

再来看时序图

 总结:    1.相位和极性都配置为1。

                2.在对寄存器进行读时,地址高位为1;对寄存器进行写时地址高位为0。

                3.读取多字节时,次高位也要为1。

啥意思呢?举个例子,假如一个寄存器地址为0X1F如果要读取这个寄存器里面的内容,在往DR寄存器写入指令时,需要将这个地址 或上 0X80,也就是 0X1F | 0X80 ,后面还会实际操作帮助理解。

重点:如果想要获取ADXL345的数据,那么每次就需要发送一个数据来完成数据的交换。不懂的需要自己去复习这相关的知识,这里不再赘述。

代码编写

先看SPI_ADXL345_Init() 初始化

void SPI_ADXL345_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	SPI_InitTypeDef	  SPI_InitStructure;
	
	
	/* 使能 GPIO 时钟 PB13  PB14 PB15 PB12*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	/*spi 时钟使能*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
	
	/*配置引脚:SCK MISO MOSI  PB13 PB14 PB15*/
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; 
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF; //引脚复用
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN; 
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_2MHz; 
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/*配置引脚:CS PB12*/
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12; 
	GPIO_InitStructure.GPIO_Mode= GPIO_Mode_OUT;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/*设置引脚复用*/
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_SPI2);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2);
	
	/* FLASH_SPI 模式配置 */
	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//通讯方向双线全双工
	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//主机模式
	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//数据帧大小是8位
	/* 设置CPOL=1 CPHA=1 */
	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_256;//时钟分频,
	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;//高位先行
	SPI_Init(SPI2,&SPI_InitStructure);
	
	/*使能FLASH_SPI*/
	SPI_Cmd(SPI2,ENABLE);	
	
    /*这里不用管,我是为了测试 */
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
	GPIO_SetBits(GPIOB,GPIO_Pin_12);

}

 需要注意的是,时钟分频从256开始调起,频率不宜太高

先看SPI_ADXL345_SendReadByte() 

uint8_t SPI_ADXL345_SendReadByte(uint8_t byte)
{
    	
    SPITimeOut = 0x1000;
	
	/*等待发送缓冲区为空,TXE标志为1,则说明发送缓冲区为空,可以写数据*/
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE)==RESET)
	{
		/*设置一个等待超时动作,如果一直等待就返回错误值*/
		if((SPITimeOut--)==0)
			/*编写一个回调函数,用作输出错误信息*/
			return SPI_TIMEOUT_USERCALLBACK(0); //这里自己改成普通的printf()就行
	}
	/*写缓冲区,把要发送的数据写入发送缓冲区*/
	SPI_I2S_SendData(SPI2,byte);
	
	
	
	SPITimeOut = 0x1000;
	/*等待接收缓冲区为非空,RXNE标志为1时,表示接收缓冲区接收到了新数据,可以去读*/
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE)==RESET)
	{
		if((SPITimeOut--)==0)
			/*编写一个回调函数,用作输出错误信息*/
			return SPI_TIMEOUT_USERCALLBACK(1);//这里自己改成普通的printf()就行
	}
	return  SPI_I2S_ReceiveData(SPI2);
}

查看ADXL345的手册,我可以看到相关寄存器

 可以看到,发送命令0X00,就能得到ADXL345设备的ID号,验证模块是正常的并且还能验证通信成功。

那么我们是不是只要代码这么写呢:SPI_Flash_SendReadByte(0x00);

回到我们之前那句话:发送指令,地址最高位为 1 代表读,而我们想要读出设备ID,那么就需要将这个 地址    0X00 | 0X80  ----》 1000 0000,其实:后五位代表地址,最高位代表读还是写,次高位代表读取多个字节。所以 获取 ADXL345 的设备ID代码如下:

uint32_t SPI_ADXL345_ReadID(void)
{
	uint32_t temp = 0;
	/*开始通讯,CS低电平*/
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
	
	SPI_Flash_SendReadByte(0x80);
	
	temp = SPI_Flash_SendReadByte(0xFF); //这里0XFF只是为了交换数据读出ID
	
	
	/*结束通讯,CS高电平*/
	GPIO_SetBits(GPIOB,GPIO_Pin_12);
	
	
	return temp;	
}

在main函数中初始化并调用这个函数,结果却发现 ,设备ID读不出来总是 0,反正就是读不出来真正的ID 0XE5。这是为什么呢,相信或许很多人都卡在了这一步。

浪费了我大半天的调试,和验证时序频率,调代码,查资料,终于发现

在模块中有个R4电阻,而ADXL345模块默认是关闭SPI协议的。解决办法就是需要手动将ADXL345 模块上的R4电阻给扣掉。

直接动手开干! 

 再次测试代码

成功读取设备ID号 E5,成功!后续就可以进一步读取三轴加速度信息,实现自己想要的功能啦!

官方的ADXL345手册网上很多,大家一定仔细查阅。关于后续的配置我会看情况继续更新。

  • 39
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
STM32开发指南》第三十四章是关于ADXL345三轴加速度传感器实验的内容。ADXL345是一款数字输出型的三轴加速度传感器,广泛用于运动控制、震动检测等领域。 在这个实验中,我们使用STM32开发板与ADXL345传感器进行连接和通信,并获取其三个轴向的加速度数据。 首先,我们需要通过I2C总线来与ADXL345传感器进行通信。在STM32开发板上,我们需要配置相应的引脚作为I2C总线的SCL和SDA信号线。 其次,我们需要通过STM32的I2C外设来与ADXL345传感器进行数据传输。在实验中,我们需要按照ADXL345的通信协议(通常是SPI或I2C)来编写STM32的I2C读取和写入程序,从而实现与传感器的数据交互。 然后,我们可以通过读取传感器的寄存器来获取其三个轴向的加速度数据。ADXL345传感器具有多个寄存器用于存储其各轴的加速度值。我们需要按照传感器的数据手册来解析和处理这些寄存器中的数据,从而得到实际的加速度值。 最后,我们可以通过适当的算法和数据处理技术来利用获取到的加速度数据。根据应用的需要,我们可以进行震动检测、姿态识别等相关的数据处理和分析。 《STM32开发指南》第三十四章的实验内容详细介绍了如何配置STM32开发板及其外设来与ADXL345传感器进行连接和通信,以及如何获取和处理传感器的加速度数据。通过这个实验,读者可以加深对STM32开发和传感器应用的理解,并能够进一步应用在实际项目中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值