在一个项目中,使用了ADXL345作为倾斜角度检测,用查询的方式来读取ADXL345的X、Y、Z三个轴的值,一切正常。 但现在我使用中断的方式来处理ADXL345的倾斜角度数据,当ADXL345发生倾斜时,才让ADXL345产生中断,当MCU检测到中断,进入中断函数进入相关处理。但是现在的这个程序,只要初始化ADXL345之后,就会一直产生中断,不停的进入中断函数。
请问,如何正确初始化ADXL345,使之发生倾斜时,就会产生中断?
(如有答案者或愿意指导的大虾,请联系我,我的邮箱:834356519@qq.com,多谢各位了)
1、ADXL345的电路图 使用的是STM32做为MCU控制器。
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=IIC_Read_Byte(0); //读取一个字节,不继续再读,发送NACK else buf=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
{ 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,多谢各位了)
0
|