//得到角度
//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;
}
该部分代码总共有8个函数,这里我们仅介绍其中4个。首先是ADXL345_Init函数,该函数用来初始化ADXL345,和前面我们提到的步骤差不多,不过本章我们而是采用查询的方式来读取数据的,所以在这里并没有开启中断。另外3个偏移寄存器,都默认设置为0。
其次,我们介绍ADXL345_RD_XYZ函数,该函数用于从ADXL345读取数据,通过该函数可以读取ADXL345的转换结果,得到三个轴的加速度值(仅是数值,并没有转换单位)。
接着,我们介绍ADXL345_AUTO_Adjust函数,该函数用于ADXL345的校准,ADXL345有偏移校准的功能,该功能的详细介绍请参考ADXL345数据手册的第29页,偏移校准部分。这里我们就不细说了,如果不进行校准的话,ADXL345的读数可能会有些偏差,通过校准,我们可以讲这个偏差减少甚至消除。
最后,我们看看ADXL345_Get_Angle函数,该函数根据ADXL345的读值,转换为与自然坐标系的角度。计算公式如下:
其中Ax,Ay,Az分别代表从ADXL345读到的X,Y,Z方向的加速度值。通过该函数,我们只需要知道三个方向的加速度值,就可以将其转换为对应的弧度值,再通过弧度角度转换,就可以得到角度值了。
其他函数,我们就不介绍了,也比较简单。保存adxl345.c,然后把该文件加入HARDWARE组下。接下来打开adxl345.h在该文件里面加入如下代码:
#ifndef __ADXL345_H
#define __ADXL345_H
#include "myiic.h"
#define DEVICE_ID 0X00 //器件ID,0XE5
#define THRESH_TAP 0X1D //敲击阀值
……省略部分寄存器定义
#define FIFO_STATUS 0X39
//0X0B TO OX1F Factory Reserved
//如果ALT ADDRESS脚(12脚)接地,IIC地址为0X53(不包含最低位).
//如果接V3.3,则IIC地址为0X1D(不包含最低位).
//开发板接V3.3,所以转为读写地址后,为0X3B和0X3A(如果接GND,则为0XA7和0XA6)
#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次,取平均
short ADXL345_Get_Angle(float x,float y,float z,u8 dir);
#endif
上面的代码省略了部分寄存器的定义,其他部分比较简单,我们不作介绍。保存adxl345.h,然后在test.c里面修改代码如下:
//x,y:开始显示的坐标位置
//num:要显示的数据
//mode:0,显示加速度值;1,显示角度值;
void Adxl_Show_Num(u16 x,u16 y,short num,u8 mode)
{
if(mode==0) //显示加速度值
{
if(num<0)
{
LCD_ShowChar(x,y,'-',16,0); //显示负号
num=-num; //转为正数
}else LCD_ShowChar(x,y,' ',16,0); //去掉负号
LCD_ShowNum(x+8,y,num,4,16); //显示值
}else //显示角度值
{
if(num<0)
{
LCD_ShowChar(x,y,'-',16,0); //显示负号
num=-num; //转为正数
}else LCD_ShowChar(x,y,' ',16,0); //去掉负号
LCD_ShowNum(x+8,y,num/10,2,16); //显示整数部分
LCD_ShowChar(x+24,y,'.',16,0); //显示小数点
LCD_ShowNum(x+32,y,num%10,1,16); //显示小数部分
}
}
int main(void)
{
u8 key;
u8 t=0;
short x,y,z;
short angx,angy,angz;
Stm32_Clock_Init(9); //系统时钟设置
uart_init(72,9600); //串口初始化为9600
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init(); //初始化LCD
usmart_dev.init(72); //初始化USMART
KEY_Init(); //按键初始化
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,200,16,16,"WarShip STM32");
LCD_ShowString(60,70,200,16,16,"3D TEST");
LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(60,110,200,16,16,"2012/9/12");
LCD_ShowString(60,130,200,16,16,"KEY0:Auto Adjust");
while(ADXL345_Init()) //3D加速度传感器初始化
{
LCD_ShowString(60,150,200,16,16,"ADXL345 Error");
delay_ms(200);
LCD_Fill(60,150,239,150+16,WHITE);
delay_ms(200);
}
LCD_ShowString(60,150,200,16,16,"ADXL345 OK");
LCD_ShowString(60,170,200,16,16,"X VAL:");
LCD_ShowString(60,190,200,16,16,"Y VAL:");
LCD_ShowString(60,210,200,16,16,"Z VAL:");
LCD_ShowString(60,230,200,16,16,"X ANG:");
LCD_ShowString(60,250,200,16,16,"Y ANG:");
LCD_ShowString(60,270,200,16,16,"Z ANG:");
POINT_COLOR=BLUE;//设置字体为红色
while(1)
{
if(t%10==0)//每100ms读取一次
{
//得到X,Y,Z轴的加速度值(原始值)
ADXL345_Read_Average(&x,&y,&z,10); //读取X,Y,Z三个方向的加速度值
Adxl_Show_Num(60+48,170,x,0); //显示加速度原始值
Adxl_Show_Num(60+48,190,y,0);
Adxl_Show_Num(60+48,210,z,0);
//得到角度值,并显示
angx=ADXL345_Get_Angle(x,y,z,1);
angy=ADXL345_Get_Angle(x,y,z,2);
angz=ADXL345_Get_Angle(x,y,z,0);
Adxl_Show_Num(60+48,230,angx,1); //显示角度值
Adxl_Show_Num(60+48,250,angy,1);
Adxl_Show_Num(60+48,270,angz,1);
}
key=KEY_Scan(0);
if(key==KEY_UP)
{
LED1=0;//绿灯亮,提示校准中
ADXL345_AUTO_Adjust((char*)&x,(char*)&y,(char*)&z);//自动校准
LED1=1;//绿灯灭,提示校准完成
}
delay_ms(10);
t++;
if(t==20)
{
t=0;
LED0=!LED0;
}
}
}
此部分代码除了main函数,还有一个Adxl_Show_Num函数,该函数用于数据显示,因为在ILI93xx.c里面,没有提供可以显示小数和负数的函数,所以我们这里编写了该函数,来实现小数和负数的显示,以满足本章要求。
其他部分,我们就不多说了。至此,我们的软件设计部分就结束了。
34.4 下载验证 在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32开发板上,可以看到LCD显示如图34.4.1所示的内容:
图34.4.1 程序运行时LCD显示内容
可以看到,X方向和Z方向的角度有些大(最佳值是0),所以我们按下WK_UP键,进行一次校准(注意校准的时候保持开发板水平,并且稳定),校准后如图34.4.2所示:
图34.4.2 校准后
可以看到,校准后,比未校准前好了很多,此时我们移动开发板到不同角度,可以看到X、Y、Z的数值和角度也跟着变化。