已回答假定已回答

ADXL345的中断如何配置

Dennis-Zhou 在 2014-8-5 詢問的問題
最後回覆由njsunyongan於2017-2-10提供

       在一个项目中,使用了ADXL345作为倾斜角度检测,用查询的方式来读取ADXL345的X、Y、Z三个轴的值,一切正常。

但现在我使用中断的方式来处理ADXL345的倾斜角度数据,当ADXL345发生倾斜时,才让ADXL345产生中断,当MCU检测到中断,进入中断函数进入相关处理。但是现在的这个程序,只要初始化ADXL345之后,就会一直产生中断,不停的进入中断函数。

 

     请问,如何正确初始化ADXL345,使之发生倾斜时,就会产生中断?

 

     (如有答案者或愿意指导的大虾,请联系我,我的邮箱:834356519@qq.com,多谢各位了

 

 

1、ADXL345的电路图

使用的是STM32做为MCU控制器。

QQ截图20140805155133.png

 

2、ADXL345的驱动代码

     2.1 ADXL345.C

/************************************************************************************
文件名称:adxl345.c
文件功能:ADXL345加速度传感器驱动
文件作者:Dennis-Zhou
编写日期:2013年8月17日
************************************************************************************/

//=====包含头文件=====
#include "adxl345.h"
#include "sys.h"
#include "delay.h"
#include "math.h"
#include "stdlib.h"

//=====宏定义=====
#define threshold 5  //倾斜角度阈值(单位:度)

//=====全局变量定义=====
short  x,y,z;      
short  angx,angy,angz;
short  actual_X,actual_Y,actual_Z;
u8   Angle[6];

/************************************************************************************
函数名称:u8 ADXL345_Init(void)
函数功能:初始化ADXL345
入口参数:无
返回参数: 0:初始化成功
   1:初始化失败
************************************************************************************/
u8 ADXL345_Init(void)
{     
IIC_Init();        //初始化IIC总线
EXTIx_Init();       //ADXL345中断初始化
if(ADXL345_RD_Reg(DEVICE_ID)==0XE5)  //读取器件ID
{   
  //=====初始化=====
  ADXL345_WR_Reg(DATA_FORMAT,0X0B); //低电平中断输出,13位全分辨率,输出数据右对齐,16g量程
  ADXL345_WR_Reg(BW_RATE,0x08);  //数据输出速度为100Hz
  ADXL345_WR_Reg(POWER_CTL,0x08);     //链接使能,测量模式
        ADXL345_WR_Reg(INT_ENABLE,0x80);    //DATA_READY 中断开启

   ADXL345_WR_Reg(OFSX,0x00);
  ADXL345_WR_Reg(OFSY,0x00);
  ADXL345_WR_Reg(OFSZ,0x05);

  ADXL345_WR_Reg(INT_MAP,0x00);       //配置到中断引脚1上
 
  GPIO_ResetBits(GPIOA,GPIO_Pin_3); //绿灯亮,提示校准中
  ADXL345_AUTO_Adjust((char*)&x,(char*)&y,(char*)&z); //自动校准
  GPIO_SetBits(GPIOA,GPIO_Pin_3);  //绿灯灭,提示校准完成

  ADXL345_Read_Angle();    //读一次ADX345,防止校准后第一次读数据错误

  return 0;
}

return 1;             
}

/************************************************************************************
函数名称:void ADXL345_WR_Reg(u8 addr,u8 val)
函数功能:写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();      //产生一个停止条件    
}

/************************************************************************************
函数名称:u8 ADXL345_RD_Reg(u8 addr)
函数功能:读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;    //返回读到的值

/************************************************************************************
函数名称:void ADXL345_RD_Avval(short *x,short *y,short *z)
函数功能:读取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;
}

/************************************************************************************
函数名称:void ADXL345_AUTO_Adjust(char *xval,char *yval,char *zval)
函数功能:自动校准ADXL345
入口参数: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);     //先进入休眠模式.
ADXL345_WR_Reg(INT_ENABLE,0x00);    //DATA_READY 中断关闭
delay_ms(100);
ADXL345_WR_Reg(DATA_FORMAT,0X2F); //低电平中断输出,13位全分辨率,输出数据右对齐,16g量程
ADXL345_WR_Reg(BW_RATE,0x0A);  //数据输出速度为100Hz


ADXL345_WR_Reg(THRESH_ACT,0x01);    //检测活动的阈值为187.5mg时产生中断
// ADXL345_WR_Reg(DUR,0xF0);       //时间范围10*625uS
    ADXL345_WR_Reg(ACT_INACT_CTL,0xEE); //使能X、Y、Z三轴的Activity和Inactivity功能
ADXL345_WR_Reg(INT_MAP,0x00);       //配置到中断引脚1上
ADXL345_WR_Reg(INT_ENABLE,0x80);    //DATA_READY中断开启
ADXL345_WR_Reg(POWER_CTL,0x28);     //链接使能,测量模式

//=====================================
ADXL345_WR_Reg(OFSX,0x00);
ADXL345_WR_Reg(OFSY,0x00);
ADXL345_WR_Reg(OFSZ,0x05);
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);

}

/************************************************************************************
函数名称:void ADXL345_RD_XYZ(short *x,short *y,short *z)
函数功能:读取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]);    
}

/************************************************************************************
函数名称:void ADXL345_Read_Average(short *x,short *y,short *z,u8 times)
函数功能:读取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;
}
}

/************************************************************************************
函数名称:short ADXL345_Get_Angle(float x,float y,float z,u8 dir)
函数功能:获取角度值
入口参数: 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;
  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*1800/3.14;
}

/************************************************************************************
函数名称:u8 ADXL345_Read_Angle(void)
函数功能:读取ADX345数据
入口参数:无
返回参数:无
************************************************************************************/
u8 ADXL345_Read_Angle(void)
{
//=====读取ADXL345的数据=====       
ADXL345_Read_Average(&x,&y,&z,10);

//=====得到角度值=====
angx=ADXL345_Get_Angle(x,y,z,1);   
angy=ADXL345_Get_Angle(x,y,z,2);  
angz=ADXL345_Get_Angle(x,y,z,0);

//=====转换成真实值=====
actual_X = angx/10;
actual_Y = angy/10;
actual_Z = angz/10;

//===将 X,Y,Z 3个轴的角度值转换并保存到Angle数组=====
if(actual_X<0)
{
  Angle[0] = '-';
  Angle[1] = (u8)abs(actual_X);//取绝对值并强制转换成u8数据类型
}
else
{
  Angle[0] = ' ';
  Angle[1] = (u8)actual_X;
}

if(actual_Y<0)
{
  Angle[2] = '-';
  Angle[3] = (u8)abs(actual_Y);
}
else
{
  Angle[2] = ' ';
  Angle[3] = (u8)actual_Y;
}

if(actual_Z<0)
{
  Angle[4] = '-';
  Angle[5] = (u8)abs(actual_Z);
}
else
{
  Angle[4] = ' ';
  Angle[5] = (u8)actual_Z;
}

//=====判断角度是否发生倾斜,如果超过+5度或-5度,就报警=====
if(    Angle[1]>threshold || (Angle[0]=='-' && Angle[1]>threshold)
  || Angle[3]>threshold || (Angle[2]=='-' && Angle[3]>threshold)
  || Angle[5]>threshold || (Angle[4]=='-' && Angle[5]>threshold) )
{
  return 1; //报警
}    
else
  return 0; //不报警

}

/************************************************************************************
函数名称:void EXTIx_Init(void)
函数功能:外部中断初始化
入口参数:无
返回参数:无
************************************************************************************/   
void EXTIx_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //EXTI外部中断参数配置结构体
NVIC_InitTypeDef NVIC_InitStructure; //NVIC嵌套向量中断参数配置结构体

//=====设置NVIC中断分组(抢占优先级和响应优先级)的位数=====
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);

