好消息:请在手机淘宝或闲鱼上搜索“电子入门趣谈”,有惊喜哦 :) 我把全本电子入门趣谈的电子版(包括科技提升和理论升华部分,共计50余万字)放到上面开始兜售啦,如果您真的喜欢这本书,又想跟作者一起聊聊天的话 :) ... ...欢迎各界电子科技爱好者朋友们斧正收藏 。作者微信:zhangbolin1202 --- 2019.05.27注
3.2.4 加速度传感器
(1)加速度传感器简介
加速度检测是基于测试仪器检测质量敏感加速度产生惯性力的测量,是一种全自主的惯性测量,加速度检测广泛应用于航天、航空和航海的惯性导航系统及运载武器的制导系统中,在振动试验、地震监测、爆破工程、地基测量、地矿勘测等领域也有广泛的应用。
测量加速度,目前主要是通过加速度传感器(俗称加速度计),并配以适当的检测电路进行的,在(1~64)Hz的设备频率下典型的加速度测量范围为(0.1~10)g。。加速度传感器的种类繁多,依据对加速度计内检测质量所产生的惯性力的检测方式来分,加速度计可分为压电式、压阻式、应变式、电容式、振梁式、磁电感应式、隧道电流式、热电式等;按检测质量的支承方式来分,则可分为悬臂梁式、摆式、折叠梁式、简支承梁式等。多数加速度传感器是根据压电效应的原理来工作的,当输入加速度时,加速度通过质量块形成的惯性力加在压电材料上,压电材料产生的变形和由此产生的电荷与加速度成正比,输出电量经放大后就可检测出加速度大小。
加速度传感器是一种惯性传感器,一般由敏感元件、转换元件、测量电路三部分组成,可用如下框图表示:
下面举一个加速度传感器应用实例。我们选择的是ADXL345加速度传感器。ADXL345是一款小而薄的低功耗3轴加速度计,分辨率高(最高13位),测量范围达±16g。数字输出数据为16位二进制补码格式,可通过SPI(3线或4线)或I2C数字接口访问。ADXL345非常适合移动设备应用。它可以在倾斜检测应用中测量静态重力加速度,还可以测量运动或冲击导致的动态加速度。其高分辨率(4 mg/LSB),能够测量不到1.0°的倾斜角度变化。该器件提供多种特殊检测功能。活动和非活动检测功能检测有无运动发生,以及任意轴上的加速度是否超过用户设置的限值。敲击检测功能可以检测单击和双击动作。自由落体检测功能可以检测器件是否正在掉落。这些功能可以映射到两个中断输出引脚中的一个。正在申请专利的32级先进先出(FIFO)缓冲器可用于存储数据,最大程度地减少主机处理器的干预。低功耗模式支持基于运动的智能电源管理,从而以极低的功耗进行阈值感测和运动加速度测量。
ADXL345采用3 mm × 5 mm × 1 mm、14引脚小型超薄塑料封装。主要应用于手机、游戏设备、仪器仪表、个人导航设备中。
(2)ADXL345主要特点(来自数据手册):
用户可选的分辨率;
10位固定分辨率;
单击/双击检测;
活动/非活动监控;
嵌入式FIFO技术可最大程度地减少主机处理器的负荷;
全分辨率,分辨率随g范围提高而提高,±16 g时达到最高分辨率13位(在所有g范围内保持4 mg/LSB的比例系数)
超低功耗:VS = 2.5 V时(典型值),测量模式下低至40 μA,待机模式下为0.1 μA
功耗随带宽自动按比例变化;
(3)ADXL345引脚图、管脚说明、寄存器映射表格:
引脚说明:
寄存器映射表格:这就相当于命令代号,和上文中的DS18B20一样,想要对ADXL345进行操作就必须先往芯片里发指令,指令代码全都列在了下表中。比如我们想改变X轴的偏移量,只需将将指针直到芯片的0x1F位置,然后往里面写数就行了。当然,如何指定位置,如何写数这都是程序要做的事,该芯片支持SPI和I2C两种通信方式,它们之间的不同我们曾在第一章提过,无非是见面之后的口令不同,下面我们会用I2C方式进行单片机和芯片之间的通信。
这里我们更关心的几个“寄存器”是0X32~0X37,因为它们6个正是我们要取得的数据,分别是X轴数据0、X轴数据1、Y轴数据0、Y轴数据1、Z轴数据0、Z轴数据1。你可能会纳闷,一个方向的加速度值就一个就完了呗,为啥还分数据0和数据1呢?不用纠结这个,想想前面遇到的一些情况,比如定时器的TH和TL您应该就能理解了。
(4)ADXL345应用电路图:
下图是ADXL345加速度计利用I2C模式传数据的外围电路。SCL、SDA分别接到单片机的两个I/O口上,INT1和INT2两个中断输出也可以按需求接到单片机中断输入口上。
(5)参考程序(用途:ADXL345模块I2C测试程序)
下面这段程序的作用是将加速度计的输出值保存到BUF寄存器中。这里的I2C程序,使用软件模拟的,有的单片机本身集成了I2C功能,自然不用这么麻烦,不过如果您能用软件自己写出I2C的驱动来会显得更加的“高大上”,而且这些程序也可以直接用在其他I2C通信协议的器件上。关于I2C的时序(也就是口令了),查查别的资料看看就行,不是我们这些凡人需要太操心的东西。咋样?赶紧先收下吧!
#include <reg52.h>
uchar BUF[6]={0,0,0,0,0,0};
sbit SCL=P2^0; //I2C时钟引脚定义
sbit SDA=P2^1; //I2C数据引脚定义
#define SlaveAddress 0xA6 //定义器件在I2C总线中的从地址,根据ALT ADDRESS地址引脚不同修改
void delayms(int ms);
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data); //单个写入数据
uchar Single_Read_ADXL345(uchar REG_Address); //单个读取内部寄存器数据
void Multiple_Read_ADXL345(); //连续的读取内部寄存器数据
//------------------------------------
void Init_ADXL345();
void ADXL345_Start();
void ADXL345_Stop();
void ADXL345_SendACK(bit ack);
bit ADXL345_RecvACK();
void ADXL345_SendByte(uchar dat);
uchar ADXL345_RecvByte();
void ADXL345_ReadPage();
void ADXL345_WritePage();
//-----------------------------------
void main()
{
uchar devid;
delayms(500); //上电延时
Init_ADXL345(); //初始化ADXL345
devid=Single_Read_ADXL345(0X00); //读出的数据为0XE5,表示正确
while(1) //循环
{
Multiple_Read_ADXL345(); //连续读出数据,存储在BUF中
delayms(1000); //延时
}
}
/**************************************
延时函数
**************************************/
void delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=0;j<110;j++);
}
/**************************************
I2C起始信号
**************************************/
void ADXL345_Start()
{
uchar i;
SDA = 1; //拉高数据线
SCL = 1; //拉高时钟线
for(i=2;i>0;i--); //延时 5us
SDA = 0; //产生下降沿
for(i=2;i>0;i--); //延时 5us
SCL = 0; //拉低时钟线
}
/**************************************
I2C停止信号
**************************************/
void ADXL345_Stop()
{
uchar i;
SDA = 0; //拉低数据线
SCL = 1; //拉高时钟线
for(i=2;i>0;i--); //延时 5us
SDA = 1; //产生上升沿
for(i=2;i>0;i--); //延时 5us
}
/**************************************
I2C发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void ADXL345_SendACK(bit ack)
{
uchar i;
SDA = ack; //写应答信号
SCL = 1; //拉高时钟线
for(i=2;i>0;i--); //延时 5us
SCL = 0; //拉低时钟线
for(i=2;i>0;i--); //延时 5us
}
/**************************************
I2C接收应答信号
**************************************/
bit ADXL345_RecvACK()
{
uchar i;
SCL = 1; //拉高时钟线
for(i=2;i>0;i--); //延时 5us
CY = SDA; //读应答信号
SCL = 0; //拉低时钟线
for(i=2;i>0;i--); //延时 5us
return CY;
}
/**************************************
向I2C总线发送一个字节数据
**************************************/
void ADXL345_SendByte(uchar dat)
{
uchar i,j;
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1; //移出数据的最高位
SDA = CY; //送数据口
SCL = 1; //拉高时钟线
for(j=2;j>0;j--); //延时 5us
SCL = 0; //拉低时钟线
for(j=2;j>0;j--); //延时 5us
}
ADXL345_RecvACK();
}
/**************************************
从I2C总线接收一个字节数据
**************************************/
uchar ADXL345_RecvByte()
{
uchar i,j;
uchar dat = 0;
SDA = 1; //使能内部上拉,准备读取数据,
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
SCL = 1; //拉高时钟线
for(j=2;j>0;j--); //延时 5us
dat |= SDA; //读数据
SCL = 0; //拉低时钟线
for(j=2;j>0;j--); //延时 5us
}
return dat;
}
//******I2C单字节写入*******************************************
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data)
{
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(REG_Address); //内部寄存器地址,请参考中文pdf22页
ADXL345_SendByte(REG_data); //内部寄存器数据,请参考中文pdf22页
ADXL345_Stop(); //发送停止信号
}
//********I2C单字节读取*****************************************
uchar Single_Read_ADXL345(uchar REG_Address)
{ uchar 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内部加速度数据,地址范围0x32~0x37
//*********************************************************
void Multiple_read_ADXL345(void)
{ uchar i;
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress); //发送设备地址+写信号
ADXL345_SendByte(0x32); //发送存储单元地址,从0x32开始
ADXL345_Start(); //起始信号
ADXL345_SendByte(SlaveAddress+1); //发送设备地址+读信号
for (i=0; i<6; i++) //连续读取6个地址数据,存储中BUF
{
BUF[i] = ADXL345_RecvByte(); //BUF[0]存储0x32地址中的数据
if (i == 5)
{
ADXL345_SendACK(1); //最后一个数据需要回NOACK
}
else
{
ADXL345_SendACK(0); //回应ACK
}
}
ADXL345_Stop(); //停止信号
for(i=2;i>0;i--); //延时5us
}
//*****************************************************************
//******初始化ADXL345,根据需要请参考数据手册进行修改**************
void Init_ADXL345()
{
Single_Write_ADXL345(0x31,0x0B); //测量范围,正负16g,13位模式
Single_Write_ADXL345(0x2C,0x08); //速率设定为12.5 参考pdf13页
Single_Write_ADXL345(0x2D,0x08); //选择电源模式 参考pdf24页
Single_Write_ADXL345(0x2E,0x80); //使能 DATA_READY 中断
Single_Write_ADXL345(0x1E,0x00); //X 偏移量
Single_Write_ADXL345(0x1F,0x00); //Y 偏移量
Single_Write_ADXL345(0x20,0x05); //Z 偏移量
}
未完待续。。。