wordpress有趣代码,seo优化推广工程师招聘,建设网站花费,快速搭建网站 数据存储一、简介 ADXL345 是一款 ADI 公司推出的基于 iMEMS 技术的超低功耗3轴加速度计#xff0c;分辨率高(13位)#xff0c;测量范围达 16g。数字输出数据为 16 位二进制补码格式#xff0c;可通过 SPI(3线或4线) 或 I2C 数字接口访问。ADXL345 非常适合移动设备应用。它可以在倾…一、简介 ADXL345 是一款 ADI 公司推出的基于 iMEMS 技术的超低功耗3轴加速度计分辨率高(13位)测量范围达 ±16g。数字输出数据为 16 位二进制补码格式可通过 SPI(3线或4线) 或 I2C 数字接口访问。ADXL345 非常适合移动设备应用。它可以在倾斜检测应用中测量静态重力加速度还可以测量运动或冲击导致的动态加速度。其高分辨率(3.9mg/LSB)能够测量不到 1.0° 的倾斜角度变化。 该器件提供多种特殊检测功能。活动和非活动检测功能通过比较任意轴上的加速度与用户设置的阈值来检测有无运动发生。敲击检测功能可以检测任意方向的单振和双振动作。自由落体检测功能可以检测器件是否正在掉落。这些功能可以独立映射到两个中断输出引脚中的一个。正在申请专利的集成式存储器管理系统采用一个32级先进先出(FIFO)缓冲器可用于存储数据从而将主机处理器负荷降至最低并降低整体系统功耗。低功耗模式支持基于运动的智能电源管理从而以极低的 功耗进行阈值感测和运动加速度测量。 官方数据手册https://pan.baidu.com/s/1-UCkno6kQFugSy8NEhNhHg?pwdtp7p 提取码tp7p
二、硬件连接
功能口引脚MISO17MOSI18SCLK20CS19
三、添加SPI驱动
查看 ESP32学习笔记19——SPI(主机)接口使用
四、SPI通信注意事项
4.1 SPI模式
一般内置 SPI 功能的单片机上都有两个寄存器配置位 CPOL 和 CPHA。 CPOL 就是决定 SCLK 这个时钟信号线在没有数据传输的时候的电平状态。 CPHA 就是决定数据位传输是从第一个时钟 (SCLK) 边沿开始还是第二个从二个时钟 (SCLK) 边沿开始。 因此 CPOL 和 CPHA 合体就形成了SPI四种模式。 模式0(CPOL0CPHA0) CPOL 0空闲时是低电平第1个跳变沿是上升沿第2个跳变沿是下降沿 CPHA 0数据在第1个跳变沿上升沿采样 模式1(CPOL0CPHA1) CPOL 0空闲时是低电平第1个跳变沿是上升沿第2个跳变沿是下降沿 CPHA 1数据在第2个跳变沿下降沿采样 模式2(CPOL1CPHA0) CPOL 1空闲时是高电平第1个跳变沿是下降沿第2个跳变沿是上升沿 CPHA 0数据在第1个跳变沿下降沿采样 模式3(CPOL1CPHA1) CPOL 1空闲时是高电平第1个跳变沿是下降沿第2个跳变沿是上升沿 CPHA 1数据在第2个跳变沿上升沿采样
查看ADXL345中文数据手册第15页得知ADXL345 SPI模式应为 模式3(CPOL1CPHA1)。
4.2 SPI读写以及多字节读取指令的区别
查看ADXL345中文数据手册第14、15页得知读的时候地址的最高位为1写的时候地址的最高位为0在进行多字节读取的时候次高位为1这样才可以多字节写和读。
4.3 SPI时钟要求
查看ADXL345中文数据手册第14页得知在设置读取速率的时候要和SPI的时钟匹配起来否则可能读到错误的数据比如设置1600HZSPI时钟要大于2MHZ。SPI读取数据时钟最大5MHZ。
4.4 器件ID寄存器
查看ADXL345中文数据手册第23页得知寄存器0x00保存0xE5的固定器件ID代码可用于校验SPI是否通信成功。
五、移植文件
5.1 board_spi.c
#include math.h
#include freertos/FreeRTOS.h
#include freertos/task.h
#include esp_log.h#include board_spi.h
#include board_adxl345.hstatic void delayMs(uint32_t time);void ADXL345_Init(void)
{ADXL345_SPI_Init();while(ADXL345_GetDeviceId() ! 0xE5){printf(ADXL345 Init Fail!\n);delayMs(1000);}ADXL345_WriteReg(DATA_FORMAT, 0x0B); // 13位全分辨率输出数据右对齐16g量程ADXL345_WriteReg(BW_RATE, 0x0A); // 数据输出速度为100HzADXL345_WriteReg(POWER_CTL, 0x08); // 无链接测量模式ADXL345_WriteReg(INT_ENABLE, 0x80); // DATA_READY中断printf(ADXL345 Init Success!\n);
}uint8_t ADXL345_GetDeviceId(void)
{uint8_t ret ADXL345_ReadReg(DEVICE_ID);return ret;
}void ADXL345_ReadXYZ(short *x, short *y, short *z)
{uint8_t x0,y0,z0;uint8_t x1,y1,z1;x0 ADXL345_ReadReg(DATA_X0);y0 ADXL345_ReadReg(DATA_Y0);z0 ADXL345_ReadReg(DATA_Z0);x1 ADXL345_ReadReg(DATA_X1);y1 ADXL345_ReadReg(DATA_Y1);z1 ADXL345_ReadReg(DATA_Z1);// printf(--------------x0:%d,y0:%d,z0:%d\tx1:%d,y1:%d,z1:%d, x0,y0,z0,x1,y1,z1);*x (short)(((uint16_t)x1 8) x0); // DATA_X1为高位有效字节*y (short)(((uint16_t)y1 8) y0); // DATA_Y1为高位有效字节*z (short)(((uint16_t)z1 8) z0); // DATA_Z1为高位有效字节// printf(--------------x%d,y%d,z%d,*x,*y,*z);
}/*读取ADXL345的数据并做滤波处理读times次再取平均值*/
void ADXL345_ReadAverage(short *x, short *y, short *z, uint8_t times)
{if(0 times){return;}uint8_t i;short x_temp,y_temp,z_temp;*x 0;*y 0;*z 0;for(i 0; i times; i){ADXL345_ReadXYZ(x_temp, y_temp, z_temp);*x x_temp;*y y_temp;*z z_temp;delayMs(5);}*x / times;*y / times;*z / times;
}/*使用偏移寄存器进行偏移校准*/
void ADXL345_AutoAdjust(void)
{uint8_t i;short x_temp,y_temp,z_temp;short x_offset 0;short y_offset 0;short z_offset 0;char x_calib 0;char y_calib 0;char z_calib 0;ADXL345_WriteReg(DATA_FORMAT, 0x0B); // 13位全分辨率输出数据右对齐16g量程ADXL345_WriteReg(BW_RATE, 0x0A); // 数据输出速度为100HzADXL345_WriteReg(POWER_CTL, 0x08); // 无链接测量模式ADXL345_WriteReg(INT_ENABLE, 0x80); // DATA_READY中断delayMs(12);for(i 0; i 10; i){ADXL345_ReadAverage(x_temp, y_temp, z_temp, 10);x_offset x_temp;y_offset y_temp;z_offset z_temp;}x_offset / 10;y_offset / 10;z_offset / 10;x_calib - x_offset / 4;y_calib - y_offset / 4;z_calib - (z_offset - 256) / 4;ADXL345_WriteReg(OFSX, x_calib);ADXL345_WriteReg(OFSY, y_calib);ADXL345_WriteReg(OFSZ, z_calib);
}/*计算ADXL345角度x/y/表示各方向上的加速度分量dir表示要获得的角度*/
short ADXL345_GetAngle(float x, float y, float z, uint8_t dir)
{float temp;float res 0; // 弧度值switch(dir){case 0: // 0表示与Z轴的角度temp sqrt((x*x y*y)) / z;res atan(temp);break;case 1: // 1表示与X轴的角度temp x / sqrt((y*y z*z));res atan(temp);break;case 2: // 2表示与Y轴的角度temp y / sqrt((x*x z*z));res atan(temp);break;}return res * 180 / 3.14; // 返回角度值// return res*180/3.14*10; //乘以10是为了取一位小数角度精确到0.1°所以要乘以10
}/**brief 写寄存器param addr -[in] 寄存器地址param data -[in] 写入数据return 无
*/
void ADXL345_WriteReg(uint8_t addr, uint8_t data)
{uint8_t send_data[2];uint32_t size 2;addr 0x3F;send_data[0] addr;send_data[1] data;SPI_CS_LOW;ADXL345_SPI_Write(send_data, size);SPI_CS_HIGH;
}/**brief 读寄存器param addr -[in] 寄存器地址return 读出一字节数据
*/
uint8_t ADXL345_ReadReg(uint8_t addr)
{uint8_t receive_data;uint32_t size 1;addr 0x3F;addr | 0x80;SPI_CS_LOW;ADXL345_SPI_Write(addr, size);ADXL345_SPI_Read(receive_data, size);SPI_CS_HIGH;return receive_data;
}/**brief 毫秒级延时函数param time -[in] 延时时间毫秒return 无
*/
static void delayMs(uint32_t time)
{vTaskDelay(time / portTICK_PERIOD_MS);
}5.2 board_spi.h
#ifndef _BOARD_SPI_H_
#define _BOARD_SPI_H_/********************************************************************** INCLUDES*/
#include stdint.h
#include driver/gpio.h/********************************************************************** DEFINITIONS*/
#define ADXL345_SPI_MISO_PIN GPIO_NUM_19
#define ADXL345_SPI_MOSI_PIN GPIO_NUM_23
#define ADXL345_SPI_SCLK_PIN GPIO_NUM_18
#define ADXL345_SPI_CS_PIN GPIO_NUM_5#define DMA_CHAN 2#define SPI_CS_LOW ADXL345_SPI_CS_Set(0)
#define SPI_CS_HIGH ADXL345_SPI_CS_Set(1)/********************************************************************** API FUNCTIONS*/
void ADXL345_SPI_Init(void);
void ADXL345_SPI_Write(uint8_t *pData, uint32_t dataLen);
void ADXL345_SPI_Read(uint8_t *pData, uint32_t dataLen);
void ADXL345_SPI_CS_Set(uint8_t level);#endif /* _BOARD_SPI_H_ */5.3 board_adxl345.c
#include math.h
#include freertos/FreeRTOS.h
#include freertos/task.h
#include esp_log.h#include board_spi.h
#include board_adxl345.hstatic void delayMs(uint32_t time);void ADXL345_Init(void)
{ADXL345_SPI_Init();while(ADXL345_GetDeviceId() ! 0xE5){printf(ADXL345 Init Fail!\n);delayMs(1000);}ADXL345_WriteReg(DATA_FORMAT, 0x0B); // 13位全分辨率输出数据右对齐16g量程ADXL345_WriteReg(BW_RATE, 0x0A); // 数据输出速度为100HzADXL345_WriteReg(POWER_CTL, 0x08); // 无链接测量模式ADXL345_WriteReg(INT_ENABLE, 0x80); // DATA_READY中断printf(ADXL345 Init Success!\n);
}uint8_t ADXL345_GetDeviceId(void)
{uint8_t ret ADXL345_ReadReg(DEVICE_ID);return ret;
}void ADXL345_ReadXYZ(short *x, short *y, short *z)
{uint8_t x0,y0,z0;uint8_t x1,y1,z1;x0 ADXL345_ReadReg(DATA_X0);y0 ADXL345_ReadReg(DATA_Y0);z0 ADXL345_ReadReg(DATA_Z0);x1 ADXL345_ReadReg(DATA_X1);y1 ADXL345_ReadReg(DATA_Y1);z1 ADXL345_ReadReg(DATA_Z1);// printf(--------------x0:%d,y0:%d,z0:%d\tx1:%d,y1:%d,z1:%d, x0,y0,z0,x1,y1,z1);*x (short)(((uint16_t)x1 8) x0); // DATA_X1为高位有效字节*y (short)(((uint16_t)y1 8) y0); // DATA_Y1为高位有效字节*z (short)(((uint16_t)z1 8) z0); // DATA_Z1为高位有效字节// printf(--------------x%d,y%d,z%d,*x,*y,*z);
}/*读取ADXL345的数据并做滤波处理读times次再取平均值*/
void ADXL345_ReadAverage(short *x, short *y, short *z, uint8_t times)
{if(0 times){return;}uint8_t i;short x_temp,y_temp,z_temp;*x 0;*y 0;*z 0;for(i 0; i times; i){ADXL345_ReadXYZ(x_temp, y_temp, z_temp);*x x_temp;*y y_temp;*z z_temp;delayMs(5);}*x / times;*y / times;*z / times;
}/*使用偏移寄存器进行偏移校准*/
void ADXL345_AutoAdjust(void)
{uint8_t i;short x_temp,y_temp,z_temp;short x_offset 0;short y_offset 0;short z_offset 0;char x_calib 0;char y_calib 0;char z_calib 0;ADXL345_WriteReg(DATA_FORMAT, 0x0B); // 13位全分辨率输出数据右对齐16g量程ADXL345_WriteReg(BW_RATE, 0x0A); // 数据输出速度为100HzADXL345_WriteReg(POWER_CTL, 0x08); // 无链接测量模式ADXL345_WriteReg(INT_ENABLE, 0x80); // DATA_READY中断delayMs(12);for(i 0; i 10; i){ADXL345_ReadAverage(x_temp, y_temp, z_temp, 10);x_offset x_temp;y_offset y_temp;z_offset z_temp;}x_offset / 10;y_offset / 10;z_offset / 10;x_calib - x_offset / 4;y_calib - y_offset / 4;z_calib - (z_offset - 256) / 4;ADXL345_WriteReg(OFSX, x_calib);ADXL345_WriteReg(OFSY, y_calib);ADXL345_WriteReg(OFSZ, z_calib);
}/*计算ADXL345角度x/y/表示各方向上的加速度分量direction表示要获得的角度*/
short ADXL345_GetAngle(float x, float y, float z, uint8_t direction)
{float temp;float res 0; // 弧度值switch(direction){case 0: // 0表示与Z轴的角度temp sqrt((x*x y*y)) / z;res atan(temp);break;case 1: // 1表示与X轴的角度temp x / sqrt((y*y z*z));res atan(temp);break;case 2: // 2表示与Y轴的角度temp y / sqrt((x*x z*z));res atan(temp);break;}return res * 180 / 3.14; // 返回角度值// return res*180/3.14*10; //乘以10是为了取一位小数角度精确到0.1°所以要乘以10
}/**brief 写寄存器param addr -[in] 寄存器地址param data -[in] 写入数据return 无
*/
void ADXL345_WriteReg(uint8_t addr, uint8_t data)
{uint8_t send_data[2];uint32_t size 2;addr 0x3F;send_data[0] addr;send_data[1] data;SPI_CS_LOW;ADXL345_SPI_Write(send_data, size);SPI_CS_HIGH;
}/**brief 读寄存器param addr -[in] 寄存器地址return 读出一字节数据
*/
uint8_t ADXL345_ReadReg(uint8_t addr)
{uint8_t receive_data;uint32_t size 1;addr 0x3F;addr | 0x80;SPI_CS_LOW;ADXL345_SPI_Write(addr, size);ADXL345_SPI_Read(receive_data, size);SPI_CS_HIGH;return receive_data;
}/**brief 毫秒级延时函数param time -[in] 延时时间毫秒return 无
*/
static void delayMs(uint32_t time)
{vTaskDelay(time / portTICK_PERIOD_MS);
}5.4 board_adxl345.h
#ifndef _BOARD_ADXL345_H_
#define _BOARD_ADXL345_H_#ifdef __cplusplus
extern C
{
#endif#include stdint.h#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 // 静止时间 比例1 sec /LSB
#define ACT_INACT_CTL 0X27 // 启用运动/静止检测
#define THRESH_FF 0X28 // 自由下落阈值 建议采用300 mg与600 mg(0x05至0x09)之间的值 比例62.5 mg/LSB
#define TIME_FF 0X29 // 自由下落时间 建议采用100 ms与350 ms(0x14至0x46)之间的值 比例5ms/LSB
#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 Z_AXIS 0
#define X_AXIS 1
#define Y_AXIS 2void ADXL345_Init(void);
uint8_t ADXL345_GetDeviceId(void);
void ADXL345_ReadXYZ(short *x, short *y, short *z);
void ADXL345_ReadAverage(short *x, short *y, short *z, uint8_t times);
short ADXL345_GetAngle(float x, float y, float z, uint8_t direction);
void ADXL345_WriteReg(uint8_t addr, uint8_t data);
uint8_t ADXL345_ReadReg(uint8_t addr);#ifdef __cplusplus
}
#endif#endif /* _BOARD_ADXL345_H_ */六、初始化流程
开机先等待 1.1ms——设置数据格式——设置功耗模式——使能相应中断——结束。 七、角度值转换公式 八、API调用
需包含头文件 board_adxl345.h
ADXL345_Init
功能ADXL345的初始化函数函数定义void ADXL345_Init(void)参数无返回无
ADXL345_GetDeviceId
功能检查SPI通信返回值为0xE5则通信正常函数定义uint8_t ADXL345_GetDeviceId(void)参数无返回固定器件ID值0xE5
ADXL345_ReadXYZ
功能读取X、Y、Z轴加速度值函数定义void ADXL345_ReadXYZ(short *x, short *y, short *z)参数要读取的方向XYZ轴返回值返回无
ADXL345_GetAngle
功能读取角度函数定义short ADXL345_GetAngle(float x, float y, float z, uint8_t direction)参数x,y,zX、Y、Z轴加速度值direction要读取的方向XYZ轴返回角度数
九、使用例子
1添加头文件
#include board_adxl345.h2添加初始化代码main.c的main函数中 首先调用 ADXL345_SPI_Init() 初始化 SPI 通信最后调用 ADXL345_Init() 初始化加速度传感器模块功能。
#include stdio.h
#include stdbool.h
#include unistd.hvoid app_main(void)
{ADXL345_Init();/*-------------------------- 创建线程 ---------------------------*/xTaskCreate(monitor_task, monitor_task, 2048, NULL, 4, NULL);
}3添加任务定时读取数据
static void monitor_task(void *arg)
{while(1) // 任务都是一个无限循环不能返回{short x_value,y_value,z_value;short x_angle,y_angle,z_angle;ADXL345_ReadAverage(x_value, y_value, z_value, 10);x_angle ADXL345_GetAngle(x_value, y_value, z_value, X_AXIS);y_angle ADXL345_GetAngle(x_value, y_value, z_value, Y_AXIS);z_angle ADXL345_GetAngle(x_value, y_value, z_value, Z_AXIS);printf(x_ang:%d y_ang:%d z_ang:%d\n, x_angle, y_angle, z_angle);vTaskDelay(1000 / portTICK_PERIOD_MS); // 1s}
}4查看打印
十、测量方向 • 由 Leung 写于 2023 年 8 月 7 日
• 参考STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块 STM32 HAL库学习笔记-(SPI驱动ADXL345) STM32CubeMX系列|ADXL345传感器 ADXL345 三轴加速度数据SPI读取、多字节读取、DMA SPI读取和FIFO数据读取