尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32C5通过IIC驱动IIS3DWB震动传感器实战

STM32C5通过IIC驱动IIS3DWB震动传感器实战 1. 项目缘起与整体方案拆解1.1 为什么选IIC而不是SPI读IIS3DWB拿到IIS3DWB这颗震动计的时候我第一反应是翻数据手册确认它的通信接口。IIS3DWB是ST自家的一款超宽带宽三轴数字加速度计专门针对工业震动监测场景设计带宽能拉到6kHz以上ODR最高到26.67kHz。它同时支持SPI和IIC两种数字接口这就带来一个选型问题到底走哪条路。SPI的优势很直接速率高、全双工、时序简单读FIFO的时候能一口气把几百个采样点拉回来。但这次项目里我最终选了IIC原因有几个。第一硬件布线上IIC只需要两根线STM32C5的板子上我已经把USART1和几个外设占得差不多了留给传感器的IO不多IIC能省引脚。第二IIS3DWB在IIC模式下虽然最高只能跑400kHz快速模式或者1MHz快速模式但对于我当前只需要读取低频震动趋势、做状态监测的应用来说这个速率完全够用。第三IIC的总线结构允许多个传感器挂在同一组线上后面如果要加温湿度或者气压计扩展起来方便。这里要提醒一句IIS3DWB在IIC模式下的从机地址是固定的7位地址为0x6BSA0接GND时或者0x6ASA0接VDD时具体看你的硬件怎么接。我板子上SA0接地所以用0x6B左移一位变成写地址0xD6、读地址0xD7。这个细节后面配置的时候会反复用到。1.2 STM32C5这颗新芯片的定位STM32C5是ST近两年推出来的新系列定位在主流性能段介于G4和H5之间。网上很多人问stm32c5和g4外设对比我实际用下来的感受是C5的IIC外设比G4更“聪明”一些它支持可配置的数字滤波器、独立的时钟占空比调节还有更灵活的总线空闲检测机制。这些特性在跑IIC的时候能明显降低误码率尤其是在总线电容偏大、上升沿偏慢的场景下。C5的IIC外设还支持模拟和数字两种噪声滤波数字滤波可以设置0到15个时钟周期的抑制模拟滤波可以抑制50ns以下的尖峰。我在实际调试中发现如果传感器和MCU之间的排线比较长把数字滤波开到4到6个周期能有效滤掉毛刺避免误触发。这个功能在G4上也有但C5的寄存器配置更直观CubeMX里直接有下拉框可以选。另外C5的时钟树比G4更灵活IIC的时钟源可以从PCLK或者HSI独立分频这样即使主频跑得不高也能保证IIC的时序精度。我这次主频配置在144MHzPCLK1分频后给到IIC再通过CCR寄存器算出正确的分频值保证SCL频率稳定在400kHz。1.3 整体数据流设计整个项目的目标很明确STM32C5通过IIC周期性读取IIS3DWB的三轴加速度数据然后通过USART1把数据打印到串口助手上方便观察震动波形。数据流是这样的IIS3DWB内部以设定的ODR采样数据存在输出寄存器和FIFO里STM32C5的IIC主机发起读操作从0x28到0x2D这六个寄存器里把X、Y、Z三轴的16位数据读出来读完之后做一下量程换算再通过USART1以文本格式发出去。这里有个设计取舍是用FIFO批量读还是直接读输出寄存器。IIS3DWB的FIFO深度是512个样本如果做高频震动分析肯定要走FIFO一次读一批减少IIC通信开销。但我当前只是做低频状态监测ODR设在416Hz直接读输出寄存器就够了代码也简单。后面如果要升级到高频采集再切到FIFO模式这个扩展路径我在代码里留了接口。USART1的配置没什么特别的波特率1152008位数据位1位停止位无校验。用DMA发送会更稳但初期调试用阻塞发送也够等数据量大了再换DMA。2. IIC通信核心细节与IIS3DWB寄存器解析2.1 IIC时序的关键参数计算IIC的时序看起来简单但实际配置的时候有几个参数必须算准否则通信不稳定。STM32C5的IIC外设里SCL频率由CCR寄存器决定计算公式分标准模式和快速模式两种情况。标准模式100kHz下CCR PCLK1 / (2 * 100000)快速模式400kHz下CCR PCLK1 / (3 * 400000)我这次PCLK1配置在72MHz快速模式下CCR 72000000 / (3 * 400000) 60。这个值写进CCR寄存器同时把F/S位设为1表示快速模式DUTY位设为0表示占空比Tlow/Thigh 2。除了CCR还有两个时间参数要设TRISE和TSSCL。TRISE是最大上升时间快速模式下最大300ns对应到PCLK1周期数就是300ns / (1/72MHz) 21.6取整为22。这个值要写进TRISE寄存器。TSSCL是模拟滤波的抑制时间如果开了模拟滤波需要设置这个值一般设1到2个PCLK周期。网上很多人问iic上拉电阻取多大这个问题其实和总线速率、总线电容直接相关。标准模式100kHz下上拉电阻一般取4.7k到10k快速模式400kHz下取2.2k到4.7k快速模式1MHz下取1k到2.2k。我这次跑400kHz总线上只挂了一个传感器电容估计在50pF左右上拉电阻用了4.7k实测波形上升沿在200ns左右满足要求。如果挂多个传感器或者排线很长电容会增大上拉电阻要相应减小但最小不能低于1k否则灌电流会超过IIC规范的限制。2.2 IIS3DWB的寄存器地图IIS3DWB的寄存器分几个区域WHO_AM_I0x0F、控制寄存器0x10到0x17、FIFO控制0x1A到0x1F、状态寄存器0x1E、0x27、输出寄存器0x28到0x2D、以及一堆配置寄存器。WHO_AM_I的值固定是0x6B上电后先读这个寄存器确认通信正常。我一般把这个作为IIC通信的第一个测试点如果读回来不是0x6B说明要么地址错了要么时序有问题要么硬件没接好。控制寄存器里CTRL10x10管ODR和电源模式CTRL20x11管量程CTRL30x12管中断和FIFO的一些使能CTRL60x15管带宽和滤波。我这次配置是CTRL1写0x60表示ODR 416Hz高性能模式CTRL2写0x00表示量程±2gCTRL6写0x00表示带宽自动跟随ODR。输出寄存器0x28到0x2D是六个字节低字节在前高字节在后。读的时候要连续读六个字节不能分开读否则数据可能不同步。IIS3DWB内部有数据锁存机制连续读的时候会锁住当前样本保证三轴数据是同一时刻的。2.3 IIC读写操作的实现方式STM32C5的IIC外设支持中断、DMA和轮询三种方式。我这次用轮询因为数据量小代码简单调试方便。轮询方式下读写流程是这样的写寄存器发START发从机地址写位等ACK发寄存器地址等ACK发数据等ACK发STOP。读寄存器发START发从机地址写位等ACK发寄存器地址等ACK发RESTART发从机地址读位等ACK读数据发NACK发STOP。这里有个细节要注意IIS3DWB在IIC模式下读操作之前必须先写寄存器地址然后再RESTART切换成读。这个流程和大多数IIC传感器一样但有些传感器支持“地址自动递增”读的时候不用每次写地址。IIS3DWB支持自动递增所以连续读六个字节的时候只需要写一次起始地址0x28然后连续读六个字节就行地址会自动加。STM32C5的IIC外设里有个AUTOEND位如果使能了发完NACK之后硬件自动发STOP不用软件干预。我一般把这个位打开减少代码量。但要注意如果是在中断里处理AUTOEND和TCIE的配合要小心避免重复发STOP。3. STM32CubeMX配置与代码实现3.1 CubeMX里的IIC和USART配置步骤打开STM32CubeMX选好STM32C5的型号我这次用的是STM32C542RET6。第一步配时钟HSE选外部晶振PLL配置到144MHzPCLK1分频到72MHz。第二步配IIC选I2C1模式选I2C速度选Fast Mode400kHz。这里CubeMX会自动算出CCR和TRISE的值但建议手动核对一下尤其是TRISE有时候自动算出来的值偏小。第三步配USART1模式选Asynchronous波特率1152008N1。第四步配GPIOIIC的SCL和SDA要设成开漏输出上拉电阻如果外部有就不用开内部上拉如果没有就开内部上拉但内部上拉比较弱大概40k左右跑400kHz可能不够还是建议外部加4.7k。第五步生成代码选MDK-ARM或者STM32CubeIDE我这次用MDK。生成的时候注意勾选“Generate peripheral initialization as a pair of .c/.h files”这样代码结构清晰。3.2 IIC底层读写函数封装CubeMX生成的HAL库函数是HAL_I2C_Mem_Write和HAL_I2C_Mem_Read这两个函数封装了写地址、写寄存器、读数据的完整流程。但HAL库有个问题它的超时时间设得比较长默认是1000ms如果通信失败会卡住很久。我一般把超时改成10ms这样出错能快速返回。封装一个读寄存器的函数uint8_t IIS3DWB_ReadReg(uint8_t reg) { uint8_t data 0; HAL_I2C_Mem_Read(hi2c1, IIS3DWB_ADDR, reg, I2C_MEMADD_SIZE_8BIT, data, 1, 10); return data; }写寄存器的函数类似用HAL_I2C_Mem_Write。连续读多个字节void IIS3DWB_ReadMulti(uint8_t reg, uint8_t *buf, uint8_t len) { HAL_I2C_Mem_Read(hi2c1, IIS3DWB_ADDR, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 10); }这里IIS3DWB_ADDR是0x6B左移一位后的值即0xD6。HAL库内部会自动处理读写位的切换。3.3 数据读取与串口打印的完整流程初始化流程上电后先延时10ms等传感器稳定然后读WHO_AM_I确认是0x6B接着写CTRL1、CTRL2、CTRL6配置ODR、量程和带宽最后延时一段时间等第一个样本准备好。主循环里先读状态寄存器0x27的DRDY位如果为1说明有新数据然后连续读0x28到0x2D六个字节拼成三个16位有符号数再乘以灵敏度系数±2g量程下是0.061mg/LSB得到实际的加速度值单位是mg。最后用printf通过USART1打印出去。printf重定向int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 10); return ch; }打印格式我一般用“X: %.2f mg, Y: %.2f mg, Z: %.2f mg\r\n”这样在串口助手上看得很清楚。这里有个坑IIS3DWB的输出数据是低字节在前高字节在后拼的时候要写成(int16_t)((high 8) | low)不能搞反。我一开始搞反了读出来的数据跳得厉害后来查了半天才发现是字节序问题。4. 调试过程中踩过的坑与排查技巧4.1 IIC通信失败的常见原因第一个坑上电后读WHO_AM_I返回0x00或者0xFF。这种情况一般是硬件问题先查SCL和SDA有没有接反再查上拉电阻有没有焊最后查传感器供电是不是3.3V。IIS3DWB的供电范围是1.71V到3.6V我用3.3V没问题。第二个坑读回来的数据偶尔错位。这个多半是时序问题把IIC速率降到100kHz试试如果降速后正常说明400kHz下时序余量不够。这时候可以调大TRISE或者减小上拉电阻。我实测把上拉从4.7k换成2.2k400kHz下就稳了。第三个坑总线锁死。IIC总线如果因为干扰或者时序错误进入死锁状态SCL被拉低不放这时候需要手动恢复把SCL配置成推挽输出发9个时钟脉冲再把SDA配置成推挽输出发STOP最后重新初始化IIC。STM32C5的IIC外设有总线恢复功能可以通过设置PE0再PE1来复位外设但有时候硬件死锁需要手动干预。4.2 数据跳动与滤波处理IIS3DWB的原始数据本身噪声不大但如果电源纹波大或者地线处理不好读出来的数据会跳。我一开始用USB供电数据跳得厉害后来换成线性稳压电源跳动明显减小。另外IIS3DWB内部有高通滤波可以通过CTRL6配置如果不需要测重力分量把高通打开能去掉直流偏置。软件上我加了一个简单的滑动平均滤波每8个样本取一次平均这样打印出来的波形更平滑。但要注意滑动平均会引入相位延迟如果做实时控制这个延迟要算进去。4.3 常见问题速查表现象可能原因排查方法解决措施WHO_AM_I读回0x00硬件未连接查供电、查接线重新焊接或换线WHO_AM_I读回0xFF地址错误确认SA0电平改地址为0x6A或0x6B数据偶尔错位时序余量不足降速到100kHz测试减小上拉电阻或调TRISE总线锁死干扰或时序错误查SCL是否被拉低手动发时钟脉冲恢复数据跳动大电源纹波换线性电源测试加滤波电容或软件滤波读数据全为0传感器未启动查CTRL1配置确认ODR和电源模式4.4 实操心得与避坑建议第一IIC的上拉电阻不要省很多开发板自带上拉但阻值偏大跑400kHz的时候上升沿太慢容易误码。我一般外部再并一个4.7k效果立竿见影。第二CubeMX生成的IIC初始化代码里时钟频率配置有时候和实际不符尤其是PCLK1分频变了之后CCR不会自动更新。我习惯在IIC初始化之后手动调一下HAL_I2C_Init把ClockSpeed重新设一遍确保时序正确。第三调试IIC的时候逻辑分析仪比示波器好用。示波器只能看两根线的波形逻辑分析仪能直接解码出地址、数据和ACK一眼就能看出问题在哪。我用的是一款几十块钱的USB逻辑分析仪配合开源软件抓IIC时序很方便。第四IIS3DWB的FIFO模式虽然复杂但做高频采集的时候必须用。如果后面要升级建议先把FIFO的水位中断调通用中断触发读取避免轮询丢数据。第五STM32C5的IIC外设有个“时钟延展”功能如果从机拉低SCL主机会等待。IIS3DWB在IIC模式下支持时钟延展但一般用不到。如果发现通信变慢可以查一下是不是从机在延展时钟。5. 从IIC到完整震动监测的扩展思路5.1 数据上云与本地存储的取舍当前方案是把数据通过USART1打到串口助手上适合调试阶段。如果要做成产品下一步要考虑数据怎么存、怎么传。本地存储可以用SD卡或者FlashIIS3DWB的ODR如果设在416Hz三轴16位数据每秒就是416 * 6 2496字节一小时大概9MB一张8GB的SD卡能存很久。上云的话可以用4G模块或者WiFi模块但要注意功耗和带宽。我个人的建议是先做本地存储把数据完整记录下来后面再做离线分析。震动监测很多时候需要看历史趋势实时上传反而容易丢数据。5.2 中断驱动与低功耗设计轮询方式读数据CPU一直在忙功耗下不来。如果做电池供电的震动监测节点必须改成中断驱动。IIS3DWB有INT1和INT2两个中断引脚可以配置成DRDY中断或者FIFO水位中断。STM32C5的EXTI外部中断响应很快中断里置个标志位主循环里再读数据这样CPU大部分时间可以进低功耗模式。STM32C5的低功耗模式比G4更丰富有Sleep、Stop0、Stop1、Stop2、Standby几种。Stop2模式下功耗大概几微安IIC外设可以保持工作适合做间歇性采集。如果ODR设得低比如26Hz完全可以做到平均功耗几十微安。5.3 多传感器组网与IIC地址冲突IIC总线上挂多个IIS3DWB的时候地址冲突是个问题。IIS3DWB只有两个可选地址最多挂两个。如果要挂更多得用IIC多路复用器比如TCA9548A一路变八路每路挂一个传感器。STM32C5的IIC外设支持多主机模式但一般用不到单主机轮询多路复用器就够了。组网的时候要注意总线电容挂的传感器越多电容越大上拉电阻要越小。如果电容超过400pFIIC规范就不保证了这时候要么降速要么用IIC缓冲器。5.4 后续可以尝试的优化方向第一个方向是把IIC换成SPI速率能拉到10MHz以上配合FIFO可以做到连续高速采集适合做频谱分析。第二个方向是加一个实时操作系统把数据采集、存储、通信分成不同任务用消息队列传递数据代码结构更清晰。第三个方向是做边缘计算在STM32C5上直接算震动特征值比如RMS、峰值、峭度只把特征值传上去减少数据量。我个人在实际操作中的体会是IIC虽然速率不高但胜在简单可靠对于大多数震动监测场景够用了。真正要拼性能的时候再考虑换接口。先把IIC这条路走通把传感器玩熟后面换SPI或者加FIFO都是水到渠成的事。
返回列表