简介:STM32G070与CS5530联合开发资料包,面向嵌入式开发者、电子爱好者及需要实现高精度数据采集的工程师。该资源整合了电路原理图与配套C语言驱动代码,覆盖MCU初始化、SPI/I2C通信、数据处理等关键环节,可帮助读者快速理解两款芯片的硬件连接方式与软件交互流程。压缩包共3个文件,包含2个C源码文件和1份PDF说明文档,整体仅105KB,便于直接阅读和移植。目前已有787人学习下载,适合正在做传感器采集、工业控制或低功耗物联网项目的开发者参考复用。资料价值在于将CS5530驱动代码与STM32G070集成示例相结合,既给出了底层寄存器配置与读写函数,也提供了原理图层面的引脚定义和信号连接说明,能有效缩短从硬件搭建到固件调试的周期,是嵌入式接口开发中难得的紧凑实例。
1. STM32G070 接 CS5530,先想清楚这一个问题
很多从 HX711 转过来的工程师,拿到 CS5530 的第一块板子往往读不出数。问题不在代码,而在 CS5530 根本不像 HX711 那样上电就能用:它要求外接 4.096MHz 晶振、要用命令字节启动校准、连 SPI 时序都要卡着时钟个数来读。STM32G070 做低成本工业采集板、称重仪表和压力变送器很常见,和 CS5530 搭配是典型组合。这篇就顺着“G070 主控 + CS5530 高精度 ADC”这条线,把硬件接线、CubeMX 配置、最小驱动、校准顺序和噪声验证讲清楚,适合正在画原理图或已经把板子点亮、正在调 SPI 的读者。
2. CS5530 的 SPI 时序、寄存器与 STM32G070 的引脚分配
2.1 CS5530 的时钟与电平要求:先别急着写代码
CS5530 内部没有振荡器,XTAL1/XTAL2 必须挂一颗 4.096MHz 晶振。这是和 HX711 最不一样的地方,很多第一版硬件死在这一步。晶振两端各接一个 10pF 到 20pF 的负载电容到地,普通的 49S 晶振就能起振。判断晶振是否工作,最直接的办法是量 DRDY,如果上电后 DRDY 一直不动,先查晶振再查 SPI。
电源要注意 CS5530 的模拟电源 VA+ 和数字电源 VD+ 是分开的,允许 VA+ 接 5V、VD+ 接 3.3V。G070 的 GPIO 只能承受 3.6V,所以推荐 VA+ 用 5V 供电以提高模拟性能,VD+ 接 3.3V,这样 SDO/SDI/SCLK 的电平就跟着 3.3V 走,可以直接连 G070,不需要电平转换。模拟地和数字地在 CS5530 附近单点汇接,开关噪声就不容易通过地回路进到模拟前端。
2.2 命令字节、配置寄存器和 24 位转换结果的帧结构
CS5530 的串行接口看起来像 SPI,实际是“命令 + 移位”的混合时序。每次操作以 CS 拉低开始,先送一个命令字节,命令之后的 SCLK 个数由命令决定:写配置寄存器命令后跟 32 位数据,启动校准的命令后不需要额外数据,读转换结果时先送一个空操作字节,后续 24 个 SCLK 把数据从 SDO 推出。所有字节都是 MSB first,SPI 模式固定为 Mode 0(CPOL=0,CPHA=1Edge)。
常用命令如下,这些是驱动里真正会用到的:
| 命令字 | 行为 | 后续数据 |
|---|---|---|
| 0x01 | 写配置寄存器 | 4 字节,共 32 位 |
| 0x03 | 自校准 | 无,完成后 DRDY 拉低 |
| 0x15 | 系统失调校准 | 无,输入应处于零点 |
| 0x17 | 系统增益校准 | 无,输入应加已知标准信号 |
| 0x00 | NOP | 读结果时用来产生时钟 |
配置寄存器共 32 位,包含通道选择、增益、单/双极性、输入范围(VRS)、字速率等字段。对最小系统来说,上电复位后的默认值就可以直接用:通道 1、增益 1、双极性、输入范围 ±VREF。显式写一遍的作用是让后续改增益时有一个确定的基准,所以初始化时写四个 0x00 已经足够跑通整个流程,需要改增益时再查手册对应的位段,不要靠猜。
2.3 STM32G070 的 SPI1 引脚与接线
G070 的 SPI1 可以映射到 PA5/PA6/PA7,CS 用普通 GPIO 控制比硬件 NSS 更省心,DRDY 接一个任意输入 GPIO。我一般把 CS 放在 PA4、DRDY 放在 PB1,这样 CubeMX 里不需要配置 NSS 硬件功能。
| G070 引脚 | 功能 | 接 CS5530 引脚 | 配置 |
|---|---|---|---|
| PA5 | SPI1_SCK | SCLK | 复用推挽,速率 High |
| PA6 | SPI1_MISO | SDO | 复用输入 |
| PA7 | SPI1_MOSI | SDI | 复用推挽 |
| PA4 | GPIO 输出 | CS | 推挽,初始拉高 |
| PB1 | GPIO 输入 | DRDY | 上拉输入或浮空输入 |
| 3.3V | 电源 | VD+ | 与 G070 同源 |
| 5V | 电源 | VA+ | 模拟电源,可选 3.3V |
| GND | 地 | AGND/DGND | 单点连接 |
注意 SCLK 不要一开始就追求高速。CS5530 的串口时钟上限约 2.1MHz,而 G070 的最高主频 64MHz,APB 分频后取 32 分频正好得到 2MHz。2MHz 对这个 ADC 完全够用,7.5SPS 字速率下一帧才 133ms,瓶颈根本不在 SPI。
如果后续打算挂多个 SPI 器件,2MHz 可能显得保守,但 CS5530 的上限就在那里。G070 的 SPI 外设本身可以跑到 32MHz,把它和一个限制 2MHz 的老 ADC 放在同一条总线上,处理办法是给 CS5530 单独分一组 SCK 分频,或者接受整体降到 2MHz。我一般建议 CS5530 独占 SPI1,别的器件放到 SPI2,省得为了它拖慢 Flash 或 DAC 的吞吐。
3. 用 STM32G070 的硬件 SPI 驱动 CS5530:最小驱动代码与配置步骤
3.1 CubeMX 里 SPI1 的 4 个参数
在 CubeMX 中把 SPI1 设为 Full-Duplex Master、8 位数据长度,BaudRatePrescaler 选 /32,Clock Polarity 和 Clock Phase 分别选 Low 和 1 Edge,即 Mode 0。NSS 选 Disable,因为 CS 用 PA4 软件控制。First Bit 保持 MSB First。对应到 HAL 初始化代码就是下面这段:
hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; HAL_SPI_Init(&hspi1);这里 32 分频在 64MHz 主频下是 2MHz,刚好贴着 CS5530 的串口时钟上限。如果后续为了和别的器件共用 SPI 而把速率降下来,/64 即 1MHz 也完全能跑,低速只会让通信更稳,不会损失转换精度。
3.2 初始化、自校准与读取的三段代码
驱动比一般 SPI 器件多两步:写配置、自校准。先把底层字节操作写出来:
uint8_t cs5530_spi_byte(uint8_t val, uint8_t *rx) { HAL_SPI_TransmitReceive(&hspi1, &val, rx, 1, 10); return *rx; } void cs5530_write_cmd(uint8_t cmd) { uint8_t tmp; CS5530_CS_LOW(); cs5530_spi_byte(cmd, &tmp); CS5530_CS_HIGH(); } void cs5530_write_config(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) { uint8_t tmp; CS5530_CS_LOW(); cs5530_spi_byte(0x01, &tmp); // 写配置寄存器命令 cs5530_spi_byte(b0, &tmp); cs5530_spi_byte(b1, &tmp); cs5530_spi_byte(b2, &tmp); cs5530_spi_byte(b3, &tmp); CS5530_CS_HIGH(); }cs5530_spi_byte 用 HAL 的全双工接口,发送命令字节的同时把 SDO 上的值收回来。CS 必须覆盖完整的命令加数据过程,中间不能拉高,否则 CS5530 会认为操作被中断。写配置命令 0x01 之后必须送满 32 位,即使只改一个字段也要把四个字节补齐。
初始化函数负责上电延时、写配置和自校准:
int cs5530_init(void) { uint32_t timeout = 1000000; HAL_Delay(50); // 等待上电复位和晶振起振 cs5530_write_config(0x00, 0x00, 0x00, 0x00); // 默认配置 HAL_Delay(10); // 配置寄存器写入后留一点建立时间 cs5530_write_cmd(0x03); // 自校准 while (HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin) == GPIO_PIN_SET) { if (--timeout == 0) return -1; // 校准超时 } return 0; }自校准是 CS5530 必做的一步,它会用内部基准把失调和增益误差测出来并写到校准寄存器里。校准期间 DRDY 保持高,校准完成后拉低,所以等待 DRDY 变低是判断校准完成的可靠依据。超时不要设太短,低字速率下自校准耗时可能达到几百毫秒。
读取转换结果是一次 CS 低电平期间发 4 个字节:
int32_t cs5530_read_raw(void) { uint8_t tx[4] = {0, 0, 0, 0}; uint8_t rx[4]; CS5530_CS_LOW(); HAL_SPI_TransmitReceive(&hspi1, tx, rx, 4, 10); CS5530_CS_HIGH(); return ((int32_t)(int8_t)rx[1] << 16) | ((uint32_t)rx[2] << 8) | rx[3]; }第一个字节是 NOP,用来对齐芯片的移位状态,后面三个字节才是 24 位转换结果。rx[1] 是数据最高字节,必须先转成 int8_t 再左移,否则负数的符号位会被当成无符号数直接丢掉,负的传感器读数会变成很大的正值。转换结果是二进制补码,0x7FFFFF 对应正满量程减一个 LSB,0x800000 对应负满量程。
读结果时用 4 字节而不是 3 字节,是为了让芯片先收到一个完整的 NOP 命令,再在紧接着的 24 个 SCLK 里把数据移出来。有的驱动只用 3 字节也能工作,那是利用了 CS 拉低后 SDO 立即输出第一个数据位的特性,换个批次或温度可能就不一样,不推荐。
注意:读结果和写配置的整个操作必须在一个 CS 拉低周期里完成,CS 拉高就认为本次操作结束,时钟数多一秒都不行。
3.3 调用顺序与主循环的写法
主循环不要每转一圈就去读一次寄存器,CS5530 的转换完成由 DRDY 指示,DRDY 没拉低时读到的还是上一帧数据。连续转换模式下,芯片在读数结束、CS 拉高后自动开始下一次转换,所以主循环最稳的写法是先等 DRDY 变低,再执行读取,读取后继续做滤波、标定和对外通信,下一轮循环再等下一下降沿:
while (1) { while (HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin) == GPIO_PIN_SET) { } int32_t raw = cs5530_read_raw(); // 滤波、标定、对外输出 }DRDY 是转换完成握手信号,它从高变低说明新的 24 位数据已经锁存到输出寄存器。如果这一帧数据隔了很久才读,读到的仍然是当前帧,不会被覆盖,只是实时性变差。想用中断方式就把 PB1 配成外部中断下降沿触发,在中断服务函数里做读取并置标志位,主循环处理滤波和协议,这样即使高字速率下也不会漏帧。
4. CS5530 的校准流程与 5 个容易把人绕进去的坑
4.1 系统失调校准和系统增益校准什么时候用
自校准只消除芯片内部的失调和增益误差,不消除传感器和前端电路的误差。称重场景里传感器和放大器会引入零点偏移,这时用系统失调校准更合适:让称台保持空载,发 0x15 命令,芯片会以当前输入作为零点基准。做量程标定则发 0x17,在输入端加一个已知标准信号后再校准。
| 场景 | 命令 | 前置条件 |
|---|---|---|
| 芯片上电首次使用 | 0x03 自校准 | 配置寄存器已设定 |
| 传感器零点偏移 | 0x15 系统失调校准 | 称台空载、输入稳定 |
| 满量程标定 | 0x17 系统增益校准 | 输入加标准信号 |
顺序是先 0x15 后 0x17,改完增益或字速率后必须重新校准。校准命令和写配置命令一样,在 CS 拉低期间发一个字节,等 DRDY 拉低表示完成。校准期间输入要稳定,称重场景下不要在校准过程中碰传感器。
4.2 DRDY 判空与转换速率的匹配
CS5530 的字速率决定噪声水平,速率越低噪声越小。7.5SPS 档的峰峰值噪声最小,适合高精度平台秤;需要快速响应的分选秤可以提到 240SPS 以上,但无噪声位数会明显下降。DRDY 在高字速率下变低的时间窗口很短,轮询读数据时如果主循环有长阻塞,可能漏掉一次转换,数据不会丢但时间戳会跳。稳妥做法是 DRDY 接外部中断,读操作放到中断上下文或置位后立即执行。
4.3 五个常见坑和排查顺序
第一个坑是晶振。CS5530 没有内部时钟,晶振没起振时 DRDY 完全不动。用示波器量 XTAL1 引脚,10x 探头低输入电容档,能看到 4.096MHz 正弦波就说明时钟活着,看不到就先换晶振和负载电容。
第二个坑是 SPI 模式。CS5530 是 Mode 0,很多从别的 ADC 迁过来的人习惯性配成 Mode 3,命令发出去全部错位。先确认 CPOL 和 CPHA 两个选项,再查时钟频率,G070 上 32 分频是上限,别再往上加压。
第三个坑是读数据时钟个数。读转换结果的这个过程必须在一个 CS 低电平周期里完成,CS5530 对串口时钟是计数的,多发一个字节或少发一个字节都会导致数据错位。用 HAL_SPI_TransmitReceive 一次传 4 字节,不要拆成多次单字节传输。
第四个坑是输入共模电压。CS5530 的 AIN+、AIN- 差分输入各自对 AGND 有一个共模范围,差不多是 AGND+0.7V 到 VA+−0.7V。传感器电桥供电后,如果共模被拉出这个范围,转换结果会顶在满偏附近,像 0x7FFFFF 或 0x800000。
第五个坑是 5V 和 3.3V 的电平。VA+ 可以接 5V,VD+ 必须按逻辑电平接,SDO、SDI、SCLK 的电平参考 VD+。VD+ 接 5V 再连 G070 的 PA5/PA6/PA7,长时间工作会损坏 G070 的引脚。判断电平是否正常的办法很简单:量一下 CS5530 SDO 引脚在空闲时的高电平是不是接近 3.3V 而不是 5V。VA+ 5V、VD+ 3.3V 是最稳的组合。
5. 做完最小系统后:用峰峰值噪声验证 CS5530 的 24 位纯度
5.1 把输入短接,统计 100 个样本的峰峰值
驱动跑通后别急着标定,先验证板子的噪声水平。把 AIN+ 和 AIN- 用短跳线连到一起,让输入为零,采集 100 个样本,统计最大值和最小值的差:
int32_t min = 0x7FFFFFFF, max = -0x7FFFFFFF; int32_t raw; for (int i = 0; i < 100; i++) { while (HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin) == GPIO_PIN_SET) { } raw = cs5530_read_raw(); if (raw < min) min = raw; if (raw > max) max = raw; } int32_t pp_lsb = max - min;峰峰值 LSB 除以满量程就是无噪声分辨率。满量程是 ±VREF/增益,LSB 大小等于 2×VREF/(增益×2^24)。VREF=2.5V、增益=1 时每个 LSB 约 0.298µV。峰峰值 30 个 LSB,对应无噪声有效位数约 24−log2(30)≈19.1 位,这是比较健康的结果。
5.2 增益匹配和数字滤波的两个参数
CS5530 的增益不是随便选的。传感器输出幅度较小且共模在范围内时,用增益 64 可以降低对模拟放大的要求,但输入范围同时缩小到 ±39mV 左右。无噪声位数的增益收益有一个拐点,通常增益 32 或 64 的性价比最高,具体以你的传感器满量程输出为准。
数字滤波在 G070 上做一阶低通就够,系数取 1/16 时收敛较快,取 1/64 时更平滑:
static int32_t filtered = 0; filtered = filtered + ((raw - filtered) >> 4); // 1/16,约 0.4s 稳定称重场合采样率 7.5SPS 时,1/16 系数下阶跃响应大概 0.4s 到稳态,既能看清加载过程,又不会把振动噪声全放进来。如果现场振动明显,把右移 4 位改成右移 6 位。除了峰峰值,标准差也能反映噪声分布:采集 1000 个样本求标准差,用 6 倍标准差估计 99.7% 的置信区间。峰峰值对偶发毛刺更敏感,标准差更贴近长期稳定性,两个都跑一遍再下结论。
5.3 和 HX711 的边界在哪里
HX711 在便携秤里仍然合适,便宜、内置稳压、双线通信、PGA 到 128 倍。但需要系统级零点/增益校准、需要可编程字速率、需要和 PLC 或变送器做长距离稳定通信时,CS5530 的寄存器访问模型和 7.5SPS 低噪声档位更合适。两者都是 24 位,但 CS5530 的系统校准能抵消传感器和前端的大部分温漂,HX711 只能靠外部补偿。把短接输入端测峰峰值这段代码留在工程里,下一块板子回板后第一个跑的就是它。
本文还有配套的精品资源,点击获取