若该文为原创文章,转载请注明原文出处。

一、介绍

ADXL345是三轴加速度传感器,根据官方网站以及官方手册(https://www.analog.com/cn/products/adxl345.html#product-overview)上的描述,它具有以下特性:

1、超低功耗:VS = 2.5 V时(典型值),测量模式下低至23μA,待机模式下为0.1 μA
2、功耗随带宽自动按比例变化
3、用户可选的分辨率:10位固定分辨率/全分辨率
分辨率随g范围提高而提高,±16 g时达到最高分辨率13位(在所有g范围内保持4 mg/LSB的比例系数)

二、通讯方式

根据官方手册可知,通信方式可参考下表:

说明:CS接入高电平则选择IIC通信,反之则SPI通信。SDO(地址引脚)接入高电平,根据手册器件的7位I2C地址是0x1D,后面跟上读取/写入位(R/W),则写寄存器为0x3A,读寄存器为0x3B;接入低电平,则7位I2C地址是0x53,同理,跟上读写标志位后写寄存器为0xA6,读寄存器为0xA7;
 

三、模块原理图

四、和STM32连接方式

这里测试使用的是I2C方式

SDA   ->  PB0

SCL   ->  PB1

3脚为CS脚,CS接入高电平则选择IIC通信, SDO(地址引脚)接入低电平,读写标志位后写寄存器为0xA6,读寄存器为0xA7

五、STM32驱动使用步骤

1、模拟I2C


#define IIC_SDA_PORT_adxl345		GPIOB
#define IIC_SDA_CLK_adxl345			(RCC_APB2Periph_GPIOB)
#define IIC_SDA_PIN_adxl345			GPIO_Pin_0

#define IIC_SCL_PORT_adxl345		GPIOB
#define IIC_SCL_CLK_adxl345			(RCC_APB2Periph_GPIOB)
#define IIC_SCL_PIN_adxl345			GPIO_Pin_1

#define IIC_SCL_OUT_1_adxl345		IIC_SCL_PORT_adxl345->BSRR = (uint32_t)IIC_SCL_PIN_adxl345 // 置1
#define IIC_SCL_OUT_0_adxl345		IIC_SCL_PORT_adxl345->BRR = (uint32_t)IIC_SCL_PIN_adxl345
#define IIC_SDA_OUT_1_adxl345		IIC_SDA_PORT_adxl345->BSRR = (uint32_t)IIC_SDA_PIN_adxl345 // 置1
#define IIC_SDA_OUT_0_adxl345		IIC_SDA_PORT_adxl345->BRR = (uint32_t)IIC_SDA_PIN_adxl345
#define IIC_SDA_IN_adxl345()		((IIC_SDA_PORT_adxl345->IDR & IIC_SDA_PIN_adxl345) != 0)


/**
  * @brief  IIC延时
  * @param  None
  * @retval None
  */
static void IIC_Delay_adxl345(void)
{
	uint8_t i;
	/* 
	 	下面的时间是通过逻辑分析仪测试得到的。
    工作条件:CPU主频72MHz ,MDK编译环境,1级优化
  
		循环次数为10时,SCL频率 = 205KHz 
		循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 
	 	循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us 
	*/
	for (i = 0; i < 10; i++);
}
/**
  * @brief  SDA输出方向配置
  * @param  None
  * @retval None
  */
void Set_IIC_SDA_OUT_adxl345(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_APB2PeriphClockCmd(IIC_SDA_CLK_adxl345, ENABLE);
	GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN_adxl345;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
	GPIO_Init(IIC_SDA_PORT_adxl345,&GPIO_InitStructure); 						
}
/**
  * @brief  SDA输入方向配置
  * @param  None
  * @retval None
  */
void Set_IIC_SDA_IN_adxl345(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_APB2PeriphClockCmd(IIC_SDA_CLK_adxl345, ENABLE);
	GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN_adxl345;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_Init(IIC_SDA_PORT_adxl345,&GPIO_InitStructure);
}
/**
  * @brief  模拟IIC初始化
  * @param  None
  * @retval None
  */
void IIC_init_adxl345()
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(IIC_SDA_CLK_adxl345 | IIC_SCL_CLK_adxl345, ENABLE);
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN_adxl345;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(IIC_SDA_PORT_adxl345, &GPIO_InitStructure);	
	GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN_adxl345;
	GPIO_Init(IIC_SCL_PORT_adxl345, &GPIO_InitStructure);	
	IIC_stop_adxl345();
}
/**
  * @brief  模拟IIC起始信号
  * @param  None
  * @retval None
  */
