三轴加速度传感器ADXL345 一、ADXL345是一款三轴、数字化的加速度传感器,它能测X、Y、Z三个方向轴上的加速度,它可以在倾斜检测应用中测量静态重力加速度,还可以测量运动或冲击导致的动态加速度。 二、特点:A.可达到最高13位的全分辨率。 B.具有+/-2g,+/-4g,+/-8g,+/-16g,几个不同的可选量程。 C.灵敏度高,最高可达3.9 mg/LSB(一般的ADC的位数为10位,当量程为+/-2g时,数字化后,即2^10LSB/4g=256LSB/g,期1g的加速度对应的输出为256,灵敏度则为其倒数即1/(256LSB/g)=3.9mg/LSB) D.低功耗,40~145uA 的超低功耗,待机模式只有 0.1uA。 E. IC 尺寸很小,只有 3mm*5mm*1mm, LGA 封装。 X、Y、Z三轴 三、当 ADXL345 沿检测轴正向加速时,它对正加速度进行检测。在检测重力时当检测轴的方向与重力的方向相反时检测到的才是正加速度。 四、ADXL345引脚配置图 引脚功能描述: 1. VDD I/O:数字接口电源电压。 2、4、5GND:该引脚必须接地。 3.RESERVED:保留。该引脚必须连接到VS或保持断开。 6.VS:电源电源。 7. CS:片选 8、9.INT1/INT2:中断1/2输出 10.NC:内部不连接 11.RESERVED:保留。该引脚必须接地或保持断开。 12.SDO/ALT ADDRESS:串行数据输出(SPI 4线)/备用I2C地址选择(I2C)。 13.SDA/SDI/SDIO:串行数据(I2C)/串行数据输入(SPI 4线)/串行数据输入和输出(SPI 3线)。 14.SCL/SCLK:串行通信时钟。SCL为I2C时钟,SCLK为SPI时钟。 五、相关硬件连接知识 用三根线将 STM32 与 ADXL345连接,主函数通过查询 ADXL345 得到 x、 y 和 z 三个方向的加速度值(读数值),然后将其转换为与自然系坐标的角度,并将结果在 LCD 模块上显示出来。DS0 来指示程序正在运行,通过按下WK_UP 按键,可以进行 ADXL345 的自动校准( DS1 用于提示正在校准)。所要用到的硬件资源如下: 1) 指示灯 DS0、 DS1 2) WK_UP 按键 3) TFTLCD 模块 4) ADXL345 ADXL345接口与 MCU (STM32F1O3)的连接原理图如下: ADXL345 通过三根线与 STM32 开发板连接,其中 IIC 总线接在 PB10 和 PB11 上面。 ADXL345 的两个中断输出, 选用其中的INT1,连接在 STM32 的 PF11 脚,另外这里的地址线是接 3.3V,所以 ADXL345 的地址是 0X1D,转换为 0X3A 写入, 0X3B 读取。(如果ALT ADDRESS脚(12脚)接地, ADXL345地址为0X53(不包含最低位),0XA7写入和0XA6读取) 1. ADXL345 的初始化步骤如下: 1) 上电 2) 等待 1.1ms 3) 初始化命令序列 4) 结束 其中上电这个动作发生在开发板第一次上电的时候,在上电之后,等待 1.1ms 左右,就可以开始发送初始化序列了,初始化序列一结束, ADXL345 就开始正常工作了。 这里的初始化序列,最简单的只需要配置 3 个寄存器DATA_FORMAT 、 POWER_CTL 、INT_ENABLE,下面对三个寄存器做简单介绍: 0x31 DATA_FORMAT 数据格式控制寄存器(读/写) D7 D6 D5 D4 D3 D2 D1 D0 SELF_TEST SPI INT_INVERT 0 FULL_RES JUSTIFY JUSTIFY D DATA_FORMAT 0x31寄存器控制寄存器0x32至0x37(即0x32 DATAX0 X轴数据0 , 0x33 DATAX1 X轴数据1(只读), 0x34 DATAY0 Y轴数据0 , 0x35 DATAY1 Y轴数据1(只读), 0x36 DATAZ0 Z轴数据0 , 0x37 DATAZ1 Z轴数据1(只读),其中DATAx/y/z0是低字节,DATAx/y/z1是高字节)的数据输出格式。超出±16 g范围以外的所有数据必须剪除,避免溢出。 SELF_TEST位:置“1” 自测力应用至传感器,造成输出数据转换,置“0”禁用自测力。 SPI位:置“1”使设备工作在3线SPI模式,置“0”使设备工作在4线SPI模式。 INT_INVERT位:置“1”中断为低电平有效,置“0”中断为高电平有效。 FULL_RES位:置“1”全分辨率模式(13位),设备输出分辨率4mg/LSB。置“0”10位模式,输出范围由RANGE位确定。 JUSTIFY位:置“1”左对齐,置“0”右对齐并进行符号扩展。 RANGE:设置测量范围,见下表 D1 D0 范围 0 0 ±2g 0 1 ±4g 1 0 ±8g 1 1 ±16g 0x2D POWER_CTL 省电特性控制 D7 D6 D5 D4 D3 D2 D1 D0 0 0 Link AUTO_SLEEP Measure Sleep WakeUp Link(链接)位:置1,该为能使能活动和静止功能,检测到静止是活动检测开始,关闭静止检测,同理,检测到活动时,开启静止检测同时关闭活动检测。置0,静止检测和活动检测同时开启。 AUTO_SLEEP位:置1,自动休眠功能使能。该模式下,如果使能静止功能,检测出静止,则 ADXL345自动切换到休眠模式。置0,禁止自动切换到休眠模式。 Measure位:置1,器件处于测量模式,置0,处于待机模式。 Sleep位:置1,休眠模式,此时将禁用DATA_READY,停止向FIFO发送数据,采样速率由WakeUp位确定,置0,正常工作模式。 WakeUp位:控制休眠模式下的读取频率,如下表: D1 D0 休眠模式采样频率(Hz) 0 0 8 0 1 4 1 0 2 1 1 1 0x2E INT_ENABLE 中断使能控制 D7 D6 D5 D4 DATA_READY SINGLE_TAP DOUBLE_TAP 活动 D3 D2 D1 D0 静止 FREE_FALL WaterMark OverRun 该寄存器各位置1,则使能对应中断功能,置0则不使用相对应中断。其中不管INT_ENABLE寄存器设置如何,如果有相应的事件发生,总是设置DATA_READY位、WaterMark(水印)位和OverRun(溢出)位,并通过读取DATAX、 DATAY和DATAZ寄存器将数据清零。 2.ADXL345相关模块网络程序参考学习 adxl345.c: #include "adxl345.h" #include "sys.h" #include "delay.h" #include "math.h" //初始化 ADXL345. //返回值:0,初始化成功;1,初始化失败. u8 ADXL345_Init(void) { IIC_Init(); //初始化 IIC 总线 if(ADXL345_RD_Reg(DEVICE_ID)==0XE5) //读取器件 ID { ADXL345_WR_Reg(DATA_FORMAT,0X2B); // 0禁用自测力,1低电平有效,1全分辨模式,0右对齐,//11测量范围±16g,则0010 1011———> 0x2B ADXL345_WR_Reg(BW_RATE,0x0A); //数据输出速度为 100Hz ADXL345_WR_Reg(POWER_CTL,0x28); //链接使能,测量模式 ADXL345_WR_Reg(INT_ENABLE,0x00); //不使用中断 ADXL345_WR_Reg(OFSX,0x00); //X轴偏移为0 ADXL345_WR_Reg(OFSY,0x00); // y轴偏移为0 ADXL345_WR_Reg(OFSZ,0x00); // z轴偏移为0 return 0; } return 1; } //写 ADXL345 寄存器 //addr:寄存器地址 //val:要写入的值 //返回值:无 void ADXL345_WR_Reg(u8 addr,u8 val) { IIC_Start(); IIC_Send_Byte(ADXL_WRITE); //发送写器件指令 IIC_Wait_Ack(); IIC_Send_Byte(addr); //发送寄存器地址 IIC_Wait_Ack(); IIC_Send_Byte(val); //发送值 IIC_Wait_Ack(); IIC_Stop(); //产生一个停止条件 } //读 ADXL345 寄存器 //addr:寄存器地址 //返回值:读到的值 u8 ADXL345_RD_Reg(u8 addr) { u8 temp=0; IIC_Start(); IIC_Send_Byte(ADXL_WRITE); //发送写器件指令 temp=IIC_Wait_Ack(); IIC_Send_Byte(addr); //发送寄存器地址 temp=IIC_Wait_Ack(); IIC_Start(); //重新启动 IIC_Send_Byte(ADXL_READ); //发送读器件指令 temp=IIC_Wait_Ack(); temp=IIC_Read_Byte(0); //读取一个字节,不继续再读,发送 NAK IIC_Stop(); //产生一个停止条件 return temp; //返回读到的值 } //读取 ADXL 的平均值 //x,y,z:读取 10 次后取平均值 void ADXL345_RD_Avval(short *x,short *y,short *z) //x、y、z为short型 { short tx=0,ty=0,tz=0; //数据清零 u8 i; for(i=0;i<10;i++) { ADXL345_RD_XYZ(x,y,z); delay_ms(10); tx+=(short)*x; ty+=(short)*y; tz+=(short)*z; } *x=tx/10; *y=ty/10; *z=tz/10; } //自动校准 //xval,yval,zval:x,y,z 轴的校准值 void ADXL345_AUTO_Adjust(char *xval,char *yval,char *zval) { short tx,ty,tz; u8 i; short offx=0,offy=0,offz=0; ADXL345_WR_Reg(POWER_CTL,0x00); //清除寄存器原来的设置. delay_ms(100); ADXL345_WR_Reg(DATA_FORMAT,0X2B); //低电平中断输出,13 位全分辨率,输出数据右对齐,16g 量程 ADXL345_WR_Reg(BW_RATE,0x0A); //数据输出速度为 100Hz ADXL345_WR_Reg(POWER_CTL,0x28); //链接使能,测量模式 ADXL345_WR_Reg(INT_ENABLE,0x00); //不使用中断 ` ADXL345_WR_Reg(OFSX,0x00); ADXL345_WR_Reg(OFSY,0x00); ADXL345_WR_Reg(OFSZ,0x00); delay_ms(12); for(i=0;i<10;i++) { ADXL345_RD_Avval(&tx,&ty,&tz); offx+=tx; offy+=ty; offz+=tz; } offx/=10; offy/=10; offz/=10; *xval=-offx/4; *yval=-offy/4; *zval=-(offz-256)/4; //结果强制转换为char型,全分辨 //率下,每个输出LSB为3.9 mg或偏移寄存器LSB的四分之一。由于偏移寄存器为附加寄存器, //0 g值被否定,并四舍五入至最接近偏移寄存器的LSB:(round为四舍五入计算) //XOFFSET = −Round(offx/4) , YOFFSET = −Round(offy/4) ,其中由于静止时XY轴数据接近0,而 //z轴接近255,所以ZOFFSET = −Round[(offz-256)/4] ,其中offz-256相当于调转Z轴,此时三个//轴静止时数据都接近0,并且他们的结果要取补码 ADXL345_WR_Reg(OFSX,*xval); ADXL345_WR_Reg(OFSY,*yval); ADXL345_WR_Reg(OFSZ,*zval); } //读取 3 个轴的数据 //x,y,z:读取到的数据 void ADXL345_RD_XYZ(short *x,short *y,short *z) { u8 buf[6],i; IIC_Start(); IIC_Send_Byte(ADXL_WRITE); //发送写器件指令 IIC_Wait_Ack(); IIC_Send_Byte(0x32); //发送寄存器地址(数据缓存的起始地址为 0X32) IIC_Wait_Ack(); IIC_Start(); //重新启动 IIC_Send_Byte(ADXL_READ); //发送读器件指令 IIC_Wait_Ack(); for(i=0;i<6;i++) { if(i==5)buf[i]=IIC_Read_Byte(0); //读取一个字节,不继续再读,发送 NACK else buf[i]=IIC_Read_Byte(1); //读取一个字节,继续读,发送 ACK } IIC_Stop(); //产生一个停止条件 *x=(short)(((u16)buf[1]<<8)+buf[0]); // 将两个8位字节转化为16位的高8位和低8位 *y=(short)(((u16)buf[3]<<8)+buf[2]); *z=(short)(((u16)buf[5]<<8)+buf[4]); } //读取 ADXL345 的数据 times 次,再取平均 //x,y,z:读到的数据 //times:读取多少次 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_RD_XYZ(&tx,&ty,&tz); *x+=tx; *y+=ty; *z+=tz; delay_ms(5); } *x/=times; *y/=times; *z/=times; } } //得到角度 //x,y,z:x,y,z 方向的重力加速度分量(不需要单位,直接数值即可) //dir:要获得的角度.0,与 Z 轴的角度;1,与 X 轴的角度;2,与 Y 轴的角度. //返回值:角度值.单位 0.1° . short ADXL345_Get_Angle(float x,float y,float z,u8 dir) { float temp,res=0; switch(dir) { case 0://与自然 Z 轴的弧度 temp=sqrt((x*x+y*y))/z; res=atan(temp); break; case 1://与自然 X 轴的弧度 temp=x/sqrt((y*y+z*z)); res=atan(temp); break; case 2://与自然 Y 轴的弧度 temp=y/sqrt((x*x+z*z)); res=atan(temp); break; } return res*1800/3.14; //把弧度转化为角度 } |
|