ADXL345加速度传感器(IIC协议 STM32)

目录

一、介绍

二、传感器原理

1.原理图

2.引脚描述

3.工作原理:常用寄存器

4.工作原理:角度计算

三、程序设计

main.c文件

adxl345.h文件

adxl345.c文件

四、实验效果 

五、资料获取

项目分享


一、介绍

        ADXL345是一款由Analog DevicesADI公司生产的三轴数字加速度传感器。它常用于消费电子、工业自动化、运动检测、游戏设备和医疗仪器等应用领域。可以同时测量XYZ三个轴的加速度和倾斜角度,支持自由空间运动和倾斜角度检测,支持I²CSPI数字接口,方便与微控制器和其他数字设备进行通信。

以下是ADXL345加速度传感器的参数:

供电电压 

DC:3~5V

使用芯片

ADXL345

通信方式

IIC/SPI通信协议

测量范围

±16g

分辨率

13

哔哩哔哩视频链接:

ADXL345加速度传感器(IIC协议 STM32)

(资料分享见文末) 

二、传感器原理

1.原理图

2.引脚描述

引脚名称

描述

VCC

供给电压5V

GND

地线

SCL

时钟线

SDA

数据线

INT1

中断1输出

INT2

中断2输出

3.工作原理:常用寄存器

下面介绍一些该传感器的控制指令常用寄存器

 

4.工作原理:角度计算

  加速度传感器Z轴与自然坐标系Z轴的夹角:     

  加速度传感器X轴与自然坐标系X轴的夹角:

  加速度传感器Y轴与自然坐标系Y轴的夹角:

三、程序设计

1.使用STM32F103C8T6读取ADXL345加速度传感器采集的数据,通过串口发送至电脑

2.将读取得到的温湿度数据同时在OLED上显示

ADXL345_SCL

PB7

ADXL345_SDA

PB6

OLED_SCL

PB11

OLED_SDA

PB10

串口

串口1

main.c文件

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"	 
#include "OLED.h"
#include "string.h" 	
#include "adxl345.h"

/*****************辰哥单片机设计******************
											STM32
 * 项目			:	ADXL345加速度传感器实验                   
 * 版本			: V1.0
 * 日期			: 2024.8.15
 * MCU			:	STM32F103C8T6
 * 接口			:	见adxl345.h							
 * BILIBILI	    :	辰哥单片机设计
 * CSDN			:	辰哥单片机设计
 * 作者			:	辰哥

**********************BEGIN***********************/

float x_angle,y_angle,z_angle;

int main(void)
{	
	unsigned char p[16]=" ";

	short temperature = 0; 				//温度值
	delay_init(72);	  
  LED_Init();		  				//初始化与控制设备连接的硬件接口
	OLED_Init();					//OLED初始化
	delay_ms(50);
	OLED_Clear();						//清屏
	//显示“角度:”
	OLED_ShowChinese(0,0,0,16,1);
	OLED_ShowChinese(16,0,1,16,1);
	OLED_ShowChar(40,0,':',16,1);
	OLED_ShowChar(25,20,'X',16,1);
	OLED_ShowChar(62,20,'Y',16,1);
	OLED_ShowChar(100,20,'Z',16,1);
	ADXL345_Init();	

	delay_ms(1000);
	USART1_Config();//串口初始化
	
 	while(1)
	{	
			get_angle(&x_angle,&y_angle,&z_angle);
		
			printf("      %2.1f  %2.1f  %2.1f \n ",x_angle,y_angle,z_angle);
			sprintf((char*)p,"%4.1f  ",(float)x_angle);
			OLED_ShowString(0,40,p ,16,1);
		
			sprintf((char*)p,"%4.1f  ",(float)y_angle);
			OLED_ShowString(40,40,p ,16,1);
		
			sprintf((char*)p,"%4.1f  ",(float)z_angle);
			OLED_ShowString(90,40,p ,16,1);
		
			delay_ms(100);
	}	
}

