
简介面向STM32嵌入式开发者的CS5532模数转换芯片驱动源码包适用于工业测量、传感器信号采集等需要高精度、低噪声ADC转换的场景。资源采用普通GPIO模拟控制时序不占用专用SPI外设便于在STM32F4等系列上灵活移植。压缩包共2个文件分别为1个C源文件和1个头文件整体仅4KB轻量易用。头文件明确给出了SCK、SDI等引脚的GPIO端口、引脚号及模式、速度配置C源文件则实现了通道选择、增益设置、转换启动与读取结果等核心驱动逻辑并封装了必要的寄存器操作和接口宏可帮助开发者快速接入自己的采集系统结合源码中的引脚定义与接口声明也能大大缩短硬件连接和软件调试时间。已有630人学习下载适合正在调试CS5532、希望免去从零编写底层驱动时间的嵌入式软硬件工程师参考借鉴。1. CS5532 是什么为什么 STM32 项目里总能看到这颗 24 位 ADC做电子秤、张力或毫伏级传感器采集时STM32 内置的 12 位 ADC 远远不够用传感器满量程输出只有几毫伏12 位分辨率分到每千克上码值太少噪声和零点漂移都压不住。最常见的替代方案就是外挂 CS5532。它是一颗 24 位 Δ-Σ 双通道 ADCSPI 接口内置可编程增益和数字滤波称重和工业采集场景里非常常见。这个“模数转换芯片CS5532基于STM32的驱动程序C源码.zip”就是让 STM32 通过 SPI 把 CS5532 驱动起来的 C 工程模板能省掉翻手册、对时序、写校准命令的几天时间。适合正在做称重仪表、变送器、高精度数据采集或准备用 CS5532 替代内置 ADC 的嵌入式工程师。2. 驱动 CS5532 之前要搞懂的底账时序、引脚和寄存器模型2.1 Δ-Σ 架构决定了它和内置 ADC 的使用方式完全不同CS5532 不是逐次比较型 ADC它靠过采样加数字滤波把量化噪声推到频带外所以分辨率能做到 24 位代价是转换速度慢。常见字率只有 7.5SPS 到 3840SPS称重场景一般取几十到几百 SPS。这个特性直接影响驱动写法你不能像读 STM32 内置 ADC 那样启动后立刻拿结果必须等转换完成再读。第一次用的人很容易在这里翻车——命令发出去了数据读回来却是上一拍的旧数据于是怀疑芯片坏了其实只是没等够时间。驱动里一般有两个选择轮询转换完成状态或者按字率倒推延时。CS5532 对外接口就是 SPI 从机的四根线SCLK、SDI、SDO、CS。SDI 进命令字SDO 出转换数据命令和数据分时复用。软件上要做的事归纳起来只有四件初始化 SPI、写配置寄存器、校准、读数据。这个源码 zip 里的 C 源码本质就是把这四件事封装成 cs5532.c 和 cs5532.h再在 main.c 里按上电顺序调用。理解了这个模型看任何版本的 CS5532 驱动都不会迷路因为换主控只是换 SPI 函数名而已。寄存器方面CS5532 内部除了转换数据寄存器还有配置寄存器、偏移校准寄存器、增益校准寄存器。配置寄存器里放着通道选择、增益倍数和字率偏移和增益寄存器一般由校准流程自动算好写进去应用层也可以覆盖它们做微调。命令字节选中哪个寄存器、是读还是写由命令字的若干位决定。不同批次的驱动源码宏命名可能有差异有的叫 CS5532_CMD_READ_CONV有的叫 CS5532_READ_DATA意思都一样把名字理顺再编译。2.2 引脚接线和电源称重传感器和基准怎么接先把硬件确认清楚再谈软件。CS5532 关键引脚包括差分输入 AIN1/AIN1-、AIN2/AIN2-参考电压 VREF/VREF-数字接口 SCLK、SDI、SDO、CS以及 AVDD、DVDD、AGND、DGND。和 STM32 的典型对应关系如下信号CS5532 引脚接 STM32说明串行时钟SCLKPA5SPI1_SCK速率先低速跑通再提数据输入SDIPA7SPI1_MOSI发命令字节数据输出SDOPA6SPI1_MISO读转换结果和状态片选CSPB6GPIO软件控制不用硬件 NSS参考电压正VREF接 2.5V/5V 精密基准REF5025、TL431 都常见参考电压负VREF-接模拟地与 AGND 单点相连称重传感器是电阻应变电桥输出 SIG、SIG- 两根差分线接 AIN1 和 AIN1-传感器激励接外部供电。差分输入测的是两根线之间的差不是对地电压所以屏蔽层只在传感器侧单点接地。VREF 是整个测量链路的尺子一般用 REF5025 出 2.5V 或 TL431 出 2.5V/5VAVDD 和 VREF 都要用 10μF 钽电容并联 100nF 陶瓷电容去耦。很多数据跳变查到最后都是基准源纹波和地线噪声的问题。上电顺序也容易忽略AVDD 和 DVDD 尽量同时上电至少不要让数字电源先于模拟电源很久。芯片内部 POR 电路在上电后会拉低 SDO 一段时间那是复位脉冲复位完成后 SDO 释放。所以 main 函数开头至少延时 50ms 到 100ms 再碰 SPI别一上来就发命令。工程上常见“上电不响应”一半是复位没完另一半是 SCLK 空闲电平不对。另外传感器激励地和 VREF 地最终要在一点汇合不要在数字地附近汇否则数字噪声会窜进模拟回路。2.3 SPI 时序和命令模型先确认 CPOL/CPHA 再写配置CS5532 的串行协议要求先确认时钟极性和相位。多数现成驱动用的是 CPOL0、CPHA1也就是 SPI MODE1也有工程用 MODE3区别是空闲电平高低不同。最可靠的做法是对着 datasheet 的时序图检查看 SCLK 空闲时是高还是低、数据在哪个边沿被采样。我一般先用 100kHz 低速试再用逻辑分析仪抓 SDO如果命令发出后 SDO 完全没有变化先怀疑极性而不是怀疑芯片。命令模型是 8 位命令字加可选参数。像“读转换数据”“写配置寄存器”“自校准”这些操作驱动里统一封装成宏。这里有一个很常见的坑不同渠道的源码包命令字宏的数值可能不一样直接用网上抄的宏去驱动另一个版本的 CS5532读回来的数据全不对。所以拿到这个 zip先把 cs5532.h 里的几个关键宏和芯片数据手册命令字表对照一遍确认一致再编译。命令字写错的特征非常明显SPI 波形正常但读到的码值恒定不变或者全 1。数据字节序也要提前确认CS5532 转换结果是 24 位SPI 一次传 8 位所以读数据是连续三次 Receive顺序是高字节、中字节、低字节。不要按 STM32 的小端习惯去反转字节后面拼接代码会一并处理。至于为什么用 STM32 硬件 SPI 而不是 GPIO 模拟硬件 SPI 能保证字节时序连续CS 拉低后发 1 字节命令再连续收 3 字节中途不会被其他中断打断出半个时钟。GPIO 模拟也能用但中断一多SCLK 间隔就会拉开CS5532 对时钟间隙有容忍上限模拟接口只建议在低速且系统不忙时用。这个源码包走的就是硬件 SPI跑起来最省事。3. 把 C 源码跑起来STM32 SPI 初始化和驱动骨架3.1 拿到 zip 之后先做三件事第一打开工程看芯片型号和引脚宏是否匹配。很多驱动包默认 SPI1引脚 PA5/PA6/PA7如果你的板子把 SPI 放在了 SPI2 或做过重映射直接编译过不了。第二在 Keil 或 STM32CubeIDE 里打开工程先编译一遍确认没有宏定义缺失再根据自己主频调整 SPI 预分频。现在也有人用 VSCode 配 CMake 搭 STM32 环境那只是编译方式不同驱动源文件还是同一套。第三把 cs5532.h 里的 CS 引脚宏改成 PCB 实际定义GPIO 的时钟使能也要对上。这个 zip 不是解压就能烧录的成品固件它是参考实现改引脚、对时序是必经步骤。用 STM32 标准库新建工程和用 HAL 库新建工程在这部分只有函数名差异流程一样。3.2 用 HAL 库配置 SPI主机模式、8 位数据、低速率起步当前多数源码包基于 STM32 HAL 库标准库版本也有两者差别只在初始化函数名。以 HAL 库为例最小初始化如下static void MX_SPI1_Init(void) { hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_MASTER; // CS5532 是从机 hspi1.Init.Direction SPI_DIRECTION_2LINES; // SDI/SDO 两根线 hspi1.Init.DataSize SPI_DATASIZE_8BIT; // 命令和寄存器都是字节 hspi1.Init.CLKPolarity SPI_POLARITY_LOW; // CPOL0 hspi1.Init.CLKPhase SPI_PHASE_2EDGE; // CPHA1即 MODE1 hspi1.Init.NSS SPI_NSS_SOFT; // CS 用 GPIO 控制 hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_64; hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; // 高位在前 HAL_SPI_Init(hspi1); }参数说明MODE_MASTER 必须CS5532 没有任何自启动能力CLKPOLARITY_LOW 加 CLKPHASE_2EDGE 是 MODE1如果手册要求 MODE3把这两个选项反着设DataSize 用 8BIT命令字节和 24 位数据都是按字节收发预分频 64 在 72MHz 主频下约 1.125MHz对 CS5532 绰绰有余。不要一上来就调到最高速高速下走线稍长就偶发通信失败低速跑通再提速是我一直推荐的做法。NSS 用软件模式因为 CS 引脚要自己用 GPIO 控制交给硬件 NSS 反而容易出片选毛刺。3.3 读写封装命令与数据必须在同一次 CS 低电平内CS5532 每次操作以 CS 拉低开始以 CS 拉高结束。读转换数据时先发命令字节再连续接收 3 个字节SDO 在这期间移出 24 位结果#define CS5532_CS_LOW() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) #define CS5532_CS_HIGH() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) static void CS5532_WriteCmd(uint8_t cmd) { HAL_SPI_Transmit(hspi1, cmd, 1, 100); } static void CS5532_ReadData(uint8_t *buf) { CS5532_CS_LOW(); CS5532_WriteCmd(CS5532_CMD_READ_CONV); // 命令码以手册为准 HAL_SPI_Receive(hspi1, buf, 3, 100); CS5532_CS_HIGH(); }逻辑说明先拉低 CS让芯片知道一次访问开始发命令后芯片在随后的时钟边沿把数据推到 SDO命令和接收要在同一次 CS 低电平内完成中间不能释放片选。有的驱动把写命令和读数据拆成两个函数中间如果 CS 被抬了一下读回来的就是无效数据。HAL 超时 100ms 足够但如果芯片正在校准时读数据SDO 可能不输出有效数据要等校准结束再读。buf 必须是三字节数组多读一个字节会把下一次命令的时序打乱。3.4 初始化序列复位、写配置、自校准CS5532 上电后有固定套路。先给芯片一个复位脉冲CS 拉低连续发多个 0xFF然后拉高。0xFF 本质上是在给串行状态机灌满 1让它重新对齐。接着写配置寄存器最后执行自校准uint8_t cfg CS5532_CFG_CH0 | CS5532_CFG_GAIN_1 | CS5532_CFG_WR_30; CS5532_CS_LOW(); for (int i 0; i 4; i) { CS5532_WriteCmd(0xFF); // 复位脉冲打断芯片当前串行状态 } CS5532_CS_HIGH(); HAL_Delay(50); CS5532_CS_LOW(); CS5532_WriteCmd(CS5532_CMD_WRITE_CONFIG); // 写配置寄存器命令宏以手册为准 CS5532_WriteCmd(cfg); CS5532_CS_HIGH(); HAL_Delay(10); CS5532_CS_LOW(); CS5532_WriteCmd(CS5532_CMD_SELF_CAL); // 自校准命令 CS5532_CS_HIGH(); HAL_Delay(200); // 校准期间不读数据保守延时逻辑说明写配置寄存器通常是先发命令字再发一个参数字节参数里编码了通道、增益、字率具体每个 bit 的含义看手册配置寄存器表。这里 cfg 的例子选了通道 0、增益 1、字率 30SPS如果你的传感器输出只有几毫伏增益 1 可能不够后面再往上调。自校准会把芯片输入端内部短接测内部失调和增益误差存进校准寄存器。校准期间芯片不响应读数据命令固定延时 200ms 是保守写法如果源码包提供查询 SDO 状态等待校准完成的接口轮询更省时间也更可靠。提示校准结果会随电源和基准变化漂移改变 VREF 或明显改动供电后必须重新执行校准序列。4. 从原始码到物理量24 位有符号拼接和滤波4.1 24 位补码拼成 int32_t符号扩展是第一步CS5532 的转换结果是 24 位二进制补码通过 SPI 按高、中、低三个字节依次送出。拼接成 int32_t 时要移位还要按第 23 位扩展符号。这一步的坑不在移位而在负数24 位补码的高 8 位必须由符号位填充否则负码值会变成一个大正数。int32_t CS5532_CodeFromBuf(const uint8_t *buf) { int32_t code; code ((int32_t)buf[0] 16); // buf[0] 是最高字节 code | ((int32_t)buf[1] 8); code | ((int32_t)buf[2]); if (code 0x800000) { // 第 23 位是符号位 code | 0xFF000000; // 符号扩展到 32 位 } return code; }逻辑说明先无符号拼出 24 位值再判断第 23 位。为 1 说明是负数把高 8 位补成 0xFFcode 才变成真正的 int32_t 负值。不做符号扩展的话负满量程会变成 16777215后面换算电压、重量全部错乱。SPI 读出来是大端顺序STM32 是小端 CPU但这里只做移位拼接不需要调用字节序翻转函数翻转反而错。4.2 码值换算电压和重量两点标定比算绝对电压更实用理论上输入电压与码值的关系近似为 Vin Code × VREF / (Gain × 2^23)。VREF5V、Gain1 时正向满码约对应 5VGain64 时满量程约 78mV正好适合应变电桥直接接入。但在工程上我不会依赖这条公式去算重量因为 VREF 精度、增益误差、传感器灵敏度都有温漂。更皮实的做法是两点标定空载记录零点码加载标准砝码记录满码之后按线性插值换算重量。我会在应用层保存一个零点码和系数比如零点 0、10kg 砝码对应码 8000000那么任意码 x 的重量就是 x × 10.0 / 8000000。这样绕开了模拟链路里所有系统误差只要传感器线性度好精度就能做起来。标定时记得先让系统预热冷机标定后十分钟零点已经飘了数据自然偏。零点码和系数要写入 Flash 或 EEPROM不能每次上电都重新标定否则批量化生产时每台设备都要重复人工校准。4.3 整数域滤波先去极值平均再换算物理量CS5532 即使开了内部数字滤波低位码值依然会跳几个 LSB这是热噪声和量化噪声叠加的结果不是芯片坏了。固件里再补一层软件滤波我常用去极值平均#define FILTER_N 8 static int32_t g_buf[FILTER_N]; static uint8_t g_idx 0; int32_t CS5532_FilterSample(int32_t new_code) { int32_t sum 0, min 0x7FFFFFFF, max -0x7FFFFFFF; uint8_t i; g_buf[g_idx] new_code; g_idx (g_idx 1) % FILTER_N; for (i 0; i FILTER_N; i) { if (g_buf[i] min) min g_buf[i]; if (g_buf[i] max) max g_buf[i]; sum g_buf[i]; } return (sum - min - max) / (FILTER_N - 2); // 去掉一个最大一个最小 }逻辑说明环形缓冲存最近 8 次码值去掉一个最大、一个最小剩下 6 个求和再平均。相比等权滑动平均它对脉冲干扰不敏感比如电机启动瞬间耦合到传感器线上的尖峰滑动平均会被拉偏好几拍去极值只损失一个样本周期。FILTER_N8 时输出速率降为采样率的约 1/4动态称重或需要快速响应的场景要调小静态称重可以调到 16。还有一点滤波要在整数码值域做不要在浮点电压域做STM32F1 的浮点运算慢而且整数域滤波结果和浮点域滤波结果在统计上等价能省则省。每次参与滤波的数据要跨转换周期采样同一个转换周期里反复读同一组码值没有平滑意义。提示滤波放在整数码值域做不要在浮点电压域做。统计上两者等价但在 F1 上整数运算快得多。5. CS5532 驱动常见问题排查现象、原因和解决CS5532 的坑大多数不在芯片本身而在它的使用方式时序、命令字、校准和滤波任何一个环节出错都会呈现为“读数不对”这一个症状。下面按出现频率排几条每条按“现象—原因—解决”写现场排查时可以直接对照。5.1 读回 0xFFFFFF 或固定值现象输入怎么变读数都是 0xFFFFFF偶尔夹杂几个 0xFFFFFE。原因SPI 时钟相位或极性反了命令字没有被正确解析或命令宏和手册不一致或 CS 引脚被初始化成了复用功能片选从没真正拉低。解决用示波器看 SCLK 空闲电平和手册时序图比对把 SPI 降到几百 kHz读配置寄存器如果读出的通道和增益符合预期说明链路通问题只在读数据命令。大部分“全 1”问题在低速下都会现形因为高速下时序裕量不足命令字恰好被错采成 0xFF。我习惯在 ReadData 里加一个调试数组把收到的三个字节原样保留出错时看规律是稳定全 1 还是乱跳定位方向完全不一样。5.2 数据跳变到满量程现象空载读数偶尔从正常值跳到正满量程或负满量程过一会儿又恢复。原因增益设太高输入噪声被放大到接近满量程模拟输入悬空、接插件松动VREF 纹波大。解决先把增益降到 1排除倍数问题输入端对地加 100nF 电容传感器线换屏蔽线查基准源输出电容。持续、高频的满量程跳变基本是硬件问题软件滤波只能抹掉零星毛刺不能掩盖持续噪声。到这里还没解决的话用一个干电池加电阻分压出毫伏级信号直接接到 AIN跨过传感器定位是前端问题还是 ADC 问题。这个方法比反复改代码快得多能省掉大半天。5.3 校准后零点漂移现象刚校完零点正常几分钟后漂几十个码。原因供电或参考没稳定就校准传感器自身热漂移自校准只能消除芯片内部失调抵消不了外部传感器漂移。校准完立刻读数数字滤波器可能还没收敛。解决上电后等几分钟再校准有条件就做系统校准把传感器也纳入校准环路软件加零点跟踪开机无负载时记录零点码。注意固定延时要大于一个字率周期否则校准寄存器写进去了但输出还没稳定采到的是过渡值。现场排查时可以试着手摸一下 CS5532 外壳芯片发热也会引起零点漂移这是硬件设计时要考虑的。5.4 SPI 偶发通信失败现象设备跑一阵子后读数全 0 或全 1复位单片机恢复过一阵又犯。原因SPI 速率过高CS 拉高瞬间还有多余时钟中断里长时间占用 SPI导致时序被拉长到芯片容忍之外。解决速率降到 500kHz 以下CS 拉高前确保发送寄存器空关掉在 SPI 传输期间抢占的中断初始化时多发几个 0xFF 让状态机重新对齐。这种问题最气人因为它调试时不一定复现往往要挂机几小时才出现。我会把 SPI 预分频调到 128 再让设备跑三天确认不再犯才是真的解决。可以说这是 CS5532 驱动里最玄学的一类故障但本质还是时序裕量不足低速一定能绕过去。5.5 上电后命令无响应现象SDO 一直低发任何命令都没反应。原因上电后立即操作POR 复位没结束AVDD/DVDD 上电顺序不对SCLK 空闲电平不对芯片状态机卡死。解决main 开头延时 100ms 再初始化 SPI检查两个电源的时序把 SCLK 空闲电平先和手册对齐再发命令。CS5532 的 POR 对电源毛刺很敏感有时候按复位键没用必须断电再上电。这类问题用示波器看 DVDD 上升沿干不干净毛刺多的要加 RC 滤波或外部复位芯片。如果你把上面几条都试完还是不对检查一下是不是拿 CS5532 的驱动去驱动 CS5534 了。CS5532 是双通道CS5534 是四通道命令字和配置寄存器不完全一样网上源码混用很常见。另一个隐蔽点是 SPI_NSS 引脚是否有外部上拉硬件 NSS 被意外拉低会干扰软件 CS 的片选逻辑导致每次操作都错位。6. 把驱动用得更稳系统校准、通道切换和验证方法先讲系统校准。自校准只负责消除芯片内部误差传感器电桥的增益误差和零偏得靠系统校准或软件标定来处理。做法是先断电给传感器加标准砝码或用精密电压源给固定毫伏信号上电发系统校准命令。和软件两点标定相比系统校准把误差写进芯片内部增益寄存器后续码值本身就更接近真实电压应用层可以少算一步。但系统校准对环境要求高现场有振动或基准不稳时反而会引入误差所以我会在产线用系统校准在野外设备上用软件标定。再讲通道切换。CS5532 是双通道同一片 SPI 总线可以切 AIN1 和 AIN2。切换后不是立刻就能读模拟输入前端和数字滤波器都需要时间重新稳定。用过 STM32 内置 ADC 切换通道的都知道要等采样电容稳定CS5532 也一样切换后至少等一个字率周期再取数最稳妥是丢弃前两拍数据。频繁切换通道时滤波缓冲区要按通道分开不然两个通道的数据混在一个滤波器里读数会出现串扰。验证方法说一个具体技巧用精密电压源验证比用万用表靠谱。把 VREF 设为 2.5VGain 设为 1用 0.1% 电压源输出 0mV、5mV、10mV、20mV 接到 AIN读码值并记录。理想情况下码值和电压严格线性偏差应在几个 LSB 以内。这个测试能一次区分出硬件接线、SPI 时序、滤波参数三方面的问题比直接接传感器更容易定位。传感器验证则用标准砝码做五点线性记录零点到满量程的码值分布算出非线性误差。最后说点个人习惯。我早期调 CS5532 总想一口气把滤波和标定全部写完再上电结果是数据一乱根本不知道是哪一层出的错。后来改成“先低速 SPI 加逻辑分析仪确认时隙再校准再读原始码全部正常后才写滤波和标定”每一步都有明确的通过标准从此很少再有查不清的诡异问题。这个顺序希望你也能用上希望帮到你。本文还有配套的精品资源点击获取