
简介本资源是一套面向嵌入式开发初学者与STM32工程师的ADXL355三轴加速度传感器实战例程聚焦低功耗物联网、可穿戴设备及运动检测等典型应用场景。资源完整覆盖SPI通信驱动、传感器寄存器配置、原始数据读取与协议解析三大核心环节帮助开发者快速掌握高精度MEMS传感器在ARM Cortex-M平台上的集成方法。压缩包共5个文件3个C源码 2个头文件总大小仅5KB结构精炼SPI.c实现STM32主控SPI底层时序适配ADXL355.c封装初始化、量程设置与加速度数据解码逻辑Communication.c提供CRC校验与数据包解析保障通信可靠性配套头文件定义寄存器地址、配置结构体及函数接口。已有1764人学习下载代码注释清晰、模块职责分明可直接移植至主流STM32系列如F1/F4/H7亦可作为传感器驱动开发范式参考支撑后续滤波算法、姿态解算或边缘触发逻辑的扩展开发。1. 为什么大家都在找ADXL355的例程和源码1.1 ADXL355是什么为什么值得专门写一篇打开搜索引擎搜ADXL355出来的结果大多都是英文数据手册或者某个论坛里零散的代码片段真正能把“寄存器配置 源码讲解 实测踩坑”串起来的中文资料其实不多。ADXL355是ADI的一颗三轴数字MEMS加速度计定位和大部分同学熟悉的MPU6050、ADXL345完全不同。它主打的是超低噪声、超低温度漂移、低功耗配合20位ADC和数字滤波适合做地震监测、结构健康监测、倾斜测量、平台稳定这类需要观察微弱低频信号的场景。我最早接触这颗芯片是在一个桥梁振动测试的项目里当时测的是0.1Hz到10Hz的微振动用MPU6050完全压不住本底噪声换ADXL355之后数据的可读性一下子出来了。从那之后凡是需要“安静的测量”的活儿我都优先考虑它。这篇文章就是把我实际用过的例程、寄存器配置和踩过的坑整理出来给准备用这颗芯片的工程师省点时间。1.2 它和MPU6050、ADXL345到底差在哪很多第一次接触ADXL355的人会拿它和MPU6050比其实这俩根本不是一类东西。MPU6050是16位ADC、自带DMP主战场是手机姿态、平衡车、四轴飞控优点是接口简单、算法库成熟缺点是本底噪声大站住不动时输出就能跳几十甚至上百个码给它做低频微振动测量基本是灾难。ADXL345更偏消费级13位有效分辨率适合计步和倾角检测精度和噪声都不够看。ADXL355则是往“仪器级”方向走的20位数字输出实际有效位数大概在18位左右低4位基本是0、X/Y轴噪声密度典型值25μg/√Hz、Z轴45μg/√Hz这个噪声水平比MPU6050低了差不多一个数量级。再加上内部集成了低通滤波器、32级FIFO、温度传感器一颗芯片就能把数据采集链路的前端都包了。所以如果你正在做的项目需要测“很慢很细”的物理量直接上ADXL355别在消费级芯片上浪费时间。1.3 这篇文章适合谁如果你符合下面任何一种情况这篇文章对你是有用的第一次用ADXL355想找一个能直接跑的例程已经能跑例程但搞不清楚量程、采样率、滤波这些寄存器怎么配或者正在做倾角、振动、地震监测、大坝桥梁健康监测这类低速高精度测量想看看这颗芯片实际表现如何。我会以STM32为主讲底层SPI读写和初始化流程最后补充一下往TMS320F28388D这类DSP移植的思路例程核心逻辑是平台无关的。2. 硬件连接与寄存器层面的关键细节2.1 SPI还是I2C多数场景我建议用SPIADXL355支持SPI和I2C两种接口I2C模式下地址由ADDR/SDO引脚决定接地是0x1D接高是0x53。I2C的好处是省引脚如果你主控的I2C资源紧可以这么接。但我在实践中更推荐SPI原因有三SPI速率上限比I2C高很多ADXL355的SPI最高可以跑到10MHz实际测试中不少人跑到更高也能工作但按手册来最稳。如果你的ODR设到500Hz以上I2C的400kHz标准模式虽然也够用但SPI留给你的余量要大得多。第二个原因是SPI读多字节时是一次性连续读出来的时序干净不容易被I2C的地址翻转搞乱。第三个原因是调试方便逻辑分析仪上看SPI的波形比I2C直观太多了出问题好定位。接线上SPI四根线CS、SCLK、MOSI、MISO。注意ADXL355的MISO和ADDR/SDO是同一个引脚接SPI时它自动做数据输出不需要额外处理。另外这颗芯片的VDD和VDDIO可以分开供电I/O电平跟着VDDIO走如果你的MCU是3.3VVDDIO接3.3V如果MCU是1.8VVDDIO接1.8V就行比较灵活。2.2 量程、采样率、滤波开局先把这三个想明白ADXL355的量程寄存器是0x1B可选±2.048g、±4.096g、±8.192g三档默认是±2.048g。虽然它有±8g的档位但如果你做倾角或振动测量我建议固定用±2.048g因为小量程下分辨率最高噪声表现最好。只有当你确定测量物体会有超过2g的冲击时才需要去切换大档。量程的切换会直接影响后面g值换算系数这个一定要注意。采样率寄存器是0x1CADXL355的ODR上限是4000Hz往下按2的幂次递减。实际上我们的低频测量很少需要很高ODR桥梁振动常见的频率范围也就是0.1到20Hz把ODR配到62.5Hz或125Hz已经非常富裕。这里给一个对应关系SAMPLING寄存器写0x06大约对应62.5Hz写0x05大约对应125Hz具体还是要对照数据手册的表格确认。滤波寄存器是0x1D内部低通滤波器的配置就在这。它的作用是在数字域上进一步限制带宽帮助抑制带外噪声。用的时候记住一个原则ODR越低LPF可选的截止频率档位越少LPF截止频率不要设得太高否则高频噪声会通过混叠折回到你关心的低频段。我通常的做法是先把ODR定下来再选一个截止频率在ODR/8到ODR/4附近的LPF档位。2.3 上电后的第一步把ID读出来不管写什么外设驱动我习惯先把器件ID读出来。ADXL355的寄存器0x00是DEVID_AD读出来应该是0xAD寄存器0x01是DEVID_MST应该读0x1D寄存器0x02是PARTID应该读0xED。如果这三项都对说明SPI/I2C链路通、芯片没虚焊、供电正常接下来调数据才是有意义的。我遇到过不止一次“数据全为0”的情况最后查到是芯片压根没跑起来因为代码里没做ID校验程序也没报错就在那空转。第一步先读ID能帮你把“通信问题”和“业务逻辑问题”快速切开。3. ADXL355例程源码逐段拆解3.1 底层SPI读写函数怎么写下面这段是STM32 HAL库环境下最基础的SPI读写封装。ADXL355的SPI读操作是先发一个命令字节最高位是1表示读低7位是寄存器地址然后继续发SCLK把数据读回来。写操作是命令字节最高位为0后面跟一个数据字节。#define ADXL355_CS_LOW() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) #define ADXL355_CS_HIGH() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) static void spi_tx_byte(uint8_t byte) { HAL_SPI_Transmit(hspi1, byte, 1, 10); } static uint8_t spi_rx_byte(void) { uint8_t rx; HAL_SPI_Receive(hspi1, rx, 1, 10); return rx; } uint8_t adxl355_read_reg(uint8_t reg) { uint8_t val; ADXL355_CS_LOW(); spi_tx_byte(0x80 | (reg 0x7F)); val spi_rx_byte(); ADXL355_CS_HIGH(); return val; } void adxl355_write_reg(uint8_t reg, uint8_t value) { ADXL355_CS_LOW(); spi_tx_byte(reg 0x7F); spi_tx_byte(value); ADXL355_CS_HIGH(); }这里有个小细节读操作时发送完命令字节后接收函数会提供SCLK时钟把数据移出来所以逻辑上是“先写命令再读数据”中间不需要额外的延时。如果你的MCU平台比较特殊比如用了软件模拟SPI注意在命令发完之后让时钟继续跑几个周期数据才会出现在MISO上。3.2 初始化流程重复做三件事省一小时调试时间初始化代码不长但顺序很重要。第一步读ID校验第二步设置量程第三步设置采样率第四步确认芯片是否进入测量模式。ADXL355上电后默认就处于测量模式所以POWER_CTL寄存器0x28一般不用动但为了稳妥我还是会把0x28写成0x00确保芯片是在正常测量状态而不是待机。uint8_t adxl355_init(void) { uint8_t id_ad, id_mst, part_id; id_ad adxl355_read_reg(0x00); id_mst adxl355_read_reg(0x01); part_id adxl355_read_reg(0x02); if (id_ad ! 0xAD || id_mst ! 0x1D || part_id ! 0xED) { return 1; // 读取失败 } // 量程±2.048g adxl355_write_reg(0x1B, 0x01); // 采样率约62.5Hz adxl355_write_reg(0x1C, 0x06); // 滤波用一档合适的低通带宽具体看数据手册表格 adxl355_write_reg(0x1D, 0x01); return 0; }实际项目里量程和采样率往往需要做成可配置的而不是写死。比如做倾角测量ODR用31.25Hz足够做地震波监测可能要用到250Hz甚至更高。我的建议是先在头文件里定义三个宏把量程、采样率、滤波档位都定义出来后面需要改参数时只动一个地方。3.3 读取三轴加速度并换算成g值读取三轴数据时X轴起始寄存器是0x08寄存器排列是XDATA3、XDATA2、XDATA1接着是YDATA3、YDATA2、YDATA1最后是ZDATA3、ZDATA2、ZDATA1。所以一次性连续读9个字节就能把三轴原始数据全拿回来。void adxl355_read_accel(float *x, float *y, float *z) { uint8_t buf[9]; int32_t raw_x, raw_y, raw_z; // 从寄存器0x08连续读9字节X/Y/Z各3字节 ADXL355_CS_LOW(); spi_tx_byte(0x80 | 0x08); for (int i 0; i 9; i) { buf[i] spi_rx_byte(); } ADXL355_CS_HIGH(); // 把3字节合并成24位整数再右移4位得到20位有效数据 raw_x ((int32_t)buf[0] 16) | ((int32_t)buf[1] 8) | buf[2]; raw_y ((int32_t)buf[3] 16) | ((int32_t)buf[4] 8) | buf[5]; raw_z ((int32_t)buf[6] 16) | ((int32_t)buf[7] 8) | buf[8]; raw_x 4; raw_y 4; raw_z 4; // 20位补码符号扩展 if (raw_x 0x80000) raw_x | 0xFFF00000; if (raw_y 0x80000) raw_y | 0xFFF00000; if (raw_z 0x80000) raw_z | 0xFFF00000; // ±2.048g量程下1g对应约256000个LSB20位 *x (float)raw_x / 256000.0f; *y (float)raw_y / 256000.0f; *z (float)raw_z / 256000.0f; }这段代码里最容易翻车的地方是符号扩展。20位补码的数据范围是-524288到524287但直接放在int32_t里时最高位并不是32位的符号位所以必须手动扩展。如果忘了这一步负方向的加速度会变成很大的正数输出的g值完全没法看。另外除数是256000如果你量程切到了±4.096g或±8.192g这个系数要跟着变通常是128000和64000具体以数据手册为准。3.4 用FIFO和中断避免在高ODR下丢数据有些应用要把ODR开到1000Hz甚至4000Hz比如做冲击信号采集。这个时候如果还用主循环轮询寄存器稍微被其他任务打断一下就可能丢样本。ADXL355内置了32级FIFO可以把测量数据缓存起来MCU抽空一次性读走这是我在高频采集场景下的首选方案。FIFO的配置也很简单先把FIFO_CTL寄存器0x2C写成0x01使能FIFO再通过INT_EN寄存器0x1F使能FIFO中断配置INT1引脚输出。之后每来一个采样点数据就会自动压进FIFOFIFO里攒了多少个样本可以从FIFO_ENTRIES_L0x05和FIFO_ENTRIES_H0x06读出来。读FIFO数据时连续读寄存器0x11每读9个字节就是一组X/Y/Z三轴数据。使用FIFO的一个好处是MCU可以不关心每个采样点的精确时刻只需要在FIFO半满或者溢出之前把数据取走。FIFO溢出时STATUS寄存器里会有一个标志位如果你的系统对数据完整性要求很高可以在中断处理里把这个标志位记录下来事后知道哪一段数据丢了。4. 实测效果与避坑经验4.1 我实测到的噪声和稳定性把芯片固定在光学平台上用±2.048g量程、ODR 62.5Hz、低通带宽大约15Hz左右去测静止状态下的输出X/Y轴输出的峰峰值大概在0.2到0.4mg之间Z轴稍差一些大约0.5到0.8mg。换算成噪声密度和我看手册标称的X/Y轴25μg/√Hz基本对得上。这个数据在MEMS加速度计里已经算非常漂亮了用来测建筑振动、桥梁摆幅完全够用。温度漂移方面ADXL355比普通加速度计好很多。我做过一次从25°C升温到60°C的简单测试零偏变化大概在几毫g级别具体数值和板子焊接应力关系很大。这里有一个很重要的心得LFCSP封装焊接完以后机械应力会让零偏发生明显偏移所以量产板最好做一次零点校准把焊接应力带来的固定偏差消掉。4.2 常见问题排查速查表现象可能原因检查方法ID读出来是0x00或0xFFSPI接线错误、芯片未上电检查CS/MOSI/MISO/SCLK是否接反用万用表量VDDID正确但三轴数据全为0POWER_CTL被写成待机、SPI时序问题确认0x28寄存器值是0x00用逻辑分析仪抓波形X/Y/Z某个轴数据明显不对焊接不良、PCB应力、量程配置不一致补焊后重新校准检查换算系数数据跳动大噪声异常电源纹波、SPI速率过高、滤波档位过宽给VDD加100nF去耦电容检查LPF配置Z轴噪声明显大于X/Y正常现象Z轴MEMS结构决定接受即可无需修复排查时我一般遵循一个顺序先确认电源电压再查SPI波形最后查寄存器值。千万别一上来就去怀疑算法因为ADXL355的SPI时序问题占了通信故障的一半以上。4.3 从STM32移植到TMS320F28388D或其他平台很多人搜ADXL355例程时会看到TMS320F28388D、ADUC7061、ESP32这些关键词说明大家都在往不同平台移植。移植的核心思路很简单底层的SPI收发函数换掉上层初始化和数据处理逻辑基本不用动。以TMS320F28388D为例它的MCU子系统里自带SPI模块你只需要把spi_tx_byte和spi_rx_byte替换成基于SpiaRegs的发送接收函数就行。C2000的SPI发送一般是这样void spia_tx_byte(uint16_t data) { while (SpiaRegs.SPISTS.bit.INT_FLAG 0); // 等待发送完成 SpiaRegs.SPITXBUF data; } uint16_t spia_rx_byte(void) { while (SpiaRegs.SPISTS.bit.INT_FLAG 0); // 等待接收完成 return SpiaRegs.SPIRXBUF; }注意C2000的SPI寄存器是16位宽的命令字节和数据字节放在低8位即可高本文还有配套的精品资源点击获取