adxl345.h文件

#ifndef __ADXL345_H
#define __ADXL345_H
#include "sys.h"

/*****************辰哥单片机设计******************
											STM32
 * 文件			:	ADXL345传感器h文件                   
 * 版本			:   V1.0
 * 日期			:   2024.8.15
 * MCU			:	STM32F103C8T6
 * 接口			:	见代码							
 * BILIBILI	    :	辰哥单片机设计
 * CSDN			:	辰哥单片机设计
 * 作者			:	辰哥

**********************BEGIN***********************/

/***************根据自己需求更改****************/
//ADXL345引脚宏定义						

#define ADXL345_SCL_PORT  			GPIOB
#define ADXL345_SCL_PIN					GPIO_Pin_7
#define ADXL345_SCL_GPIO_CLK  	RCC_APB2Periph_GPIOB
#define ADXL345_SDA_PORT  			GPIOB
#define ADXL345_SDA_PIN					GPIO_Pin_6
#define ADXL345_SDA_GPIO_CLK   	RCC_APB2Periph_GPIOB

#define ADXL345_IIC_SCL    	PBout(7) //SCL
#define ADXL345_IIC_SDA    	PBout(6) //SDA	 
#define ADXL345_READ_SDA		PBin(6)  //输入SDA 

/*********************END**********************/

#define X_AXLE 0   //x轴
#define Y_AXLE 1   //y轴
#define Z_AXLE 2   //z轴

#define	slaveaddress   0xA6	  //定义器件在IIC总线中的从地址,根据ALT  ADDRESS地址引脚不同修改
//                              ALT  ADDRESS引脚接地时地址为0xA6,接电源时地址为0x3A

#define THRESH_TAP     0X1D	  //敲击中断阈值(用于正常敲击检测)
//                              16g模式中,62.5mg/Bit

#define OFSX           0X1E   //X轴偏移寄存器  15.6mg/Bit  0xff = 4g
#define OFSY           0X1F   //Y轴偏移寄存器  15.6mg/Bit  0xff = 4g
#define OFSZ           0X20   //Z轴偏移寄存器  15.6mg/Bit  0xff = 4g
#define DUR            0x21   //敲击阈值时间   625uS/Bit
#define LATENT         0X22   //敲击事件到时间窗口的延迟时间,在此期间
//                              可检测第二次敲击时间  1.25mg/Bit
#define WINDOW         0X23   //敲击窗口,延迟时间满后的时间量,在此期间
//                              能开始进行第二次有效敲击  1.25mg/Bit
#define THRESH_ACT     0X24   //检测活动的阈值,活动事件的幅度与该寄存器
//                              的值进行比较  62.5mg/Bit
#define	THRESH_INACT   0X25   //检测静止的阈值,静止事件的幅度与该寄存器
//                              的值进行比较  62.5mg/Bit
#define TIME_INACT     0X26   //加速度时间量小于该寄存器的值表示静止 1S/Bit

#define ACT_INACT_CTL  0X27 
//Bit  7,3  ACT交流/直流[INACT交流/直流]:0选择直流耦合;1使能交流耦合 直流时将
//                                       当前加速度值直接与THRESH_ACT和THRESH_INACT
//                                       进行比较,确定检测到的是活动还是静止
//     6,2  ACT_X使能[INACT_X使能]:设置为1,使能X轴参与检测活动或静止;活动检测时,
//                                 所有轴为逻辑"或",有任意轴超过阈值时,活动功能触发
//                                 禁止检测时,所有轴为逻辑"与",只有当所有轴低于阈值
//                                 时,静止功能触发
//     5,1  ACT_Y使能[INACT_Y使能]:与X轴类似 
//     4,0  ACT_Z使能[INACT_Z使能]:与X轴类似
#define THRESH_FF      0X28   //阈值,用于自由落体检测,所有轴加速度与该寄存器值比较
//                              ,以确定是否发生自由落体 62.5mg/Bit,建议300mg与600mg之间
#define TIME_FF        0X29   //维持THRESH_FF阈值的最小时间,以生成自由落体中断 5mS/Bit

