在一个项目中,使用了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<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,多谢各位了)
一周热门 更多>