
简介一份完整的触摸式取暖器温控电路设计说明文档面向嵌入式系统学习者、电子类专业学生以及需要完成温控项目设计的开发者重点展示了基于STM8S105K4单片机的温控系统架构与模块化设计思路。文档以STM8S105K4单片机为核心完整介绍了电容式触摸按键软件库、COSMIC C编程和ST TOOLSET开发环境的使用方法同时覆盖红外遥控控制、热敏电阻温度采集与ADC转换、实时时钟更新、TM1668驱动LED显示、蜂鸣器报警提示以及电源低功耗设计等关键环节能够帮助读者理解从硬件选型、电路搭建到软件实现的整体流程。包内仅有1个doc文件容量为3.72MB内容结构清晰、论述集中适合作为课程设计或毕业设计的参考模板。目前已有98人学习下载对于学习STM8系列开发或制作智能取暖设备的用户具有较强的借鉴意义。1. 触摸式取暖器温控电路为什么用 STM8S105K4 而不是专用触控芯片取暖器这种温控产品用户感知最强的反而不是温度精度而是按键手感和整个系统的响应是否跟手。传统机械开关用久了氧化冬天手湿或者戴手套时无法触发。这个项目把电容触摸按键、温度采集、红外遥控和 LED 显示全部收敛到一颗 STM8S105K4 上利用 ST 官方的触摸感应软件库完成电容按键识别省掉了一颗专用触控芯片整板 BOM 成本被压得很低。文章后面会围绕 RC 触摸采样、NTC 测温和回差控制、IrDA 红外解码、TM1668 显示驱动以及 ST TOOLSET 加 Cosmic C 的调试环境把这套温控电路从原理到可复现的细节讲清楚。适合正在做家电类低成本人机交互和温控功能的嵌入式工程师参考。2. RC 触摸感应与 IrDA 红外遥控输入链路的两种实现2.1 电容触摸为什么用 RC 充电采样STM8S105K4 本身不带电容触摸外设ST 给 8 位机提供的是一套基于 RC 充电时间的软件方案。感应焊盘在 PCB 上就是一块铜皮它与地之间有一个固定寄生电容手指靠近后这个电容增大用同一根 IO 对焊盘充电充满到逻辑高电平的时间也会变长。落到 MCU 上就是先把 IO 配成推挽输出低电平让焊盘放电再把 IO 切成输入并打开内部上拉用一个循环数引脚电平翻转前的时间。这样就不需要额外的电容感应芯片缺点是计数值受电源、温度和焊盘尺寸影响大需要后期做标定。下面是一段可以直接放到 STVD 里的采样函数原型#define TOUCH_IO_EN PA_DDR #define TOUCH_IO_CR1 PA_CR1 #define TOUCH_IO_IDR PA_IDR #define TOUCH_PIN 0x01 uint16_t Touch_Measure(void) { uint16_t cnt 0; // 1. IO 配置为推挽输出低对感应焊盘放电 TOUCH_IO_EN | TOUCH_PIN; TOUCH_IO_CR1 | TOUCH_PIN; TOUCH_IO_CR2 ~TOUCH_PIN; // 给足放电时间否则下一次测量会偏小 for (volatile uint16_t d 0; d 400; d); // 2. 切成输入浮空释放焊盘开始计时充电 TOUCH_IO_EN ~TOUCH_PIN; TOUCH_IO_CR1 ~TOUCH_PIN; TOUCH_IO_CR2 ~TOUCH_PIN; // 3. 充电期间引脚为低翻高后退出循环 while ((TOUCH_IO_IDR TOUCH_PIN) 0 cnt 0xFFFF) { cnt; } return cnt; }这里把 STM8S 的寄存器操作封成了宏实际项目里可以用标准外设库的 GPIO 接口替换。关键点有两个放电时间不能太短否则焊盘残余电荷会把下次测量的基线抬高充电计时用的内部上拉电阻在不同芯片之间阻值可能差 30% 以上所以绝对计数值没有意义要用相对差值判断。ST 官方触摸库内部还会做通道间补偿原理是同一套如果产品面板厚、按键多直接调库比裸写更容易收敛。触摸采样参数可以参考这张表后续调试再按实际面板微调参数参考值说明感应焊盘直径8~12mm覆盖 3mm 亚克力时灵敏度合适采样次数8~16 次每次取最大值或平均抑制毛刺无触摸基线由启动时采样得到不能直接写死温漂太大触摸判定阈值基线 30~80 count取暖器工作后温度升高会导致基线漂移扫描周期20~50ms太慢按键反应迟太快抗干扰差2.2 触摸按键的软件状态判断裸的充电计数值不能直接用。取暖器加热丝一动作电源上就会叠加干扰触摸通道计数值会整体抖动。常见做法是加滑动平均和基线慢速跟踪按键没有按下时每个扫描周期把基线向当前采样值靠近一点按键按下后立即冻结基线防止把按键状态当成温漂吸收掉。判定成立后还要连续两次都满足才确认这就是去抖。uint8_t key_pressed 0; uint16_t touch_raw 0; uint16_t touch_base 1000; // 每 20ms 调用一次 uint8_t Touch_KeyScan(void) { touch_raw Touch_Measure(); // 未按下时才更新基线按下后保持基线的稳定 if (key_pressed 0) { if (touch_raw touch_base) touch_base (touch_raw - touch_base) 3; else touch_base - (touch_base - touch_raw) 5; } if (touch_raw touch_base 50) { if (key_pressed 0) { key_pressed 1; return 1; // 边沿触发一次按下只返回一次 } } else { key_pressed 0; } return 0; }代码逻辑是“边沿触发”按下瞬间返回一次 1后面按住不重复上报。 3和 5是低通滤波用的移位除法省去浮点运算。 3跟踪快 5跟踪慢因为按键释放后的抖动脉冲比温度漂移短用慢速滤波就可以滤掉。如果环境变热导致基线升高过快可以把 3改成 4。2.3 IrDA 红外接收与 NEC 解码原文里写的是 IrDA 器件但实际家用取暖器遥控用的是 NEC 协议物理层是同一类红外载波很多工程师习惯统称 IrDA。接收头输出是解调后的脉冲序列接 MCU 外部中断脚同时在单片机里开一个定时器记录边沿间隔。volatile uint16_t edge_interval[64]; volatile uint8_t edge_index 0; volatile uint16_t last_tim 0; // 红外接收头 OUT 接到 PD2EXTI2 中断 void EXTI2_IRQHandler(void) { uint16_t now TIM4_GetCounter(); edge_interval[edge_index] now - last_tim; last_tim now; if (edge_index 64) { edge_index 0; ir_decode_flag 1; } }定时器 TIM4 配置成 10μs 一个 count9ms 引导码对应的间隔大概是 900逻辑 1 的 2.25ms 对应 225逻辑 0 的 1.125ms 对应 112。解码时先找 900 附近的引导间隔再往后数 32 位数据位。这里要提醒一点不要试图在中断里跑完 NEC 完整解析只应该收边沿主循环再处理否则遥控连发码一进来中断响应时间就被拉长触摸扫描也会跟着抖。3. NTC 温度采集与温控算法取暖器温控电路的核心3.1 热敏电阻分压与 ADC 接口NTC 温度传感器利用的是负温度系数阻值随温度升高而下降。电路接法很简单NTC 接在 VCC 和采样点之间固定电阻接在采样点和 GND 之间这样温度升高采样点电压下降。固定电阻取值一般选 NTC 在常温下的标称阻值比如 25℃ 下 10kΩ 的 NTC分压电阻就用 10kΩ这样 25℃ 时采样点正好是 VCC/2测量范围能覆盖 0~80℃。ADC 引脚并联一个 0.1μF 陶瓷电容滤掉高频干扰对减小采样抖动非常有效。STM8S105K4 的 ADC 是 10 位参考电压直接用 MCU 供电的 5V因为主板是 5V 系统。采样时要注意不要连续读一次就换算至少要取 8~16 次做中位值平均因为 NTC 分压点阻抗高单次采样结果会跳好几个 LSB。#define ADC_CH_NTC 2 #define R_FIX 10000.0f #define R25 10000.0f #define B_VALUE 3950.0f #define VREF 5.0f float NTC_GetTemperature(void) { uint16_t adc_sum 0; uint16_t adc_arr[8]; uint8_t i, j; // 连续采样 8 次 for (i 0; i 8; i) { adc_arr[i] ADC_GetConversionValue(ADC_CH_NTC); for (j 0; j 20; j); // 让 ADC 采样电容充分放电 } // 简单去极值平均排序后取中间 4 个平均 for (i 0; i 8; i) for (j i 1; j 8; j) if (adc_arr[i] adc_arr[j]) { uint16_t t adc_arr[i]; adc_arr[i] adc_arr[j]; adc_arr[j] t; } adc_sum adc_arr[2] adc_arr[3] adc_arr[4] adc_arr[5]; float adc_v (float)adc_sum / 4.0f / 1024.0f * VREF; float r R_FIX * (VREF - adc_v) / adc_v; float t 1.0f / (1.0f / 298.15f (1.0f / B_VALUE) * logf(r / R25)) - 273.15f; return t; }这段代码把采样、滤波、阻值换算、温度换算全部放在一个函数里。逻辑说明ADC 值除以 1024 得到归一化电压再用分压关系反推 NTC 阻值。B 值公式是工程上最常用的简化算法25℃ 附近误差很小但低温端会偏差 1~2℃。如果取暖器控温区间是 15~30℃这个精度足够了。要求更高的产品可以把厂商提供的 R-T 温度电阻表改成查表加线性插值避免logf带来的浮点库开销。3.2 温控回差控制取暖器不像热水器那样需要快速精确控温加热丝是一个大惯性对象如果只在设定温度点做单点开关继电器会在目标温度附近频繁吸合和释放。这个项目用的是回差控制温度低于“设定值-回差”时开启加热温度高于“设定值”时关闭加热。回差范围一般取 1.5~3℃太窄继电器动作频繁太宽用户觉得温度波动大。#define SET_TEMP 28.0f #define HYSTERESIS 2.0f uint8_t heater_on 0; void Temp_Control(float current_temp) { if (heater_on 0 current_temp SET_TEMP - HYSTERESIS) { heater_on 1; Relay_On(); } else if (heater_on 1 current_temp SET_TEMP) { heater_on 0; Relay_Off(); } }这个状态机比if(temp 26) on; if(temp 28) off;更好因为有heater_on记录当前状态不会出现设定值附近的反复翻转。实际工程中Relay_On前要做 200ms 左右的延时因为 NTC 采到的温度有滞后加热丝刚停时温度还会惯性上升 0.5℃这种余量由回差吸收。如果后续想升级成功率可调可以换成双向可控硅加过零检测但控制逻辑要从开关量变成功率百分比成本会涨一截。3.3 加热设备电源电路与双重保护这个项目里加热丝是强电回路控制板是弱电回路不能把 MCU 的 GND 和加热丝回路直接混在一起。常见做法是220V 经过保险丝和手动复位温控器比如 85℃ 常闭温控开关串联再到继电器触点最后接加热丝。MCU 通过 ULN2003 驱动继电器线圈线圈两端并一个续流二极管。倾倒断电开关放在整机强电入口处倾斜超过设定角度就切断 220V这样即使 MCU 跑飞强电侧也能被硬件切断。这个思路不只是论文里的一句“安全节能”而是家电产品必须考虑的冗余保护。4. TM1668 显示驱动、HYM1302 时钟与 ST TOOLSET 工程搭建4.1 TM1668 驱动 LED 显示TM1668 是带键盘扫描的 LED 显示驱动芯片本设计只用它的显示部分。它用 CLK、DIO、STB 三根线与 MCU 通信支持 10 段 7 栅可以驱动 4 位共阴数码管加若干指示灯。初始化时要先发送显示模式控制字再设置亮度最后往段地址写段码。写入时序是低位先出读写命令不能写错否则显示会乱码。#define TM1668_STB_H PA_ODR | 0x04 #define TM1668_STB_L PA_ODR ~0x04 #define TM1668_CLK_H PA_ODR | 0x08 #define TM1668_CLK_L PA_ODR ~0x08 #define TM1668_DIO_H PA_ODR | 0x10 #define TM1668_DIO_L PA_ODR ~0x10 void TM1668_WriteByte(uint8_t dat) { uint8_t i; for (i 0; i 8; i) { TM1668_CLK_L; if (dat 0x01) TM1668_DIO_H; else TM1668_DIO_L; TM1668_CLK_H; dat 1; } } void TM1668_SetSeg(uint8_t addr, uint8_t seg) { TM1668_STB_H; TM1668_WriteByte(0x44); // 写显示寄存器命令 TM1668_STB_L; TM1668_STB_H; TM1668_WriteByte(0xC0 | addr); // 起始地址 TM1668_WriteByte(seg); TM1668_STB_L; }写完后必须把 STB 拉低TM1668 才会锁存数据。段码顺序要和 PCB 上数码管引脚一一对应不同 PCB 段码表不同不要直接抄参考示例里的表。显示部分要避开触摸扫描时间片因为 CLK 信号可能耦合到感应焊盘表现为手指没摸触摸值自己跳。可以把显示刷新放到触摸采样之后或者至少间隔 1ms 以上。4.2 HYM1302 实时时钟读写HYM1302 是 DS1302 的国产兼容型号走时功能完全一致外部接 32.768kHz 晶振和 3V 纽扣电池。它和单片机之间是类似 SPI 的三线接口但命令格式特殊先写命令字节其后才是数据字节。地址的最低位是读写标志0 写 1 读。这里给一个读单字节的时序示例uint8_t RTC_Read(uint8_t addr) { uint8_t i, dat 0; RTC_CE_HIGH(); RTC_WriteByte((addr 1) | 0x01); // 读命令 for (i 0; i 8; i) { RTC_CLK_LOW; if (RTC_DIO_READ()) dat | 0x80; RTC_CLK_HIGH; dat 1; } RTC_CE_LOW(); return dat; }注意这个代码中读数据时是“先读后移”和写数据是反的。时间寄存器里的值全部是 BCD 码比如秒寄存器读到 0x59表示 59 秒需要转换second (bcd 4) * 10 (bcd 0x0F)。向 HYM1302 写入时间前最好把秒寄存器的 CH 位清零否则读回来的时间不会走动。这个坑在首次上电时非常常见日期停在某个固定值不动基本都是忘了停掉 CH 位。4.3 5V 开关电源与整板电源分配温控板的功率分两部分控制电和加热电。控制电取自主板上的 5V 开关电源输入是 220V 整流滤波后的高压直流输出稳定 5V然后分别供给 STM8S105K4、TM1668、HYM1302 和红外接收头。NTC 分压、触摸焊盘共用模拟电源路径需要在 5V 输出端加一个 10Ω 电阻和 100μF 电解电容再进入模拟地避免数码管段电流变化时主电源跌落。实际调试中如果触摸采样值跟着显示内容变化就是模拟地和数字地没分开。开关电源纹波对触摸影响很大。我一般会在 5V 输出和 MCU 供电引脚之间再串联一颗 10μH 电感配合 0.1μF 和 10μF 电容组成 π 型滤波触摸基线能稳定很多。STM8S105K4 是单电源供电内部带 ADC 参考但如果想追求温控稳定性可以在 VREF 引脚外加一个 2.5V 基准代价是多一颗芯片和一点布局面积。4.4 ST TOOLSET 与 Cosmic C 的环境参数软件部分用的是 ST TOOLSET 提供的 ST Visual Develop 集成环境编译器选择 Cosmic C。Cosmic 的免费 license 需要去官网申请收到回复后把 license 文件放到安装目录一年一续。工程配置时有几个参数很容易被忽略第一是 MCU 型号必须精确选到 STM8S105K4选错 GPIO 和 ADC 映射全乱第二是堆栈大小至少给到 0x300触摸库和浮点运算都会吃栈第三是优化等级建议选 -O2开优化后要注意延时函数里的空循环是否被编译器优化掉延时函数里的循环变量需要加volatile。配置项建议值说明MCUSTM8S105K4TQFP32 或 LQFP32编译器Cosmic CXSTM8免费授权一年优化等级-O2兼顾代码体积和实时性堆栈大小0x300触摸库和中断嵌套需要时钟源内部 16MHz RC 或外部 8MHz 晶振需要走时钟显示时优先外部晶振调试器ST-LINK/V2支持 SWIM 调试接口我在这里踩过最深的坑是STVD 里不配置 STM8 SWIM 调试接口烧录后程序跑不进去。另外 Cosmic 的printf默认会占掉 2KB 以上 Flash量产代码里不要留串口打印改成 LED 指示灯或蜂鸣器提示。5. 触摸阈值标定、ADC 滤波与取暖器温控整机调试技巧刚把温控电路全部接好第一个发现的现象往往是触摸按键乱跳温度显示来回抖继电器吸合瞬间整个显示闪烁一遍。这些问题不是原理错误而是没有做现场的阈值标定和采样滤波。下面几个技巧是我在这套电路上调完板子之后最有效的手段。第一个是触摸阈值标定。不要在软件里写死一个固定 threshold取暖器在生产时面板材料厚度会有波动同一块 PCB 在不同壳体上无触摸基线的差异可能达到 200 个 count。比较可靠的做法是上电 1 秒后确认是冷启动连续采集 16 次触摸充电时间取平均作为基线阈值取基线加 50。如果板子上有 EEPROM也可以把出厂标定值存进去下次开机直接读取。void Touch_Calibration(void) { uint32_t sum 0; uint8_t i; for (i 0; i 16; i) { sum Touch_Measure(); } touch_base (uint16_t)(sum 4); touch_threshold touch_base 50; }标定时机必须在继电器第一次动作之前因为继电器吸合瞬间的地弹会把充电时间拉长如果标定时加热已经开启基线会被抬高导致后面触摸永远不触发。第二个技巧是 ADC 滤波不要用全平均。NTC 分压网络的阻抗在 10kΩ 量级单次 ADC 采样结果受电源纹波影响很大。我一般用去极值平均采 8 次丢掉最大和最小剩下 6 个取平均。也可以用中位值排序但取暖器主循环里同时要跑触摸扫描和红外解码排序占用的 CPU 时间偏多控温周期又不需要那么高的响应去极值平均已经够用。第三个技巧是处理继电器动作时对触摸的干扰。很多人会花很长时间去调触摸阈值结果发现根源在继电器。解决办法有两个一是把触摸扫描和继电器开关放在同一个时隙的两端不在继电器动作后 10ms 内去读触摸二是在继电器线圈两端并续流二极管并在触点之间加 RC 吸收。实际测试中把这两个措施做好之后触摸基线的抖动幅度可以从 ±40 count 降到 ±10 count。最后说一个整机联调时的观察点用定时器同时记录加热开启时长和关闭时长当设定温度 28℃、回差 2℃ 时正常房间内一个开关周期应该在 10 分钟左右。如果开关周期小于 2 分钟说明回差太小或 NTC 贴近加热丝温控系统在振荡如果周期大于 20 分钟温度波动会超过用户接受范围。拿这个周期范围去反推回差取值比盯着温度数值调要直观得多。本文还有配套的精品资源点击获取