#define TAP_AXES       0X2A   
// Bit  7:4  0
//       3   抑制  两次敲击之间出现大于THRESH_TAP值得加速度,设置抑制会抑制双击检测
//       2   TAP_X使能  设置为1时,使能X轴进行敲击检测,0时排除该轴的敲击检测
//       1   TAP_Y使能  设置为1时,使能Y轴进行敲击检测,0时排除该轴的敲击检测
//       0   TAP_Z使能  设置为1时,使能Z轴进行敲击检测,0时排除该轴的敲击检测
#define ACT_TAP_STATUS 0X2B   /*只读寄存器*/
// Bit  7   0
//     6,2  ACT_X来源,TAP_X来源:表示涉及敲击或活动事件的第一轴,设置为1时,对应事件参与
//                              设置为0时,对应未参与.不会自动清零,新数据覆盖,中断清零前
//                              应读取该寄存器
//     5,1	ACT_Y来源,TAP_Y来源:与X相似
//     4,0	ACT_Z来源,TAP_Z来源:与X相似
//      3   休眠设置为1时,器件进入休眠状态
#define BW_RATE        0X2C  
// Bit  7:5   0
//       4	 LOW_POWER 低功耗位,0选择正常模式,1进入低功耗模式
//      3:0  速率位
#define POWER_CTL      0X2D
// Bit  7,6   0
//       5    链接   设置1时,延迟活动开始,直到检测到静止.检测到活动后,禁止检测开始,活动
//                   检测停止,设置时动态链接活动和静止交替检测;设置0时静止与活动同时检测
//       4    AUTO_SLEEP  设置1时自动休眠,检测出静止后,进行休眠模式,活动使能后被唤醒
//       3    测量   0待机 1测量模式
//       2	  休眠   0普通 1休眠
//      1,0	  唤醒(休眠模式下的读取频率) "00":8HZ  "01":4HZ  "10":2HZ  "11":1HZ
#define INT_ENABLE     0X2E  //中断使能配置
// Bit  7  DATA_READY
//      6  SINGLE_TAP
//      5  DOUBLE_TAP
//      4  Activity
//      3  Inactivity
//      2  FREE_FALL   自由落体中断
//      1  Watermark
//      0  Overrun
#define INT_MAP        0X2F   //中断映射 自读寄存器
//位与INT_ENABLE对应,,设置为0,该中断映射到INT1引脚;设置为1,该中断映射到INT2引脚
#define INT_SOURCE     0X30   //中断来源
//位与INT_ENABLE对应,1表示该功能触发
#define DATA_FORMAT    0X31
// Bit   7  SELF_TEST  设置1,自测力应用至传感器,造成输出数据转换;0时禁用自测力
//       6  SPI        1设置为3线SPI模式,0时设置4线SPI模式
//       5  INT_INVERT 0时中断高电平有效,1时低电平有效
//       4	0
//       3  FULL_RES   1时设置全分辨率模式,输出以4mg/Bit增加;0时为10位模式
//       2  Justify    1为左对齐模式;8为右对齐模式,并带有符号扩展
//      1:0 范围位     "00"±2g  "01"±4g  "10"±8g  "11"±16g
#define DATAX0         0X32
#define DATAX1         0X33  //与DATAX0组成x轴输出数据(二进制补码),DATAX1为高位,4mg/Bit
#define DATAY0         0X34
#define DATAY1         0X35  //与DATAY0组成Y轴输出数据(二进制补码),DATAY1为高位,4mg/Bit
#define DATAZ0         0X36
#define DATAZ1         0X37  //与DATAZ0组成Z轴输出数据(二进制补码),DATAZ1为高位,4mg/Bit
#define FIFO_CTL       0X38
// Bit  7,6  FIFO_MODE  "00" 旁路模式
//						"01" FIFO模式 可收集最多32个值,然后停止收集数据
//						"10" 流模式   FIFO保存最后32个数据值,FIFO满时,新数据覆盖最早数据(先进先出)
//						"11" 触发器   通过触发位触发,FIFO在触发事件前保存最后的数据样本,然后
//									  继续收集数据直到填满;填满后,不再收集新数据
//		 5   触发位     0链接触发器模式下的触发事件至INT1,1链接至INT2
//		 4:0 样本		功能取决于FIFO模式:FIFO模式时,指定触发水印中断需要的FIFO条目数
//                                         流模式时,指定触发水印中断需要的FIFO条目数
//                                         触发器模式:指定触发事件之前在FIFO缓冲区要保留的FIFO样本数
//                      样本位设置为0时,不管哪种FIFO模式,立即在INT_SOURCE寄存器设置水印状态位
#define FIFO_STATUS    0X39	  /*只读寄存器*/
// Bit   7   FIFO_TRIG  FIFO_TRIG为1时表示有触发事件发生 
//       6   0
//      5:0	 条目位 报告FIFO存储的数据值的数量

