简介:面向STM32嵌入式入门开发者,这份基于STM32的T12悍台工程包,整合HAL库驱动、外设配置与配套文档,可帮助快速上手时钟、GPIO、ADC、PWM、中断、UART、I2C、SPI等核心外设,并理解实际硬件项目从配置到调试的完整流程。资源共116个文件,以61个h头文件与31个c源码为主,涵盖I2C、TIM、ADC等HAL驱动,另有IOC配置、make/cmake构建脚本、ld链接脚本、markdown说明、drawio/emmx设计文件及PDF文档等,整体仅800KB,轻量但结构完整。目前已有417人学习下载,适用于课程设计、毕业设计或个人DIY场景,可提取其中可复用的外设驱动与配置模块。通过阅读工程内的驱动与配置,初学者可以掌握STM32CubeMX初始化代码生成、HAL库调用、外设中断处理与调试技巧,并借鉴清晰的目录划分和注释规范;在遇到通信不稳定、ADC采样异常等问题时,也能借助配套文档与设计图快速定位思路,从而降低实战门槛。
1. T12焊台为什么值得用STM32重新做一套
T12焊台的核心其实不是“加热”,而是“控温”,而且是在200毫秒级别内稳定控住一个热惯性极小的烙铁头。白光T12烙铁头的热电偶就集成在发热芯内部,测温点离发热丝只有几毫米,升温快、回温猛,但也意味着温度闭环的迟滞极小,用普通运放比较器方案很难把温度稳定在±2℃以内。换成STM32做数字PID控制,ADC读取热电偶毫伏信号,定时器输出过零同步的PWM驱动可控硅,整套闭环的控制周期可以做到10ms以内,这是模拟方案很难达到的精度边界。
这套“基于stm32的T12悍台”压缩包里的文件值得去翻一翻,它是一套建在STM32F103 HAL库上的完整固件源码,覆盖了I2C、TIM、ADC、Flash等多个外设模块,几乎把一块T12控制板能用到的外设都占了。适合两类人:一是正在用STM32做温控类项目的,可以参考它的ADC滤波、PID参数和过零触发逻辑;二是手头有T12手柄和可控硅板子,想省掉市面上几十块钱控制板成本、自己写固件的人。
从文件结构看,项目用的是标准HAL库加定时器、ADC的中断或DMA方式,没有引入复杂的RTOS,代码组织和外设分层都比较清晰,可以直接在STM32CubeIDE或Keil里编译烧录。接下来的内容会按照这套源码实际涉及的硬件链路,从采样、控制、输出到排错逐一拆解,末尾还会给出几个能在调试台上直接用的参数整定技巧。
2. 烙铁头控温逻辑:ADC采样、冷端补偿与PID模型
2.1 热电偶毫伏信号与ADC量程分配
T12烙铁头的热电偶输出大约在室温下为0mV,300℃时约10mV,400℃时约14mV,信号幅度非常小。STM32F103的ADC输入范围是0到3.3V,12位分辨率下LSB对应约0.8mV,直接采样热电偶信号等于拿大炮打蚊子,200℃和300℃之间只差几十个LSB,噪声稍微一抖温度就飘了。
所以固件里必须有信号调理的配合。常见做法是先经过一级运放把热电偶信号放大到100倍左右,再加一个偏置电压把静态工作点抬到ADC量程中段。项目源码里stm32f1xx_hal_adc.c和adc_ex.c两个文件的配置就是围绕这条路展开的。ADC的采样通道、采样时间、连续转换模式都需要根据前级运放的增益去反推。例如放大100倍后,400℃对应约1.4V,加上1.65V偏置会顶到3.05V,比较接近满量程但留了余量,这个设计是合理的。
ADC配置时有一个关键参数容易忽视:采样时间。STM32F103的ADC采样时间最短可以设到1.5个周期,但热电偶信号源内阻高,尤其是经过运放后,源阻抗仍然可能有几千欧姆,采样时间太短会导致采样电容充不满,读出来的数值呈现非线性偏差。建议把采样时间设到28.5周期以上,在1152个时钟周期下大约需要28μs一次采样,对于控温环路10ms周期来说完全够用。
// ADC初始化核心参数(STM32CubeMX生成的HAL代码基础上修改) hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; // 单通道模式 hadc1.Init.ContinuousConvMode = DISABLE; // 非连续转换,避免CPU忙等 hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 用定时器触发,固定采样节奏 hadc1.Init.NbrOfConversion = 1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8; sConfig.Channel = ADC_CHANNEL_0; // 热电偶信号接在PA0 sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; // 55.5周期,兼容高内阻源这段配置里ExternalTrigConv用软件触发是临时方案,实际项目里建议改成定时器触发,这样采样时刻和可控硅过零点保持固定相位关系,能显著降低工频干扰。
2.2 冷端补偿为什么不能省
T12手柄的冷端在航空插头附近,环境温度变化会直接影响热电偶的绝对测量值。如果固件不做冷端补偿,夏天和冬天同一设定温度下实际烙铁头温度能差到20℃以上。
补偿方式有两种,一种是在航插冷端放一个NTC或者DS18B20,读取环境温度后查表补偿热电偶冷端电势;另一种是数字温度传感器直接读取冷端温度,在PID的期望值侧做等效换算。源码中如果只看到ADC和I2C的外设文件,大概率走的是第二种方案——I2C挂载数字温度传感器。
补偿计算的核心逻辑是:把目标温度换算成对应的毫伏值,加上冷端温度对应的毫伏补偿量,再反查或拟合出目标热端温度对应的“原始毫伏电压”,PID的偏差就基于这个补偿后的电压值计算。
// 冷端补偿与目标值换算,伪代码示意 float target_temp = 350.0f; // 用户设定目标温度,单位℃ float cold_temp = read_sensor_temp(); // 读取冷端温度,例如25℃ // 热电偶分度表查表或拟合函数 float target_mv = tc_temperature_to_mv(target_temp); float cold_comp_mv = tc_temperature_to_mv(cold_temp); // 补偿后的ADC期望值(假设运放增益gain=100,偏置offset_mv=1650mV) float target_adc_value = ((target_mv + cold_comp_mv) * 100.0f + 1650.0f) / 3300.0f * 4095.0f;这里用的是线性叠加原理,严格来说热电偶的热电势与温度呈非线性关系,但在300℃到450℃的工作区间内,拟合误差可以控制在2℃以内。
注意:target_mv和cold_comp_mv的单位必须一致,且都是绝对温度对应的毫伏值,不能用相对温差代替。
2.3 PID用位置式还是增量式
T12焊台的加热对象是几十克重的铜合金烙铁头,热容小,热惯性低,pid参数如果按照普通温控器的经验值去调,很容易出现反复过冲和震荡。比较好的策略是位置式PID + 输出限幅 + 积分分离。
位置式PID的输出直接对应可控硅的导通角或斩波周期数,语义直观,便于加抗饱和逻辑。增量式虽然对执行器有天然保护,但在这个场景下输出量的绝对值和可控硅导通周期直接对应,增量式换算反而多一步,调试时不如位置式直观。
float pid_update(float setpoint, float measured) { float error = setpoint - measured; // 积分分离:误差过大时禁止积分,防止饱和 if (fabs(error) > 50.0f) { integral = 0.0f; } else { integral += error * dt; } float derivative = (measured - last_measured) / dt; // 对测量值微分,避免设定值突变冲击 float output = kp * error + ki * integral - kd * derivative; // 输出限幅:对应0%到100%加热功率 if (output > 100.0f) output = 100.0f; if (output < 0.0f) output = 0.0f; last_measured = measured; return output; }代码里对微分项的处理是常规做法,对测量值求导而不是对误差求导,避免设定温度一步跳变时产生微分尖峰。另外积分分离的阈值不是固定不变的,如果冷机启动时目标温度和室温差出300℃,50℃阈值虽然能抑制超调,但会让升温慢,常见做法是阈值随误差动态变化,或者用变速积分。
PID采样周期dt不能太大,T12烙铁头的时间常数大约在2秒左右,采样周期超过50ms之后控制质量明显下降。建议把PID计算放在一个10ms的定时器中断里,ADC取样的抖动问题通过DMA或固定触发源解决。
3. HAL库工程在STM32F103上的搭建与关键代码
3.1 从标准库到HAL库的迁移要点
压缩包里stm32f1xx_hal_i2c.c、stm32f1xx_hal_tim.c、stm32f1xx_hal_flash_ex.c这些文件说明项目是基于STM32CubeMX生成的HAL工程,工程里用到的外设和T12焊台的硬件资源是对应的:定时器负责产生PWM和过零检测的时间基准,ADC读取热电偶反馈,I2C挂载温度传感器或者EEPROM,Flash则用来保存PID参数和校准偏置。
用HAL库构建这类项目比用标准库的明显优势在于外设初始化代码是自动生成的,时钟树、引脚复用不用自己手动寄存器级配置,聚焦点在业务逻辑上。但代价是HAL库的抽象层会引入性能损耗,比如ADC转换完成回调是在中断上下文执行的,如果回调里做了浮点PID运算,整个系统的中断延迟会变大。所以结构上要把采样和PID计算分开:中断里只做标志位和原始数据搬运,主循环里做浮点运算。
// 定时器中断回调:只做采样触发与标志置位 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM3) { // 10ms控制周期定时器 sampling_flag = 1; // 主循环轮询该标志位 } } // 主循环中的PID计算 while (1) { if (sampling_flag) { HAL_ADC_Start(&hadc1); if (HAL_ADC_PollForConversion(&hadc1, 1) == HAL_OK) { raw_adc = HAL_ADC_GetValue(&hadc1); temperature = process_temperature(raw_adc); pwm_duty = pid_update(target_temp, temperature); update_pwm_duty(pwm_duty); } sampling_flag = 0; } }但这种轮询方式要注意ADC转换时间,HAL_ADC_PollForConversion的第二个参数是超时时间,单位毫秒。如果ADC配置了55.5周期的采样时间加12.5周期的转换时间,总时间大约在十几微秒量级,1ms超时足够了。如果把超时设到10ms会导致主循环其他任务被阻塞太久,影响按键响应和显示刷新。
3.2 定时器PWM输出频率:选10kHz还是100Hz
T12焊台的加热负载是发热芯,等效电阻8Ω左右,属于纯阻性负载,适合用PWM控制通断时间比。但直接控制市电的器件是可控硅,可控硅一旦触发导通,必须要等电流过零才能关断,所以PWM输出不能像驱动LED那样高频,不然可控硅会一直处在半导通状态,发热芯实际功率严重不可控。
这里有两个策略,一个是用低频PWM调制市电周期数,比如加热100ms、停止50ms,通过TIM输出一个6.67Hz的方波驱动可控硅的触发电路;另一个是用过零检测同步,市电每半个周期检测到过零点后,延迟α角度触发可控硅,调节α来改变功率。低频PWM方式实时性差,但胜在代码简单,对PID输出做限幅和线性换算很直接。项目中stm32f1xx_hal_tim.c和tim_ex.c两个文件同时在场,说明定时器配置不止一路,很可能一路输出低频PWM做功率控制,另一路做ADC采样触发或者用于过零检测的输入捕获。
// 定时器PWM输出配置:50Hz周期,占空比由PID输出控制 void update_pwm_duty(float duty_percent) { // 假设TIM2用于PWM输出,自动重装载值对应100%占空比 uint32_t compare_value = (uint32_t)(duty_percent / 100.0f * (TIM2_ARR + 1)); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, compare_value); }需要注意的是,跨平台的PWM参数不能直接用百分比整定。脉冲数量方式更适合:以100ms为控制窗口,窗口内包含5个完整市电周期(50Hz),PID输出0到100映射为0到5个周期导通。这样每次PID计算的结果在窗口边界处只改变一次状态,可控硅的导通和关断都不会产生半周期波形,EMC干扰也小得多。
3.3 Flash参数存储:PID参数和校准值的持久化
stm32f1xx_hal_flash_ex.c在工程里的角色是参数存储。焊台的PID参数、冷端补偿校准值、温度示数校准值这些数据如果每次上电都重新设置就太蠢了,必须有掉电保存机制。STM32F103内部Flash容量一般有256KB以上,尾部几个扇区拿来存参数完全够用,不需要外挂EEPROM。
Flash写入有几个坑需要注意。F103的Flash按页擦除,一页大小是1KB(小容量)或2KB(中容量),但写操作可以按32位半字进行。写入前必须确保目标地址是擦除过的,否则写进去的数据是乱的。另外Flash写操作期间CPU不能执行Flash取指,所以写入函数要放到RAM里执行,或者用HAL库自带的FLASH接口加上适当的延时处理。
// 写入一组校准参数到Flash typedef struct { float kp; float ki; float kd; int16_t temp_calib_offset; uint16_t crc; } tx_params_t; void save_params(tx_params_t *params) { // 计算简单CRC16校验 params->crc = calc_crc16((uint8_t*)params, sizeof(tx_params_t) - 2); HAL_FLASH_Unlock(); // 擦除最后一个页 FLASH_EraseInitTypeDef erase_cfg = { .TypeErase = FLASH_TYPEERASE_PAGES, .PageAddress = PARAM_BASE_ADDR, .NbPages = 1 }; uint32_t page_err = 0; HAL_FLASHEx_Erase(&erase_cfg, &page_err); // 按64位写入(F103支持双字编程) HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, PARAM_BASE_ADDR, *(uint64_t*)params); HAL_FLASH_Lock(); }参数存储里最容易忽略的是C语言结构体对齐问题。上面代码里把struct内容直接全部拷贝到Flash,如果结构体里有float又有int16_t,编译器会填充字节对齐空隙,数据大小在不同编译器版本下可能不一致。严谨的做法是在结构体声明前加#pragma pack(push, 1),或者干脆定义一个字节数组手动组装,避免灾难性的兼容性问题。
4. 过零检测与PWM输出:可控硅调功的时序细节
4.1 过零检测电路与MCU引脚保护
T12焊台的加热执行链路是:单片机GPIO -> 光耦MOC3021 -> 双向可控硅BT136 -> 手柄发热芯。可控硅过零触发的先决条件是MCU能感知市电过零时刻,否则PWM输出和电网相位不同步,轻则功率不准,重则加热一半老半天电压上不来或者闪断。
过零检测的典型电路是从市电经过高阻电阻降压(比如两个220kΩ串联)后,接到光耦的发光二极管端,光耦次级在过零附近输出一个窄脉冲到MCU的EXTI输入引脚。脉冲宽度和光耦的CTR相关,通常会有100μs到500μs的宽度,MCU侧要做的就是在上升沿或者下降沿触发中断后开始计时。
// EXTI中断回调:记录过零时刻 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == ZERO_CROSS_PIN) { zero_cross_time = HAL_GetTick() + __HAL_TIM_GET_COUNTER(&htim2) / 1000.0f; // 高精度时间戳 zero_cross_valid = 1; } }但这个方案的精度取决于中断响应时间和定时器分辨率。STM32F103的定时器最高工作在72MHz,1μs分辨率不难达到,过零检测电路本身的光耦延迟会有几百纳秒到几微秒,对于T12焊台这种热惯性系统完全够用。注意MCU引脚要加齐纳二极管或钳位电路,光耦输出瞬间和电网共地时会有一个很大的共模干扰脉冲,不保护好容易把IO口打坏。
4.2 半周期控制还是全周期控制
之前提到过用100ms窗口内导通周期数来控制功率,还有一种更精细的方案是半周期控制。50Hz市电每10ms一个半波,如果MCU过零中断跟得上每个半波,就能实现最小10ms颗粒度的功率调节。PID输出0到100映射到每个半波是否导通,150℃低温段可以三个半波通一个,350℃高温段五个半波通四个,纹波和温度波动都远小于全周期控制。
半周期控制的问题在于软件复杂度上升:过零中断10ms一次,每次中断里要根据当前占空比和相位位置决定本次要不要触发可控硅。程序的状态机要维护一个半波计数器,计数器超过周期总数后重新从0开始。为了平均功率的稳定性,导通半波的位置要在周期内均匀分布,不能全部挤在前面。
// 半周期控制状态机 volatile uint8_t half_wave_count = 0; volatile uint8_t duty_half_waves; // 每个控制周期内导通的半波数 void zero_cross_isr(void) { half_wave_count++; if (half_wave_count >= CONTROL_CYCLE_HALF_WAVES) { half_wave_count = 0; } // 均匀分布导通半波:导通索引由duty和周期数共同决定 uint8_t threshold = (uint16_t)duty_half_waves * (half_wave_count + 1) / CONTROL_CYCLE_HALF_WAVES - (uint16_t)duty_half_waves * half_wave_count / CONTROL_CYCLE_HALF_WAVES; if (threshold == 1) { HAL_GPIO_WritePin(TRIAC_DRIVE_PIN, GPIO_PIN_SET); // 触发可控硅 } else { HAL_GPIO_WritePin(TRIAC_DRIVE_PIN, GPIO_PIN_RESET); } }这段逻辑用的是Bresenham直线算法的变体,本质是把duty_half_waves个导通位置在N个半波周期里尽量均匀铺开,避免集中的间歇加热。触发引脚每次电平翻转后再加一小段延时拉低,确保MOC3021的触发电流维持足够时间让可控硅可靠导通。
注意:可控硅触发脉冲宽度不能太长,超过半波时间的10%就可能在下半波误触发。实测BT136的触发保持时间在几百微秒量级,1ms的脉冲宽度已经非常可靠。
4.3 PWM频率与过零同步的协调
如果采用低频PWM直通控制方式,PWM的周期必须与市电周期严格同步。假设PWM周期设为100ms,正好是5个市电周期,PWM输出高电平时加热,低电平时停热,但同步性要求PWM周期起始时刻必须在过零中断里对齐。最好的做法是PWM定时器不进普通计数模式,而是在过零中断里对定时器计数器清零并重新加载ARR值,这样PWM和过零之间不会累计相位漂移。
HAL库对这种情况有一个便捷机制,就是定时器的Gated Slave Mode配合外部触发信号。过零信号接到定时器的从模式输入上,定时器只在过零脉冲到来后重新启动计数,这样PWM输出天然和市电同步。源码里的stm32f1xx_hal_tim_ex.c会包含TimerEx的扩展功能配置,这类从模式配置就是在tim_ex文件中实现的。
// TIM2从模式配置:外部信号触发重启计数 TIM_SlaveConfigTypeDef sSlaveConfig = {0}; sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED; sSlaveConfig.InputTrigger = TIM_TS_TI1FP1; HAL_TIM_SlaveConfigSynchro(&htim2, &sSlaveConfig);配置完成后,PWM的起始边沿和过零点的误差只取决于信号路由延迟,通常是纳秒级,不再受软件中断响应时间的抖动影响。
5. 手柄识别与休眠唤醒:软件和阈值的处理
5.1 手柄型号识别与温度校准查表
T12手柄和不同型号的烙铁头(比如TS-I尖头、TS-B弯头、TS-K刀头),它们的发热芯功率和热电偶曲线存在细微差异。固件里若要做药品级控温,就需要支持多套校准表。但项目压缩包里没有看到传感器相关的库文件,用手柄内置的NTC电阻值来识别型号是一个省成本的方案:每款手柄在航插的特定针脚上焊接不同阻值的电阻,STM32通过ADC读取分压值就能判断烙铁头类型。
手柄识别和热插拔检测是两回事。热插拔要求在休眠期间持续给手柄供一个微安级别的检测电流,风扇或LED状态变化时MCU要能感应到。注意T12发热芯冷态电阻约8Ω,热态电阻约3Ω,热插拔瞬间触点抖动会反射出假的电阻跳变,软件里要做至少三到五次连续读取防抖判断。
// 手柄热插拔检测防抖示例 uint8_t detect_soldering_iron(void) { static uint8_t stable_count = 0; uint8_t present = (read_handle_resistance() < HANDLE_R_MAX); if (present) { if (stable_count < 5) stable_count++; } else { if (stable_count > 0) stable_count--; } return (stable_count >= 5) ? 1 : 0; }阈值判断逻辑里有很常见的一个坑:HANDLE_R_MAX要根据供电电压和分压电阻的容差来动态计算,不能写死。电池供电的设备电压会从4.2V掉到3.3V,同一个手柄在不同电压下测到的ADC值不同,阈值如果不跟着基准电压走,会误判手柄拔出。常用的做法是每100ms测一次VREF,实际阈值 = 固定比例 × 当前VREF。
5.2 休眠策略与运动传感器
T12焊台的休眠逻辑通常有两种触发方式,一是拿起烙铁时手柄上的振动开关触发唤醒,二是长时间无操作自动降低温度到休眠设定值(比如180℃)。振动开关的处理在MCU侧就是EXTI外部中断,配置为上升沿和下降沿都触发,同时带一个几十毫秒的软件消抖。
休眠降温的速率要控制好,从350℃降到180℃如果直接让PID输出归零,烙铁头依然会因为热惯性继续往下冲,到150℃再反弹回来,会出现欠冲。更好的做法是设置一个降温斜坡,每秒降低5℃到10℃,让系统在准平衡态下降温,这样进入休眠状态时温度正好稳定在目标值附近,重新唤醒时升温也快。
// 休眠降温斜坡逻辑:每100ms运行一次 void sleep_temp_control(uint32_t tick) { static uint32_t last_step = 0; if (tick - last_step < 100) return; // 100ms步进一次 target_temp -= 1; // 每100ms降1℃,即10℃/s if (target_temp < SLEEP_TEMP) target_temp = SLEEP_TEMP; last_step = tick; }这个斜坡速率要根据烙铁头的热容调整。铜头热容大,降温时实际温度和设定值偏差也大,用10℃/s的斜坡会追不上,反而把PID输出拉满又导致温度反弹。我见过不少项目在开机快速升温时效果很好,休眠唤醒几次之后温度漂移越来越明显,问题就出在这个斜坡速率和PID饱和的配合上。
5.3 待机功耗与低功耗模式取舍
T12焊台很多是便携版本,用3S锂电池供电。如果休眠时MCU还在全速跑着PID和ADC,整机功耗可能在几十毫瓦以上,静置一晚上就没电了。STM32F103有Sleep、Stop和Standby三种模式,考虑到需要保持参数RAM不丢,Stop模式更合适,可以在2μA左右维持内存供电。
进入Stop模式前要把ADC、定时器、可控硅驱动引脚全部处理干净,尤其注意可控硅驱动引脚要拉到确定电平,避免MCU停止运行后引脚浮空导致光耦误触发。唤醒源可以用EXTI接振动开关,或者定时器唤醒,RTC唤醒最稳。
// 进入Stop模式前的准备工作 void enter_stop_mode(void) { HAL_ADC_Stop(&hadc1); HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); HAL_GPIO_WritePin(TRIAC_DRIVE_PIN, GPIO_PIN_RESET); // 确保关闭触发 HAL_SuspendTick(); // 暂停HAL时基 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 唤醒后重新配置系统时钟 HAL_ResumeTick(); SystemClock_Config(); }HAL库的HAL_PWR_EnterSTOPMode有个容易踩的坑:进入Stop前必须调用HAL_SuspendTick,否则SysTick中断会在WFI后立刻唤醒MCU,休眠直接失效。唤醒后还要调用SystemClock_Config重新初始化时钟,因为F103从Stop模式恢复后默认回到HSI运行,外部晶振的PLL配置全部丢失。
6. 硬件排错与参数整定:从波形到代码的调试技巧
6.1 用示波器验证ADC采样信号链
拿到一块T12控制板,先别急着烧程序,第一步用示波器看ADC输入引脚的波形。热电偶信号经过放大和偏置后,应该是一条干净的直流电平,叠加很小的工频纹波。如果波形上有明显的毛刺尖峰,多半是运放电源去耦不够,或者PCB上热电偶走线和可控硅驱动走线挨得太近。
用示波器直流耦合档看波形时,要同时记录下加热和停止加热两种状态下的电平。两者不应该有明显跳变,如果加热时ADC输入电平被拉低了,说明电源或地平面有大的压降,根源是可控硅导通瞬间冲击电流把模拟地电位抬高了。这种情况换再好的运放也没用,必须改PCB布局,把功率地和小信号地在单点汇合。
电压信号确认没问题后,再用ADC悬空时的读数验证MCU侧的稳定性。把ADC输入短到VREF,连续读取100次,应该全部落在4095附近且抖动不超过±3个LSB。抖动量级如果到了±10 LSB,就要检查VREF引脚上的退耦电容,F103的VREF对噪声很敏感,建议至少放一个100nF加4.7μF。
6.2 PID参数整定顺序表
T12焊台的PID整定要比普通加热块更小心,因为烙铁头升温太快、回温太猛,直接从经验值起步容易把可控硅打到满功率然后温度飞掉。下面这张表是我自己用的整定顺序,从纯P到PID逐级往上加:
| 参数调整步骤 | Kp | Ki | Kd | 预期观察现象 | 异常情况检查 |
|---|---|---|---|---|---|
| 第1步:纯P粗整 | 从2.0开始,每次加0.5 | 0 | 0 | 设置目标温度后3秒内温度逼近但稳定在目标下方3~5℃ | 温度持续为正弦振荡时降低Kp |
| 第2步:KI消除稳态差 | 固定上一步Kp不变 | 0.05起步,0.02递增 | 0 | 稳态误差缓慢消失,稳定在±1℃以内 | 出现低频呼吸式波动时减小Ki |
| 第3步:KD抑制超调 | Kp和Ki不变 | 不变 | 0.5起步,0.3递增 | 升温曲线过冲减小,响应依然迅速 | 高频抖动如果出现,检查微分滤波 |
| 第4步:综合微调 | 微调Kp +0.2 | 微调Ki -0.01 | 微调Kd +0.2 | 350℃设定下1分钟内稳定,冷端补偿进入有效区间 | 超调>5℃时优先增加Kd,振荡时减少Kp |
实际整定时有个容易忽略的点:Kd参数要配合测量值的低通滤波,滤波截止频率设太低会把微分作用过滤掉,设太高又把噪声拖进控制环路。一阶低通滤波器的时间常数取控制周期的5到10倍比较合适,这个项目里控制周期10ms,滤波时间常数50~100ms即可。
6.3 过零脉冲丢失时的关键检查
过零检测是T12焊台的命脉,脉冲如果丢失,固件输出直接瘫痪。排查时先用示波器看MCU的过零引脚,波形应该是60Hz或50Hz的方波,高低电平各占一半左右。如果波形正常但固件里检测不到,多半是EXTI配置的引脚和实际连接对不上,或者IO口没有配置成输入模式。
另一种情况:过零脉冲正常但偶尔丢一个,PID输出功率低。这和可控硅的触发时序有关系。过零脉冲检测到后,MCU延时α角度触发可控硅,但触发脉冲的宽度如果不够,或者MOC3021的LED电流不足,会导致部分半波没有被触发成功。检查MOC3021输入端的限流电阻,3.3V逻辑电平最好串220Ω,20mA电流才足够可靠触发。
6.4 手柄电阻分压验证Tip识别
手柄识别如果用了NTC电阻方案,调试时的标准流程是:拔下手柄,量一下航空插头对应引脚间的电阻值,记住这个值。再把手柄插上,读取MCU的ADC原始值。两者之间的比例关系就是分压电阻的比值,如果不匹配,检查分压电阻的焊盘是否有虚焊。
电阻识别还有一个常被忽略的点:手柄在冷态和热态时NTC的阻值会变化,NTC在25℃时10kΩ,在100℃时可能掉到1kΩ。如果选择的手柄识别阈值没有留足余量,焊台工作时手柄握把温度上来后,识别结果可能会漂移成错误的型号,导致补偿曲线用错。阈值设计至少要覆盖冷态到热态全范围的中间值。
// 手柄类型查表判断 typedef struct { uint16_t adc_min; uint16_t adc_max; uint8_t tip_type; } tip_map_t; const tip_map_t tip_table[] = { {3000, 3500, TIP_TS_I}, // 尖头:典型ADC值3250 {2200, 2700, TIP_TS_B}, // 弯头:典型ADC值2450 {1400, 1900, TIP_TS_K}, // 刀头:典型ADC值1650 }; uint8_t identify_tip(uint16_t adc_val) { for (int i = 0; i < sizeof(tip_table) / sizeof(tip_table[0]); i++) { if (adc_val >= tip_table[i].adc_min && adc_val <= tip_table[i].adc_max) { return tip_table[i].tip_type; } } return TIP_UNKNOWN; }上电时先做一次识别,判断结果是unknown就直接进待机不加热,避免完全没有接手柄时程序把PID输出叠满导致可控硅直通,这一步对安全很重要,也是量产固件上容易漏掉的一道防线。
本文还有配套的精品资源,点击获取