之前使用的是ADXL362测量加速度,功耗特别低,使用的还可以,但是后来用于测量角度时误差特别大,最终更换为MMA8452Q ,这个芯片较便宜,测量设备静态的倾角,还是蛮好用的,我的使用中只需要测量Z轴的倾角。
/*************************************************************************************************************
* 文件名: MMA8452Q.c
* 功能: MMA8452Q驱动
* 作者: cp1300@139.com
* 创建时间: 2018-04-09
* 最后修改时间: 2018-04-09
* 详细: MMA8452Q三轴加速度传感器
依赖SoftwareIIC
*************************************************************************************************************/
#include "system.h"
#include "MMA8452Q.h"
#include "math.h"
#include <stdio.h>
#include "SoftwareIIC.h"
//调试宏开关
#define MMA8452Q_DBUG 1
#if MMA8452Q_DBUG
#include "system.h"
#define MMA8452Q_Debug(format,...) uart_printf(format,##__VA_ARGS__)
#else
#define MMA8452Q_Debug(format,...) /\
/
#endif //MMA8452Q_DBUG
#define PI 3.1415926535898
u8 MMA8452Q_ReadOneReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr); //MMA8452Q读取一个寄存器
void MMA8452Q_ReadMultReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr, u8 RegNum, u8 DataBuff[]); //MMA8452Q读取多个寄存器
void MMA8452Q_WriteOneReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr,u8 data); //MMA8452Q写一个寄存器
/*************************************************************************************************************************
*函数 : bool MMA8452Q_Init(MMA8452Q_HANDLE *pHandle, u8 SlaveAddr)
*功能 : MMA8452Q初始化
*参数 : pHandle:句柄;SlaveAddr:芯片IIC地址
*返回 : TRUE:初始化成功;FALSE:初始化失败
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2018-04-09
*最后修改时间 : 2018-04-09
*说明 :
*************************************************************************************************************************/
bool MMA8452Q_Init(MMA8452Q_HANDLE *pHandle, u8 SlaveAddr)
{
u8 temp;
if(pHandle == NULL) return FALSE;
pHandle->SlaveAddr = SlaveAddr;
MMA8452Q_WriteOneReg(pHandle, 0x2A, 0x01);
MMA8452Q_WriteOneReg(pHandle, 0x2B, 0x02);
temp = MMA8452Q_ReadOneReg(pHandle, 0x0D); //读取器件ID
if(temp != 0x2A) //ID不对
{
uart_printf("初始化失败,ID错误:0x%02X\r\n", temp);
return FALSE;
}
uart_printf("ID:0x%02X\r\n", temp);
return TRUE;
}
/*************************************************************************************************************************
*函数 : u8 MMA8452Q_ReadOneReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr)
*功能 : MMA8452Q读取一个寄存器
*参数 : pHandle:句柄;RegAddr:寄存器地址
*返回 : 读取的寄存器值
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2018-04-09
*最后修改时间 : 2018-04-09
*说明 :
*************************************************************************************************************************/
u8 MMA8452Q_ReadOneReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr)
{
u8 data;
SIIC_Start(&pHandle->IIC_Handle); //产生IIC起始信号
if(SIIC_SendByte(&pHandle->IIC_Handle, pHandle->SlaveAddr) == FALSE) //发送设备地址+写信号
{
DEBUG("没有收到ACK\r\n");
}
SIIC_SendByte(&pHandle->IIC_Handle, RegAddr); //发送寄存器地址
SIIC_Start(&pHandle->IIC_Handle); //产生IIC起始信号
SIIC_SendByte(&pHandle->IIC_Handle, pHandle->SlaveAddr|BIT0); //发送设备地址+读信号
data = SIIC_ReadByte(&pHandle->IIC_Handle, TRUE); //SIIC读取一个字节
SIIC_Stop(&pHandle->IIC_Handle); //产生IIC停止信号
return data;
}
/*************************************************************************************************************************
*函数 : void MMA8452Q_ReadMultReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr, u8 RegNum, u8 DataBuff[])
*功能 : MMA8452Q读取多个寄存器
*参数 : pHandle:句柄;RegAddr:寄存器地址;RegNum:寄存器数量;DataBuff:返回结果缓冲区
*返回 : 无
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2018-04-09
*最后修改时间 : 2018-04-09
*说明 :
*************************************************************************************************************************/
void MMA8452Q_ReadMultReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr, u8 RegNum, u8 DataBuff[])
{
u8 i;
SIIC_Start(&pHandle->IIC_Handle); //产生IIC起始信号
SIIC_SendByte(&pHandle->IIC_Handle, pHandle->SlaveAddr); //发送设备地址+写信号
SIIC_SendByte(&pHandle->IIC_Handle, RegAddr); //发送寄存器地址
SIIC_Start(&pHandle->IIC_Handle); //产生IIC起始信号
SIIC_SendByte(&pHandle->IIC_Handle, pHandle->SlaveAddr|BIT0); //发送设备地址+读信号
for(i = 0;i < RegNum;i ++)
{
if(i == (RegNum-1)) //最后一字节不响应ACK
{
DataBuff[i] = SIIC_ReadByte(&pHandle->IIC_Handle, FALSE); //SIIC读取一个字节-NAK
}
else
{
DataBuff[i] = SIIC_ReadByte(&pHandle->IIC_Handle, TRUE); //SIIC读取一个字节-ACK
}
}
SIIC_Stop(&pHandle->IIC_Handle); //产生IIC停止信号
}
/*************************************************************************************************************************
*函数 : void MMA8452Q_WriteOneReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr,u8 data)
*功能 : MMA8452Q写一个寄存器
*参数 : pHandle:句柄;RegAddr:寄存器地址;data:要写入的值
*返回 : 无
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2018-04-09
*最后修改时间 : 2018-04-09
*说明 :
*************************************************************************************************************************/
void MMA8452Q_WriteOneReg(MMA8452Q_HANDLE *pHandle,u8 RegAddr,u8 data)
{
SIIC_Start(&pHandle->IIC_Handle); //产生IIC起始信号
SIIC_SendByte(&pHandle->IIC_Handle, pHandle->SlaveAddr); //发送设备地址+写信号
SIIC_SendByte(&pHandle->IIC_Handle, RegAddr); //发送寄存器地址
SIIC_SendByte(&pHandle->IIC_Handle, data); //发送要写入的数据
SIIC_Stop(&pHandle->IIC_Handle); //产生IIC停止信号
}
/*************************************************************************************************************************
*函数 : bool MMA8452Q_ReadAcceleration(MMA8452Q_HANDLE *pHandle, s16 *pXa,s16 *pYa, s16 *pZa)
*功能 : MMA8452Q 读取三轴加速度
*参数 : pHandle:句柄;pXa:返回X轴加速度;pYa:返回Y轴加速度;pZa:返回Z轴加速度
*返回 : TRUE:成功;FALSE:失败
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2018-04-09
*最后修改时间 : 2018-04-09
*说明 :
*************************************************************************************************************************/
bool MMA8452Q_ReadAcceleration(MMA8452Q_HANDLE *pHandle, s16 *pXa,s16 *pYa, s16 *pZa)
{
u8 buff[6];
s16 temp;
temp = MMA8452Q_ReadOneReg(pHandle, 0x0D); //读取器件ID
if(temp != 0x2A) //ID不对
{
return FALSE;
}
MMA8452Q_ReadMultReg(pHandle, 1, 6, buff); //读取数据
temp = buff[0];
temp<<=4;
temp|= buff[1]>>4;
if(buff[0] & BIT7) //负数
{
temp |= 0xF000;
}
*pXa = temp; //X轴
temp = buff[2];
temp<<=4;
temp|= buff[3]>>4;
if(buff[2] & BIT7) //负数
{
temp |= 0xF000;
}
*pYa = temp; //Y轴
temp = buff[4];
temp<<=4;
temp|= buff[5]>>4;
if(buff[4] & BIT7) //负数
{
temp |= 0xF000;
}
*pZa = temp; //Z轴
return TRUE;
}
/*************************************************************************************************************************
*函数 : void ADXL362_CalAngle(s16 Xa,s16 Ya, s16 Za, float *pAngleX, float *pAngleY, float *pAngleZ)
*功能 : ADXL362 通过加速度计算角度信息
*参数 : Xa:X轴加速度;Ya:Y轴加速度;Za:Z轴加速度,pAngleX:X方向倾角;pAngleY:Y方向倾角;pAngleZ:Z方向倾角
*返回 : 无
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2016-04-06
*最后修改时间 : 2018-03-13
*说明 : 需要进行浮点,反正切运算
*************************************************************************************************************************/
void MMA8452Q_CalAngle(s16 Xa,s16 Ya, s16 Za, float *pAngleX, float *pAngleY, float *pAngleZ)
{
double A;
//X方向
A = (double)Ya*Ya+(double)Za*Za;
A = sqrt(A);
A = (double)Xa/A;
A = atan(A);
A = A*180/PI;
if(Za<0) //将坐标转换为±180度
{
if(A <0)A=-90-(A+90);
else A=90+(90-A);
}
if(A <0) //将坐标转换为360度
{
A=fabs(A);
A = 180+180-A;
}
*pAngleX = A;
//Y方向
A = (double)Xa*Xa+(double)Za*Za;
A = sqrt(A);
A = (double)Ya/A;
A = atan(A);
A = A*180/PI;
if(Za<0)//将坐标转换为±180度
{
if(A <0)A=-90-(A+90);
else A=90+(90-A);
}
if(A <0) //将坐标转换为360度
{
A=fabs(A);
A = 180+180-A;
}
*pAngleY = A;
//Z方向
A = (double)Xa*Xa+(double)Ya*Ya;
A = sqrt(A);
A = (double)A/abs(Za);
A = atan(A);
A = A*180/PI;
uart_printf("XA:%d\tYA:%d\tZA:%d\t",Xa,Ya,Za);
/*if(Za<0)//将坐标转换为±180度
{
if(A <0)A=-90-(A+90);
else A=90+(90-A);
}
if(A <0) //将坐标转换为360度
{
A=fabs(A);
A = 180+180-A;
}*/
*pAngleZ = A;
}
/*************************************************************************************************************************
*函数 : bool MMA8452Q_GetZAxisAngle(MMA8452Q_HANDLE *pHandle,s16 AcceBuff[3], float *pAngleZ)
*功能 : MMA8452Q 获取Z轴倾角
*参数 : pHandle:句柄;AcceBuff:3个轴的加速度;pAngleZ:Y方向倾角
*返回 : TRUE:成功;FALSE:失败
*依赖 : 底层宏定义
*作者 : cp1300@139.com
*时间 : 2018-04-09
*最后修改时间 : 2018-04-09
*说明 :
*************************************************************************************************************************/
bool MMA8452Q_GetZAxisAngle(MMA8452Q_HANDLE *pHandle,s16 AcceBuff[3], float *pAngleZ)
{
double fx,fy,fz;
double A;
s16 Xa,Ya,Za;
if(MMA8452Q_ReadAcceleration(pHandle, &Xa, &Ya, &Za) == FALSE) return FALSE; //ADXL362 读取加速度数据
//uart_printf("Xa:%d \tYa:%d \tZa:%d \r\n",Xa,Ya,Za);
AcceBuff[0] = Xa; //x轴加速度
AcceBuff[1] = Ya; //y轴加速度
AcceBuff[2] = Za; //z轴加速度
fx = Xa;
fx *= 10.0/1024;
fy = Ya;
fy *= 10.0/1024;
fz = Za;
fz *= 10.0/1024;
//uart_printf("fx:%.04f\tfy:%.04f\tfz:%.04f\t\r\n",fx,fy,fz);
//Z方向
A = fx*fx+fy*fy;
A = sqrt(A);
A = (double)A/fz;
A = atan(A);
A = A*180/PI;
*pAngleZ = A;
//uart_printf("=======角度:%.04f\r\n",*pAngleZ);
return TRUE;
}
/*************************************************************************************************************
* 文件名: MMA8452Q.c
* 功能: MMA8452Q驱动
* 作者: cp1300@139.com
* 创建时间: 2018-04-09
* 最后修改时间: 2018-04-09
* 详细: MMA8452Q三轴加速度传感器
*************************************************************************************************************/
#ifndef _MMA8452Q_H_
#define _MMA8452Q_H_
#include "system.h"
#include "SoftwareIIC.h"
//MMA8452Q 句柄
typedef struct
{
SIIC_HANDLE IIC_Handle;
u8 SlaveAddr;
}MMA8452Q_HANDLE;
bool MMA8452Q_Init(MMA8452Q_HANDLE *pHandle, u8 SlaveAddr); //MMA8452Q初始化
bool MMA8452Q_ReadAcceleration(MMA8452Q_HANDLE *pHandle, s16 *pXa,s16 *pYa, s16 *pZa); //MMA8452Q 读取三轴加速度
bool MMA8452Q_GetZAxisAngle(MMA8452Q_HANDLE *pHandle,s16 AcceBuff[3], float *pAngleZ); //MMA8452Q 获取Z轴角度信息
#endif /*_MMA8452Q_H_*/
//测试
g_SysFlag.ADXL362_Status = MMA8452Q_Init(&g_SysFlag.MMA8452Q_Handle, 0x1C<<1);
if(g_SysFlag.ADXL362_Status == FALSE)
{
DEBUG("MMA8452Q初始化失败!\r\n");
}
if(MMA8452Q_GetZAxisAngle(&g_SysFlag.MMA8452Q_Handle, g_SysFlag.AcceBuff, &AngleZ) == FALSE) //ADXL362 获取角度信息
{
//角度读取失败
AngleZ = 0; //读取失败,固定为0
}
附上IIC接口: https://blog.csdn.net/cp1300/article/details/75644988