stm32---ADXL345

作者: 飞向深空 | 来源:发表于2019-08-24 08:34 被阅读0次

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


    检测轴

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


    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);
                
        }
        
    }
    
    4.PNG

    相关文章

      网友评论

        本文标题:stm32---ADXL345

        本文链接:https://www.haomeiwen.com/subject/xtlfectx.html