//#define slaveaddress 0XA6//write
#define regaddress 0XA7//read
#define DEVICE_ID 0X00

void ADXL345_IIC_SDA_Mode(u8 mode);//ADXL345引脚输出模式控制
void ADXL345_IIC_SDA_OUT(void);
void ADXL345_IIC_SDA_IN(void);
void ADXL345_IIC_Init(void);
void ADXL345_IIC_Start(void);
void ADXL345_IIC_Stop(void);
void ADXL345_IIC_Ack(void);
void ADXL345_IIC_NAck(void);
u8 ADXL345_IIC_Wait_Ack(void);
void ADXL345_IIC_Send_Byte(u8 txd);
u8 ADXL345_IIC_Read_Byte(u8 ack);

void ADXL345_Init(void);
u8 adxl345_read_reg(u8 addr);
void adxl345_write_reg(u8 addr,u8 val);
void adxl345_read_data(short *x,short *y,short *z);
void adxl345_read_average(float *x,float *y,float *z,u8 times);
void ADXL345_Start(void);
void ADXL345_Stop(void);
void get_angle(float *x_angle,float *y_angle,float *z_angle);
#endif

adxl345.c文件

#include "adxl345.h"
#include "delay.h"
#include "math.h"

/*****************辰哥单片机设计******************
											STM32
 * 文件			:	ADXL345加速度传感器c文件                   
 * 版本			:   V1.0
 * 日期			:   2024.8.15
 * MCU			:	STM32F103C8T6
 * 接口			:	见ADXL345.h文件							
 * BILIBILI	    :	辰哥单片机设计
 * CSDN			:	辰哥单片机设计
 * 作者			:	辰哥

**********************BEGIN***********************/			

//ADXL345引脚输出模式控制
void ADXL345_IIC_SDA_OUT(void)//SDA输出方向配置
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	
	GPIO_InitStructure.GPIO_Pin=ADXL345_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//SDA推挽输出
	GPIO_Init(ADXL345_SDA_PORT,&GPIO_InitStructure); 						

}