void IIC_start_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_SDA_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SDA_OUT_0_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();
}
/**
  * @brief  模拟IIC停止信号
  * @param  None
  * @retval None
  */
void IIC_stop_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_SDA_OUT_0_adxl345;
	IIC_Delay_adxl345();
	IIC_SDA_OUT_1_adxl345;
}
/**
  * @brief  模拟IIC主机应答
  * @param  None
  * @retval None
  */
void IIC_ack_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
  IIC_SDA_OUT_0_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();	
	IIC_SDA_OUT_1_adxl345;
}
/**
  * @brief  模拟IIC主机不应答
  * @param  None
  * @retval None
  */
void IIC_noack_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
  IIC_SDA_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();
}
/**
  * @brief  模拟IIC等待从机应答
  * @param  None
	* @retval 1: 接收应答失败 0: 接收应答成功
  */
uint8_t IIC_wait_ack_adxl345()
{
	uint8_t rec = 0;
	Set_IIC_SDA_OUT_adxl345();
	IIC_SDA_OUT_1_adxl345;
	IIC_Delay_adxl345();
	Set_IIC_SDA_IN_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_Delay_adxl345();
	rec = IIC_SDA_IN_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();
	
	return rec;
}
/**
	* @brief  模拟IIC发送一个字节
  * @param  None
  * @retval None
  */
void IIC_send_byte_adxl345(uint8_t txd)
{
	uint8_t i=0;
	Set_IIC_SDA_OUT_adxl345();
	for(i=0;i<8;i++)
	{
		if(txd&0x80) IIC_SDA_OUT_1_adxl345;
		else IIC_SDA_OUT_0_adxl345;
		IIC_Delay_adxl345();
		IIC_SCL_OUT_1_adxl345;
		IIC_Delay_adxl345(); // 发送数据
		IIC_SCL_OUT_0_adxl345;
		if(i == 7) IIC_SDA_OUT_1_adxl345; // 最后一位数据发送完要释放SDA总线
		txd <<= 1;
		IIC_Delay_adxl345();
	}
}
/**
	* @brief  模拟IIC读取一个字节
	* @param  ack: 0,读完不产生应答 1,读完产生应答
  * @retval 返回读取到的字节
  */
uint8_t IIC_read_byte_adxl345(uint8_t ack)
{
	uint8_t i,receive=0;
	Set_IIC_SDA_IN_adxl345();
	for(i=0;i<8;i++)
	{
		receive <<= 1;
		IIC_SCL_OUT_1_adxl345;
		IIC_Delay_adxl345();
		if(IIC_SDA_IN_adxl345()) receive++; // 连续读取八位
		IIC_SCL_OUT_0_adxl345;
		IIC_Delay_adxl345();	
	}
  if(!ack) IIC_noack_adxl345();
	else IIC_ack_adxl345();

	return receive; // 返回读取到的字节
}

	

2、寄存器初始化配置


/**
  * @brief  ADXL345初始化
  * @param  None
  * @retval None
  */
uint8_t ADXL345_init(void)
{
	IIC_init_adxl345();
	if(ADXL345_read_reg(DEVICE_ID) == 0xE5)
	{
		ADXL345_write_reg(DATA_FORMAT,0X0B); // 低电平中断输出,13位全分辨率,输出数据右对齐,16g量程 
		ADXL345_write_reg(BW_RATE,0x0E); // 数据输出速度为100Hz
		ADXL345_write_reg(POWER_CTL,0x08); // 链接使能,测量模式,省电特性
		ADXL345_write_reg(INT_ENABLE,0x80); // 不使用中断		 
	 	ADXL345_write_reg(OFSX,0x00);
		ADXL345_write_reg(OFSY,0x00);
		ADXL345_write_reg(OFSZ,0x05);
		return 0;
	}
	return 1;
}

3、读入数据

/**
  * @brief  ADXL345计算角度
  * @param  None
  * @retval None
  */
void get_angle(float *x_angle,float *y_angle,float *z_angle)
{
  short ax,ay,az;
  ADXL345_read_average(&ax,&ay,&az,10);
  *x_angle=atan(ax/sqrt((az*az+ay*ay)))*180/3.14;
  *y_angle=atan(ay/sqrt((ax*ax+az*az)))*180/3.14;
  *z_angle=atan(sqrt((ax*ax+ay*ay)/az))*180/3.14;
}

六、源码

/*
ADXL345三轴倾斜度模块
*/
#include "ADXL345.h"
#include "delay.h"
#include "math.h"


#define IIC_SDA_PORT_adxl345		GPIOB
#define IIC_SDA_CLK_adxl345			(RCC_APB2Periph_GPIOB)
#define IIC_SDA_PIN_adxl345			GPIO_Pin_0

#define IIC_SCL_PORT_adxl345		GPIOB
#define IIC_SCL_CLK_adxl345			(RCC_APB2Periph_GPIOB)
#define IIC_SCL_PIN_adxl345			GPIO_Pin_1

#define IIC_SCL_OUT_1_adxl345		IIC_SCL_PORT_adxl345->BSRR = (uint32_t)IIC_SCL_PIN_adxl345 // 置1
#define IIC_SCL_OUT_0_adxl345		IIC_SCL_PORT_adxl345->BRR = (uint32_t)IIC_SCL_PIN_adxl345
#define IIC_SDA_OUT_1_adxl345		IIC_SDA_PORT_adxl345->BSRR = (uint32_t)IIC_SDA_PIN_adxl345 // 置1
#define IIC_SDA_OUT_0_adxl345		IIC_SDA_PORT_adxl345->BRR = (uint32_t)IIC_SDA_PIN_adxl345
#define IIC_SDA_IN_adxl345()		((IIC_SDA_PORT_adxl345->IDR & IIC_SDA_PIN_adxl345) != 0)


/**
  * @brief  IIC延时
  * @param  None
  * @retval None
  */
static void IIC_Delay_adxl345(void)
{
	uint8_t i;
	/* 
	 	下面的时间是通过逻辑分析仪测试得到的。
    工作条件:CPU主频72MHz ,MDK编译环境,1级优化
  
		循环次数为10时,SCL频率 = 205KHz 
		循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 
	 	循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us 
	*/
	for (i = 0; i < 10; i++);
}
/**
  * @brief  SDA输出方向配置
  * @param  None
  * @retval None
  */
void Set_IIC_SDA_OUT_adxl345(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_APB2PeriphClockCmd(IIC_SDA_CLK_adxl345, ENABLE);
	GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN_adxl345;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
	GPIO_Init(IIC_SDA_PORT_adxl345,&GPIO_InitStructure); 						
}
/**
  * @brief  SDA输入方向配置
  * @param  None
  * @retval None
  */
void Set_IIC_SDA_IN_adxl345(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_APB2PeriphClockCmd(IIC_SDA_CLK_adxl345, ENABLE);
	GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN_adxl345;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_Init(IIC_SDA_PORT_adxl345,&GPIO_InitStructure);
}
/**
  * @brief  模拟IIC初始化
  * @param  None
  * @retval None
  */
void IIC_init_adxl345()
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(IIC_SDA_CLK_adxl345 | IIC_SCL_CLK_adxl345, ENABLE);
	GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN_adxl345;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(IIC_SDA_PORT_adxl345, &GPIO_InitStructure);	
	GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN_adxl345;
	GPIO_Init(IIC_SCL_PORT_adxl345, &GPIO_InitStructure);	
	IIC_stop_adxl345();
}
/**
  * @brief  模拟IIC起始信号
  * @param  None
  * @retval None
  */
void IIC_start_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_SDA_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SDA_OUT_0_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();
}
/**
  * @brief  模拟IIC停止信号
  * @param  None
  * @retval None
  */
void IIC_stop_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_SDA_OUT_0_adxl345;
	IIC_Delay_adxl345();
	IIC_SDA_OUT_1_adxl345;
}
/**
  * @brief  模拟IIC主机应答
  * @param  None
  * @retval None
  */
