stm32---ADXL345

ADXL345是一款三轴加速度传感器,广泛用于手机、游戏手柄等设计。
ADXL 支持标准的 I2C 或 SPI 数字接口,自带 32 级 FIFO 存储,并且内 部有多种运动状态检测和灵活的中断方式等特性,常用I2C接口


13367077-399ad5f7008bf43d.PNG
检测轴

初始化步骤
1) 上电
2) 等待 1.1ms
3) 初始化命令序列
4) 结束
其中上电这个动作发生在开发板第一次上电的时候,在上电之后,等待 1.1ms 左右,就可以开始发送初始化序列了,初始化序列一结束, ADXL345 就 开始正常工作了


13367077-d646e76312aae81f.PNG
stm里的硬件电路

adxl345.c

#include "adxl345.h"
#include "iic.h"
#include "math.h"
#include "SysTick.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);   //低电平中断输出,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);  
        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);        //发送寄存器地址(数据缓存的起始地址为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);    //不使用中断      

    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;      
    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++)//连续读取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°.
//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;
}

adxl345.h

#ifndef _adxl345_H
#define _adxl345_H

#include "system.h"



#define DEVICE_ID       0X00    //器件ID,0XE5
#define THRESH_TAP      0X1D    //敲击阀值
#define OFSX            0X1E
#define OFSY            0X1F
#define OFSZ            0X20
#define DUR             0X21
#define Latent          0X22
#define Window          0X23 
#define THRESH_ACK      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 DATA_X0         0X32
#define DATA_X1         0X33
#define DATA_Y0         0X34
#define DATA_Y1         0X35
#define DATA_Z0         0X36
#define DATA_Z1         0X37
#define FIFO_CTL        0X38
#define FIFO_STATUS     0X39


//0X0B TO OX1F Factory Reserved  
//如果ALT ADDRESS脚(12脚)接地,ADXL地址为0X53(不包含最低位).
//如果接V3.3,则ADXL地址为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

main.c



#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "tftlcd.h"
#include "key.h"
#include "adxl345.h"


//x,y:开始显示的坐标位置
//num:要显示的数据
//mode:0,显示加速度值;1,显示角度值;
void ADXL_Show_num(u16 x,u16 y,short num,u8 mode)   //ADXL345显示
{
    u8 valbuf[3];
    if(mode==0)   //显示加速度值
    {
        if(num<0)
        {
            num=-num;
            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16,"-");
        }
        else
        {
            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16," ");
        }
        valbuf[0]=num/100+0x30;
        valbuf[1]=num%100/10+0x30;
        valbuf[2]=num%100%10+0x30;  
        LCD_ShowString(x+10,y,tftlcd_data.width,tftlcd_data.height,16,valbuf);  
    }
    else         //显示角度值
    {
        if(num<0)
        {
            num=-num;
            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16,"-");
        }
        else
        {
            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16," ");
        }
        valbuf[0]=num/10+0x30;
        valbuf[1]='.';
        valbuf[2]=num%10+0x30;  
        LCD_ShowString(x+10,y,tftlcd_data.width,tftlcd_data.height,16,valbuf);      
    }       
}

void data_pros()    //数据处理函数
{
    short x,y,z;
    short xang,yang,zang;   
    u8 key;
    ADXL345_Read_Average(&x,&y,&z,10);  //读取x,y,z 3个方向的加速度值 总共10次
    ADXL_Show_num(60,120,x,0);
    ADXL_Show_num(60,140,y,0);
    ADXL_Show_num(60,160,z,0);

    xang=ADXL345_Get_Angle(x,y,z,1);
    yang=ADXL345_Get_Angle(x,y,z,2);
    zang=ADXL345_Get_Angle(x,y,z,0);
    ADXL_Show_num(60,180,xang,1);
    ADXL_Show_num(60,200,yang,1);
    ADXL_Show_num(60,220,zang,1);

    key=KEY_Scan(0);
    if(key==KEY_UP)       //按下K_UP校准
    {
        led2=0;     //LED2亮表示正在校准
        ADXL345_AUTO_Adjust((char*)&x,(char*)&y,(char*)&z);
        led2=1;    //LED2灭表示校准完成
    }
}

int main()
{
    u8 i=0;

    SysTick_Init(72);
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
    LED_Init();
    USART1_Init(9600);
    TFTLCD_Init();          //LCD初始化
    KEY_Init();
    
    FRONT_COLOR=BLACK;

    LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,"PRECHIN STM32F1");
    LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,"www.prechin.net");
    LCD_ShowString(10,50,tftlcd_data.width,tftlcd_data.height,16,"ADXL345 Test");
    LCD_ShowString(10,90,tftlcd_data.width,tftlcd_data.height,16,"K_UP:ADXL345 Adjust");
    LCD_ShowString(10,120,tftlcd_data.width,tftlcd_data.height,16,"X Val:");
    LCD_ShowString(10,140,tftlcd_data.width,tftlcd_data.height,16,"Y Val:");
    LCD_ShowString(10,160,tftlcd_data.width,tftlcd_data.height,16,"Z Val:");
    LCD_ShowString(10,180,tftlcd_data.width,tftlcd_data.height,16,"X Ang:");
    LCD_ShowString(10,200,tftlcd_data.width,tftlcd_data.height,16,"Y Ang:");
    LCD_ShowString(10,220,tftlcd_data.width,tftlcd_data.height,16,"Z Ang:");
    
    FRONT_COLOR=RED;
    
    while(ADXL345_Init())
    {
        printf("ADXL345 Error!\r\n");
        LCD_ShowString(130,50,tftlcd_data.width,tftlcd_data.height,16,"Error  ");
        delay_ms(200);
    }
    printf("ADXL345 OK!\r\n");
    LCD_ShowString(130,50,tftlcd_data.width,tftlcd_data.height,16,"Success");
    while(1)
    {
        
        i++;
        if(i%20==0)
        {
            led1=!led1;
            data_pros();
        }
        delay_ms(10);
            
    }
    
}
13367077-4a2954821e2a0f43.PNG
4.PNG
  • 11
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值