发新帖本帖赏金 3.00元(功能说明)我要提问
12下一页
返回列表
[STM32F1]

ST分享大集结+STM32 ADXL345 加速度传感器

[复制链接]
2538|32
手机看帖
扫描二维码
随时随地手机跟帖
gaoke231|  楼主 | 2017-11-24 22:16 | 显示全部楼层 |阅读模式
ADXL345  加速度传感器简介ADXL345 是一款完整的 3 轴加速度测量系统,可选择的测量范围有±2 g,±4 g,±8 g 或±16 g。既能测量运动或冲击导致的动态加速度,也能测量静止加速度,例如重力加速度,使得器件可作为倾斜传感器使用。它的分辨率为 13 位,测量范围达± 16g。数字输出数据为 16 位二进制补码格式,可通过 SPI(3 线或 4 线)或 I2C 数字接口访问。这节课我们讲述的是使用
I2C 操作的方式。ADXL345 传感器的检测轴如图1:



1.png
gaoke231|  楼主 | 2017-11-24 22:19 | 显示全部楼层
当 ADXL345 沿检测轴正向加速时,它对正加速度进行检测。在检测重力时用户需要注意,当检测轴的方向与重力的方向相反时检测到的是正加速度。图2所示为输出对重力的响应:





2.png

使用特权

评论回复

打赏榜单

21ic小管家 打赏了 3.00 元 2017-12-13

gaoke231|  楼主 | 2017-11-24 22:21 | 显示全部楼层
ADXL345 原理图


3.png

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:23 | 显示全部楼层
ADXL345 写寄存器操作
在这里,我们主要讲述的是使用 IO 口模拟 I2C 的操作方式,因为 STM32 的硬件 I2C太复杂,操作起来有时候有出现 GUG。
写寄存器的操作步骤为:
1) 发送起始信号
2) 发送 I2C 写器件地址
3) 等待应答
4) 发送要写入的寄存器地址
5) 等待应答
6) 发送要写入的数据
7) 等待应答
8) 发送结束信号

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:23 | 显示全部楼层
例程函数的程序实现为:

static int8_t ADX345_WriteReg(uint8_t addr, uint8_t dat)
{
IIC_Start();
IIC_SendData(ADX345_ADDR); //24C02 写地址
if(IIC_WaitAck()) //如果无应答,表示发送失败
{
return 0xFF;
}
IIC_SendData(addr);
if(IIC_WaitAck()) //如果无应答,表示发送失败
{
return 0xFF;
}
IIC_SendData(dat);
if(IIC_WaitAck())
{
return 0xFF;
}
IIC_Stop();
return 0;
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:27 | 显示全部楼层
ADXL345 的读寄存器操作
ADXL345 的读寄存器操作步骤如下:
1) 发送起始信号
2) 发送 I2C 写器件地址
3) 等待应答
4) 发送 I2C 要读的寄存器地址
5) 等待应答
6) 发送起始信号
7) 发送 I2C 读器件地址
8) 等待应答
9) 接收返回数据
10) 发送结束信号

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:29 | 显示全部楼层
例程函数的程序实现为:

static uint8_t ADX345_ReadReg(uint8_t addr)
{
uint8_t readValue = 0xFF;
IIC_Start();
IIC_SendData(ADX345_ADDR); //24C02 写地址
if(IIC_WaitAck())
{
return readValue;
}
IIC_SendData(addr);
if(IIC_WaitAck())
{
return readValue;
}
IIC_Start();
IIC_SendData(ADX345_ADDR + 1); //24C02 读地址
if(IIC_WaitAck())
{
return readValue;
}
readValue = IIC_ReceiveData(0);
IIC_Stop();
return readValue;
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:35 | 显示全部楼层
ADXL345 初始化
在使用 ADXL345 之前,我们要对其寄存器进行一定的设置。首先我们来看一下它的寄存器命令。这里的初始化操作主要是:
1) 查看器件 ID。ADXL345 的 ID 寄存器为 0x00,它的 ID 为:
2) 设置 ADXL345 存储数据的方式和通信方式。这里我们设置寄存器地址为:0x31。
这里我们主要看一下我们要设置的位的意义,详细的数据大家可以查看数据手册。
 D6:是设置是否使用 SPI。
 D7:设置数据的存储方式,我们知道,ADXL345 的分辨率为 13位,那么当它用 16 位寄存器保存的时候,就会空 3 位。这里是设置数据存储的时候是选择数据保存左对齐还是右对齐。
