ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

高精度温度采集实战:GD32F30x驱动CS1237测量PT1000

高精度温度采集实战:GD32F30x驱动CS1237测量PT1000 先把我最近踩完的一个坑完整交代一遍。项目里要用 GD32F30x 采集 PT1000 铂电阻的温度一开始图省事直接用单片机自带的 12 位 ADC结果在 0°C 附近连 0.1°C 都分辨不出来整个系统测出来的温度像在坐电梯。后来换成 CS1237 这颗 24 位 Sigma-Delta ADC从硬件接线到软件读码再到把 ADC 原始码值换算成 PT1000 阻值、最后算出温度整条链路打通之后问题才算真正收尾。这篇文章就是完整复现这条链路GD32F30x 驱动 CS1237、比例法测电阻、IEC 60751 公式换算温度以及我在实际调试里碰到的一堆坑和排查方法。如果你正在做工业温度采集、暖通传感器、电池包热管理、电机保护这类需要“慢但准”的场景或者刚接触高精度 ADC、对数字滤波和传感器标定没什么头绪这篇文章应该能帮你少走不少弯路。文章里所有代码都基于 GD32 标准外设库拿过去改个引脚就能跑。1. 方案与测量原理1.1 为什么是“GD32F30x CS1237 PT1000”GD32F30x 是一颗 Cortex-M4 内核的国产 MCU主频、Flash、外设资源都不错价格也合适很多量产项目里都拿它当主控。但它内置 ADC 只有 12 位做一般的电压采集没问题做 PT1000 精密测温就有点勉强。PT1000 在 0°C 时的标称阻值是 1000Ω温度每升高 1°C阻值大约增加 3.85Ω。如果要求分辨率到 0.1°C那就得能分辨 0.385Ω 的阻值变化。用 12 位 ADC 配合一个 2.2kΩ 的分压电阻去测整个 -50°C 到 200°C 的温度范围内ADC 码值变化大约只有 700~900 个 LSB折合下来一个 LSB 对应 0.3°C 以上这还没算噪声。也就是说12 位 ADC 在这个场景里连“稳定显示 0.1°C”都做不到。CS1237 是芯海科技一颗 24 位 Sigma-Delta ADC内部带 PGA可以放大 1~128 倍接口非常精简只有一根时钟线和一根双向数据线成本也很低。它天生就是给称重传感器、电桥、精密电阻测量这类小信号高精度场景用的。配合 PT1000 本身信号幅度不算小PGA 设成 1 倍就够24 位分辨率能把这个测温方案的分辨率做到 0.001°C 级别剩下的问题主要是噪声和标定而不是 ADC 位数不够。1.2 比例法测量让结果不依赖 3.3V 精度测温电路我选的是最常见的串联分压结构3.3V 电源先经过一个精密电阻 Rref再经过 PT1000 到 GNDCS1237 的差分输入端 VIN 接两个电阻的中间节点VIN- 接 GND。REF 和 REF- 直接接 3.3V 和 GND不另做基准源。这里有个核心思路叫“比例测量”。ADC 输出码值本质上是输入电压和参考电压的比值raw / full VIN / VREF在这个电路里VIN VDD * R_pt1000 / (Rref R_pt1000) VREF VDD所以raw / full R_pt1000 / (Rref R_pt1000)你看VDD 在分子分母里同时出现最终约掉了。也就是说3.3V 电源纹波大一点、LDO 输出偏一点只要 VDD 和 VREF 是同一条电源轨测量结果几乎不受影响。这就是比例测量比“固定稳压源 固定参考电压”省心的原因也非常适合不追求极端精度但想省成本的嵌入式方案。如果你换一种接法比如用专门的恒流源给 PT1000 供电再用高精度基准芯片做参考电压那当然可以做得更准但电路成本、PCB 面积、调试工作量都会上来。对于大多数非计量级的工业测温场景比例法在“够用”和“简单”之间是最平衡的。1.3 先算一笔账Rref、分辨率与温度误差Rref 的选择直接影响测量范围和灵敏度。假设温度范围是 -50°C 到 200°CPT1000 阻值大概在 803Ω 到 1758Ω 之间。我选了 2.2kΩ 的精密电阻作为 Rref原因有三个在 -50°C 时中间节点电压约为 VDD 的 26.7%在 200°C 时中间节点电压约为 VDD 的 44.4%。输入信号不会超过 ADC 参考电压也不会接近满量程饱和。工作电流大约是 3.3V / (2.2k 1k) ≈ 1mAPT1000 自身的发热功率约 1mW自热效应可以接受。2.2kΩ 是 E96 系列里很容易买到的 0.1% 贴片电阻不需要定制。用 24 位 ADC 时正满量程码值是 0x7FFFFF也就是 8388607。温度从 -50°C 到 200°C码值变化大约从 0.267 × 8388607 ≈ 224 万到 0.444 × 8388607 ≈ 372 万跨度约 148 万个码。250°C 的温度跨度分了 148 万份理想分辨率远超 0.001°C。当然Sigma-Delta ADC 有噪声实际有效位数可能是 18~20 位但依然足够。Rref 的精度会直接转成温度误差。如果 Rref 是 ±0.1%在 0°C 附近大约产生 1000 × 0.1% 1Ω 的误差对应温度误差约 0.26°C。所以我建议用 0.1% 起步有条件就上 0.05% 或更高精度温度采集的最终精度上限很大程度取决于这颗电阻。2. 硬件接线2.1 元件清单整个实验需要的东西不多GD32F30x 最小系统板或者你自己的 GD32F30x 核心板CS1237 模块SOP-8 封装PT1000 铂电阻A 级或 B 级都可以A 级更好2.2kΩ 精密电阻0.1% 精度温漂越低越好4.7kΩ 上拉电阻用在 SDA 数据线上10μF 和 0.1μF 电容各几个做电源去耦3.3V LDO比如 AMS1117-3.3 或者更好的低噪声 LDO万用表或精密电阻箱用来标定和验证2.2 接线图与引脚对照我的接线方式如下表CS1237 引脚连接到VDD / AVDD / DVDD3.3V就近放 0.1μF 10μF 电容VSS / AVSS / DVSSGNDVINRref 与 PT1000 的中间节点VIN-GNDREF3.3VREF-GNDSCLKGD32F30x PB0SDA / DOUTGD32F30x PB1另接 4.7kΩ 上拉到 3.3V对应的串联分压电路可以画成这样3.3V ---- Rref(2.2kΩ) -------- PT1000 ---- GND | CS1237 VIN VIN- GND REF 3.3V REF- GND这里有一个容易忽略的点PT1000 和 Rref 的中间节点同时接在 VIN 上而 VIN- 接 GND所以 ADC 测量的是 PT1000 两端的电压。REF 和 REF- 直接接整个串联电路的电源两端这样 ADC 的参考电压就是整个串联回路的总电压。只要这两个电压来源于同一条电源轨比例关系就成立。如果你用的是集成好的 CS1237 模块很多模块已经把 REF、REF- 在 PCB 内部接好只引出 VCC、GND、SCK、DOUT 四个脚。这种模块一般默认用 3.3V 做参考我建议你确认一下模块原理图如果模块上根本没引出 REF 引脚那也说明它内部已经帮你处理了。2.3 电源、去耦与布板注意CS1237 是 Sigma-Delta ADC对电源噪声比普通 MCU 敏感。不要直接用一个 DCDC 输出的 3.3V 裸奔最好加一级 LDOLDO 后面放一个 10μF 钽电容或者陶瓷电容再在 CS1237 的 VDD 引脚旁边放一个 0.1μF 高频去耦电容。SCLK 和 SDA 两根线要尽量短不要和电机驱动、PWM 输出、WiFi 天线这些强干扰源平行走线。如果必须布长线SDA 上可以串一个 100Ω 电阻再接 4.7kΩ 上拉这样能有效抑制振铃和 RF 干扰。GD32F30x 和 CS1237 之间如果距离稍远建议把 SCLK 频率放慢一点代码里延时拉长到 2~5μs别追求极限速率。测温本来就不需要高吞吐稳定压倒一切。还有一点是关于 PT1000 的引线。如果 PT1000 和主板距离很近两线制没问题如果距离超过几米导线电阻就会叠加进测量结果铜导线在温度变化时电阻也会漂。这时候要么改三线制用两个 ADC 通道分别测量并程序补偿要么直接用四线制铂电阻。这个教程先按两线制讲长线场景后续可以单独展开。3. GD32F30x 驱动 CS12373.1 初始化 GPIO一个时钟线加一根双向数据线CS1237 的接口不是标准 SPI它只有 SCLK 和 SDA。SDA 是一根双向数据线写命令时由 MCU 驱动读数据时切换到输入模式由 CS1237 把数据推出来。GD32 的 GPIO 切换输入输出非常方便用标准外设库就是 gpio_init 重新配置模式。这里我把 SCLK 放在 PB0SDA 放在 PB1。#include gd32f30x.h #define CS1237_SCLK_PORT GPIOB #define CS1237_SCLK_PIN GPIO_PIN_0 #define CS1237_SDA_PORT GPIOB #define CS1237_SDA_PIN GPIO_PIN_1 #define CS1237_SCLK_HIGH() gpio_bit_set(CS1237_SCLK_PORT, CS1237_SCLK_PIN) #define CS1237_SCLK_LOW() gpio_bit_reset(CS1237_SCLK_PORT, CS1237_SCLK_PIN) #define CS1237_SDA_HIGH() gpio_bit_set(CS1237_SDA_PORT, CS1237_SDA_PIN) #define CS1237_SDA_LOW() gpio_bit_reset(CS1237_SDA_PORT, CS1237_SDA_PIN) #define CS1237_SDA_READ() gpio_input_bit_get(CS1237_SDA_PORT, CS1237_SDA_PIN) void CS1237_Init(void) { rcu_periph_clock_enable(RCU_GPIOB); gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0); gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); CS1237_SCLK_LOW(); CS1237_SDA_LOW(); }这里要注意一个细节CS1237 是按 SCLK 的边沿来计数的初始化时最好先把 SCLK 拉低避免上电瞬间 GPIO 抖动导致 CS1237 内部移位寄存器误收几个时钟。我吃过这个亏调试时第一帧数据总是不对后来发现是初始化顺序的问题。再写一个切换 SDA 方向的辅助函数static void CS1237_SDA_SetMode(uint8_t output) { if (output) { gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); CS1237_SDA_HIGH(); } else { gpio_init(GPIOB, GPIO_MODE_IN_PU, GPIO_OSPEED_50MHZ, GPIO_PIN_1); } }读数据时用输入模式带内部上拉配合外部 4.7kΩ 上拉可以保证在 CS1237 释放 SDA 的时候这根线不会悬空。3.2 写配置命令与读 24 位数据CS1237 上电后默认配置不一定是我们要的所以必须主动写一次命令字。CS1237 的命令字一共 26 位按位从高到低发送。我这里只关心两件事增益设成 1 倍、输出速率设成 10Hz。命令字位定义我按下面的理解用位含义本工程取值bit25RESET 复位控制0bit24掉电控制0bit23通道选择0bit22-20PGA 增益000 表示 1 倍000bit19-18输出速率00 表示 10Hz00bit17-16保留位00bit15-0本芯片无 CRC全部补 00所以实际发送的命令字就是0x00000000。如果你用的是带 CRC 校验的 CS1238那低位就要按 CRC 算法补齐CS1237 这个工程直接发 26 个低电平时钟即可。写命令的函数如下void CS1237_WriteCmd(uint32_t cmd) { uint8_t i; CS1237_SDA_SetMode(1); for (i 0; i 26; i) { CS1237_SCLK_LOW(); if (cmd 0x02000000) { CS1237_SDA_HIGH(); } else { CS1237_SDA_LOW(); } CS1237_SCLK_HIGH(); cmd 1; } CS1237_SCLK_LOW(); CS1237_SDA_HIGH(); }读数据函数是本驱动的核心。CS1237 转换完成后会把 SDA 拉低表示数据准备好了。这时候 MCU 把 SDA 切成输入然后给出 24 个 SCLK 脉冲在每个脉冲读取一位MSB 在前。读完 24 位之后再补 1 个 SCLK 脉冲让 ADC 开始下一轮转换。int32_t CS1237_ReadRaw(void) { int32_t raw 0; uint8_t i; CS1237_SDA_SetMode(0); // 等待 CS1237 把 SDA 拉低表示转换完成 for (i 0; i 200; i) { if (CS1237_SDA_READ() 0) { break; } delay_1ms(1); } if (i 200) { return 0x7FFFFFFF; // 超时 } // 读取 24 位数据MSB 在前 for (i 0; i 24; i) { CS1237_SCLK_HIGH(); delay_us(2); raw 1; if (CS1237_SDA_READ()) { raw | 1; } CS1237_SCLK_LOW(); delay_us(2); } // 补一个时钟触发下一轮转换 CS1237_SCLK_HIGH(); delay_us(2); CS1237_SCLK_LOW(); raw 8; raw 8; // 24 位数据做符号扩展得到 int32_t return raw; }函数返回的是 int32_t不是 uint32_t。因为 CS1237 输出是二进制补码正输入时最高位是 0负输入时最高位是 1。做一次左移 8 位、再算术右移 8 位就能把 24 位补码正确扩展成 32 位有符号数。如果你的板子和我用的时序正好反过来读出来总是乱码可以把采样点从上升沿改成下降沿试试。也就是先采样再拉升 SCLK或者把读 SDA 的位置移到 SCLK 变低之后。这是个很常见的兼容性问题不同批次模块上可能表现不一样。3.3 数字滤波去极值滑动平均CS1237 在 10Hz 输出速率下单独看每一帧数据还是会有少量抖动尤其当电源不干净或者 PCB 布局不好的时候。温度信号本身变化慢完全可以用滤波把它磨平。我用的滤波方式是“去极值滑动平均”先连续采 N 个点丢掉一个最大值和一个最小值剩下 N-2 个点取平均。这样既能滤掉随机噪声又能干掉偶发的异常毛刺。int32_t CS1237_ReadFiltered(uint8_t times) { int32_t sum 0; int32_t min 0x7FFFFFFF; int32_t max -0x7FFFFFFF; int32_t v; uint8_t i; if (times 3) { times 3; } for (i 0; i times; i) { v CS1237_ReadRaw(); if (v 0x7FFFFFFF) { i--; continue; } sum v; if (v min) min v; if (v max) max v; } return (sum - min - max) / (times - 2); }注意if (v 0x7FFFFFFF)这种超时判断不能丢尤其是上电初期CS1237 可能需要几百毫秒才输出第一帧有效数据。如果连续超时直接死等会卡住主循环。采样次数 times 我一般取 8。10Hz 输出速率下采 8 个点大约需要 0.7~0.8 秒响应速度对温度控制来说够用。如果你希望响应更快可以把命令字里的速率改成 30Hz 或 60Hz但噪声会略微变大times 可以适当减少。3.4 采样节奏控制调用时机也是有讲究的。CS1237 配置成 10Hz 后每 100ms 出一帧数据。如果你在 while(1) 里疯狂调用 ReadRaw函数里等待 SDA 拉低的部分会主动阻塞到下一帧数据准备好所以不会重复读到旧数据。初始化完成后代码流程可以这样写int main(void) { int32_t raw; float res; float temp; systick_config(); CS1237_Init(); CS1237_WriteCmd(0x00000000); // PGA 1输出速率 10Hz delay_1ms(200); // 等第一帧转换完成 while (1) { raw CS1237_ReadFiltered(8); if (raw 0x7FFFFFFF) { printf(CS1237 read timeout\r\n); continue; } res CS1237_RawToResistance(raw); temp PT1000_ResistanceToTemp(res); printf(raw%d, R%.2f Ohm, T%.2f C\r\n, raw, res, temp); } }CS1237_WriteCmd 只需要在初始化时发送一次。除非你需要切换增益或速率否则不要每帧都发命令否则会打乱它内部的转换节奏。读码函数末尾补的那个 SCLK 已经通知芯片开始下一轮转换了。4. 从 ADC 码到阻值再到温度4.1 阻值换算公式前面推导过比例关系raw / full R_pt1000 / (Rref R_pt1000)其中full 0x7FFFFF 8388607这是因为 CS1237 是带符号的 24 位 ADC正满量程是 8388607。解方程得到R_pt1000 Rref * raw / (full - raw)这段代码很直接#define CS1237_FULL_SCALE 8388607.0f #define RREF 2200.0f float CS1237_RawToResistance(int32_t raw) { float r; if (raw 0) { raw 0; // 输入接反或异常 } r RREF * (float)raw / (CS1237_FULL_SCALE - (float)raw); return r; }如果 raw 变成负数大概率是 VIN 和 VIN- 接反了或者 RTD 两端虚焊导致输入悬空先不要急着改算法去查硬件。raw 接近 0 说明 PT1000 阻值接近 0可能是短路。raw 接近满量程说明 R_pt1000 非常大常见原因就是 PT1000 断路公式里分母接近 0计算结果会爆炸成天文数字正好可以作为断线故障的判断条件。4.2 PT1000 的阻值—温度关系PT1000 的阻值随温度变化不是完全线性的工业上最常用的标准是 IEC 60751。0°C 以上用二次多项式就能描述R(T) R0 * (1 A*T B*T^2)0°C 以下需要再加上一个三次修正项R(T) R0 * (1 A*T B*T^2 C*(T-100)*T^3)其中对于 PT1000R0 1000ΩA 3.9083e-3B -5.775e-7C -4.183e-12几个关键温度点的标准阻值如下表可以用来验证你的程序算得对不对温度PT1000 标准阻值-50°C803.06Ω0°C1000.00Ω25°C1097.35Ω50°C1193.97Ω100°C1385.06Ω150°C1573.25Ω200°C1758.56Ω网上也有很多人用简化线性公式也就是认为每 1°C 对应 3.85Ω。这个公式在 0°C 附近误差不大但到了 200°C 误差可能到 2~3°C。所以我建议要么用上面的 IEC 60751 多项式要么做一个查找表加线性插值。查找表适合 Flash 充足、想避开浮点运算的场景多项式适合代码简单、追求连续输出的场景。4.3 C 语言温度求解代码从阻值反算温度0°C 以上可以直接解二次方程。方程是B * T^2 A * T (1 - R/R0) 0求根公式取正根T (-A sqrt(A^2 - 4*B*(1 - R/R0))) / (2*B)0°C 以下因为有三次项没法直接求解析解我用牛顿迭代法迭代十几次就能收敛到 0.001°C。完整代码如下#include math.h float PT1000_ResistanceToTemp(float r) { const float R0 1000.0f; const float A 3.9083e-3f; const float B -5.775e-7f; const float C -4.183e-12f; float t; float disc; if (r R0) { // 0°C 及以上二次方程求解 disc A*A - 4.0f * B * (1.0f - r / R0); if (disc 0.0f) { disc 0.0f; } t (-A sqrtf(disc)) / (2.0f * B); } else { // 0°C 以下牛顿迭代 t -100.0f; // 初始猜测值 for (int i 0; i 20; i) { float rt R0 * (1.0f A*t B*t*t C * (t - 100.0f) * t*t*t); float dRdT R0 * (A 2.0f * B*t C * (4.0f*t*t*t - 300.0f*t*t)); float delta (rt - r) / dRdT; t - delta; if (fabsf(delta) 0.0001f) { break; } } } return t; }如果你不太想维护浮点迭代也可以把 -50°C 到 200°C、每 1°C 的阻值表提前烧进 Flash运行时用二分查找加线性插值。精度取决于表的密度1°C 步进的表插值误差可以控制在 0.05°C 以内。这个表可以用一段小脚本生成把常数代入公式逐点打印即可。4.4 标定与误差控制即使程序换算公式完全正确硬件误差依然会进到最终温度里。主要的误差来源有三个。第一个是 Rref 的精度和温漂。前面算过0.1% 的 Rref 就能带来大约 0.26°C 的温度误差所以 Rref 必须用好电阻。如果项目允许我会在出厂前做一次软件标定用 0.01% 的精密电阻替换 PT1000比如放一个 1000Ω 和一个 1400Ω 的标准电阻记录 ADC 原始码然后反推出实际 Rref 值把软件里的 RREF 常量修正掉。第二个是导线电阻。两线制下PT1000 两端的引线电阻会直接加在测量值里。0.5m 的普通连接线可能带来 0.1Ω 左右的误差对应 0.03°C 左右短距离可以忽略长距离就得改三线制。第三个是自热效应。1mA 电流流过 PT1000在 0°C 时大约产生 1mW 功率。在空气中这个自热可能造成 0.1~0.4°C 的偏高如果传感器埋在导热良好的介质里影响会小很多。想要进一步压低自热可以增大 Rref 到 4.7kΩ让工作电流降到 0.6mA 左右代价是分辨率略微下降但 24 位 ADC 完全扛得住。5. 调试踩坑与实测记录5.1 读数为 0、满量程、乱跳的处理我调试过程中最常见的故障现象就三种读码永远是 0、读码接近满量程、读码上下乱跳。对应的排查思路也基本固定整理成表现象可能原因处理措施raw 始终为 0 或很小VIN 与 VIN- 之间短路PT1000 短路虚焊用万用表测 VIN 电压应该接近 GNDraw 接近满量程或异常大PT1000 开路或 VIN 悬空或 Rref 断路测中间节点电压开路时接近 3.3V等待 SDA 拉低超时CS1237 没供电、SCLK 极性不对、模块损坏查 VDD 电压查 SCLK 是否正常翻转raw 乱跳电源噪声、SDA 上拉缺失、采样边沿不对加 LDO、加 4.7kΩ 上拉、换采样边沿数据稳定但整体偏大导线电阻、Rref 偏大、自热软件标定 Rref或改用三线制还有一个特别容易踩的点CS1237 的 SDA 是双向引脚不是普通 SPI 的 DOUT。如果你把它当成只读引脚一直配成输入模式写命令的时候数据根本进不去芯片就会一直保持默认配置读数不可能对。我建议调试时先用示波器抓 SDA写命令阶段能看到 MCU 拉出来的波形读数据阶段能看到 CS1237 主动推出来的波形一眼就能判断驱动方向切换对不对。5.2 温度不准的排查如果 ADC 读数稳定换算出来的阻值也和万用表测到的 PT1000 阻值对得上但最终温度不对那问题基本出在阻值到温度这一步。先用 0°C 验证。把 PT1000 放到冰水混合物里程序应该算出约 1000Ω、温度 0°C。如果显示 1°C 以上优先怀疑自热断电后用万用表单独测阻值应该接近 1000Ω。再用 100°C 验证。把 PT1000 放到沸水里程序应该算出约 1385Ω、温度 100°C。如果这里偏差大检查你的公式是用的 PT100 常数还是 PT1000 常数很多人把 R0 写成 100 就全偏了。如果高低点都偏同一个固定值比如都偏 0.5Ω那是导线电阻或者接触电阻软件里减一个固定偏移即可。如果偏移随温度变化那基本是 Rref 实际值和理论值不一致用标准电阻箱做两点修正。5.3 实测数据对比我在调试时用精密电阻箱模拟 PT1000 的阻值再把程序和万用表读数做了一组对比。实测下来是这样的电阻箱设定值程序计算阻值程序计算温度1000.0Ω1000.3Ω0.08°C1097.4Ω1097.7Ω25.10°C1194.0Ω1193.7Ω49.90°C1385.1Ω1386.2Ω100.30°C偏差主要来自 Rref 的 0.1% 误差和读数噪声没有做软件标定之前能到这个水平我认为这套方案已经非常可用了。如果你把 Rref 也换成 0.05% 以下的电阻再在软件里做一次零点和增益校准整体做到 ±0.15°C 不是问题。5.4 几个容易被忽略的细节最后分享几个我在项目里总结出来的小经验。第一调试阶段一定要先把原始 ADC 码值通过串口打出来不要上来就直接看温度。原始码值能帮你区分是硬件问题还是换算问题。比如换算公式写错时原始码可能是对的但你看到的温度全错。第二CS1237 的 SCLK 和 SDA 在 GD32 上占用普通 GPIO 就行不需要映射到 SPI 外设。GPIO 翻转速度足够而且软件模拟时序在调试时更容易看清每一步。第三CS1237 是慢速高精度 ADC别拿它做高速采样。10Hz 输出速率加上 8 次滤波一帧有效数据要 0.8 秒。如果你的系统需要更快的温度响应可以把速率调到 30Hz 或者 60Hz但滤波次数和噪声要重新平衡。第四给 CS1237 供电的 LDO 尽量选低噪声的别用那种开关电源的 3.3V 直供。比例测量虽然能抵消 VDD 的慢漂移但对 VDD 上的高频噪声没有免疫力这部分噪声会直接进到 ADC 参考电压和输入电压里。第五如果你以后要量产建议把 Rref 的选型和焊接管控写进工艺文件。这颗电阻的温漂系数比容差更关键普通的 0805 贴片电阻温度系数可能有 100ppm/°C而 25ppm/°C 的精密电阻也好找价格差不了多少但对最终温飘影响很大。这套“GD32F30x CS1237 PT1000”方案做下来整体成本很低电路简单精度和稳定性却比我预想的好很多。如果你只是需要做一个高精度的单点温度采集不需要触摸、显示这些外设这个组合完全可以直接搬进产品里。后续如果要做多通道测温可以考虑多片 CS1237 挂在不同 GPIO 上或者换带多通道输入的 CS1238软件架构基本不用大改。
返回列表