void ADXL345_IIC_SDA_IN(void)//SDA输入方向配置
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	
	GPIO_InitStructure.GPIO_Pin=ADXL345_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//SCL上拉输入
	GPIO_Init(ADXL345_SDA_PORT,&GPIO_InitStructure);
	
}
//以下为模拟IIC总线函数
void ADXL345_IIC_Init()
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(ADXL345_SCL_GPIO_CLK, ENABLE);	 	//使能SCL端口时钟
	GPIO_InitStructure.GPIO_Pin = ADXL345_SCL_PIN;					//配置为推挽输出,SCL
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 		//IO口速度为50MHz
	GPIO_Init(ADXL345_SCL_PORT, &GPIO_InitStructure);				
	GPIO_SetBits(ADXL345_SCL_PORT,ADXL345_SCL_PIN); 
	
	RCC_APB2PeriphClockCmd(ADXL345_SDA_GPIO_CLK, ENABLE);	 	//使能SDA端口时钟
	GPIO_InitStructure.GPIO_Pin = ADXL345_SDA_PIN;					//配置为推挽输出,SDA
	GPIO_SetBits(ADXL345_SDA_PORT,ADXL345_SDA_PIN); 
	
//	I2C_SCL_H;
//	I2C_SDA_H;//均拉高
}
void ADXL345_IIC_Start()
{
	ADXL345_IIC_SDA_OUT();
	ADXL345_IIC_SDA=1;	  	  
	ADXL345_IIC_SCL=1;
	delay_us(5);
	ADXL345_IIC_SDA=0;
	delay_us(5);
	ADXL345_IIC_SCL=0;
}
void ADXL345_IIC_Stop()
{
	ADXL345_IIC_SDA_OUT();
	ADXL345_IIC_SCL=0;
	ADXL345_IIC_SDA=0;
	delay_us(5);
	ADXL345_IIC_SCL=1; 
	ADXL345_IIC_SDA=1;
	delay_us(5);
}
//主机产生一个应答信号
void ADXL345_IIC_Ack()
{
	ADXL345_IIC_SCL=0;
	ADXL345_IIC_SDA_OUT();
	ADXL345_IIC_SDA=0;
	
	delay_us(2);
	ADXL345_IIC_SCL=1;
	delay_us(5);
	ADXL345_IIC_SCL=0;	
}
//主机不产生应答信号
void ADXL345_IIC_NAck()
{
	ADXL345_IIC_SCL=0;
	ADXL345_IIC_SDA_OUT();
	ADXL345_IIC_SDA=1;
	delay_us(2);
	ADXL345_IIC_SCL=1;
	delay_us(2);
	ADXL345_IIC_SCL=0;
}
//等待从机应答信号
//返回值:1 接收应答失败
//		  0 接收应答成功
u8 ADXL345_IIC_Wait_Ack()
{
	u8 tempTime=0;
	ADXL345_IIC_SDA_IN();
	ADXL345_IIC_SDA=1;
	delay_us(1);
	ADXL345_IIC_SCL=1;
	delay_us(1);

	while(ADXL345_READ_SDA)
	{
		tempTime++;
		if(tempTime>250)
		{
			ADXL345_IIC_Stop();
			return 1;
		}	 
	}

	ADXL345_IIC_SCL=0;
	return 0;
}
void ADXL345_IIC_Send_Byte(u8 txd)
{
	u8 i=0;
	ADXL345_IIC_SDA_OUT();
	ADXL345_IIC_SCL=0;;//拉低时钟开始数据传输
	for(i=0;i<8;i++)
	{
		ADXL345_IIC_SDA=(txd&0x80)>>7;//读取字节
		txd<<=1;
		ADXL345_IIC_SCL=1;
		delay_us(2); //发送数据
		ADXL345_IIC_SCL=0;
		delay_us(2);
	}
}
//读取一个字节
u8 ADXL345_IIC_Read_Byte(u8 ack)
{
	u8 i=0,receive=0;
	ADXL345_IIC_SDA_IN();
   for(i=0;i<8;i++)
   {
			ADXL345_IIC_SCL=0;
			delay_us(2);
			ADXL345_IIC_SCL=1;
			receive<<=1;//左移
			if(ADXL345_READ_SDA)
			receive++;//连续读取八位
			delay_us(1);	
   }

   	if(!ack)
	   	ADXL345_IIC_NAck();
	else
		ADXL345_IIC_Ack();

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



//传感器初始化
void ADXL345_Init()
{
		ADXL345_IIC_Init();
	
		adxl345_write_reg(0X31,0X0B);		//低电平中断输出,13位全分辨率,输出数据右对齐,16g量程 
		adxl345_write_reg(0x2C,0x0B);		//数据输出速度为100Hz
		adxl345_write_reg(0x2D,0x08);		//链接使能,测量模式,省电特性
		adxl345_write_reg(0X2E,0x80);		//不使用中断		 
	 	adxl345_write_reg(0X1E,0x00);
		adxl345_write_reg(0X1F,0x00);
		adxl345_write_reg(0X20,0x05);	
	
	
}
//写寄存器函数
void adxl345_write_reg(u8 addr,u8 val) 
{
	ADXL345_IIC_Start();  				 
	ADXL345_IIC_Send_Byte(slaveaddress);     	//发送写器件指令	 
	ADXL345_IIC_Wait_Ack();	   
  ADXL345_IIC_Send_Byte(addr);   			//发送寄存器地址
	ADXL345_IIC_Wait_Ack(); 	 										  		   
	ADXL345_IIC_Send_Byte(val);     		//发送值					   
	ADXL345_IIC_Wait_Ack();  		    	   
	ADXL345_IIC_Stop();						//产生一个停止条件 	   
}
//读寄存器函数
u8 adxl345_read_reg(u8 addr)
{
	u8 temp=0;		 
	ADXL345_IIC_Start();  				 
	ADXL345_IIC_Send_Byte(slaveaddress);	//发送写器件指令	 
	temp=ADXL345_IIC_Wait_Ack();	   
    ADXL345_IIC_Send_Byte(addr);   		//发送寄存器地址
	temp=ADXL345_IIC_Wait_Ack(); 	 										  		   
	ADXL345_IIC_Start();  	 	   		//重新启动
	ADXL345_IIC_Send_Byte(regaddress);	//发送读器件指令	 
	temp=ADXL345_IIC_Wait_Ack();	   
    temp=ADXL345_IIC_Read_Byte(0);		//读取一个字节,不继续再读,发送NAK 	    	   
    ADXL345_IIC_Stop();					//产生一个停止条件 	    
	return temp;
}
//读取数据函数
void adxl345_read_data(short *x,short *y,short *z)
{
	u8 buf[6];
	u8 i;
	ADXL345_IIC_Start();  				 
	ADXL345_IIC_Send_Byte(slaveaddress);	//发送写器件指令	 
	ADXL345_IIC_Wait_Ack();	   
    ADXL345_IIC_Send_Byte(0x32);   		//发送寄存器地址(数据缓存的起始地址为0X32)
	ADXL345_IIC_Wait_Ack(); 	 										  		   
 
 	ADXL345_IIC_Start();  	 	   		//重新启动
	ADXL345_IIC_Send_Byte(regaddress);	//发送读器件指令
	ADXL345_IIC_Wait_Ack();
	for(i=0;i<6;i++)
	{
		if(i==5)buf[i]=ADXL345_IIC_Read_Byte(0);//读取一个字节,不继续再读,发送NACK  
		else buf[i]=ADXL345_IIC_Read_Byte(1);	//读取一个字节,继续读,发送ACK 
 	}	        	   
    ADXL345_IIC_Stop();					//产生一个停止条件
	*x=(short)(((u16)buf[1]<<8)+buf[0]); 	//合成数据    
	*y=(short)(((u16)buf[3]<<8)+buf[2]); 	    
	*z=(short)(((u16)buf[5]<<8)+buf[4]); 
}
//连读读取几次取平均值函数
//times 取平均值的次数
void adxl345_read_average(float *x,float *y,float *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;
	}
}
void get_angle(float *x_angle,float *y_angle,float *z_angle)
{
	float 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;
//return x_angle;
}

四、实验效果 

五、资料获取

项目分享

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值