void IIC_ack_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
  IIC_SDA_OUT_0_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();	
	IIC_SDA_OUT_1_adxl345;
}
/**
  * @brief  模拟IIC主机不应答
  * @param  None
  * @retval None
  */
void IIC_noack_adxl345()
{
	Set_IIC_SDA_OUT_adxl345();
  IIC_SDA_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_Delay_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();
}
/**
  * @brief  模拟IIC等待从机应答
  * @param  None
	* @retval 1: 接收应答失败 0: 接收应答成功
  */
uint8_t IIC_wait_ack_adxl345()
{
	uint8_t rec = 0;
	Set_IIC_SDA_OUT_adxl345();
	IIC_SDA_OUT_1_adxl345;
	IIC_Delay_adxl345();
	Set_IIC_SDA_IN_adxl345();
	IIC_SCL_OUT_1_adxl345;
	IIC_Delay_adxl345();
	rec = IIC_SDA_IN_adxl345();
	IIC_SCL_OUT_0_adxl345;
	IIC_Delay_adxl345();
	
	return rec;
}
/**
	* @brief  模拟IIC发送一个字节
  * @param  None
  * @retval None
  */
void IIC_send_byte_adxl345(uint8_t txd)
{
	uint8_t i=0;
	Set_IIC_SDA_OUT_adxl345();
	for(i=0;i<8;i++)
	{
		if(txd&0x80) IIC_SDA_OUT_1_adxl345;
		else IIC_SDA_OUT_0_adxl345;
		IIC_Delay_adxl345();
		IIC_SCL_OUT_1_adxl345;
		IIC_Delay_adxl345(); // 发送数据
		IIC_SCL_OUT_0_adxl345;
		if(i == 7) IIC_SDA_OUT_1_adxl345; // 最后一位数据发送完要释放SDA总线
		txd <<= 1;
		IIC_Delay_adxl345();
	}
}
/**
	* @brief  模拟IIC读取一个字节
	* @param  ack: 0,读完不产生应答 1,读完产生应答
  * @retval 返回读取到的字节
  */
uint8_t IIC_read_byte_adxl345(uint8_t ack)
{
	uint8_t i,receive=0;
	Set_IIC_SDA_IN_adxl345();
	for(i=0;i<8;i++)
	{
		receive <<= 1;
		IIC_SCL_OUT_1_adxl345;
		IIC_Delay_adxl345();
		if(IIC_SDA_IN_adxl345()) receive++; // 连续读取八位
		IIC_SCL_OUT_0_adxl345;
		IIC_Delay_adxl345();	
	}
  if(!ack) IIC_noack_adxl345();
	else IIC_ack_adxl345();

	return receive; // 返回读取到的字节
}

	


/**
  * @brief  ADXL345初始化
  * @param  None
  * @retval None
  */
uint8_t ADXL345_init(void)
{
	IIC_init_adxl345();
	if(ADXL345_read_reg(DEVICE_ID) == 0xE5)
	{
		ADXL345_write_reg(DATA_FORMAT,0X0B); // 低电平中断输出,13位全分辨率,输出数据右对齐,16g量程 
		ADXL345_write_reg(BW_RATE,0x0E); // 数据输出速度为100Hz
		ADXL345_write_reg(POWER_CTL,0x08); // 链接使能,测量模式,省电特性
		ADXL345_write_reg(INT_ENABLE,0x80); // 不使用中断		 
	 	ADXL345_write_reg(OFSX,0x00);
		ADXL345_write_reg(OFSY,0x00);
		ADXL345_write_reg(OFSZ,0x05);
		return 0;
	}
	return 1;
}
/**
  * @brief  ADXL345写寄存器
  * @param  None
  * @retval None
  */
