本帖最后由 正点原子 于 2013-3-22 23:41 编辑
//读取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; } 该部分代码总共有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的数值和角度也跟着变化。 |