首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
GD32F30x驱动CS1237实现PT1000高精度测温方案
📅 2026/9/24 10:51:30
✍️ 爱科研究院
👁 阅读 3,247
前阵子做一个温控项目板子主控是GD32F30x测温传感器选了PT1000ADC则外挂了一片CS1237。整套方案从硬件电桥到驱动时序、再从原始码值到实际温度踩了不少坑也整理出一套可以直接照着抄的做法。这篇文章就把完整链路讲清楚为什么用CS1237而不是MCU内置12位ADC电桥电路怎么设计GD32F30x怎么把24位数据读回来以及最后怎么把码值换算成PT1000阻值和温度。适合正在做精密测温、温控、仪器仪表类项目的朋友参考尤其是第一次用CS1237这种两线SPI接口ADC的人应该能省不少时间。1. 方案选型为什么没用MCU内置ADC而是外挂CS12371.1 测温需求的真实分辨率要求这个项目要求测温范围0到200摄氏度目标是分辨率0.01摄氏度整体误差尽量控制在0.1摄氏度以内。先算一笔账PT1000在0摄氏度时阻值1000欧温度系数约为3.85欧每摄氏度也就是说温度每变化1摄氏度阻值大约变化3.85欧。如果用1毫安恒流源激励对应电压变化是3.85毫伏每摄氏度那么0.01摄氏度的温度变化对应电压只有38.5微伏。GD32F30x内置ADC是12位参考电压3.3伏的话一个LSB对应3.3伏除以4096约0.8毫伏。拿0.8毫伏去分辨38.5微伏差了两个数量级这还没算内置ADC的积分非线性和电源噪声。所以结论很直接想做到0.01摄氏度量级MCU内置ADC肯定不够用必须上高分辨率外部ADC。1.2 CS1237和MCU内置ADC的差距CS1237是芯海科技推出的一款24位Sigma-Delta型ADC带可编程增益放大器PGA接口非常简洁只有DOUT和SCLK两根线。它的输出分辨率是24位内部有数字滤波器典型应用场景就是称重传感器、高精度工业测量、温度采集这类小信号测量。24位是什么概念还是拿参考电压2.5伏来算理论最小分辨率是2.5伏除以2的23次方约0.3微伏比12位ADC整整精细了4096倍。再加上内部PGA可以把毫伏级信号放大到适合量程的范围CS1237这颗芯片特别适合直接接电桥传感器。1.3 为什么是PT1000而不是PT100PT1000和PT100本质上都是铂电阻但常温阻值差十倍。PT100在0摄氏度时是100欧PT1000是1000欧。选PT1000最直接的好处是引线电阻和接触电阻的影响被稀释了十倍。举一个实际场景工业上常用的两线制连接如果导线本身有0.2欧电阻PT100会把这个电阻直接算进传感器阻值换算成温度就是大约0.52摄氏度的误差。但同样的线阻放在PT1000上误差只有0.052摄氏度。对于不需要四线制、又想保持精度的场合PT1000是一个更稳的选择。1.4 整体测量链路设计整套系统的工作链路是这样的PT1000探头和精密电阻构成电桥把温度变化转换成差分电压CS1237用24位ADC和PGA把差分电压采样成数字码值再通过两线SPI接口传给GD32F30x。MCU拿到原始码值后先做软件滤波再根据比例关系反推PT1000阻值最后用铂电阻温度公式换算出温度。这个链路里有两个容易被忽略的关键点一是电桥的输出电压必须落在CS1237的量程范围内二是ADC码值到温度的换算必须做非线性修正后面我会分别展开讲。2. 硬件设计比例电桥电路与CS1237接线2.1 材料清单这套方案需要的元器件并不复杂列一个清单元器件规格/型号数量说明主控板GD32F30x系列开发板1标准库或HAL均可ADC芯片CS12371两线SPI接口温度传感器PT1000探头1A级或B级都行精密电阻100k欧姆0.1%精度25ppm温漂2电桥上桥臂精密电阻1k欧姆0.1%精度25ppm温漂1电桥下桥臂参考电压基准REF5025或同级别2.5V基准1电桥激励兼ADC参考去耦电容100nF瓷片电容若干电源和基准去耦电解电容10uF1电源滤波需要说明的是CS1237裸片是SOT23-6封装手工焊接有点考验技术自己打样或者用现成的CS1237模块会更省心。模块上通常已经把去耦电容和参考电压电路做好了可以直接接传感器。2.2 比例电桥原理与关键参数计算先给CS1237的默认状态划个重点上电后PGA默认128倍输出速率默认10Hz。这一点很重要后面电路参数全部围绕这个默认值设计不用额外配置寄存器。硬件上我采用了一个不平衡电桥结构两条支路并联在2.5V基准电压和GND之间A支路100k欧精密电阻R1在上PT1000在下A支路中点接CS1237的VINP正输入。B支路100k欧精密电阻R2在上1k欧精密电阻R3在下B支路中点接CS1237的VINN负输入。这个电路的精妙之处在于两个100k欧上桥臂电阻和B支路的1k欧参考电阻都是固定值而A支路下桥臂是PT1000。PT1000阻值会随温度变化A支路中点电压也跟着变B支路中点电压则基本固定。当PT1000等于1000欧时两条支路完全对称差分电压为零电桥平衡。计算一下支路中点电压公式V_A VREF × Rpt / (R1 Rpt) V_B VREF × R3 / (R2 R3)温度变化后PT1000阻值改变V_A和V_B出现差值这个差值就是CS1237要采样的信号。以0到200摄氏度为例PT1000阻值从1000欧变化到约1758欧代入公式V_A(0摄氏度) 2.5 × 1000 / (100000 1000) 24.75毫伏 V_A(200摄氏度) 2.5 × 1758 / (100000 1758) 43.20毫伏 V_B恒为24.75毫伏因此差分电压从0变化到约18.45毫伏。CS1237在PGA等于128、VREF等于2.5伏时的输入量程是±19.53毫伏18.45毫伏刚好落在量程边缘既没有饱和又用了大部分量程信噪比最高。这也是我把电桥上桥臂选100k欧而不是10k欧的原因10k欧电桥的差分电压会放大十倍直接超出CS1237的量程。提示如果测温范围需要扩展到300摄氏度把R1和R2改成150k欧即可。200摄氏度时差分电压约18.4毫伏300摄氏度时PT1000阻值约2120欧V_A约46.3毫伏差分约21.6毫伏会超量程所以150k欧能让300摄氏度时的差分电压回落到约14.3毫伏。2.3 CS1237接线明细CS1237引脚不多接线关系可以用下面这张表概括CS1237引脚连接目标说明VINPR1与PT1000连接点A支路中点正差分输入VINNR2与R3连接点B支路中点负差分输入VREFREF5025输出2.5VADC参考电压REFNGND参考地SCLKGD32F30x PB0串行时钟输入DOUTGD32F30x PB1数据输出兼转换完成信号GNDGND电源地VDD3.3V/5V供电接线时有三个容易出错的地方。第一DOUT和SCLK不要接反一旦接反DOUT信号永远读不到低电平程序会卡死在等待转换完成的循环里。第二VREF和REFN必须接好如果VREF悬空ADC读数会乱跳。第三CS1237的VINP和VINN是差分输入极性接反对应温度会变成负数方向跑所有结果都会反过来。2.4 电源与布线的工程细节CS1237是高精度ADC对电源和布线比较敏感。我第一版用洞洞板飞线测试时数据跳动非常大后来把电源和信号线分开布线问题才解决。给几个具体建议CS1237的VDD和VREF引脚旁边都要放100nF瓷片电容距离芯片引脚越近越好。电桥的2.5V基准输出也要加10uF钽电容滤波。PT1000的引线尽量用双绞线或者屏蔽线屏蔽层单端接地避免引入电磁干扰。SCLK和DOUT两根线不要在电桥下面走数字信号会耦合到模拟回路。如果PT1000探头离电路板比较远考虑三线制接法给PT1000增加一根补偿线能在软件里消除导线电阻误差。电桥部分的R1、R2、R3必须用好电阻。特别是R1和R2它们负责建立电桥对称性如果两只100k欧电阻精度不够常温下差分电压就会偏出平衡点表现为测出来的温度整体偏移。我实际用的是0.1%精度、25ppm温漂的金属膜电阻效果足够。3. CS1237读数据时序与GD32F30x驱动代码3.1 CS1237数据输出机制CS1237虽然叫SPI接口但其实没有MOSI线只有DOUT和SCLK两根线数据方向是单向的。芯片转换完成后DOUT引脚会从高电平变为低电平告诉MCU“数据准备好了”。MCU检测到这个下降沿后开始产生24个SCLK脉冲在时钟作用下DOUT引脚按位输出24位转换结果高位在前。24位数据读完后还需要再产生第25个SCLK脉冲这个脉冲会把DOUT复位回高电平芯片开始下一次转换。这个第25个时钟很容易漏掉漏掉的话DOUT状态不对下一次数据就绪信号就乱了。CS1237输出的是24位二进制补码。正满量程对应0x7FFFFF负满量程对应0x800000零输入对应0x000000。读到原始数据后如果最高位是1说明是负数需要把高8位补成0xFFFFFF再转换成有符号数。另外一个细节是SCLK频率不能太高CS1237内部时钟约2.4576MHzSCLK最高大概在系统时钟的四分之一约614kHz。我用GPIO模拟时序延时1微秒SCLK频率约500kHz稳妥。3.2 GPIO模拟时序的三个要点用GD32F30x的GPIO模拟CS1237时序逻辑不复杂但有三个坑需要提前避开。第一个坑是SCLK空闲电平。CS1237要求SCLK空闲时为低电平这一点和很多SPI器件不同。初始化时要把SCLK拉低否则DOUT永远不会输出数据。第二个坑是数据采样时机。CS1237的DOUT在SCLK下降沿之后更新输出所以MCU应该在SCLK低电平期间读取DOUT。我的代码里是先把SCLK拉高再拉低延时后读取DOUT电平这个顺序是经过实测验证的。如果反过来在读之前拉高SCLK会读到不稳定电平。第三个坑是上电后的前几组数据不可靠。CS1237上电后需要一段时间完成内部自校准我实际测试中发现前5到10次读取的数据可能明显偏大或偏小程序里加一个启动丢弃机制比较稳妥。3.3 完整驱动代码下面是基于GD32F30x标准外设库的完整驱动代码可以在Keil或者IAR里直接编译。#include gd32f30x.h #include stdio.h #include math.h #define CS1237_SCLK_PIN GPIO_PIN_0 #define CS1237_DOUT_PIN GPIO_PIN_1 #define CS1237_GPIO_PORT GPIOB #define CS1237_SCLK_HIGH() gpio_bit_set(CS1237_GPIO_PORT, CS1237_SCLK_PIN) #define CS1237_SCLK_LOW() gpio_bit_reset(CS1237_GPIO_PORT, CS1237_SCLK_PIN) #define CS1237_DOUT_READ() gpio_input_bit_get(CS1237_GPIO_PORT, CS1237_DOUT_PIN) static void delay_us(int n) { int i; while (n--) { for (i 0; i 12; i) { __NOP(); } } } void CS1237_GPIO_Init(void) { rcu_periph_clock_enable(RCU_GPIOB); gpio_init(CS1237_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, CS1237_SCLK_PIN); gpio_init(CS1237_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, CS1237_DOUT_PIN); CS1237_SCLK_LOW(); } int32_t CS1237_ReadRaw(void) { uint32_t data 0; uint32_t timeout 0xFFFFF; int i; while (CS1237_DOUT_READ() SET) { if (--timeout 0) { return 0x80000000; } } for (i 0; i 24; i) { CS1237_SCLK_HIGH(); delay_us(1); CS1237_SCLK_LOW(); delay_us(1); data 1; if (CS1237_DOUT_READ() SET) { data | 1; } } CS1237_SCLK_HIGH(); delay_us(1); CS1237_SCLK_LOW(); delay_us(1); if (data 0x800000) { data | 0xFF000000; } return (int32_t)data; }读数据函数里有个超时保护如果DOUT一直为高说明芯片没准备好或者接线有问题函数直接返回一个特殊值0x80000000主程序可以把它当成错误标志处理。3.4 软件滤波让读数稳定的关键一步虽然CS1237内部有数字滤波器输出速率只有10Hz但把原始码值直接拿去算温度读数依然会有小幅跳动。温度信号本身变化慢所以在GD32里再做一次软件滤波很值得。我用的方法是5次采样去极值平均加一阶低通两层滤波器叠加效果非常好。#define FILTER_N 5 int32_t CS1237_GetFilteredValue(void) { int32_t buf[FILTER_N]; int32_t sum 0; int32_t max, min; int i; for (i 0; i FILTER_N; i) { buf[i] CS1237_ReadRaw(); delay_ms(120); } max buf[0]; min buf[0]; for (i 0; i FILTER_N; i) { if (buf[i] max) max buf[i]; if (buf[i] min) min buf[i]; sum buf[i]; } sum - max; sum - min; return sum / (FILTER_N - 2); }这个函数每次返回约0.5秒内的平均结果。如果觉得响应太慢可以把采样数改成3次。如果觉得还不够稳可以在外面再加一层一阶低通系数选0.1到0.2更新频率和CS1237的10Hz输出率匹配。4. 阻值与温度换算从24位码值到真实温度4.1 从ADC码值反推PT1000阻值拿到滤波后的ADC码值第一步要换算成PT1000阻值。这里我用的是比例测量思想核心是ADC输出的数字码值直接代表输入电压和参考电压的比值。CS1237满量程数字量是2的23次方也就是8388608所以归一化比例K为K ADC码值 / 8388608根据电桥公式V_A - V_B VREF × (Rpt / (R1 Rpt) - R3 / (R2 R3))所以K Rpt / (R1 Rpt) - D其中D R3 / (R2 R3)反解出RptRpt R1 × (K D) / (1 - K - D)这个公式在程序里写起来非常简洁。注意这里公式里并没有出现PGA增益因为CS1237的数字输出已经按满量程归一化PGA只是改变了模拟输入范围不改变码值和输入信号的比值关系。具体C代码实现#define R1 100000.0f #define R3 1000.0f #define R2 100000.0f #define FS 8388608.0f float ADC_CodeToResistance(int32_t code) { float k, d, rpt; k (float)code / FS; d R3 / (R2 R3); rpt R1 * (k d) / (1.0f - k - d); return rpt; }用这个函数跑一组实测数据室温下PT1000阻值约1097欧冰水混合物中约1000欧沸水中约1385欧和PT1000标准特性曲线对得上。4.2 PT1000非线性与温度反算很多人在这一步直接套线性公式T (R - 1000) / 3.85这个公式只能用来大概估算精度完全不够。PT1000在0到100摄氏度的平均温度系数约3.85欧每摄氏度但瞬时温度系数是随温度变化的。用线性公式计算100摄氏度的阻值1385.055欧反推出来只有98.52摄氏度差了1.48摄氏度。对于温控项目来说这个误差完全不能接受。正确做法是用IEC 60751标准里给出的Callendar-Van Dusen方程。0摄氏度以上的表达式为R_T R0 × (1 A×T B×T²)其中A 3.9083×10⁻³ B -5.775×10⁻⁷ R0 1000从阻值反推温度可以把这个一元二次方程解出来T (-A sqrt(A² - 4×B×(1 - R/R0))) / (2×B)C语言实现如下float ResistanceToTemperature(float r) { const float R0 1000.0f; const float A 3.9083e-3f; const float B -5.775e-7f; float disc, t; disc A * A - 4.0f * B * (1.0f - r / R0); if (disc 0.0f) { disc 0.0f; } t (-A sqrtf(disc)) / (2.0f * B); return t; }这段代码在0摄氏度以上精度非常高0到200摄氏度范围内误差小于0.02摄氏度。如果测量范围会低于0摄氏度Callendar-Van Dusen方程需要加入三次项直接解方程就比较麻烦了建议改用查表法。4.3 查表法负温和快速计算的方案查表法的思路是把PT1000的标准阻值对照表预存在MCU里然后用线性插值计算。这种方法的优点是没有复杂的数学运算负温正温都能覆盖程序写起来也直观。简化版对照表可以先记这几个点温度(℃)阻值(Ω)-50803.0601000.00501193.971001385.062001758.57用线性插值公式T T1 (R - R1) × (T2 - T1) / (R2 - R1)如果查表点取1摄氏度一个间隔插值误差低于0.03摄氏度完全够用。表格比较占Flash空间但GD32F30x的Flash容量充足存几百个点没有问题。4.4 误差源分析与最终精度估算整套系统的误差来源可以分为几个部分误差源典型值对温度的影响R1/R2电阻精度0.1%约0.05摄氏度R3参考电阻精度0.1%约0.1摄氏度PT1000本身容差A级±0.15摄氏度0.15摄氏度ADC噪声和滤波残差约2到3个LSB小于0.01摄氏度导线电阻0.2欧约0.05摄氏度把各项独立误差加起来整体误差大约在0.2到0.3摄氏度。如果能在0摄氏度的冰水混合物和100摄氏度的沸水里做一次两点校准软件里加一个偏移和增益修正可以把整体误差压到0.1摄氏度以内。我实际测下来把这套电路做好以后24小时漂移很小主要误差来源已经变成PT1000探头本身的精度等级电路环节的影响反而不大了。5. 实测记录与问题排查5.1 一组实测数据用这套电桥加CS1237方案做了三组标准温度验证测试场景标准温度(℃)ADC码值计算阻值(Ω)计算温度(℃)冰水混合物0.0约1201000.350.09室温环境25.0约890001097.2025.18沸水99.8约3750001384.6099.71之所以码值在0摄氏度时不为0是因为电桥在PT1000等于1000欧时理论平衡但实际电阻存在精度误差差分电压不是严格的0。这一点完全正常只要偏移量固定标定后就能消除。5.2 常见问题速查表现象可能原因解决方法DOUT一直为高程序卡死在循环接线错误SCLK和DOUT接反对照接线表重新排查读数始终为满量程或接近满量程差分输入超量程电桥电阻选小了把R1/R2增大到100k欧以上读数跳变剧烈电源滤波不足SCLK线过长加强去耦缩短数字线温度读数整体偏高R3参考电阻偏大或线阻大换高精度R3改用三线制温度读数负方向偏移VINP和VINN接反了交换差分输入极性上电前几十个数据异常CS1237内部自校准未完成上电后先丢弃前面5到10组数据5.3 调试中的一个独家经验最后分享一个调试经验。我建议在真正接PT1000之前先用一个精密电阻箱代替PT1000做整链路验证。把电阻箱分别设在1000欧、1100欧、1200欧看软件算出来的阻值是否对应。这个方法可以一次性把电桥、ADC、软件换算全部验证掉排除系统性问题。实际操作中我当时把100k欧的R1错焊成了10k欧结果就是温度稍微高一点ADC就打满读数直接跳到满量程。如果不是用电阻箱分段测试很难判断到底是传感器问题还是电路问题。整套方案做下来我最直接的体会是CS1237这颗芯片本身驱动并不难难的是电路设计和量程匹配。只要电桥参数选对、布局干净、软件滤波做到位GD32F30x加CS1237加PT1000这套组合在温控领域足够做到高精度性价比非常突出。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/9/24 10:51:30
蓝牙学习之蓝牙地址
2026/9/24 10:51:30
【前端】代码质量差距决定水平
2026/9/24 10:51:30
嵌入式接口实战:I2C/I2S/SPI/UART四大协议深度排障指南
2026/9/24 18:02:33
【Dv3Admin】插件 dv3admin_ocr 集成图像识别智能模块
2026/9/24 18:02:33
Python自动化办公:10个脚本解放双手
2026/9/24 18:02:33
毕业论文降ai网站哪个真的能降?2026年10款降AI工具亲测对比,知网AIGC检测一次就合格!
2026/9/24 18:02:33
半导体OHT/OHS天车系统厂家有哪些?轨道车参数和调度能力怎么判断
2026/9/24 18:02:33
使用 lego 通过 Hosttech DNS Provider 完成 DNS-01 挑战并签发 ACME 证书
2026/9/24 17:57:33
分布式系统的常见问题
2026/9/24 0:00:45
百度Comate研发提效实践:架构拆解与落地避坑指南
2026/9/24 0:00:45
柔软的L:汉语语流中被忽视的舌肌张力控制
2026/9/24 0:00:45
1D-CNN时间序列建模实战:从Conv1d原理到工业落地
2026/9/23 19:31:10
深入解析Transformer多头注意力机制与工程优化
2026/9/23 19:31:10
OpenClaw 的 Skills 跑学习任务,模型通道改到 TaoToken 通道行不行?
2026/9/23 19:31:09
ChatGPT报错Oops, an error occurred! 全链路排查指南