uint8_t ADXL345_write_reg(u8 addr,u8 val) 
{
	IIC_start_adxl345();  				 
	IIC_send_byte_adxl345(slaveaddress); // 发送写器件指令	 
	if(IIC_wait_ack_adxl345())
	{
		return 1;
	}    
  IIC_send_byte_adxl345(addr); // 发送寄存器地址
	if(IIC_wait_ack_adxl345())
	{
		return 2;
	} 	 										  		   
	IIC_send_byte_adxl345(val); // 发送值					   
	if(IIC_wait_ack_adxl345())
	{
		return 3;
	}   		    	   
  IIC_stop_adxl345(); // 产生一个停止条件 	   
	return 0;
}
/**
  * @brief  ADXL345读寄存器
  * @param  None
  * @retval None
  */
u8 ADXL345_read_reg(u8 addr)
{
	u8 temp=0;		 
	IIC_start_adxl345();  				 
	IIC_send_byte_adxl345(slaveaddress); // 发送写器件指令	 
	if(IIC_wait_ack_adxl345())
	{
		return 1;
	}   
  IIC_send_byte_adxl345(addr); // 发送寄存器地址
	if(IIC_wait_ack_adxl345())
	{
		return 2;
	}  										  		   
	IIC_start_adxl345(); // 重新启动
	IIC_send_byte_adxl345(regaddress); // 发送读器件指令	 
	if(IIC_wait_ack_adxl345())
	{
		return 3;
	} 	   
  temp=IIC_read_byte_adxl345(0); // 读取一个字节,不继续再读,发送NAK
  IIC_stop_adxl345(); // 产生一个停止条件 	    
	return temp;
}
/**
  * @brief  ADXL345读取数据
  * @param  None
  * @retval None
  */
void ADXL345_read_data(short *x,short *y,short *z)
{
	u8 buf[6];
	u8 i;
	IIC_start_adxl345();  				 
	IIC_send_byte_adxl345(slaveaddress); // 发送写器件指令	 
	IIC_wait_ack_adxl345();	   
  IIC_send_byte_adxl345(0x32); // 发送寄存器地址(数据缓存的起始地址为0X32)
	IIC_wait_ack_adxl345(); 	 										  		   
 
 	IIC_start_adxl345(); // 重新启动
	IIC_send_byte_adxl345(regaddress); // 发送读器件指令
	IIC_wait_ack_adxl345();
	for(i=0;i<6;i++)
	{
		if(i==5)buf[i]=IIC_read_byte_adxl345(0); // 读取一个字节,不继续再读,发送NACK  
		else buf[i]=IIC_read_byte_adxl345(1);	// 读取一个字节,继续读,发送ACK 
 	}	        	   
  IIC_stop_adxl345();	// 产生一个停止条件
	*x=(short)(((u16)buf[1]<<8)+buf[0]); // 合成数据    
	*y=(short)(((u16)buf[3]<<8)+buf[2]); 	    
	*z=(short)(((u16)buf[5]<<8)+buf[4]); 
}
/**
  * @brief  ADXL345连读读取几次取平均值
  * @param  None
  * @retval None
  */
void ADXL345_read_average(short *x,short *y,short *z,u8 times)
{
	u8 i;
	short tx,ty,tz;
	*x=0;
	*y=0;
	*z=0;
	if(times)//读取次数不为0
	{
		for(i=0;i<times;i++)//连续读取times次
		{
			ADXL345_read_data(&tx,&ty,&tz);
			*x+=tx;
			*y+=ty;
			*z+=tz;
			delay_ms(5);
		}
		*x/=times;
		*y/=times;
		*z/=times;
	}
}
/**
  * @brief  ADXL345计算角度
  * @param  None
  * @retval None
  */
void get_angle(float *x_angle,float *y_angle,float *z_angle)
{
  short ax,ay,az;
  ADXL345_read_average(&ax,&ay,&az,10);
  *x_angle=atan(ax/sqrt((az*az+ay*ay)))*180/3.14;
  *y_angle=atan(ay/sqrt((ax*ax+az*az)))*180/3.14;
  *z_angle=atan(sqrt((ax*ax+ay*ay)/az))*180/3.14;
}


测试数据正常,直接通过仿真查看数据。

通过更改ADXL345模块方位,摇晃等,可以明显看出xyz发送了改变,说明我们已经驱动ADXL345模块,同时能获取相关数据。可后期对该数据进行采集,平均值,卡尔曼滤波等处理,使得更加稳定。

如有侵权,或需要完整代码,请及时联系博主。

更多推荐