一、前言本文完整讲解基于 STM32F103C8T6 ADXL345 MEMS 三轴加速度传感器 0.96 寸 I2C OLED 的整套工程原理、硬件接线、寄存器配置、数据换算与现象分析采用软件模拟 I2C通信无需硬件 I2C 外设新手友好适合单片机课程教学、姿态检测入门实验。整套工程实现逻辑 模块姿态 / 振动 / 运动改变 → ADXL345 内部 MEMS 采集加速度 → 软件 I2C 读取三轴原始数据 → 转换为 mg 单位 → OLED 实时打印 X/Y/Z 三轴加速度数值视频讲解STM32F103 驱动ADXL345三轴加速度传感器(软件I2COLED实时显示)https://www.bilibili.com/video/BV1wjMd6EEDW/?share_sourcecopy_webvd_source91b967b41a17a5686913521545a8c3fb二、硬件接线说明2.1 器件引脚对应表ADXL345 模块引脚STM32F103 引脚功能说明SDAPA0软件 I2C 数据线SCK(SCL)PA1软件 I2C 时钟线SPI 标 SCKI2C 模式等效 SCLCS3.3V拉高切换至 I2C 通信模式SDO/ALT ADDRESSGNDI2C 从机地址 0x53VCC3.3V传感器供电严禁直连 5V无稳压模块仅支持 2~3.6VGNDGND单片机与传感器共地通信稳定前提OLED 屏幕引脚STM32F103 引脚功能说明SCLPB8OLED 软件 I2C 时钟SDAPB9OLED 软件 I2C 数据VCC3.3V屏幕供电GNDGND共地2.2 关键引脚补充说明CS 引脚拉高时 ADXL345 工作在 I2C 模式若拉低则切换 SPI 通信本工程全程使用 I2C必须接 3.3V。SDO 地址选择引脚接地7 位 I2C 地址0x53写地址0xA6读地址0xA7本工程使用接 3.3V7 位地址变为0x1D代码需要同步修改否则读不到数据I2C 上拉电阻I2C 为开漏总线标准需要 4.7kΩ 上拉至 3.3V市面上成品 ADXL345 模块大多自带板载上拉电阻若出现数据乱跳、通信失败自行增加上拉电阻排查。供电要求芯片额定电压 2.0~3.6V只有自带稳压、电平转换的 5V 兼容模块才能接 5V教学实验统一推荐 3.3V 供电避免烧坏传感器。三、ADXL345 核心工作原理ADXL345 是数字输出 MEMS 三轴加速度传感器核心是芯片内部微型机械质量块结构。3.1 信号转换流程姿态 / 晃动 / 振动 → 惯性使内部质量块产生微小位移 → 两侧差分电容容量发生变化 → 内部电路放大、滤波、ADC 模数转换 → 输出 X/Y/Z 三轴数字加速度值可检测两种加速度静态加速度重力传感器静止时仅受重力用于判断倾斜角度、设备姿态动态加速度晃动、撞击、运动产生可做振动检测、敲击识别。重点知识点传感器只采集加速度无法直接获取位移、速度仅单次读数不能推算移动距离。3.2 静止时数值规律地球恒定存在 1g 重力加速度1000mg设备平放静止时Z 轴垂直地面Z≈±1000mgX、Y 平行地面X、Y≈0mg 翻转传感器后坐标轴正负号反转任意倾斜状态下三轴矢量合加速度约等于 1000mg。自由落体特殊现象完全失重状态下 X/Y/Z 三轴读数全部趋近 0mg。四、软件 I2C 通信与三轴数据读取逻辑本工程不使用 STM32 硬件 I2C 外设将 PA0、PA1 配置为开漏输出通过翻转 GPIO 电平模拟标准 I2C 时序。4.1 I2C 基础通信时序单次寄存器读写完整流程 起始信号 → 从机地址 读写位 → 寄存器地址 → 读写数据 → 停止信号起始SCL 高电平SDA 由高拉低应答 ACK每传输 8bit 数据从机拉低 SDA 产生第 9 位应答停止SCL 高电平SDA 由低拉高寄存器读操作先发写指令指定寄存器重复起始信号后切换读模式接收数据。4.2 连续读取 6 字节数据原因ADXL345 三轴数据寄存器地址连续排布从0x32开始依次存储 X 低、X 高、Y 低、Y 高、Z 低、Z 高寄存器地址寄存器名存储内容0x32DATAX0X 轴低字节0x33DATAX1X 轴高字节0x34DATAY0Y 轴低字节0x35DATAY1Y 轴高字节0x36DATAZ0Z 轴低字节0x37DATAZ1Z 轴高字节一次性连续读取 6 字节保证 X/Y/Z 三轴数据来自同一采样周期分开单轴读取会存在采样时间差姿态数据失真。4.3 16 位有符号原始值合成规则数据存储格式低字节在前高字节在后采用二进制补码存储正负加速度C 语言处理代码s16 x (s16)((X高字节 8) | X低字节); s16 y (s16)((Y高字节 8) | Y低字节); s16 z (s16)((Z高字节 8) | Z低字节);五、寄存器初始化配置与单位换算5.1 关键寄存器配置表上电初始化严格按照下表配置开启测量模式后才能读取有效加速度寄存器名地址写入值功能作用DEVID0x00只读校验传感器 ID正确值 0xE5通信故障识别依据POWER_CTL0x2D0x00配置参数前进入待机模式DATA_FORMAT0x310x0B开启全分辨率量程 ±16gBW_RATE0x2C0x0A正常功耗传感器输出速率 100HzOFSX/OFSY/OFSZ0x1E~0x200x00三轴硬件偏移寄存器默认不校准INT_ENABLE0x2E0x00关闭所有中断采用轮询读取数据FIFO_CTL0x380x00不使用 FIFO 缓存POWER_CTL0x2D0x08MEASURE 位置 1传感器启动测量5.2 原始值转 mg 单位计算工程配置 ±16g 全分辨率模式分辨率参数1 LSB 3.9mg换算公式加速度(mg) 原始采样值 × 3.9单片机避免浮点运算使用整数等效计算int mg raw_value * 39 / 10;单位说明文中 mg 代表毫重力加速度和质量单位毫克无关换算关系1000mg 1g ≈ 9.8m/s²换算示例原始采样值计算后 mg 数值等效重力00mg0g128499mg0.5g256998mg1g-256-998mg-1g5.3 主程序整体运行流程系统延时初始化 OLED 屏幕初始化初始化 PA0/PA1 软件 I2C读取 DEVID 寄存器校验 IDID≠0xE5OLED 打印 Sensor error1s 后重新检测ID0xE5正常进入采样流程连续读取 6 字节三轴原始数据拼接 16 位有符号原始值换算 mgOLED 刷新三轴加速度数据延时 200ms循环采样。补充传感器内部数据刷新 100Hz10ms 更新一次程序 200ms 刷新屏幕显示速度满足实验观察需求。main.c代码/* * ADXL345 three-axis acceleration teaching demo * ADXL345 SDA - PA0, SCK/SCL - PA1 * OLED SCL - PB8, SDA - PB9 */ #include delay.h #include sys.h #include oled.h #include ADXL345.h #define ADXL345_REFRESH_MS 200U static void ADXL345_ShowData(const ADXL345_DataTypeDef *data); static void ADXL345_ShowError(u8 device_id); static void OLED_ShowSignedNum(u8 x, u8 y, s32 value, u8 digits, u8 size); static void OLED_ShowHexByte(u8 x, u8 y, u8 value, u8 size); int main(void) { ADXL345_DataTypeDef sensor_data; u8 sensor_ok; delay_init(); NVIC_Configuration(); OLED_Init(); OLED_ColorTurn(0); OLED_DisplayTurn(0); OLED_Clear(); OLED_ShowString(36, 0, (u8 *)ADXL345, 16); OLED_ShowString(16, 22, (u8 *)SDA PA0 SCK PA1, 12); OLED_ShowString(25, 42, (u8 *)Initializing, 12); OLED_Refresh(); sensor_ok ADXL345_Init(); while(1) { if((sensor_ok ! 0U) (ADXL345_ReadAcceleration(sensor_data) ! 0U)) { ADXL345_ShowData(sensor_data); delay_ms(ADXL345_REFRESH_MS); } else { ADXL345_ShowError(ADXL345_ReadDeviceID()); delay_ms(1000); sensor_ok ADXL345_Init(); } } } static void ADXL345_ShowData(const ADXL345_DataTypeDef *data) { OLED_Clear(); OLED_ShowString(16, 0, (u8 *)ADXL345 /-16g, 12); OLED_ShowString(0, 16, (u8 *)X:, 12); OLED_ShowSignedNum(18, 16, ADXL345_RawToMilliG(data-x), 5U, 12); OLED_ShowString(54, 16, (u8 *) mg, 12); OLED_ShowString(0, 32, (u8 *)Y:, 12); OLED_ShowSignedNum(18, 32, ADXL345_RawToMilliG(data-y), 5U, 12); OLED_ShowString(54, 32, (u8 *) mg, 12); OLED_ShowString(0, 48, (u8 *)Z:, 12); OLED_ShowSignedNum(18, 48, ADXL345_RawToMilliG(data-z), 5U, 12); OLED_ShowString(54, 48, (u8 *) mg, 12); OLED_Refresh(); } static void ADXL345_ShowError(u8 device_id) { OLED_Clear(); OLED_ShowString(36, 0, (u8 *)ADXL345, 16); OLED_ShowString(22, 20, (u8 *)Sensor error, 12); OLED_ShowString(10, 36, (u8 *)SDA PA0 SCK PA1, 12); OLED_ShowString(34, 50, (u8 *)ID:0x, 12); OLED_ShowHexByte(64, 50, device_id, 12); OLED_Refresh(); } static void OLED_ShowSignedNum(u8 x, u8 y, s32 value, u8 digits, u8 size) { u32 magnitude; if(value 0) { OLED_ShowChar(x, y, -, size); magnitude (u32)(-value); } else { OLED_ShowChar(x, y, , size); magnitude (u32)value; } OLED_ShowNum((u8)(x size / 2U), y, magnitude, digits, size); } static void OLED_ShowHexByte(u8 x, u8 y, u8 value, u8 size) { u8 high; u8 low; high (u8)((value 4) 0x0FU); low (u8)(value 0x0FU); OLED_ShowChar(x, y, (high 10U) ? (u8)(0 high) : (u8)(A high - 10U), size); OLED_ShowChar((u8)(x size / 2U), y, (low 10U) ? (u8)(0 low) : (u8)(A low - 10U), size); }ADXL345.c代码#include ADXL345.h #include delay.h /* * ADXL345 软件 I2C 驱动 * * 硬件连接 * ADXL345 SDA - STM32F103C8T6 PA0 * ADXL345 SCK/SCL - STM32F103C8T6 PA1 * * PA0 和 PA1 配置成开漏输出通过软件模拟 I2C 时序。 * CS 引脚必须接 3.3V 以选择 I2C 模式ALT ADDRESS/SDO 接地时 * ADXL345 的 7 位从机地址为 0x53对应写地址 0xA6、读地址 0xA7。 */ /* I2C 从机地址最低位由读写方向自动补充。 */ #define ADXL345_I2C_ADDRESS 0x53U #define ADXL345_WRITE_ADDRESS (ADXL345_I2C_ADDRESS 1) #define ADXL345_READ_ADDRESS ((ADXL345_I2C_ADDRESS 1) | 0x01U) /* 本驱动使用的 ADXL345 寄存器地址。 */ #define ADXL345_REG_DEVID 0x00U /* 器件标识寄存器固定值为 0xE5 */ #define ADXL345_REG_OFSX 0x1EU /* X 轴零偏校准寄存器 */ #define ADXL345_REG_OFSY 0x1FU /* Y 轴零偏校准寄存器 */ #define ADXL345_REG_OFSZ 0x20U /* Z 轴零偏校准寄存器 */ #define ADXL345_REG_BW_RATE 0x2CU /* 输出数据速率和低功耗控制寄存器 */ #define ADXL345_REG_POWER_CTL 0x2DU /* 电源模式和测量模式控制寄存器 */ #define ADXL345_REG_INT_ENABLE 0x2EU /* 中断使能寄存器 */ #define ADXL345_REG_DATA_FORMAT 0x31U /* 量程、全分辨率和数据格式寄存器 */ #define ADXL345_REG_DATAX0 0x32U /* 三轴数据起始地址DATAX0DATAZ1 */ #define ADXL345_REG_FIFO_CTL 0x38U /* FIFO 工作模式控制寄存器 */ /* 软件 I2C 引脚操作开漏输出写 1 表示释放总线写 0 表示拉低总线。 */ #define ADXL345_SDA_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_0) #define ADXL345_SDA_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_0) #define ADXL345_SCL_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_1) #define ADXL345_SCL_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_1) #define ADXL345_READ_SDA() GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) /* 软件 I2C 底层函数只在本文件内部使用。 */ static void ADXL345_I2C_Delay(void); static void ADXL345_I2C_Start(void); static void ADXL345_I2C_Stop(void); static void ADXL345_I2C_SendAck(u8 send_ack); static u8 ADXL345_I2C_SendByte(u8 data); static u8 ADXL345_I2C_ReadByte(void); static void ADXL345_I2C_BusRecovery(void); /* * I2C 时序延时。 * 5us 半周期对应的总线速度低于 100kHz适合教学和杜邦线连接环境。 */ static void ADXL345_I2C_Delay(void) { delay_us(5); } /* * 产生 I2C 起始信号 * SCL 为高电平时SDA 由高电平变为低电平。 */ static void ADXL345_I2C_Start(void) { ADXL345_SDA_HIGH(); ADXL345_SCL_HIGH(); ADXL345_I2C_Delay(); ADXL345_SDA_LOW(); ADXL345_I2C_Delay(); ADXL345_SCL_LOW(); ADXL345_I2C_Delay(); } /* * 产生 I2C 停止信号 * SCL 为高电平时SDA 由低电平变为高电平。 */ static void ADXL345_I2C_Stop(void) { ADXL345_SCL_LOW(); ADXL345_SDA_LOW(); ADXL345_I2C_Delay(); ADXL345_SCL_HIGH(); ADXL345_I2C_Delay(); ADXL345_SDA_HIGH(); ADXL345_I2C_Delay(); } /* * 从最高位开始向 I2C 总线发送一个字节并读取从机应答。 * 返回值1 表示收到 ACK0 表示收到 NACK。 */ static u8 ADXL345_I2C_SendByte(u8 data) { u8 i; u8 acknowledged; /* 依次发送 D7D0每个时钟周期发送一位。 */ for(i 0U; i 8U; i) { ADXL345_SCL_LOW(); if((data 0x80U) ! 0U) ADXL345_SDA_HIGH(); else ADXL345_SDA_LOW(); ADXL345_I2C_Delay(); ADXL345_SCL_HIGH(); ADXL345_I2C_Delay(); data 1; } /* * 第 9 个时钟用于读取应答先释放 SDA再由 ADXL345 拉低 SDA。 * SDA 为低表示 ACK说明从机已经正确接收当前字节。 */ ADXL345_SCL_LOW(); ADXL345_SDA_HIGH(); ADXL345_I2C_Delay(); ADXL345_SCL_HIGH(); ADXL345_I2C_Delay(); acknowledged (ADXL345_READ_SDA() Bit_RESET) ? 1U : 0U; ADXL345_SCL_LOW(); ADXL345_I2C_Delay(); return acknowledged; } /* * 从 I2C 总线读取一个字节按 D7D0 的顺序接收。 * 本函数只负责读取 8 位数据读完后的 ACK/NACK 由调用者发送。 */ static u8 ADXL345_I2C_ReadByte(void) { u8 i; u8 data; data 0U; ADXL345_SDA_HIGH(); for(i 0U; i 8U; i) { ADXL345_SCL_LOW(); ADXL345_I2C_Delay(); ADXL345_SCL_HIGH(); ADXL345_I2C_Delay(); data 1; if(ADXL345_READ_SDA() ! Bit_RESET) data | 0x01U; } ADXL345_SCL_LOW(); ADXL345_I2C_Delay(); return data; } /* * 主机向从机发送应答位。 * send_ack 1发送 ACK表示还要继续读取后续字节 * send_ack 0发送 NACK表示当前字节是最后一个字节。 */ static void ADXL345_I2C_SendAck(u8 send_ack) { ADXL345_SCL_LOW(); if(send_ack ! 0U) ADXL345_SDA_LOW(); else ADXL345_SDA_HIGH(); ADXL345_I2C_Delay(); ADXL345_SCL_HIGH(); ADXL345_I2C_Delay(); ADXL345_SCL_LOW(); ADXL345_SDA_HIGH(); ADXL345_I2C_Delay(); } /* * I2C 总线恢复释放 SDA 后输出 9 个 SCL 脉冲再发送停止信号。 * 如果从机因上次通信被意外中断而一直占用 SDA该操作可使其退出未完成状态。 */ static void ADXL345_I2C_BusRecovery(void) { u8 i; ADXL345_SDA_HIGH(); for(i 0U; i 9U; i) { ADXL345_SCL_LOW(); ADXL345_I2C_Delay(); ADXL345_SCL_HIGH(); ADXL345_I2C_Delay(); } ADXL345_I2C_Stop(); } /* * 向 ADXL345 的指定寄存器写入一个字节。 * 通信顺序起始信号 - 写地址 - 寄存器地址 - 数据 - 停止信号。 * 任意阶段未收到 ACK 都会立即停止通信并返回 0。 */ u8 ADXL345_WriteRegister(u8 register_address, u8 data) { ADXL345_I2C_Start(); if(ADXL345_I2C_SendByte(ADXL345_WRITE_ADDRESS) 0U) { ADXL345_I2C_Stop(); return 0U; } if(ADXL345_I2C_SendByte(register_address) 0U) { ADXL345_I2C_Stop(); return 0U; } if(ADXL345_I2C_SendByte(data) 0U) { ADXL345_I2C_Stop(); return 0U; } ADXL345_I2C_Stop(); return 1U; } /* * 从指定起始寄存器连续读取多个字节。 * * 先以写方向发送寄存器地址再发送重复起始信号并切换到读方向 * 除最后一个字节外每读完一个字节都发送 ACK最后一个字节发送 NACK。 */ u8 ADXL345_ReadRegisters(u8 start_address, u8 *data, u8 length) { u8 i; if((data 0) || (length 0U)) return 0U; ADXL345_I2C_Start(); if(ADXL345_I2C_SendByte(ADXL345_WRITE_ADDRESS) 0U) { ADXL345_I2C_Stop(); return 0U; } if(ADXL345_I2C_SendByte(start_address) 0U) { ADXL345_I2C_Stop(); return 0U; } ADXL345_I2C_Start(); if(ADXL345_I2C_SendByte(ADXL345_READ_ADDRESS) 0U) { ADXL345_I2C_Stop(); return 0U; } for(i 0U; i length; i) { data[i] ADXL345_I2C_ReadByte(); ADXL345_I2C_SendAck((i (u8)(length - 1U)) ? 1U : 0U); } ADXL345_I2C_Stop(); return 1U; } /* 从指定寄存器读取一个字节是连续读取接口的单字节封装。 */ u8 ADXL345_ReadRegister(u8 register_address, u8 *data) { return ADXL345_ReadRegisters(register_address, data, 1U); } /* * 读取器件标识寄存器。 * 正常连接的 ADXL345 应返回 0xE5通信失败时返回初始值 0x00。 */ u8 ADXL345_ReadDeviceID(void) { u8 device_id; device_id 0U; (void)ADXL345_ReadRegister(ADXL345_REG_DEVID, device_id); return device_id; } /* * 初始化软件 I2C 引脚和 ADXL345 工作参数。 * * 配置过程 * 1. 将 PA0、PA1 配置为 50MHz 开漏输出并恢复 I2C 总线 * 2. 读取 DEVID确认连接的器件确实是 ADXL345 * 3. 进入待机模式后配置全分辨率、±16g 和 100Hz 数据速率 * 4. 清零三轴偏移量关闭本示例未使用的中断和 FIFO * 5. 设置 MEASURE 位开始连续测量。 * * 返回值1 表示初始化成功0 表示器件标识错误或寄存器写入失败。 */ u8 ADXL345_Init(void) { GPIO_InitTypeDef gpio_init_structure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); gpio_init_structure.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1; gpio_init_structure.GPIO_Speed GPIO_Speed_50MHz; gpio_init_structure.GPIO_Mode GPIO_Mode_Out_OD; GPIO_Init(GPIOA, gpio_init_structure); ADXL345_SDA_HIGH(); ADXL345_SCL_HIGH(); delay_ms(5); ADXL345_I2C_BusRecovery(); if(ADXL345_ReadDeviceID() ! ADXL345_DEVICE_ID) return 0U; /* 修改测量参数前先进入待机模式。 */ if(ADXL345_WriteRegister(ADXL345_REG_POWER_CTL, 0x00U) 0U) return 0U; /* FULL_RES 1、Range 11选择全分辨率和 ±16g 量程。 */ if(ADXL345_WriteRegister(ADXL345_REG_DATA_FORMAT, 0x0BU) 0U) return 0U; /* LOW_POWER 0、Rate 0x0A选择正常功耗和 100Hz 输出速率。 */ if(ADXL345_WriteRegister(ADXL345_REG_BW_RATE, 0x0AU) 0U) return 0U; /* 教学演示暂不进行零偏校准三个偏移寄存器均写入 0。 */ if(ADXL345_WriteRegister(ADXL345_REG_OFSX, 0x00U) 0U) return 0U; if(ADXL345_WriteRegister(ADXL345_REG_OFSY, 0x00U) 0U) return 0U; if(ADXL345_WriteRegister(ADXL345_REG_OFSZ, 0x00U) 0U) return 0U; /* 本教学演示采用轮询读取因此关闭中断和 FIFO 功能。 */ if(ADXL345_WriteRegister(ADXL345_REG_INT_ENABLE, 0x00U) 0U) return 0U; if(ADXL345_WriteRegister(ADXL345_REG_FIFO_CTL, 0x00U) 0U) return 0U; /* POWER_CTL 的 MEASURE 位置 1退出待机并开始连续转换。 */ if(ADXL345_WriteRegister(ADXL345_REG_POWER_CTL, 0x08U) 0U) return 0U; delay_ms(10); return 1U; } /* * 一次连续读取 DATAX0DATAZ1 共 6 个寄存器。 * ADXL345 按低字节在前、高字节在后的顺序输出数据合并后转换为 s16 * 从而保留负加速度的二进制补码符号。 */ u8 ADXL345_ReadAcceleration(ADXL345_DataTypeDef *data) { u8 buffer[6]; if(data 0) return 0U; if(ADXL345_ReadRegisters(ADXL345_REG_DATAX0, buffer, 6U) 0U) return 0U; /* 每个轴由相邻的低、高两个字节组成。 */ >ADXL345.h代码#ifndef __ADXL345_H #define __ADXL345_H #include sys.h /* * ADXL345 三轴加速度传感器驱动头文件 * * 硬件连接 * ADXL345 SDA - STM32F103C8T6 PA0 * ADXL345 SCK/SCL - STM32F103C8T6 PA1 * * 注意ADXL345 的 CS 引脚需要接 3.3V才能进入 I2C 通信模式 * ALT ADDRESS/SDO 接地时器件的 7 位 I2C 地址为 0x53。 */ /* ADXL345 的固定器件标识读取 DEVID 寄存器应得到 0xE5。 */ #define ADXL345_DEVICE_ID 0xE5U /* 保存一次采样得到的 X、Y、Z 三轴原始有符号数据。 */ typedef struct { s16 x; /* X 轴原始数据 */ s16 y; /* Y 轴原始数据 */ s16 z; /* Z 轴原始数据 */ } ADXL345_DataTypeDef; /* * 初始化 GPIO 和 ADXL345。 * 配置为全分辨率、±16g、100Hz 输出数据速率并进入测量模式。 * 返回值1 表示初始化成功0 表示通信或器件检测失败。 */ u8 ADXL345_Init(void); /* 读取 DEVID 寄存器正常模块应返回 ADXL345_DEVICE_ID0xE5。 */ u8 ADXL345_ReadDeviceID(void); /* 向指定寄存器写入一个字节成功返回 1失败返回 0。 */ u8 ADXL345_WriteRegister(u8 register_address, u8 data); /* 从指定寄存器读取一个字节成功返回 1失败返回 0。 */ u8 ADXL345_ReadRegister(u8 register_address, u8 *data); /* 从 start_address 开始连续读取 length 个字节。 */ u8 ADXL345_ReadRegisters(u8 start_address, u8 *data, u8 length); /* 连续读取 X、Y、Z 三轴加速度原始数据。 */ u8 ADXL345_ReadAcceleration(ADXL345_DataTypeDef *data); /* * 将原始数据换算为 mg毫重力加速度。 * 全分辨率模式下的典型比例系数为 3.9mg/LSB1000mg 约等于 1g。 */ s32 ADXL345_RawToMilliG(s16 raw_value); #endif六、OLED 屏幕显示效果解析6.1 正常运行界面ADXL345 /-16g X:00000 mg Y:00000 mg Z:00998 mg字段释义/-16g当前传感器测量量程X/Y/Z三轴加速度正负号代表受力方向mg毫重力加速度单位。6.2 通信故障报错界面ADXL345 Sensor error SDA PA0 SCK PA1 ID:0x00出现报错排查顺序供电、共地、CS 引脚、SDO 地址引脚、SDA/SCL 接线、I2C 上拉电阻。七、量程、分辨率与实验现象分析ADXL345 支持 4 档量程±2g、±4g、±8g、±16g本工程选用 ±16g可捕捉大幅度晃动、冲击全分辨率模式下所有量程统一 3.9mg/LSB±16g 可达 13 位高精度。倾斜实验设备缓慢倾斜重力矢量在三轴重新分配一个轴数值减小另一轴增大静止状态下三轴平方和开根号≈1000mg。晃动冲击实验快速摆动、敲击传感器动态加速度叠加重力分量单轴读数会超过 ±1000mg属于正常现象非硬件损坏。自由落体实验脱手自由下落瞬间三轴读数全部接近 0mg失重检测是 ADXL345 内置功能本工程未启用中断。八、传感器误差来源与简易校准方案实际采样数值和理论值存在偏差主要误差来源零偏误差无重力分量轴存在固定几十 mg 偏移灵敏度误差1g 位置读数偏离 1000mg安装机械误差PCB 安装不水平重力分解至多轴干扰误差电源波动、长线接线、电机振动、温度漂移。简易校准步骤传感器水平静止放置多次采样取平均值降低随机抖动确定理论标准值平放 Z 轴 1000mgX/Y 为 0mg平均值减去理论值得到三轴零偏补偿值两种补偿方式软件读取后手动减法、写入 OFSX/OFSY/OFSZ 硬件偏移寄存器。拓展优化多次采样滑动平均滤波、一阶低通滤波消除数值抖动。