搞嵌入式这么多年跟传感器打交道算是家常便饭但真正让我觉得“这个芯片有点意思”的还是最近在 STM32C5 上跑通 IIS3DWB10IS 这件事。这颗宽带振动传感器带宽最高能到 6kHz噪声又低做设备状态监测、预测性维护非常合适。我这次直接用 SPI 接口把三轴震动数据读出来整个过程从 CubeMX 配置、寄存器读写到最终换算成 mg 单位踩了不少坑也攒了不少经验。这篇文章就把完整思路和实操细节整理出来给正在用或者准备用 IIS3DWB10IS 做振动采集的工程师一些参考。1. 为什么是 STM32C5 IIS3DWB10IS1.1 项目要解决什么问题先说你到底在做什么事。所谓“震动计数据”本质是加速度传感器输出的三轴加速度数值。设备一振动传感器内部的质量块就会跟着动通过电容或压阻效应转成电信号再经过 ADC 量化成寄存器里的 16 位数字量。你要做的就是把 SPI 总线上的这些数字量准确、稳定、及时地搬回 MCU再换算成有物理意义的 mg毫g或者 mm/s²。这个场景最常见的应用是工业状态监测。电机、轴承、泵、风机这类旋转设备运行的时候会有固定的振动特征频率。一旦轴承磨损、转子不平衡、齿轮断齿振动特征就会变。传感器采集振动数据MCU 做 FFT 频谱分析就能在设备彻底坏之前预警。IIS3DWB10IS 这颗芯片定位就是宽带低噪声加速度计非常适合这类应用。用 STM32C5 的原因也很实际它基于 Cortex-M33 内核主频足够跑 FFT 和后续算法外设也齐全。ST 自家的传感器配自家 MCU文档和例程能对上省去了不少跨厂商适配的麻烦。如果你手头只有 F103 或者 G4 系列其实也可以只是高采样率下连续 DMA 搬运和数据处理压力会更大。1.2 为什么选 SPI 而不是 I2C这是项目里最值得说清楚的一个决策。IIS3DWB10IS 同时支持 SPI 和 I2C但我强烈建议用 SPI。原因不是 I2C 不能用而是振动监测这个场景对带宽和吞吐的要求太高。I2C 标准模式只有 100kbps快速模式 400kbps高速模式虽然能到 1Mbps 甚至 3.4Mbps但很多 MCU 的 I2C 外设和传感器组合实际跑不到理论值而且 I2C 有应答、地址、重复起始位这些额外开销。振动传感器要连续读 6 个字节XYZ 各两字节如果采样率跑到 1kHz 以上I2C 总线负载会很高稍微有点干扰就容易 NACK。SPI 就简单多了。全双工、移位寄存器、没有应答位时钟推着数据走效率极高。IIS3DWB10IS 的 SPI 时钟最高能到 10MHz理论上一次读 6 个字节只要 6 微秒左右即使加上 CS 切换和软件处理1kHz 采样率下总线占用率也才百分之几。更重要的一点是SPI 没有外部上拉电阻的要求时序也更容易用逻辑分析仪去抓。一句话总结I2C 适合低速配置和低采样率场景SPI 才是高数据率振动采集的正解。这个选型纯属工程取舍不是偏好问题。1.3 整体框架与数据流整个系统的数据流是这样的IIS3DWB10IS 的加速度信号经过内部 ADC 量化后放入输出寄存器MCU 通过 SPI 以特定速率读取 X/Y/Z 三轴共 6 字节原始数据再由软件换算成 mg 或 mm/s²。读到的数据可以缓存到环形缓冲区后续做窗口处理、FFT、特征提取或者直接通过串口、CAN 转发到上位机。需要特别注意的是“采样率”这个词在传感器和 MCU 两个层面的含义。传感器内部有固定的 ODR输出数据率比如 1.6Hz 到 6kHz 之间可配。单片机应当以等于或略高于 ODR 的频率去读数据读太快会读到重复或半新数据读太慢会丢数据。如果 MCU 的读取频率和传感器内部更新频率不同步最直接的表现是波形上出现不正常的毛刺和跳变。2. 硬件准备与接线2.1 引脚确认与连接先别急着写代码硬件上确认几件事能省很多排查时间。IIS3DWB10IS 常见的封装是 LGA-12引脚不算多但不同板子丝印可能不一样。我这边用的是定制的传感器小板关键引脚如下VDD1.8V~3.6V我直接接 3.3VGND电源地CSSPI 片选低有效SPCSPI 时钟SDI/SDOSPI 数据输入MOSISDO/SA0SPI 数据输出MISO同时兼作 I2C 地址选择引脚STM32C5 这边我选了 SPI1 外设对应引脚是 PA5SCK、PA6MISO、PA7MOSI、PA4CS。之所以选 SPI1是因为它挂在 APB2 总线上时钟频率更高分频后的 SPI 时钟选项更灵活。如果你用 SPI2 或 SPI3 也可以但要注意 APB1 的外设时钟最高频率可能低于 APB2分频计算结果不一样最终 SPI 实际速率可能达不到预期。接线就这么几条但有个细节很容易被忽略传感器和 MCU 的电平域是否一致。IIS3DWB10IS 的 VDD 接 3.3V那 SPC、SDI、SDO 的电平也是 3.3V 逻辑。如果 MCU 是 5V 供电SPI 引脚输出高电平可能是 5V直接接到传感器 3.3V 引脚上长期工作轻则信号畸变、重则损坏芯片。所以务必确认逻辑电平一致或者加电平转换。2.2 电源与去耦振动传感器对电源纹波非常敏感。你想想加速度计量的是微小的机械位移变化电源上哪怕几十毫伏的纹波都可能被 ADC 当成加速度信号采进去。我实测过如果 VDD 引脚旁边只放一个 0.1μF 电容静态时输出数据噪声明显偏大加上一个 4.7μF 的钽电容或陶瓷电容后噪声下降了一个数量级。建议的做法是 0.1μF 高频去耦电容尽量靠近 VDD 引脚放置1μF~10μF 的大容量电容放在稍远位置。如果系统里还有电机、继电器这类大电流负载最好单独给传感器用 LDO 供电别和数字电路共用一个开关电源。另外如果有 I2C 地址选择功能SA0 引脚不要悬空。悬空状态下引脚电平不确定可能导致 SPI 模式下误识别为 I2C 地址配置出现通信不稳定的怪问题。用万用表测一下这个引脚的默认电平确定后明确接高或接低。2.3 硬件 NSS 还是软件 CSSPI 的片选信号有两条路一是直接用 MCU 的硬件 NSS 引脚二是用普通 GPIO 软件控制。IIS3DWB10IS 的 CS 引脚对时序有要求建议用软件 GPIO 控制理由后面展开讲。STM32 的硬件 NSS 有两种模式NSS 输出模式和 NSS 输入模式。输出模式下SPI 外设会在传输开始时自动拉低 NSS结束后拉高省一个引脚也省 CPU 干预。听起来很好用但实际有风险如果 SPI 总线上挂了多个设备硬件 NSS 只能控制一个固定的引脚不能动态切换片选如果 SPI 配置成 NSS 脉冲模式还会在每次字节传输之间产生片选脉冲这在大多数传感器场景下是不能接受的。软件 CS 就不一样了。你可以把任意 GPIO 配置成推挽输出操作顺序完全自己掌控。读数据之前先拉低 CS确保传感器 SPI 状态机复位到命令接收状态传输完成后延时几微秒再拉高避免片选释放太快导致最后一个字节没锁存。这个可控性是硬件 NSS 给不了的。3. STM32CubeMX 配置 SPI3.1 CubeMX 里 SPI 参数怎么填打开 STM32CubeMX选中 STM32C5 型号后在 Pinout Configuration 面板里找到 SPI1模式选 “Full-Duplex Master”。然后看 Parameter Settings 那一栏重点配置以下几个参数Frame FormatMotorola 模式Data Size8 bitsFirst BitMSB FirstPrescaler根据实际时钟算Clock PolarityCPOLLowClock PhaseCPHA1 EdgeNSSSoftwareCPOLLow 表示空闲时钟线为低电平CPHA1 Edge 表示数据在时钟上升沿采样、下降沿移位。这个组合对应 SPI Mode 0也是 IIS3DWB10IS 数据手册推荐的默认时序。有些资料把 IIS3DWB 的 SPI 时序写成 Mode 3CPOLHighCPHA2 Edge其实手册里是支持 Mode 0 和 Mode 3 的具体看 CTRL 寄存器里的配置。如果后面调试时读数不对可以顺手把 CPOL 改 High、CPHA 改 2 Edge 试试我当时就被这个坑折磨过——按默认 Mode 0 配WHO_AM_I 读得对不对但数据偶尔跳变后来发现是 Mode 3 更稳。Prescaler 的值不能拍脑袋填。IIS3DWB10IS 的 SPI 最高 10MHzSTM32C5 的 SPI1 挂在 APB2 上假设 APB2 时钟 80MHz那 Prescaler 选 8 分频SPI 时钟就是 10MHz。如果选 4 分频就是 20MHz超了传感器规格属于危险操作。边界情况下可以试但带负载能力下降长线传输时波形劣化明显。保守起见先 8 分频跑通再根据实际需要提速。3.2 硬件片选和软件片选在 CubeMX 里的表达有的新手在 CubeMX 里看到 “NSS” 类型选项就慌了不知道该选 Hardware 还是 Software。我的建议是选 Software然后在代码里自己控制 CS 引脚。在 CubeMX 里选 Software 之后还需要手动把一个 GPIO 配置为 Output并起个清晰的名字比如 CS_IIS3DWB。生成的代码里这个 GPIO 初始化为推挽输出默认电平由你在 GPIO Output Level 里决定——这里记得选 High因为 CS 低有效空闲时必须为高否则传感器一上电就被选中SPI 状态机可能提前乱掉。如果你用的是硬件 NSSCubeMX 会自动把 NSS 引脚配置成复用功能。这种方案省事但就像前面说的多设备共总线时动态切 CS 很不方便所以我建议用软件 GPIO。3.3 时钟树与分频关系SPI 频率的计算逻辑是SPI 时钟 SPI 外设总线时钟 / Prescaler。STM32C5 的 SPI1 在 APB2 上SPI2/SPI3 在 APB1 上。CubeMX 的 Clock Configuration 页面里先把系统时钟配置好比如 160MHz 主频然后看 APB1 和 APB2 分频后的实际频率。这里有个容易忽略的点SPI 外设的输入时钟不一定等于总线上看到的 80MHz 或者 40MHz还要看芯片手册里 SPI 外设是否有独立的时钟使能位。STM32 系列一般没这么复杂SPI 挂哪个总线就用哪个总线时钟但具体到 STM32C5建议在生成的 main.c 里打断点查看HAL_RCC_GetPCLK2Freq()的返回值确认实际频率再反推 Prescaler。如果你不确认某个配置对不对就用逻辑分析仪抓 SCK 引脚的频率一抓一个准。示波器能看具体波形边沿质量逻辑分析仪能直接读出频率和时序关系两个都很有用。4. SPI 原理与寄存器读写实现4.1 SPI 时序怎么映射到代码SPI 本质上是一个环形移位寄存器。主机往 MOSI 上移出一个 bit 的同时从 MISO 上采样一个 bit。所以读操作其实也是写操作——读的时候主机必须持续输出时钟并且发送一个“空字节”通常 0x00 或 0xFF来产生时钟传感器才会把数据放到 MISO 上。对于 ST 的传感器SPI 读命令的格式是第一个字节的高位是读标记通常地址的最高位bit7设为 1。例如要读地址 0x0F就发送 0x8F。如果是多字节读地址的 bit6 如果是自动递增标记IF_ADD_INC那第二个字节开始地址会自动加 1很方便不用对每个寄存器重新发命令。写命令则相反bit7 为 0例如写 0x20 寄存器就发送 0x20。实际代码建议封装两个基础函数。一个是读单字节一个是写单字节。读多字节和写多字节可以在这两个基础上扩展。#define IIS3DWB_CS_LOW() HAL_GPIO_WritePin(CS_IIS3DWB_GPIO_Port, CS_IIS3DWB_Pin, GPIO_PIN_RESET) #define IIS3DWB_CS_HIGH() HAL_GPIO_WritePin(CS_IIS3DWB_GPIO_Port, CS_IIS3DWB_Pin, GPIO_PIN_SET) uint8_t IIS3DWB_ReadReg(uint8_t reg) { uint8_t txData (reg 1) | 0x80; // 有些传感器地址是7位左移1位bit0表示读写 uint8_t rxData 0; uint8_t dummy 0x00; IIS3DWB_CS_LOW(); HAL_SPI_Transmit(hspi1, txData, 1, 10); HAL_SPI_TransmitReceive(hspi1, dummy, rxData, 1, 10); IIS3DWB_CS_HIGH(); return rxData; }这里有个细节不同型号的 ST 加速度计SPI 命令地址格式可能不一样。有的直接用 8 位地址加读写位bit7 1 读有的要求地址左移一位再加读写位。IIS3DWB10IS 的寄存器地址定义是 8 位我用的是reg | 0x80表示读reg 0x7F表示写。如果你拿到的是官方例程仔细看 ReadReg 的实现别直接照搬别的传感器代码。4.2 读 WHO_AM_I 验证通信代码写好后第一件事不是读加速度而是读 WHO_AM_I 校验通信链路。这个寄存器地址通常是 0x0F读出来的值对 IIS3DWB 系列应该是 0x4B。这一步的价值在于如果 ID 读不对说明你 SPI 时序、接线、供电、引脚配置至少有一样有问题。如果 ID 读对了通信链路基本就通了后面寄存器配置和读数据都是基于这个基础。我调试时遇到过一种怪异情况第一次上电 WHO_AM_I 读出来是 0x4B但程序复位一次之后变成 0xFF再复位又变成 0x4B。排查了很久发现是传感器上电后需要一段稳定时间几毫秒MCU 复位后立刻去读传感器 SPI 还没准备好。解决方案是在初始化函数开头加 10ms 以上的延时再做第一次通信问题就消失了。4.3 配置传感器寄存器通信验证通过后就可以配置传感器的工作模式了。IIS3DWB10IS 的关键寄存器不多主要有几个CTRL1通常 0x20配置 ODR 和低通滤波器带宽CTRL2通常 0x21软件复位等CTRL3通常 0x22SPI 读地址自动递增使能等CTRL4通常 0x23满量程范围、BDU 等先说 CTRL3 里的 IF_ADD_INC 位。这个位要使能否则每次读一个寄存器都得重新发地址极低效。配置方法是在写 CTRL3 时把这个位置 1。这算是我见过最影响读取效率的寄存器位之一。// 使能寄存器地址自动递增 uint8_t ctrl3 0x00; ctrl3 | 0x04; // IF_ADD_INC 1 IIS3DWB_WriteReg(0x22, ctrl3);再说 ODR。IIS3DWB10IS 的 ODR 最高能到 26.7kHz带宽 6kHz。但实际项目里我一般先配 1kHz 或 3.3kHz。为什么不全开最高一个是功耗采样率每翻一倍电流消耗大概跟着涨另一个是数据量26.7kHz 意味着每秒钟要读 26.7k 次、每次 6 字节也就是 160KB/s 的数据流对 STM32C5 来说能扛但后续处理和存储压力大。满量程这边IIS3DWB 支持 ±2g、±4g、±16g。做状态监测时我习惯先用 ±16g防止设备启动阶段瞬间冲击导致削波。如果确认被测设备振动幅度不大再改 ±4g分辨率更高。BDU 位也要说一下。BDU 是 Block Data Update 的缩写把它置 1 后传感器在高、低字节更新时会锁存另一字节防止你读到“半个新数据 半个旧数据”的错位组合。这个在高速采样时必须开否则波形上会出现随机的跳变点干扰后续 FFT 分析。// 配置 CTRL1ODR 1kHz uint8_t ctrl1 0x00; ctrl1 | (0x08 4); // 具体值由ODR决定这里示意 IIS3DWB_WriteReg(0x20, ctrl1); // 配置 CTRL4满量程 ±16gBDU 使能 uint8_t ctrl4 0x00; ctrl4 | 0x80; // BDU 1 ctrl4 | 0x40; // FS ±16g这里需要按手册确认编码 IIS3DWB_WriteReg(0x23, ctrl4);配置完寄存器强烈建议回读一遍确认写入成功。有些芯片存在“写时忽略某些位”的情况如果只写不读配置错了一时半会也发现不了。4.4 读原始数据并换算成 mg配置好之后就是真正读取三轴加速度数据。IIS3DWB 的输出寄存器从 OUT_X_L、OUT_X_H、OUT_Y_L、OUT_Y_H、OUT_Z_L、OUT_Z_H 开始连续 6 个字节。使能了 IF_ADD_INC 后可以用一次 SPI 读命令连续读完。关键点是读命令只发一次地址后面连续收 6 个字节。主机在接收每个字节时都要发送一个 dummy 字节通常 0x00来产生 SCK。typedef struct { int16_t x; int16_t y; int16_t z; } AxisRaw_t; AxisRaw_t IIS3DWB_ReadAccel(void) { uint8_t txBuf[7] {0}; uint8_t rxBuf[7] {0}; AxisRaw_t raw {0}; txBuf[0] 0x28 | 0x80; // 0x28 OUT_X_L读命令加读标志 for (int i 1; i 7; i) { txBuf[i] 0x00; // dummy } IIS3DWB_CS_LOW(); HAL_SPI_TransmitReceive(hspi1, txBuf, rxBuf, 7, 10); IIS3DWB_CS_HIGH(); raw.x (int16_t)((rxBuf[2] 8) | rxBuf[1]); raw.y (int16_t)((rxBuf[4] 8) | rxBuf[3]); raw.z (int16_t)((rxBuf[6] 8) | rxBuf[5]); return raw; }注意字节顺序。IIS3DWB 数据手册里默认是小端模式也就是低字节在前、高字节在后。所以rxBuf[1]是 X 轴低字节rxBuf[2]是高字节。如果你配置了大端模式BLE 位拼接顺序就要反过来。得到 int16_t 的原始值后换算成 mg 需要乘以灵敏度。不同满量程对应的灵敏度不同±2g0.061 mg/LSB±4g0.122 mg/LSB±16g0.488 mg/LSB举个例子读到的原始值是 2048满量程 ±4g那对应的加速度就是 2048 × 0.122 249.856mg约等于 0.25g。这个数值就是振动加速度的瞬时值后续可以做 RMS、峰值、FFT 等分析。换算时要注意数据类型。int16_t 乘 float 时会自动转成 float没问题但如果你用 int 存结果可能会截断。建议用 float 存物理量float IIS3DWB_ConvertToMg(int16_t raw, float sensitivity) { return (float)raw * sensitivity; }5. 用 DMA 和中断提高采样稳定性5.1 为什么阻塞读取不够用最开始我图省事直接在 while 循环里调用 HAL_SPI_TransmitReceive 阻塞读。低速采样还好一旦把采样率提到 1kHz 以上问题就来了。阻塞读意味着 CPU 在 SPI 传输完成之前不能干别的。SPI 时钟 10MHz、读 6 字节需要大约 4.8 微秒命令 1 字节 数据 6 字节共 7 字节7×8/10MHz 5.6μs这本身不算长。但 HAL 库的 HAL_SPI_TransmitReceive 有锁定标志、等待超时等额外时间实测一次调用可能要 20~30μs。以 1kHz 采样周期1000μs来算占用率 2%~3%问题不大。可如果后面要同时跑 FFT、LCD 刷新、串口打印这些时间叠加起来就很可观容易造成采样周期抖动。更关键的是传感器有 FIFO 容量和数据更新周期如果 MCU 不能在规定时间内把数据读走新数据会覆盖旧数据你自以为采集到了完整序列实际上波形已经出现缺口了FFT 出来的频谱全是混叠噪声。5.2 切入 DMA 模式DMA 模式的核心思想是CPU 只负责启动传输SPI 外设借助 DMA 自动把数据搬到内存传输完成后触发中断通知 CPU。这样 CPU 在传输期间可以去处理其他任务比如浮点运算、状态机切换。CubeMX 里配置 DMA 也很简单。在 SPI1 的 DMA Settings 选项卡里添加 DMA Request一个用于发送SPI1_TX一个用于接收SPI1_RX方向分别选 Memory-To-Peripheral 和 Peripheral-To-Memory模式选 Normal数据宽度选 Byte。启动 DMA 传输的代码用的是 HAL_SPI_TransmitReceive_DMAuint8_t txDmaBuf[7] {0}; uint8_t rxDmaBuf[7] {0}; void IIS3DWB_StartDmaRead(void) { txDmaBuf[0] 0x28 | 0x80; for (int i 1; i 7; i) { txDmaBuf[i] 0x00; } IIS3DWB_CS_LOW(); HAL_SPI_TransmitReceive_DMA(hspi1, txDmaBuf, rxDmaBuf, 7); }然后在 SPI 的 TxRxCpltCallback 回调里拉高 CS处理数据void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { if (hspi-Instance SPI1) { IIS3DWB_CS_HIGH(); process_accel_data(rxDmaBuf); IIS3DWB_StartDmaRead(); // 准备下一次读取 } }这个思路能跑得很稳但有几个注意点。一是 DMA buffer 必须是全局或静态变量不能是局部变量否则栈上地址 DMA 访问不到。二是回调里处理数据要快不能做耗时操作比如浮点 FFT 应该放主循环或另一个任务里不能再在中断里做。三是连续 DMA 启动时CS 拉高后立刻拉低中间最好加几个空的延时否则传感器 SPI 状态机可能来不及复位导致后续读取错位。5.3 传感器 FIFO 和中断引脚配合除了 DMAIIS3DWB10IS 还带了 FIFO。FIFO 的作用相当于一个缓冲水池传感器内部按 ODR 往 FIFO 里存数据MCU 可以攒一批再一起读走。用 FIFO 的好处是降低 MCU 的实时性要求。比如 ODR 1kHzFIFO 深度足够的话你可以每 10ms 读一次每次读 10 组数据而不是每 1ms 读一次。这样 CPU 有大量时间处理其他任务。FIFO 的读取不能盲读。建议先把中断引脚 INT1 连接到 MCU 的 EXTI 或 GPIO 中断配置为 FIFO 阈值中断。当 FIFO 里的数据达到设定值比如 15/16 满INT1 拉高MCU 中断触发然后再通过 SPI 把一批数据读出来。这样最省 CPU也绝不会丢数据。不过 FIFO 模式会引入一定复杂度初期调试建议先把单次读取跑通再用 DA 的方式提速最后再加 FIFO 做优化。一步一步来出问题好定位。6. 实测数据与波形观察6.1 三轴数据怎么可视化数据读出来了怎么看对不对最简单的方法是串口打印出来用串口调试助手或者 Python 脚本绘图。我常用的是 Python pyserial matplotlib读串口数据实时画三轴波形。代码不复杂但有个点要注意串口打印会占用大量时间如果你一边用 DMA 高速采样一边 printf可能互相干扰。建议的做法是把数据存在一个环形缓冲区里主循环低优先级慢慢打印不实时打这样采样中断不会被阻塞。打印格式建议用 CSV 一行一行的形式timestamp,x_mg,y_mg,z_mg 1000,12.3,-5.6,1010.2这样后续处理非常方便Excel 也能直接打开。6.2 静态与振动对比拿到波形后先做一个静态测试。把传感器平放在桌面上Z 轴应该读到约 1000mgX 和 Y 轴接近 0mg。这是因为重力加速度 1g 作用在 Z 轴上。如果你测出来 X 轴是 1000mg、Z 轴是 0mg说明传感器摆放方向和你预期不一样不是 bug。然后用手轻轻敲击桌面或者用手机振动马达贴在传感器附近观察波形是否能捕捉到瞬态冲击。这一步主要看响应速度和幅值是否合理。初次调试时如果读数一直在某个固定值附近抖动但抖动幅度只有几个 LSB那是正常噪声如果抖动幅度几百个 LSB那就要检查电源去耦和 SPI 读时序是否有问题。6.3 实测中发现的一个典型问题我记得第一次高速读取时FFT 频谱里总是有一个 500Hz 左右的尖峰怎么都消不掉。我开始以为是传感器本身频率响应问题后来用示波器测传感器电源引脚发现上面叠加了一个 500Hz 的纹波来自隔壁 DC-DC 电源的开关频率。把传感器供电单独拉出去用 LDO 供电并加大滤波电容后这个尖峰消失了。这类问题在振动测量里特别典型——你测到的可能不是设备振动而是电源噪声。所以做振动采集电源设计怎么强调都不过分。7. 常见问题排查与避坑7.1 WHO_AM_I 读回来全 0xFF 或全 0x00这是 SPI 通信最常见的故障几乎所有人都遇到过。我用一个表格整理排查路径方便你对照现象可能原因排查办法读回 0xFFMISO 悬空或电平不对检查 MISO 接线和焊点确认传感器供电读回 0x00传感器没进入 SPI 模式确认 CS 电平、检查 SA0 引脚是否悬空读回错误但稳定值SPI 模式不匹配CPOL/CPHA 试四种组合时好时坏电源不稳定或 CS 毛刺加大滤波电容CS 加 10kΩ 上拉到 VDD复位后第一次失败上电时序问题初始化前加 10ms~100ms 延时7.2 数据全是 0 或者恒定如果通信正常WHO_AM_I 对但加速度数据全是 0优先检查寄存器配置有没有生效。尤其是 CTRL1 里的 ODR 配置如果把 ODR 配成了 0传感器可能不更新数据输出寄存器一直保持上电默认值。另一种情况是传感器进入了低功耗模式或者待机模式。有些传感器上电默认是待机模式必须写 CTRL1 切到连续测量模式才更新数据。看数据手册的“上电默认状态”章节确认默认模式。还有一个很低级但常见的坑读出来数据字节顺序搞反了。如果你用(rxBuf[1] 8) | rxBuf[2]而不是(rxBuf[2] 8) | rxBuf[1]数据会表现为在小范围跳动但数值明显不对比如 Z 轴不是 1000mg 而是几万 mg。这种一旦发现改一下拼接顺序就好。7.3 CS 片选毛刺问题软件 CS 比较灵活但如果控制不好会在数据线上引入毛刺。最常见的问题是 CS 拉低之前MOSI 上还没有准备好数据。这就要求你在 CS_LOW 之后、SPI 传输之前稍微延时几个时钟周期让 MOSI 稳定下来。HAL 库的 TransmitReceive 会自动准备但如果你自己拼凑逻辑最好加一个短延时。CS 拉高也有讲究。如果最后一个字节的 SCK 下降沿刚结束立即拉高 CS传感器可能来不及锁存最后一个字节。稳妥的做法是等 SPI 传输完成标志置位后再拉高 CS这也是为什么 DMA 回调里拉高 CS 更可靠的原因。7.4 SPI 速率和信号质量把 SPI 速率调到 10MHz 后如果用了杜邦线连接波形会明显变差。杜邦线有分布电容和电感高速边沿会被拉缓MISO 数据在采样时刻可能还没稳定。建议用短导线或者直接焊接SPI 时钟 10MHz 时导线尽量控制在 10cm 以内。实在要用杜邦线可以考虑把 SPI 速率降到 1MHz~2MHz传输时间多几十微秒但在大多数振动监测场景下完全够用。稳定性比极限速度重要得多。7.5 SPI 和 I2C 共用一个总线的风险IIS3DWB10IS 的 SPI 和 I2C 共用引脚。如果你在系统里既想用 I2C 又想用 SPI或者把传感器同时接到两条总线上必须确保 CS 引脚在 I2C 模式下被拉高。否则传感器会误以为工作在 SPI 模式I2C 通信完全异常。同理SPI 模式下不要让 SPC 和 SDI 长时间浮空最好通过初始化配置把它们拉到确定的电平。一个经验SPI 模式下把 CS 内部上拉使能或外部加 10kΩ 上拉能有效防止上电期间的片选毛刺。这个细节在很多参考设计里都有值得照做。8. 后续扩展方向跑通 SPI 读取 IIS3DWB10IS 之后可以做很多实际应用。我自己接下来的方向是在 STM32C5 上做实时 FFT 频谱分析。STM32C5 的 Cortex-M33 主频足够可以跑 2048 点 FFT每 100ms 输出一次频谱再配合阈值判断实现简单的设备异常报警。还想试的功能是多传感器同步。一个系统里挂两个或多个 IIS3DWB分别贴在设备的不同位置SPI 总线共用CS 分别控制。采集时需要注意同步采样因为振动信号相位信息很重要两台设备不同步测出来的相位差是假的没法用于模态分析。如果对无线传输感兴趣也可以把 STM32C5 接 WiFi 或 BLE 模块采集到的数据实时上传到上位机或云平台做成远程监测系统。不过无线传输的吞吐量和实时性有限建议在边缘端做压缩或特征提取只上传特征值而不是原始波形。最后再分享一个小技巧开发阶段建议把 SPI 的几条线引出测试点方便逻辑分析仪抓波形。我调试时被 SPI 时序折腾过好几回有了测试点之后一个逻辑分析仪扫描命令和应答一目了然定位问题效率高很多。项目做完了再考虑删掉测试点或者改成小焊盘。