[quote][size=2][url=forum.php?mod=redirect&goto=findpost&pid=227499&ptid=8573][color=#999999]hikzwyah 发表于 2026-8-9 17:27[/color][/url][/size]
/************************************************************************************************* ...[/quote]
我已经获得了足够的信息来给出一个完整、有依据的分析。让我归纳结论。
关键手册依据(来自 STC8A8K64D4 手册 ADC 章节):
- "适当加长对外部信号的采样时间,就是对ADC内部采样保持电容的充电或放电时间,时间够,内部才能和外部电势相等。"
- 采样保持电容前串接抗静电电阻 R_{ESD} = 700Ω,内部采样保持电容 C_{ADC} = 16.5pF
- 12位 ADC 转换速度不能高于 800KHz
现在让我系统分析这个"长时间后所有NTC通道同时偏低10度、可调电阻正常、且卡在60/49.9到不了110"的现象。
我先整理出完整的分析,包括硬件根因和代码缺陷,再给出代码修正建议。
核心分析
先明确一个关键点:NTC 与可调电阻的本质差异在于"源阻抗"。
你的分压电路是:Vref → 51K上拉电阻 → 采样点(ADC) → NTC → GND(或反接,取决于你的NTC接法,但结论一致)。
- NTC 阻值随温度变化:低温时阻值极大(表格最大 568000Ω),高温时阻值小(10800Ω)。
- 可调电阻阻值恒定、且通常较小。
硬件根因(我认为是主因):高阻抗 NTC + 采样保持时间不足 → 采样电容充电不充分 → ADC 值偏低
STC8A8K64D4 内部采样保持电容 C_{ADC}=16.5pF,前串 R_{ESD}=700Ω。ADC 采样时,采样电容要通过 外部信号源阻抗 充电到与外电势相等。
采样时间常数 τ = (外部等效源阻抗 + 700Ω) × 16.5pF。
对于 NTC 高阻端(如 300kΩ~568kΩ),源阻抗极大,τ 非常大。即使你的采样时间是 SMPDUTY=31(采样时间约 (31+1)×ADC时钟周期),如果 ADC 时钟偏快,采样时间仍不足以让采样电容完全充电到位,导致采样到的电压低于实际分压值 → ADC 数字量偏低 → 计算阻值偏低 → 查表得到偏低温度。
可调电阻是低阻值恒定阻抗,充电瞬间完成,因此不受采样时间影响,读数正常——这正是你观察到的"NTC全低、可调正常"的关键差异。
而长时间运行后更明显,可能叠加:
- MCU 与 ADC 因长时间运行发热,ADC 内部特性漂移
- NTC 自热/老化使阻值略有漂移
- 采样电容电荷泄漏累积
这些都是"慢漂移",最终被温度突变限幅逻辑"咬"住,形成你看到的卡在固定值(60/49.9)到不了上限。
代码逻辑缺陷(叠加因素)
-
temp_out 是 uint16,温度限幅减法下溢
uint16 temp_out;
int16 temp_diff;
...
if(temp_diff < -TEMP_MAX_STEP)
temp_out = last_temp[i] - TEMP_MAX_STEP; // 若 last_temp<150,下溢成巨大数
last_temp[i] - TEMP_MAX_STEP 当 last_temp[i] 小于 150 时会下溢回绕成 65535 附近的大数,虽然后面有 if(temp_out > 11000) temp_out = 11000 兜底,但这会让温度被钳在11000上限或在下界反复跳动。
-
NTC 阻值越界分支的 raw_adc < 100 条件逻辑混乱
if((resistance < NTC_R_MIN || resistance > NTC_R_MAX) && raw_adc < 100)
当 NTC 阻值超上限(低温端,raw_adc 很小接近0)时,符合条件会沿用 last_temp[i]。但如果 last_temp 从未被正确初始化(上电为0),则低温端会一直输出0,无法跟踪。旋可调电阻到最小(高温端),raw_adc 接近4096,这个分支不成立走正常查表,理论上能到11000——但若原始ADC被硬件压低了,查表出的温度就上不去。
-
ADC_Filter 中 sum += filt_buf[ch] 缺下标(贴代码疑似被格式化,若真是如此会造成均值使用数组地址,结果异常)。
-
NTC 阻值计算使用 uint32 resistance,adc_val * 51000UL 为32位,denominator 为 uint32,计算没问题,但需确保不溢出。
现在,我需要给出针对性的解决方案。核心是:
硬件层面:加长采样时间 + 在 ADC 引脚并联滤波电容降低源阻抗影响 + NTC 分压并联电容。
手册明确建议"适当加长对外部信号的采样时间"。你当前 SMPDUTY=31 已是最大值,但若 ADC 时钟过快,实际采样时间仍可能不足。应该降低 ADC 时钟速度(增大 SPEED 分频),把 Fadc 控制在合理范围(最好 ≤ 数百 kHz),让采样时间足够长。
让我先给出分析,并说明需要补充的信息以给出精确的代码修复。
我给出完整答复。让我把采样时间计算清楚,并给出建议配置。
假设你的系统时钟。你配置 ADC_SPEED_2X16T,即 SPEED 使得 Fadc = Sysclk/2/16。若 Sysclk=24MHz,Fadc=750kHz,Adc周期≈1.333μs。采样时间=(SMPDUTY+1)×Adc周期=32×1.333≈42.7μs。
42.7μs 对 NTC 高阻端(如 400kΩ)来说:τ ≈ 400k×16.5pF ≈ 6.6μs,看似够 6 个 τ(≈40μs)。但当 NTC 阻值接近 568kΩ 且叠加 PCB 走线寄生电容时,τ 会更大,且长时间运行后充电不足的累积效应会显现。
更稳妥:在 ADC 采样点对地并联一个 0.1μF~1μF 电容(构成低通滤波 + 电荷存储),让采样电容每次能快速从大电容取电,从根本上解决充电不足。同时把采样时间进一步加长(降低 Fadc)。
现在给出结构化答复。
我发现你问题的根因,并且需要先说明:"所有 NTC 通道同时偏低、可调电阻正常" 这个硬件现象,是判断问题方向最强的线索。 它直接指向采样保持时间与高输入阻抗 NTC 的匹配问题,而非单纯代码 bug。
一、根因分析(硬件层面为主)
1. 现象判定
- 所有 NTC 通道 同时 偏低 → 说明是公共环节出问题(ADC 采样时序 / 采样保持),不是某一通道的 NTC 元件坏。
- 可调电阻通道正常 → 可调电阻是低阻值恒定源阻抗,采样电容瞬间充满,不受影响。
- NTC 是高阻值、随温度剧烈变化的源阻抗 → 采样保持电容充电慢,容易充不满。
这正是引起偏差的核心差异。
2. 手册依据(STC8A8K64D4 手册 ADC 章节)
"适当加长对外部信号的采样时间,就是对ADC内部采样保持电容的充电或放电时间,时间够,内部才能和外部电势相等。"
内部采样保持电容 C_{ADC} = 16.5pF,采样保持电容前串接抗静电电阻 R_{ESD} = 700Ω。
采样时,C_{ADC} 要经外部信号源阻抗充电到与分压点电势相等。NTC 高阻端(如 300k~568kΩ)源阻抗极大,采样时间常数 τ ≈ R_{源}\times C_{ADC} 非常大。若 ADC 工作时钟偏快、采样时间不足,采样电容充电不充分 → 采样电压偏低 → ADC 数字量偏低 → 计算阻值偏低 → 查表温度偏低。
可调电阻源阻抗低,τ 极小,瞬间充满,因此读数正常。这就是"NTC全低、可调正常"的直接原因。
3. 为什么运行 10~36 小时后才出现
长时间运行后,MCU/ADC 温升引起内部特性漂移 + NTC 自热/老化 + 采样电容电荷累积泄漏,使原本"临界够用"的采样时间变成"不够用",偏差逐渐累积。
4. 为什么"卡在 60 / 49.9 到不了 110"
当 ADC 原始值被硬件系统性压低后,温度查表结果偏低。此时叠加你代码里的温度突变限幅逻辑,每 2ms 只能变化 150(1.5℃),把偏低结果"咬"在一个伪平衡点上,形成卡死。另外 temp_out 是 uint16,减法下溢回绕也会干扰。
二、代码逻辑缺陷(需一并修正)
缺陷 A:温度限幅减法下溢(uint16 temp_out)
if(temp_diff < -TEMP_MAX_STEP)
temp_out = last_temp[i] - TEMP_MAX_STEP; // last_temp[i]<150时下溢成巨大数
修正:限幅差值运算强制用 int 类型、且先做符号处理,或直接对整型结果限幅。
缺陷 B:NTC 阻值越界分支 && raw_adc < 100 逻辑混乱
if((resistance < NTC_R_MIN || resistance > NTC_R_MAX) && raw_adc < 100)
temp_out = last_temp[i]; // 沿用上次
- 高温端(raw_adc≈4096,阻值最小 <NTC_R_MIN)不满足
raw_adc<100,走正常查表(本应能到11000);
- 但因为原始 ADC 被硬件压低,查出的温度上不去,再被限幅钳住。
建议去掉 && raw_adc < 100,越界一律沿用并加抖动判断。
缺陷 C:last_temp[10] 未初始化清零
声明时没有 = {0},上电随机值会导致低温端首次沿用错误值。应在初始化时 uint16 last_temp[10] = {0};。
缺陷 D:ADC_Filter 中 sum += filt_buf[ch] 缺 [i]
(若贴代码被格式化,请确认源文件)应为 sum += filt_buf[ch][i];,否则累加的是数组首地址而非采样值,均值完全错误。
缺陷 E:ADC_Filter 的 val < 0 判断
val 是 uint16,val < 0 永远不成立,且 int32 diff 已能处理,此句冗余。
三、解决方案
硬件层面(治本,优先)
- 加长采样时间 / 降低 ADC 时钟:把 ADC 工作频率降低,让采样时间足够长。当前
ADC_Speed=ADC_SPEED_2X16T 若 Sysclk 较高,采样时间可能不足。建议把 Fadc 压到 数百 kHz 级,并可将 SMPDUTY 保持 31(最大)。
- 在每条 ADC 输入脚(NTC 采样点)对地并联一个 0.1μF~1μF 电容:构成信号低通滤波 + 电荷存储,让内部 C_{ADC} 每次快速从大电容取电荷,彻底解决高阻 NTC 充电不足。这是最有效的一招。(注意并联电容后 ADC 采样需等电容电压稳定,但你的轮询周期足够。)
- 检查 NTC 分压上拉电阻(51K)与表格
Find_Const 的匹配,确认分压点电压随阻值单调对应。
软件层面(治标,必改)
- 修正上述代码缺陷 A~E。
- 把
temp_out 改为 int16 或对限幅差运算强制 int。
- 给
last_temp[10]、tmp_reg[13] 明确清零。
- 温度输出限幅最好加"死区/方向"判断,避免把真实慢漂移也当干扰咬死。
四、请补充以下信息以便我给出精确的修改代码
- 系统主频 Sysclk 是多少 MHz?(用于核算当前采样时间)
- NTC 分压电路的具体接法:是 "VCC→51K→采样点→NTC→GND" 还是反接?(决定 high = 高温还是低温)
- NTC 的 B 值 / 25℃ 阻值,确认与
Find_Const 表格(-10~100℃)匹配的 R25 基准。
如果你方便,把 AD_DEAL.h 里 usSRegHoldBuf、usSRegInBuf 的定义和 ADC_Filter 的完整源码贴一下(确认下标是否被格式化),我可以立即给出可直接替换的修正版 AD_Deal() 函数。
我的核心结论是:这是高阻抗 NTC 的采样保持时间不足导致的系统性 ADC 偏低(硬件根因),叠加代码里温度限幅下溢与越界分支缺陷造成的"卡死"现象。请优先在 ADC 输入加并联电容 + 降低 ADC 时钟,并修正代码缺陷。
🔍 搜索 "* 文件名称:AD_DEAL.…"
⏱️ 查找用时 34.6s | 总回答用时 63.2s