美文网首页物联网
ADXL345中断模式产生ACTIVITY中断信号

ADXL345中断模式产生ACTIVITY中断信号

作者: stnevermore | 来源:发表于2019-10-26 01:40 被阅读0次
    • 需求描述
      ADXL345是计算三轴加速度值的IC, 在有些需求中并不需要进行数据显示,而仅仅想在某些情况下检测到中断信号.例如,硬盘跌落检测,在硬盘中嵌入一个ADXL345的芯片,仅仅在硬盘跌落的时候断电以保护数据,这里并没有任何数据需要显示.笔者的需求是,当设备活动的时候ADXL345通过中断告诉MCU设备目前处于活动状态,当其静止时候也可以获取当前静止的状态以便主控芯片能进行相关逻辑控制.
    • 技术实现方式
      ADXL345一共有8个中断源,Data_Ready, Single_Tap, Double_Tap, Activity, Inactivity, Free_Fall, Watermark, Overrun. 一般常用的为Data_Ready,表示有新的测量数据会产生中断; Activity,表示当前处于活动状态,也可以理解为芯片在动(动的幅度可通过相关寄存器设置), Inactivity,表示静止状态产生的中断,静止的幅度也可以设置,处于静止的时间也需要设置.Free_Fall,表示自由下落产生的中断,这个就可以应用在上述关于硬盘跌落检测的需求描述中.
    • 相关资料
      三轴加速度传感器在跌倒检测中的应用(必看)
      加速度传感器ADXL345典型应用
      STM32应用-第4节-震动传感器ADXL345
    • 硬件连接
      我这里使用的是C8051F320芯片,因为只连接了一个ADXL345的一个中断,即INT1. 使用的是软件模拟IIC, MCU的P1^5为SCL, SDA是P1^6. 这两个端口连接ADXL345的SCL和SDA接口. ADXL345的INT1连接MCU的INT1(MCU的端口为P0^1). C8051F320有两个外部中断,INT0和INT1,可以通过寄存器进行映射到相应的端口.
    • 代码示例
      I2C驱动代码
    #ifndef _ADXL345_IIC_H_
    #define _ADXL345_IIC_H_
    #include "c8051f320.h"
    #include "mytype.h"
    
    #define SlaveAddress   0xA6   //定义器件在IIC总线中的从地址,根据ALT  ADDRESS地址引脚不同修改
                                  //ALT  ADDRESS引脚接地时地址为0xA6,接电源时地址为0x3A
    
    sbit SCL = P1^5;            //IIC总线时钟线
    sbit SDA = P1^6;            //IIC总线数据线
                                  
    //extern uint8 ADXL345_Recv_BUF[8];  
    
    void Init_ADXL345();             //初始化ADXL345
    void ADXL345_Start();
    void ADXL345_Stop();
    void ADXL345_SendACK(bit ack);
    bit  ADXL345_RecvACK();
    void ADXL345_SendByte(uint8 dat);
    uint8 ADXL345_RecvByte();
    
    void  Single_Write_ADXL345(uint8 REG_Address,uint8 REG_data);   //单个写入数据
    uint8 Single_Read_ADXL345(uint8 REG_Address);                   //单个读取内部寄存器数据
    //void Multiple_read_ADXL345(void);                               //连续的读取内部寄存器数据
    
    #define ADXL345_REG_DEVID               (0x00)    // Device ID
    #define ADXL345_REG_THRESH_TAP          (0x1D)    // Tap threshold
    #define ADXL345_REG_OFSX                (0x1E)    // X-axis offset
    #define ADXL345_REG_OFSY                (0x1F)    // Y-axis offset
    #define ADXL345_REG_OFSZ                (0x20)    // Z-axis offset
    #define ADXL345_REG_DUR                 (0x21)    // Tap duration
    #define ADXL345_REG_LATENT              (0x22)    // Tap latency
    #define ADXL345_REG_WINDOW              (0x23)    // Tap window
    #define ADXL345_REG_THRESH_ACT          (0x24)    // Activity threshold
    #define ADXL345_REG_THRESH_INACT        (0x25)    // Inactivity threshold
    #define ADXL345_REG_TIME_INACT          (0x26)    // Inactivity time
    #define ADXL345_REG_ACT_INACT_CTL       (0x27)    // Axis enable control for activity and inactivity detection
    #define ADXL345_REG_THRESH_FF           (0x28)    // Free-fall threshold
    #define ADXL345_REG_TIME_FF             (0x29)    // Free-fall time
    #define ADXL345_REG_TAP_AXES            (0x2A)    // Axis control for single/double tap
    #define ADXL345_REG_ACT_TAP_STATUS      (0x2B)    // Source for single/double tap
    #define ADXL345_REG_BW_RATE             (0x2C)    // Data rate and power mode control
    #define ADXL345_REG_POWER_CTL           (0x2D)    // Power-saving features control
    #define ADXL345_REG_INT_ENABLE          (0x2E)    // Interrupt enable control
    #define ADXL345_REG_INT_MAP             (0x2F)    // Interrupt mapping control
    #define ADXL345_REG_INT_SOURCE          (0x30)    // Source of interrupts
    #define ADXL345_REG_DATA_FORMAT         (0x31)    // Data format control
    #define ADXL345_REG_DATAX0              (0x32)    // X-axis data 0
    #define ADXL345_REG_DATAX1              (0x33)    // X-axis data 1
    #define ADXL345_REG_DATAY0              (0x34)    // Y-axis data 0
    #define ADXL345_REG_DATAY1              (0x35)    // Y-axis data 1
    #define ADXL345_REG_DATAZ0              (0x36)    // Z-axis data 0
    #define ADXL345_REG_DATAZ1              (0x37)    // Z-axis data 1
    #define ADXL345_REG_FIFO_CTL            (0x38)    // FIFO control
    #define ADXL345_REG_FIFO_STATUS         (0x39)    // FIFO status
    #define ADXL345_MG2G_MULTIPLIER (0.004)  // 4mg per lsb
    
    /*
    Activity 加速度值大于THRESH_ACT寄存器(地址0x24)存储值时,Activity(活动)中断置位, 由任一轴参与, 通过ACT_INACT_CTL寄存器(0x27)置位
    Inactivity 加速度值小于THRESH_INACT寄存器(地址0x25)的存储值时,Inactivity(静止)位置位,所有轴参与,多于TIME_INACT寄存器(地址0x26)规定的时间,ACT_INACT_CTL寄存器((地址0x27)置位。TIME_INACT最大值为255秒
    */
    #endif
    
    #include "adxl345_iic.h"
    #include "tools.h"
    
    //uint8 ADXL345_Recv_BUF[8];                         //接收数据缓存区          
        
    
    /**************************************
    起始信号
    **************************************/
    void ADXL345_Start()
    {
        SDA = 1;                    //拉高数据线
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        SDA = 0;                    //产生下降沿
        Delay5us();                 //延时
        SCL = 0;                    //拉低时钟线
    }
    
    /**************************************
    停止信号
    **************************************/
    void ADXL345_Stop()
    {
        SDA = 0;                    //拉低数据线
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        SDA = 1;                    //产生上升沿
        Delay5us();                 //延时
    }
    
    /**************************************
    发送应答信号
    入口参数:ack (0:ACK 1:NAK)
    **************************************/
    void ADXL345_SendACK(bit ack)
    {
        SDA = ack;                  //写应答信号
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        SCL = 0;                    //拉低时钟线
        Delay5us();                 //延时
    }
    
    /**************************************
    接收应答信号
    **************************************/
    bit ADXL345_RecvACK()
    {
        SCL = 1;                    //拉高时钟线
        Delay5us();                 //延时
        CY = SDA;                   //读应答信号
        SCL = 0;                    //拉低时钟线
        Delay5us();                 //延时
    
        return CY;
    }
    
    /**************************************
    向IIC总线发送一个字节数据
    **************************************/
    void ADXL345_SendByte(uint8 dat)
    {
        uint8 i;
    
        for (i=0; i<8; i++)         //8位计数器
        {
            dat <<= 1;              //移出数据的最高位
            SDA = CY;               //送数据口
            SCL = 1;                //拉高时钟线
            Delay5us();             //延时
            SCL = 0;                //拉低时钟线
            Delay5us();             //延时
        }
        ADXL345_RecvACK();
    }
    
    /**************************************
    从IIC总线接收一个字节数据
    **************************************/
    uint8 ADXL345_RecvByte()
    {
        uint8 i;
        uint8 dat = 0;
    
        SDA = 1;                    //使能内部上拉,准备读取数据,
        for (i=0; i<8; i++)         //8位计数器
        {
            dat <<= 1;
            SCL = 1;                //拉高时钟线
            Delay5us();             //延时
            dat |= SDA;             //读数据               
            SCL = 0;                //拉低时钟线
            Delay5us();             //延时
        }
        return dat;
    }
    
    //******单字节写入*******************************************
    
    void Single_Write_ADXL345(uint8 REG_Address,uint8 REG_data)
    {
        ADXL345_Start();                  //起始信号
        ADXL345_SendByte(SlaveAddress);   //发送设备地址+写信号
        ADXL345_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf22页 
        ADXL345_SendByte(REG_data);       //内部寄存器数据,请参考中文pdf22页 
        ADXL345_Stop();                   //发送停止信号
    }
    
    //********单字节读取*****************************************
    uint8 Single_Read_ADXL345(uint8 REG_Address)
    {  
        uint8 REG_data;
        ADXL345_Start();                          //起始信号
        ADXL345_SendByte(SlaveAddress);           //发送设备地址+写信号
        ADXL345_SendByte(REG_Address);            //发送存储单元地址,从0开始   
        ADXL345_Start();                          //起始信号
        ADXL345_SendByte(SlaveAddress+1);         //发送设备地址+读信号
        REG_data=ADXL345_RecvByte();              //读出寄存器数据
        ADXL345_SendACK(1);   
        ADXL345_Stop();                           //停止信号
        return REG_data; 
    }
    
    
    
    //*****************************************************************
    
    //初始化ADXL345,根据需要请参考pdf进行修改************************
    void Init_ADXL345()
    {
    //////////////////////////////////////////////////////////
        //0x2D, D7(0) D6(0) D5(链接) D4(AUTO_SLEEP)   D3测量  D2休眠 D1D0 唤醒
        //Single_Write_ADXL345(ADXL345_REG_POWER_CTL,0x00); //先进入休眠模式
        //ADXL345_REG_INT_ENABLE--0x2E 写入0x00
        Single_Write_ADXL345(ADXL345_REG_INT_ENABLE,0x00);//阻止所有功能的中断
    
        /*寄存器0x31-DATA_FORMAT, D7(SELF_TEST) D6(SPI) D5(INT_INVERT) D4(0) D3(FULL_RES) D2(Justify) D1 D0(Range)
        // INT_INVERT位,0-中断高电平有效, 1-中断低电平有效
        //精度为13位(因为每一个1代表4mg,所以16g就是16*2/4m=8000=13位)*/
        Single_Write_ADXL345(ADXL345_REG_DATA_FORMAT,0x0B);   //测量范围,正负16g,13位模式,中断高电平有效
    
        //数据速率及功率模式控制寄存器0x2C, D7(0) D6(0) D5(0) D4(LOW_POWER,低功耗) D3-D2-D1-D0(速率),
        //LOW_POWER设置为0,正常操作,设置为1,选择低功率操作,速率位 1010为100hz, 1001为50hz,1000为25hz,0111为12.5hz     默认值0x0A,100hz,这里不需要任何高速率,所以我设置为最低速率,并且使用低功耗模式
        //寄存器的值为0001 0111, 即0x17
        Single_Write_ADXL345(ADXL345_REG_BW_RATE,0x17);   //采集速率设定为12.5hz,低功耗模式
    
        ////////////////这个寄存器的设置很重要///////////////////////////////////////
    
        //POWER_CTL寄存器0x2D, D7(0) D6(0) D5(链接) D4(AUTO_SLEEP) D3(测量) D2(休眠) D1-D0(唤醒)
        //如果ADXL345在静止期间启动切换到休眠模式,可以省电。要使用此功能,在THRESH_INACT寄存器(0x25)和TIME_INACT寄存器(0x26)设置一个值表示静止(适当值应视应用情况而定),
        //链接位:活动和静止功能的链接位设置为1,延迟活动功能开始,直到检测到静止。检测到活动后,静止检测开始,活动检测停止。该位串行链接活动和静止功能。此位设置为0时,静止功能和活动功能同时进行
        //AUTO_SLEEP位:设置链接位, AUTO_SLEEP位设置为1,自动休眠功能使能
        //测量位:测量位设置为0,将器件置于待机模式,设置为1,置于测量模式
        //休眠位:休眠位设置为0,将器件置于普通工作模式,设置为1,置于休眠模式
        //唤醒位:控制休眠模式下的读取频率
        //这里不能设置链接位,启用自动休眠Auto_Sleep,进行测量,所以为0001 1000,即0x18. 我设置为0x38,是没有办法正常产生中断
        Single_Write_ADXL345(ADXL345_REG_POWER_CTL,0x18); // 测量位为1,测量模式
    
        Single_Write_ADXL345(ADXL345_REG_OFSX,0x00);  //X 偏移量 根据测试传感器的状态写入pdf29页
        Single_Write_ADXL345(ADXL345_REG_OFSY,0x00);  //Y 偏移量 根据测试传感器的状态写入pdf29页  
        Single_Write_ADXL345(ADXL345_REG_OFSZ,0x00); //Z 偏移量 根据测试传感器的状态写入pdf29页, 
        
        Delay50us();
        Single_Write_ADXL345(ADXL345_REG_THRESH_ACT,0x04);  //检测活动(ACTIVITY)的阈值,62.5mg/LSB ,其中0x10代表16, 16*62.5=1000mg, 也就是1g, 0x04表示4*62.5 = 250mg
        Single_Write_ADXL345(ADXL345_REG_THRESH_INACT,0x02);  //检测静止的阈值,62.5mg/LSB, 0x02表示 2* 62.5mg = 125mg
        Single_Write_ADXL345(ADXL345_REG_TIME_INACT,0x02);  //当小于inactivity值时间超过这个值的时候进入睡眠,其中02代表2秒 , 单位是1sec/LSB,所以最大可以设置255s,即0xFF就是255s
    
        //ADXL345_REG_ACT_INACT_CTL----0x27----轴使能控制活动和静止检测寄存器
        //D7-Activity_X交流/直流  D6-Activity_X使能 D5-Activity_Y使能 D4-Activity_Z使能  D3-Inactivity_X交流/直流  D2-Inactivity_X使能 D1-Inactivity_Y使能 D0-Inactivity_Z使能  
        //D7和D3设置为0,选择直流耦合操作,桨当前加速度值直接与Thresh_act和Thresh_inact进行比较,以确定检测到的使活动还是静止
        //选择交流耦合工作模式,活动检测开始时候的加速度值作为参考值,在此基础之上,将新的加速度采样与该参考值进行比较,如果差值大小超过thresh_act,会触发活动中断, 静止的情况类似
        //这里我曾设置为0x77发现是不能正常产生中断,貌似是因为和阈值对比的方法不同而导致的
        Single_Write_ADXL345(ADXL345_REG_ACT_INACT_CTL,0xff);
    
    
        //ADXL345_REG_INT_MAP----0x2F----中断映射寄存器,D7-Data_Ready D6-Single_tap D5-DOUBLE_TAP D4-Activity D3-Inactivity D2-Free_FALL D1-Watermark D0-Overrun
        //对应的位置为1---对应中断发送到INT2引脚    对应的位设置为0----对应中断发送到INT1
        Single_Write_ADXL345(ADXL345_REG_INT_MAP,0x00);    //ACTIVITY映射到INT1引脚
        Delay50us();
    
        //ADXL345_REG_INT_ENABLE-----0x2E-----中断使能寄存器,D7-DATA_READY  D6-SINGLE_TAP D5-DOUBLE_TAP D4-Activity D3-Inactivity D2-Free_FALL D1-Watermark D0-Overrun
        //对应位置为1---生成相应中断  对应位置为0---阻止相应中断 
        Single_Write_ADXL345(ADXL345_REG_INT_ENABLE,0x10);   //开中断,这里仅仅使能D4的activity中断,所以置1
    
        /*FIFO控制寄存器0x38, D7-D6 FIFO模式, 11表示触发器模式, D5 触发位(0:链接触发器模式下的触发事件到INT1,1:链接到INT2),D4-D0样本                                                                                                                      */
        Single_Write_ADXL345(ADXL345_REG_FIFO_CTL,0xDF);// 0x1101 1111, 设置链接触发器模式,触发事件链接至INT1
    }
    
    // 没用用到这个函数//*********************************************************
    ////
    ////连续读出ADXL345内部加速度数据,地址范围0x32~0x37
    ////
    ////*********************************************************
    //void Multiple_read_ADXL345(void)
    //{   
    //  uint8 i;
    //    ADXL345_Start();                          //起始信号
    //    ADXL345_SendByte(SlaveAddress);           //发送设备地址+写信号
    //    ADXL345_SendByte(0x32);                   //发送存储单元地址,从0x32开始  
    //    ADXL345_Start();                          //起始信号
    //    ADXL345_SendByte(SlaveAddress+1);         //发送设备地址+读信号
    //  for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中ADXL345_Recv_BUF
    //    {
    //        ADXL345_Recv_BUF[i] = ADXL345_RecvByte();          //ADXL345_Recv_BUF[0]存储0x32地址中的数据
    //        if (i == 5)
    //        {
    //           ADXL345_SendACK(1);                //最后一个数据需要回NOACK
    //        }
    //        else
    //        {
    //          ADXL345_SendACK(0);                //回应ACK
    //       }
    //   }
    //    ADXL345_Stop();                          //停止信号
    //    Delay5ms();
    //}
    
    #include "external_int.h"
    #include "system.h"
    #include "main.h"
    
    // P0.0 - digital   open-drain  /INT0
    // P0.1 - digital   open-drain  /INT1
    
    void Ext_Interrupt_Init (void)
    {
         //TCON = 0x55; //INT0和INT1都是边沿触发 , 并且定时器1 和定时器0 都允许,与上面有点区别
         //   IT01CF---INT0/INT1配置寄存器---bit7(0:INT1低电平有效,1:INT1高电平有效) bit6-4 INT1端口引脚选择
         //001--P0.1引脚,因此高4位为0001, 低四位为0000
         TCON = 0x05;//也可以把定时器1和定时器0禁止,
         IT01CF = 0x10;                  // /INT0 active low; /INT0 on P0.0;
                                         // /INT1 active low; /INT1 on P0.1
         EX1 = 1;
    
    }
    
    
    //-----------------------------------------------------------------------------
    // /INT0 ISR
    //-----------------------------------------------------------------------------
    void INT0_ISR (void) interrupt 0
    {
    }
    
    //-----------------------------------------------------------------------------
    // /INT1 ISR
    //-----------------------------------------------------------------------------
    void INT1_ISR (void) interrupt 2
    {
        /*当检测到一个由IT1定义的边沿/电平时,该标志由硬件置位。该位可以用软件清0,但当CPU转向外部中断1中断服务程序时该位被自动清0(如果IT1=1)。
        当IT1=0时,该标志在/INT1有效时被置‘1’(有效电平由IT01CF寄存器中的IN1PL位定义)。
         IE1=0;
        */
       IE1=0;
       Prints("aaaaaa\r\n");
    }
    

    TCON 定时器控制寄存器
    (位7) TF1: 定时器1溢出标志 (位6)TR1:定时器1运行控制 (位5)TF0:定时器溢出标志 (位4)TR0:定时器0运行控制 (位3)IE1:外部中断1 (位2)IT1:中断1类型选择 (位1)IE0: 外部中断0 (位0)IT0:中断0类型选择
    位2 IT1和位0 IT0 设置是相同的,0表示电平触发, 1表示边沿触发. 所以上述 TCON 设置为0000 0101即0x05
    IT01CF INT0/INT1配置寄存器
    设置为0001 0000 前四位表示INT1低电平有效, INT1编号选择001,即P0.1表示INT1. 后四位0000表示INT0为低电平有效, INT0编号选择了000编号,即P0.0为INT0.


        PCA0MD &= ~0x40;  // Disable Watchdog timer, bit6(WDTE,看门狗定时器使能位)清零,看门狗被禁止
        //配置引脚
        XBR1= 0x40;         //打开交叉开关,使能弱上拉,要使GPIO生效,必须打开交叉开关|  XBR1为端口I/O交叉开关控制1,位6表示XBARE,XBARE置1表示使能交叉开关 
        InitOSC();          //初始化晶振
        Ext_Interrupt_Init();
        UART0_Init();       //初始化串口
    
        Delay(2048);
        Init_ADXL345();
    
        EA=1;               //允许所有中断    
        while(1)
        {
            //这句非常重要,如果缺少,是无法产生中断的,0x30是adxl的INT_SOURCE寄存器,只读
            Single_Read_ADXL345(0x30);
            Delay(200);
        }
    

    一动ADXL345就会产生中断,禁止的时候就不会产生中断. 产生中断是以串口打印来显示.效果如下图.

    Activity产生中断.jpg
    这个图是以100hz速率产生的中断,代码中把速率调整到最低例如12.5hz,那么产生的中断就会少很多.(打印aaaaaa的次数就会大幅减少)

    相关文章

      网友评论

        本文标题:ADXL345中断模式产生ACTIVITY中断信号

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