上次写了一篇《Arduino使用ADXL345加速度传感器模块》,不过里面是直接用了现成的库。对于做原型,使用现成的库来快速实现想法当然可行,不过并不能真正理解里面的原理。其实个人认为,学习嵌入式外设最好的方式莫过于自己在51单片机上实现一遍。所以,这次我用51单片机来操作ADXL345加速度传感器模块。
=================阶段一:ADXL345原理概述===============
ADXL345加速度模块与单片机之间的通信使用的是I2C协议。作为前置学习,我已经写了一篇《51单片机使用I2C总线》,为51单片机封装了I2C的函数库。I2C协议概括地说,无非就是读写两个操作,可以表示为void write(address,register,data)和uint8 read(address,register)。也就是说,读的时候,指定设备地址、寄存器地址,读出一个字节;写的时候,指定设备地址、寄存器地址,写入一个字节。
网上买来的ADXL345模块的长这样:
在一般的应用中,只有四根线用得着,分别是VCC,GND,SDA和SCL。其中VCC是泛指最上面的5V和3V3,两种电压皆可。当这么接时,ADXL345使用I2C通信,设备地址是0x53。
ADXL345所有的寄存器地址与功能列表可以查看硬件手册《ADXL345中文资料》。这里贴一张总览:
====================阶段二:通用代码=================
接下来给出一段51单片机操作ADXL345的通用代码,其中需要用到的types.h、i2c.h、i2c.c请参考《51单片机使用I2C总线》,还需要用到buffered_uart.h和buffered_uart.c请参考《为51单片机打造带接收缓冲区的串口(Buffered Uart)》。
main.c
#include "reg51.h" #include "types.h" #include "i2c.h" #include "buffered_uart.h" #define ADXL345_ADDR 0x53 void main() { uint8 t_low,t_high; uint8 t_buffer[4]; //初始化串口缓冲区 uart_init(4800,t_buffer,4); //不断读取DEVICE_ID,直到读到0xE5,说明正常 while(i2c_read(ADXL345_ADDR,0x00)!=0xE5); //设置测量范围为±16g,精度13位 i2c_write(ADXL345_ADDR,0x31,0x0B); //采集速率设定为50Hz i2c_write(ADXL345_ADDR,0x2C,0x09); //电源模式 i2c_write(ADXL345_ADDR,0x2D,0x08); while(1) { //读取X轴数据的低8位 t_low=i2c_read(ADXL345_ADDR,0x32); //读取X轴数据的高8位 t_high=i2c_read(ADXL345_ADDR,0x33); uart_write(t_low); uart_write(t_high); } }
在该例子中,首先初始化串口,设置波特率为4800,缓冲区大小为4字节:
uart_init(4800,t_buffer,4);
然后,不断读取ADXL345上地址为0x00的寄存器(DEVID),直到读到0xE5为止:
while(i2c_read(ADXL345_ADDR,0x00)!=0xE5);
这是因为根据上面的寄存器映射表可知,上电后ADXL345的DEVID=11100101=0xE5。
通过如下代码向寄存器0x31(DATA_FORMAT)写入0x0B
i2c_write(ADXL345_ADDR,0x31,0x0B);
设置数据模式为±16g,精度为13位(因为每一个1代表4mg,所以16g就是16*2/4m=8000=13位)。DATA_FORMAT具体用法可以查手册得到:
接着,代码
i2c_write(ADXL345_ADDR,0x2C,0x09);
把采样速率设置为50Hz。寄存器0x2C(BW_RATE)设置见下图:
低功耗模式下,功耗会降低,采样数值的噪音会稍微大一些。正常模式和低功耗模式下采样速率、设置值、功耗见下两表:
最后,通过
i2c_write(ADXL345_ADDR,0x2D,0x08);
向寄存器0x2D(POWER_CTL)写入0x80,也就是把“测量”位置为1。POWER_CTL格式如图:
测量位置为1后,才能读到数据。
最后,在while循环中不断读取0x32(DATAX0)和0x33(DATAX1)寄存器中的数据,并通过串口输出:
t_low=i2c_read(ADXL345_ADDR,0x32); t_high=i2c_read(ADXL345_ADDR,0x33);
====================阶段三:真机实验==================
把以上代码烧入51单片机中,ADXL345的5V接51单片机的VCC,ADXL345的GND接51单片机的GND,ADXL345的SCL接51单片机的P1^0,ADXL345的SDA接51单片机的P1^1(可以修改i2c.c中的宏定义)。
上电之后,串口不停输出X轴加速度低8位和高8位: