news 2026/10/26 11:46:52

STM32F103与PT100温度采集实战:从接线调参到两点标定避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F103与PT100温度采集实战:从接线调参到两点标定避坑指南

简介:这份资源面向嵌入式初学者与需要做温度采集实验的开发者,围绕STM32F103C8T6微控制器展开,解决如何用片上ADC读取PT100热电阻阻值变化、再经USART串口把温度数据实时上传到计算机的问题,涉及ADC通道配置、采样时间与参考电压设置、连续转换与DMA/中断读取、串口波特率与帧格式匹配等核心环节。压缩包共253个文件,约7.42MB,以40个h头文件、38个c源文件为主体,配合Keil工程文件(uvprojx、uvoptx)、编译中间产物(o、d、crf、__i)、hex与axf可执行文件、map映射文件及sct分散加载文件,另附说明文档与PDF资料,构成一套可直接编译下载的完整工程。已有1214人学习下载。读者可从中获得ADC采集与串口通信的完整代码框架、外设初始化与中断/DMA配置思路,以及计算机端解析温度帧的参考实现,便于对照移植到自己的测温项目。

1. 拿到 STM32F103 与 PT100 的压缩包,先别急着烧录

拆开一个名为STM32f103PT100.zip的压缩包,里面大概率躺着一套基于 STM32F103C8T6 最小系统板读取 PT100 铂电阻温度的程序。这类资源在工业测温、恒温控制、实验箱改造里出现频率极高,核心诉求就一句话:把 PT100 那点毫欧级的阻值变化,稳定地变成串口或屏幕上能看的温度值。它适合手里有 C8T6 蓝板、想快速跑通三线制 PT100 采集的嵌入式从业者,也适合课程设计阶段需要一份能改能调的参考工程的人。但我要先把丑话说前面:PT100 的坑不在代码,在模拟前端和标定,压缩包给的是骨架,血肉得自己填。下面按「这是什么 → 怎么接线调参 → 哪里会翻车」的顺序拆。

2. 先看清信号链:PT100 到 STM32F103 之间到底发生了什么

2.1 为什么不能把 PT100 直接怼到 ADC 引脚

PT100 在 0℃ 时是 100Ω,每摄氏度大约变化 0.385Ω,100℃ 时约 138.5Ω。这个阻值变化量放到 STM32F103C8T6 的 12 位 ADC 上,如果直接分压,分辨率根本不够看。C8T6 的 ADC 参考电压通常取 3.3V,12 位意味着每个 LSB 约 0.8mV,而 PT100 在 1℃ 上产生的电压变化,取决于你给的激励电流。常见做法是恒流源激励,比如 1mA 流过 PT100,1℃ 对应 0.385mV,勉强能分辨,但导线电阻、自热、ADC 噪声一叠加,精度就崩了。所以压缩包里如果带运放电路(常见是 LM358、OP07 或 AD623 这类),别嫌它多余,那是把微小差分放大到 ADC 舒适区间的关键。我一般会先确认工程里 ADC 采的是单端还是差分、有没有做零点偏移,再决定要不要动硬件。

2.2 三线制接法与恒流源选型

工业现场 PT100 多为三线制,目的是抵消引线电阻。两线制把两根引线电阻全算进测量值,几米线就是零点几欧,折合好几度,血泪经验。三线制要求两根同色线接在 PT100 一端、另一根接另一端,配合恒流源和差分放大,让引线电阻在两条支路上相互抵消。压缩包若只给了两线制的分压电路,你得自己补:常见做法是用一个基准电压加运放搭 1mA 恒流源,或者直接用专用芯片如 MAX31865(SPI 接口,内置 15 位 ADC 和 RTD 线性化)。如果工程是基于 C8T6 内部 ADC 的,那基本是「恒流源 + 仪表放大 + 单端进 ADC」的路子,代码里会有一个电压到电阻、电阻到温度的换算函数,这个函数就是你要重点审的地方。

2.3 工程结构速览:哪些文件值得先打开

拿到压缩包,先别编译,按这个顺序翻:

文件/目录看什么判断标准
main.c初始化顺序、主循环里 ADC 采样与温度换算的调用有没有滤波、有没有标定系数
adc.c/stm32f10x_adc.c相关采样通道、采样时间、是否用 DMA采样时间是否够长(PT100 前端输出阻抗高时需加长)
温度换算函数(常在pt100.c或main.c里)用的是线性近似还是查表/Callendar-Van Dusen 公式线性近似在 0~100℃ 误差可接受,宽温区必须用公式
usart.c串口波特率、printf 重定向方便你直接看数
原理图/说明文档(若有)激励电流、放大倍数、接线定义没有的话自己反推

如果压缩包里没有原理图,别硬猜,先用万用表量板上运放周边电阻,反推放大倍数,再对照代码里的换算系数,两边对不上就是坑。

3. 把工程跑起来:时钟、ADC 与温度换算的实操配置

3.1 时钟与 ADC 采样时间的设置

C8T6 跑 72MHz 时,ADC 时钟不能超过 14MHz,所以 ADC 预分频通常设 6 分频(12MHz)。采样时间这个参数很多人忽略:PT100 经运放输出后,如果运放输出阻抗偏高,采样时间太短会导致采样电容充不满,读数偏低且跳。我一般把采样时间设到 55.5 或 71.5 个周期,宁可慢一点。下面是一段典型的 ADC 单通道配置,放在adc.c里:

// ADC1 通道0(PA0),独立模式,单次转换,软件触发 void PT100_ADC_Init(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_ADC1EN; // PA0 模拟输入 GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0); GPIOA->CRL |= GPIO_CRL_CNF0; // 输入模式,模拟 RCC->CFGR &= ~RCC_CFGR_ADCPRE; RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; // 72MHz/6 = 12MHz ADC1->CR1 &= ~ADC_CR1_SCAN; // 单通道,不扫描 ADC1->CR2 &= ~ADC_CR2_CONT; // 单次转换 ADC1->SMPR2 |= ADC_SMPR2_SMP0; // 通道0 采样时间 55.5 周期 ADC1->SQR1 &= ~ADC_SQR1_L; // 规则序列长度 1 ADC1->SQR3 &= ~ADC_SQR3_SQ1; ADC1->SQR3 |= 0; // 序列第一个转换通道 0 ADC1->CR2 |= ADC_CR2_ADON; // 上电 for(volatile int i=0;i<1000;i++); // 等待稳定 ADC1->CR2 |= ADC_CR2_CAL; // 启动校准 while(ADC1->CR2 & ADC_CR2_CAL); } uint16_t PT100_ReadRaw(void) { ADC1->CR2 |= ADC_CR2_ADON; // 再次置位启动转换 while(!(ADC1->SR & ADC_SR_EOC)); return ADC1->DR; }

这段代码的逻辑说明:先开 GPIOA 和 ADC1 时钟,把 PA0 配成模拟输入,避免数字输入缓冲引入漏电;ADC 预分频设 6 分频保证不超频;采样时间选 55.5 周期是给高阻抗前端留余量;校准那一步别省,C8T6 的 ADC 不校准零点漂移能到十几个 LSB。参数上,如果你前端输出阻抗很低(比如运放跟随输出),采样时间可以降到 13.5 周期换速度;如果读数抖动大,先加采样时间再考虑硬件滤波。

3.2 从 ADC 码值到电阻再到温度

假设硬件是 1mA 恒流源、放大倍数 G、零点偏移 Voff,那么 ADC 码值 N 对应电压 V = N/4096×3.3,再反推 PT100 电阻 R = (V/G - Voff)/0.001。这一步的系数必须和硬件严格对应,压缩包里的宏定义就是你要核对的。电阻到温度,0~100℃ 用线性近似 R = 100×(1+0.00385×T) 反解误差在 0.5℃ 以内,够用;宽温区或要 0.1℃ 精度,用 Callendar-Van Dusen 公式:

// Callendar-Van Dusen,T >= 0 段 // R = R0 * (1 + A*T + B*T*T),A=3.9083e-3, B=-5.775e-7 float PT100_ResToTemp(float R) { const float R0 = 100.0f; const float A = 3.9083e-3f; const float B = -5.775e-7f; // 解一元二次方程 B*T^2 + A*T + (1 - R/R0) = 0 float c = 1.0f - R / R0; float disc = A*A - 4.0f*B*c; if (disc < 0) return -999.0f; // 异常值保护 return (-A + sqrtf(disc)) / (2.0f*B); }

逻辑说明:这里取正根是因为 T≥0 时物理上对应较大根;disc<0说明电阻值超出合理范围,多半是断线或短路,返回一个明显异常值让上层报警。参数上 A、B 是 PT100 的标准系数,别自己改;R0 用实测值替换 100.0 可以吃掉传感器个体偏差。注意这个公式只覆盖 0℃ 以上,负温段要换另一组系数,压缩包若只做常温测量就不用管。

3.3 加一层滑动平均,别让读数跳舞

原始 ADC 码值跳几个 LSB 很正常,直接换算成温度会看到小数点后乱蹦。我一般在上层加 8 点或 16 点滑动平均,成本低、效果立竿见影:

#define FILTER_LEN 16 static uint16_t buf[FILTER_LEN]; static uint8_t idx = 0; static uint32_t sum = 0; uint16_t PT100_Filter(uint16_t raw) { sum -= buf[idx]; buf[idx] = raw; sum += raw; idx = (idx + 1) % FILTER_LEN; return (uint16_t)(sum / FILTER_LEN); }

这段是环形缓冲滑动平均,sum增量更新避免每次累加 16 个数,适合放在 1ms~10ms 的定时采样里。参数上 FILTER_LEN 越大越稳但响应越慢,测温这种慢变量取 16 很合适;如果你要做快速阶跃响应测试,临时改成 4。注意sum用 32 位,16 个 12 位值最大 65520,不会溢出。

4. 避坑与排查:PT100 采集翻车的五个高频现场

4.1 读数恒定不变或满量程

现象:串口一直打印同一个温度,或者直接顶到量程上限。原因多半是前端断线、运放没供电、或者 ADC 通道配错。先量 PT100 两端电压是否随手捏变化,再量运放输出是否在 0~3.3V 合理区间,最后核对SQR3里的通道号和实际焊接引脚是否一致。C8T6 的 PA0 是通道 0,PA1 是通道 1,接错一个脚就是满量程。

4.2 温度整体偏高几度,且线性偏移

现象:冰水混合物里显示 3~5℃,沸水附近也同比偏高。原因基本是引线电阻没抵消或恒流源实际值偏离标称。两线制接法下,每米导线约 0.02Ω,几米就是零点几欧,折合 1℃ 以上。解决:改三线制,或者在代码里减掉一个实测的引线电阻常数;恒流源用万用表串进去实测,别信电阻分压算出来的理论值。

4.3 读数随环境温度漂,手一碰板子就变

现象:吹口气温度就跳,板子发热后零点漂移。原因是运放失调电压温漂大,或者基准电压用的是 VDDA 而非外部基准。C8T6 的 VDDA 直接来自 3.3V LDO,LDO 本身有温漂。解决:换算时用实测 VDDA 而非固定 3.3,或者换外部基准如 TL431;运放选低失调低温漂型号,别用 LM358 凑合高精度场景。

4.4 采样值周期性跳动,和某个定时器同频

现象:温度值以固定频率上下跳,周期和 PWM 或某个定时中断一致。原因是 ADC 采样时刻撞上了开关噪声或数字电路翻转。解决:把 ADC 采样放在定时器触发、且避开 PWM 开通瞬间;模拟地和数字地单点连接;采样时间加长。这类问题玄学感很强,但用示波器看 ADC 输入引脚和 PWM 沿的关系,一抓一个准。

4.5 串口打印乱码或没输出

现象:接上 USB-TTL 只看到乱码。原因通常是波特率不匹配或 printf 重定向没做。核对usart.c里的波特率和串口助手一致(常见 115200),确认fputc重定向函数存在且工程勾选了 MicroLIB。C8T6 用外部晶振还是内部 HSI 也会影响波特率误差,8MHz HSI 跑 115200 误差偏大,建议外部 8MHz 晶振倍频到 72MHz。

5. 进阶:用两点标定把误差压到 0.1℃ 级

压缩包给的换算系数是理论值,实际板子上运放电阻精度、恒流源偏差、ADC 增益误差叠加,不标定很难进 0.5℃。我的习惯是拿到任何一套 PT100 采集板,先做两点标定:冰水混合物(0℃)和沸水(当地气压下约 99~100℃,用标准温度计读实际值),记录两个点的 ADC 码值和标准温度,反解出增益和偏移,写回代码。具体做法是把换算函数改成T = k * N + b的形式,k、b 由两点算出:

// 两点标定:N0/T0 为冰点码值与温度,N1/T1 为沸点 float k = (T1 - T0) / (float)(N1 - N0); float b = T0 - k * N0; // 之后温度 = k * filtered_raw + b

逻辑说明:这是把整个信号链当成线性系统处理,在 0~100℃ 区间内足够;如果你要更宽温区,就做多点分段线性或直接用查表。参数上 N0、N1 要取滤波后的稳定值,每个点等 2~3 分钟让传感器热平衡,别刚放进去就读。标定完把 k、b 存到 Flash 或直接写死,下次上电不用重标。

还有一个验证技巧:标定后别只看显示值,拿标准电阻箱替代 PT100,输入 100.00Ω、138.51Ω 两个阻值,看输出是否对应 0℃ 和 100℃,这能区分是传感器问题还是电路问题。我吃过一次亏,现场温度总差 1.5℃,查了半天代码,最后发现是传感器插头氧化接触电阻,从那以后每次上线前都先用电阻箱过一遍全链路,再换真传感器。这套流程走下来,STM32f103PT100.zip里的骨架才算真正变成你能用的东西。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 11:46:41

CTB地形切片生成器:将TIF高程数据转换为Cesium地形瓦片

简介&#xff1a;这份资源是面向三维 GIS 与 Cesium 开发者的地形数据处理工具&#xff0c;用于将 TIF 高程影像切割为 Cesium 可直接加载的 .terrain 瓦片&#xff0c;解决地形切片流程繁琐、格式不兼容的问题&#xff0c;适合具备一定 GIS 基础、需要自建地形服务的开发与测绘…

作者头像 李华
网站建设 2026/10/26 11:46:27

OPNET中ALOHA与CSMA随机接入协议仿真对比

第一次在 OPNET 里把 ALOHA 和 CSMA 摆进同一个场景跑对比&#xff0c;是接一个链路层协议分析任务的时候。当时手上就一句需求——“给出两种随机接入协议在不同负载下的性能差异”&#xff0c;没有参考模型、没有既定参数、也没有人说清楚“性能”到底指吞吐还是时延。我最初…

作者头像 李华
网站建设 2026/10/26 11:44:49

SQL Server 2022权限与架构管理最佳实践

1. SQL Server 2022权限与架构管理核心解析 作为微软数据库产品线的旗舰版本&#xff0c;SQL Server 2022在安全管控体系上进行了全面升级。我在实际企业级项目中发现&#xff0c;90%的数据泄露事件都源于权限配置不当或架构设计缺陷。新版通过动态数据掩码(Dynamic Data Maski…

作者头像 李华
网站建设 2026/10/26 11:44:43

Cursor开发者必看:发票报销全流程指南

1. 为什么开发者需要关注Cursor的发票报销问题作为一名长期使用Cursor的开发者&#xff0c;我发现很多同行在使用这款智能编程工具时&#xff0c;往往会忽略一个看似简单却至关重要的问题——如何正确开具发票进行报销。Cursor作为当前最受开发者欢迎的AI编程助手之一&#xff…

作者头像 李华
网站建设 2026/10/26 11:44:32

impeccable:从命名到交付,如何打造无可挑剔的项目

1. 一个词撑起一个项目名&#xff1a;impeccable 到底在说什么第一次看到“impeccable”这个词被拿来当项目标题&#xff0c;我脑子里蹦出来的第一个念头是&#xff1a;这大概率不是一个功能型命名&#xff0c;而是一个态度型命名。功能型命名会告诉你“我做了什么”&#xff0…

作者头像 李华
网站建设 2026/10/26 11:44:19

面对模糊项目标识的工程拆解方法:从三个字母到可执行任务

1. 当标题只剩三个字母时&#xff0c;我在想什么第一次看到“rea”这个标题&#xff0c;我盯着屏幕愣了好几秒。没有正文&#xff0c;没有关键词&#xff0c;没有摘要&#xff0c;连一个标点符号都没有。这种输入状态在真实工作里其实并不罕见——你接手一个项目&#xff0c;前…

作者头像 李华