一、方向判断
注意看管脚1,x,y,z三轴如图所示,当重力加速度方向与坐标轴方向相反时为正,重力加速度方向与坐标轴相同时为负。
二、驱动
采用了IIC接口,实际上也支持SPI接口。
ADXL345.h:
#ifndef _ADXL345_H
#define _ADXL345_H
typedef unsigned char u8;
//0x0B To 0x1F Factory Reserved
#define DEVICE_ID 0x00 //器件ID,0xE5
#define THRESH_TAP 0x1D //敲击阈值
#define OFSX 0x1E //X轴偏移
#define OFSY 0x1F //Y轴偏移
#define OFSZ 0x20 //Z轴偏移
#define DUR 0x21 //敲击持续时间
#define Latent 0x22 //敲击延时
#define Window 0x23 //敲击窗口
#define THRESH_ACT 0x24 //活动阈值
#define THRESH_INACT 0x25 //静止阈值
#define TIME_INACT 0x26 //静止时间
#define ACT_INACT_CTL 0x27 //轴使能控制活动和静止检测
#define THRESH_FF 0x28 //自由落体阈值
#define TIME_FF 0x29 //自由落体时间
#define TAP_AXES 0x2A //单击/双击轴控制
#define ACT_TAP_STATUS 0x2B //单击/双击源
#define BW_RATE 0x2C //数据速率及功率模式控制
#define POWER_CTL 0x2D //省电特性控制
#define INT_ENABLE 0x2E //中断使能控制
#define INT_MAP 0x2F //中断映射控制
#define INT_SOURCE 0x30 //中断源
#define DATA_FORMAT 0x31 //数据格式控制
#define DATAX0 0x32 //X轴数据0
#define DATAX1 0x33 //X轴数据1
#define DATAY0 0x34 //Y轴数据0
#define DATAY1 0x35 //Y轴数据1
#define DATAZ0 0x36 //Z轴数据0
#define DATAZ1 0x37 //Z轴数据1
#define FIFO_CTL 0x38 //FIFO控制
#define FIFO_STATUS 0x39 //FIFO状态
//如果ALT ADDRESS脚(12脚)接地,ADXL 7位地址为0x53,第8位为R/W,0xA7为读,0xA6为写
//如果ALT ADDRESS脚(12脚)接3.3V,ADXL 7位地址为0x1D,第8位为R/W,0x3B为读,0x3A为写
#define ADXL_READ 0x3B
#define ADXL_WRITE 0x3A
u8 ADXL345_Init(void);//初始化ADXL345
void ADXL345_WR_Reg(u8 addr, u8 val);//写ADXL345寄存器
u8 ADXL345_RD_Reg(u8 addr); //读ADXL345寄存器
void ADXL345_RD_XYZ(short *x, short *y, short *z);//读取一个值
void ADXL345_RD_Avval(short *x, short *y, short *z);//读取平均值
void ADXL345_AUTO_Adjust(char *xval,char *yval, char *zval);//自动校准
void ADXL345_Read_Average(short *x, short *y, short *z, u8 times);//连续读取times次,取平均
void ADXL345_Get_Angle(float x, float y, float z, u8 dir);
#endif
ADXL345.c:
#include "ADXL345.h"
#include "math.h"
//初始化ADXL345,返回值:0-初始化成功, 1-初始化失败
u8 ADXL345_Init(void)
{
IIC_Init();
if(ADXL345_RD_Reg(DEVICE_ID)==0xE5)//固定为0xE5
{
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);//不使用中断
//X轴,Y轴,Z轴偏移设置为0
ADXL345_WR_Reg(OFSX,0x00);
ADXL345_WR_Reg(OFSY,0x00);
ADXL345_WR_Reg(OFSZ,0x00);
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; //返回读到的值
}
//读取3个轴的数据,x,y,z:读取到的数据
void ADXL345_RD_XYZ(short *x, short *y, short *z)
{
u8 buf[6];
u8 i;
IIC_Start();
IIC_Send_Byte(ADXL_WRITE);//发送写器件指令
IIC_Wait_Ack();
IIC_Send_Byte(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]);
*y=(short)(((u16)buf[3]<<8)+buf[2]);
*z=(short)(((u16)buf[5]<<8)+buf[4]);
}
//读取ADXL的平均值,x,y,z:读取10次后取平均值
void ADXL345_RD_Avval(short *x, short *y, short *z)
{
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);//不使用中断
//X轴,Y轴,Z轴偏移设置为0
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;
//灵敏度为256LSB/g,OFSX,OFSY,OFSZ的寄存器比例因子为15.6mg/LSB
//15.6/(1000/256)=3.9936,近似为4,又因为校准置于z轴1g的重力场下,Zog=Z+1g-Sz Sz为灵敏度256
*xval=-offx/4;
*yval=-offy/4;
*zval=-(offz-256)/4;
ADXL345_WR_Reg(OFSX,*xval);
ADXL345_WR_Reg(OFSY,*yval);
ADXL345_WR_Reg(OFSZ,*zval);
}
//读取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++)
{
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°,与自然坐标系轴的角度
//res得到的是弧度值,需要将其转换成角度值也就是*180/3.14
short ADXL345_Get_Angle(float x, float y, float z, u8 dir)
{
float temp;
float 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*180/3.14;
}