//=====使能AFIO复用功能时钟=====
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

//=====设置EXTI外部中断参数=====
   GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1); //选择GPIO管脚用作外部中断线路
EXTI_InitStructure.EXTI_Line = EXTI_Line1;     //外部中断线0 
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;   //设置EXTI线路为中断请求
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //设置输入线路上升沿和下降沿为中断请求 fa
EXTI_InitStructure.EXTI_LineCmd = ENABLE;     //使能外部中断线
EXTI_Init(&EXTI_InitStructure);        //初始化外部中断
EXTI_ClearITPendingBit(EXTI_Line1);       //清除LINE1上的中断标志位 

//=====设置NVIC嵌套向量中断参数=====
   NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;   //使能按键K2所在的外部中断通道
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级1
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;   //子优先级1
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      
   NVIC_Init(&NVIC_InitStructure);
}

/************************************************************************************
函数名称:void EXTI1_IRQHandler(void)
函数功能:外部中断1服务程序
入口参数:无
返回参数:无
************************************************************************************/   
void EXTI1_IRQHandler(void)
{
u8 i;

for(i=0; i<5; i++)
{
  GPIO_ResetBits(GPIOA,GPIO_Pin_3); //绿灯亮,提示校准中
  delay_ms(300);
  GPIO_SetBits(GPIOA,GPIO_Pin_3);  //绿灯灭,提示校准完成
  delay_ms(100);
}

EXTI_ClearITPendingBit(EXTI_Line1); //清除LINE1上的中断标志位 
}

 

 

/*********************************************************************************/

/*********************************************************************************/

 

 

     2.2 ADXL345.h

/************************************************************************************
文件名称:adxl345.h
文件功能:adxl345加速度传感器相关定义和声明
文件作者:Dennis-Zhou
编写日期:2013年8月17日
************************************************************************************/

//=====包含头文件=====
#ifndef __ADXL345_H
#define __ADXL345_H
#include "simulation_IIC.h"   
#include "stm32f10x_exti.h"               

//=====adxl345指令宏定义=====
#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_ACT  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
#define ADXL_READ     0X3B
#define ADXL_WRITE    0X3A

//=====adxl345相关函数声明=====
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);   //获取角度值
void  Adxl_Show_Num(u16 x,u16 y,short num,u8 mode);    //显示ADXL345的加速度值或角度值
u8   ADXL345_Read_Angle(void);         //转换ADX345角度值
void  EXTIx_Init(void);           //ADXL345中断初始化
#endif

 

(如有答案者或愿意指导的大虾,请联系我,我的邮箱:834356519@qq.com,多谢各位了

結果