3) 设置数据的输出速率这里我们设置的是 BW_RATE 寄存器,地址为:0x2C。我们这里设置为正常模式,传输速率 100HZ。
4) 设置测量模式和链接模式设置 POWER_CTL 寄存器。这里设置使用测量模式,不使用中断模式。而且链接模式也是设置为 1。
5) 设置不启用中断设置 INT_ENABLE 寄存器,设置它不使用中断模式。
6) 初始化偏移量。也就是设置 OFSX 寄存器、OFSY 寄存器、OFSZ 寄存器。

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:36 | 显示全部楼层
初始化的例程函数:
int ADX345_Init(void)
{
IIC_Config();
if(ADX345_ReadReg(ADX_DEVID) == 0xE5)
{
ADX345_WriteReg(ADX_DATA_FORMAT,0x2B);//13 位全分辨率,
输出数据右对齐,16g 量程
ADX345_WriteReg(ADX_BW_RATE,0x0A); // 数 据 输 出 速 度 为
100Hz
ADX345_WriteReg(ADX_POWER_CTL,0x28); //链接使能,测量模

ADX345_WriteReg(ADX_INT_ENABLE,0x00); //不使用中断
ADX345_WriteReg(ADX_OFSX,0x00); //敲击阀值
ADX345_WriteReg(ADX_OFSY,0x00); //X 轴偏移
ADX345_WriteReg(ADX_OFSZ,0x00); //Y 轴偏移
return 0;
}
return 0xFF; //返回初始化失败
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:37 | 显示全部楼层
读取 ADXL345 的 XYL 值。
ADX345 的 XYL 值,每个值有 2 个字节,一共 6 个字节,这 6 个字节(寄存器 0x32 至寄存器 0x37)都为 8 位字节,保存各轴的输出数据。寄存器 0x32和 0x33 保存 x 轴输出数据,寄存器 0x34 和 0x35 保存 y 轴输出数据,寄存器 0x36 和 0x37 保存 z 轴输出数据。输出数据为二进制补码,DATAx0 为最低有效字节,DATAx1 为最高有效字节,其中 x 代表 X、Y 或 Z。DATA_FORMAT 寄存器(地址 0x31)控制数据格式。建议所有寄存器执行多字节读取,以防止相继寄存器读取之间的数据变化。



使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:38 | 显示全部楼层
读取函数为
static int8_t ADX345_ReadXYZ(int16_t *xValue, int16_t *yValue, int16_t
*zValue)
{
uint8_t readValue[6], i;
IIC_Start();
IIC_SendData(ADX345_ADDR); //24C02 写地址
if(IIC_WaitAck())
{
return 0xFF;
}
IIC_SendData(0x32); //发送读地址(X 轴首地址)
if(IIC_WaitAck())
{
return 0xFF;
}
IIC_Start();
IIC_SendData(ADX345_ADDR + 1); //24C02 读地址
if(IIC_WaitAck())
{
return 0xFF;
}
/* 读取六个字节数据 */
for(i=0; i<6; i++)
{
if(i == 5) //接收最后一个字节时,发送 NACK
{
readValue = IIC_ReceiveData(0);
}
else //发送接收后应答
{
readValue = IIC_ReceiveData(1);
}
}
IIC_Stop();
/* 处理读取到的数据 */
*xValue = (uint16_t)(readValue[1] << 8) + readValue[0];
*yValue = (uint16_t)(readValue[3] << 8) + readValue[2];
*zValue = (uint16_t)(readValue[5] << 8) + readValue[4];
return 0;
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:39 | 显示全部楼层
所有例程代码为:
int16_t ADX_GetAngle(float xValue, float yValue, float zValue, uint8_t dir)
{
float temp;
float res = 0;
switch(dir)
{
/* 与自然 Z 轴的角度 */
case 0:
temp = sqrt((xValue * xValue + yValue * yValue)) / zValue;
res = atan(temp);
break;
/* 与自然 X 轴的角度 */
case 1:
temp = xValue / sqrt((yValue * yValue + zValue * zValue));
res = atan(temp);
break;
/* 与自然 Y 轴的角度 */
case 2:
temp = yValue / sqrt((xValue * xValue + zValue * zValue));
res = atan(temp);
break;
default:
break;
}
res = res * 1800 / 3.14;
return res;
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-24 22:40 | 显示全部楼层
主函数
int main(void)
{
uint8_t ledState;
uint32_t i;
/* 初始化 */
TFT_Init();
FLASH_Init();
SYSTICK_Config();
USART1_Config(9600);
LED_Config();
while(ADX345_Init())
{
GUI_Show12Char(60, 42, "ADX345 ERROR!", RED, BLACK);
SYSTICK_Delay1ms(100);
}
GUI_DisplayInit();
ADX345_Adjust();
while(1)
{
i++;
if(i > 0x02FFFF)
{
/* 读取 X,Y,Z 的加速度值 */
ADX_GetXYZData(&Xval, &Yval, &Zval);
printf(" x:%d \n", Xval);
printf(" y:%d \n", Yval);
printf(" z:%d \n", Zval);
/* 将读取到的加速度值转换为角度值 */
Xang=ADX_GetAngle(Xval, Yval, Zval,1);
Yang=ADX_GetAngle(Xval, Yval, Zval,2);
Zang=ADX_GetAngle(Xval, Yval, Zval,0);
GUI_DisplayData();
i = 0;
if(ledState == 0xFE)
{
ledState = 0xFF;
}
else
{
ledState = 0xFE;
}
LED_SetState(ledState);
}
}
}

使用特权

评论回复
hanzhen654| | 2017-11-24 22:49 | 显示全部楼层
不错,我有个六轴的不知道怎么用?这个代码可以参考吗?

使用特权

评论回复
sopc12| | 2017-11-25 09:33 | 显示全部楼层
不错,学习啦

使用特权

评论回复
gaoke231|  楼主 | 2017-11-26 22:36 | 显示全部楼层

相互学习了,懂得分享。

使用特权

评论回复
gaoke231|  楼主 | 2017-11-26 22:38 | 显示全部楼层
设置ADX345寄存器
static int8_t ADX345_WriteReg(uint8_t addr, uint8_t dat)
{
        IIC_Start();
        IIC_SendData(ADX345_ADDR); //24C02写地址
    if(IIC_WaitAck())          //如果无应答,表示发送失败
    {
        return 0xFF;
    }
    IIC_SendData(addr);
    if(IIC_WaitAck())         //如果无应答,表示发送失败
    {
        return 0xFF;
    }
    IIC_SendData(dat);
    if(IIC_WaitAck())
    {
        return 0xFF;
    }
   
    IIC_Stop();
    return 0;   
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-26 22:40 | 显示全部楼层
读取ADX345寄存器
static uint8_t ADX345_ReadReg(uint8_t addr)
{
    uint8_t readValue = 0xFF;

    IIC_Start();
        IIC_SendData(ADX345_ADDR);    //24C02写地址
    if(IIC_WaitAck())
    {
        return readValue;
    }
    IIC_SendData(addr);
    if(IIC_WaitAck())
    {
        return readValue;
    }

    IIC_Start();
        IIC_SendData(ADX345_ADDR + 1); //24C02读地址
    if(IIC_WaitAck())
    {
        return readValue;      
    }
    readValue = IIC_ReceiveData(0);
    IIC_Stop();

    return readValue;
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-26 22:40 | 显示全部楼层
读取X,Y,Z的AD值
static int8_t ADX345_ReadXYZ(int16_t *xValue, int16_t *yValue, int16_t *zValue)
{
    uint8_t readValue[6], i;
    IIC_Start();
        IIC_SendData(ADX345_ADDR);    //24C02写地址
    if(IIC_WaitAck())
    {
        return 0xFF;
    }
    IIC_SendData(0x32);           //发送读地址(X轴首地址)
    if(IIC_WaitAck())
    {
        return 0xFF;
    }

    IIC_Start();
        IIC_SendData(ADX345_ADDR + 1); //24C02读地址
    if(IIC_WaitAck())
    {
        return 0xFF;      
    }

    /* 读取六个字节数据 */
    for(i=0; i<6; i++)
    {
        
        if(i == 5)        //接收最后一个字节时,发送NACK
        {
            readValue[i] = IIC_ReceiveData(0);
        }
        else             //发送接收后应答
        {
            readValue[i] = IIC_ReceiveData(1);
        }
    }
    IIC_Stop();
    /* 处理读取到的数据 */
        *xValue = (uint16_t)(readValue[1] << 8) + readValue[0];             
        *yValue = (uint16_t)(readValue[3] << 8) + readValue[2];             
        *zValue = (uint16_t)(readValue[5] << 8) + readValue[4];           

   return 0;
}

使用特权

评论回复
gaoke231|  楼主 | 2017-11-26 22:41 | 显示全部楼层
初始化ADX345,并核对ADX的ID
int ADX345_Init(void)
{
    IIC_Config();
    if(ADX345_ReadReg(ADX_DEVID) == 0xE5)
    {
        ADX345_WriteReg(ADX_DATA_FORMAT,0x2B);//13位全分辨率,输出数据右对齐,16g量程
                ADX345_WriteReg(ADX_BW_RATE,0x0A);          //数据输出速度为100Hz
                ADX345_WriteReg(ADX_POWER_CTL,0x28);  //链接使能,测量模式
                ADX345_WriteReg(ADX_INT_ENABLE,0x00); //不使用中断                 
                 ADX345_WriteReg(ADX_OFSX,0x00);       //敲击阀值
                ADX345_WriteReg(ADX_OFSY,0x00);       //X轴偏移
                ADX345_WriteReg(ADX_OFSZ,0x00);       //Y轴偏移
        return 0;
    }
   
    return 0xFF; //返回初始化失败
}

使用特权

评论回复
发新帖 本帖赏金 3.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

1310

帖子

5

粉丝