## 项目概述 智能温控器是嵌入式领域的经典实战项目,它融合了传感器采集、控制算法、人机交互等多个模块。本教程选用STM32F103作为主控,搭配DS18B20温度传感器、固态继电器(SSR)驱动的加热棒,以及0.96寸OLED显示屏,实现目标温度设定、实时温度显示和PID闭环控制。 ## 系统架构与原理 ### 硬件组成 - **主控**:STM32F103C8T6(72MHz,资源丰富) - **温度传感器**:DS18B20(单总线,12位精度,-55~125°C) - **加热执行器**:加热棒(220V/500W)通过SSR控制,SSR由PWM信号驱动 - **显示模块**:SSD1306驱动的OLED(I2C接口,128x64) - **按键**:两个按键用于设定目标温度(加减) ### 控制原理 PID(比例-积分-微分)控制器通过计算偏差的线性组合来调节输出。本系统采用**增量式PID**,输出为PWM占空比的增量,避免积分饱和,适合加热棒这类惯性较大的对象。 公式: ``` Δu = Kp*(e(k)-e(k-1)) + Ki*e(k) + Kd*(e(k)-2*e(k-1)+e(k-2)) ``` 其中e(k)为当前偏差(目标温度-实际温度)。 ## 关键模块实现 ### 1. DS18B20驱动 DS18B20使用单总线协议,时序要求严格。以下为初始化与读取温度的核心代码(使用GPIO模拟时序): ```c // 复位DS18B20 uint8_t DS18B20_Reset(void) { uint8_t presence; GPIO_InitTypeDef gpio; // 配置为输出 gpio.Mode = GPIO_MODE_OUTPUT_OD; gpio.Pin = DS18B20_PIN; HAL_GPIO_Init(DS18B20_PORT, &gpio); HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET); delay_us(480); HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET); delay_us(60); // 配置为输入 gpio.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(DS18B20_PORT, &gpio); presence = HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN); delay_us(420); return presence; // 0表示存在 } // 读取温度(12位精度) float DS18B20_ReadTemp(void) { uint8_t tempL, tempH; int16_t temp; DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过ROM DS18B20_WriteByte(0x44); // 启动转换 while(DS18B20_ReadBit()==0); // 等待转换完成 DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读取暂存器 tempL = DS18B20_ReadByte(); tempH = DS18B20_ReadByte(); temp = (tempH << 8) | tempL; return temp * 0.0625; // 12位分辨率 } ``` ### 2. 温度滤波 由于环境噪声,采样值需滤波。采用滑动平均滤波(窗口5): ```c #define FILTER_SIZE 5 float filter_buf[FILTER_SIZE]; uint8_t filter_index = 0; float Temperature_Filter(float new_val) { float sum = 0; filter_buf[filter_index] = new_val; filter_index = (filter_index + 1) % FILTER_SIZE; for (int i = 0; i < FILTER_SIZE; i++) sum += filter_buf[i]; return sum / FILTER_SIZE; } ``` ### 3. 增量式PID控制器 ```c typedef struct { float Kp, Ki, Kd; float target, actual; float err, last_err, prev_err; float output; // 占空比增量 } PID_TypeDef; void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd) { pid->Kp = kp; pid->Ki = ki; pid->Kd = kd; pid->err = pid->last_err = pid->prev_err = 0; pid->output = 0; } float PID_Calc(PID_TypeDef *pid, float target, float actual) { pid->target = target; pid->actual = actual; pid->prev_err = pid->last_err; pid->last_err = pid->err; pid->err = target - actual; // 增量式输出 pid->output += pid->Kp*(pid->err - pid->last_err) + pid->Ki*pid->err + pid->Kd*(pid->err - 2*pid->last_err + pid->prev_err); // 限幅(0~100%占空比) if (pid->output > 100) pid->output = 100; if (pid->output < 0) pid->output = 0; return pid->output; } ``` ### 4. PWM控制加热棒 使用定时器2产生20kHz的PWM,通过比较值控制占空比。SSR需要低电平触发,因此PWM极性需配置为反相。 ```c // 初始化PWM void PWM_Init(void) { TIM_HandleTypeDef htim2; TIM_OC_InitTypeDef sConfig; __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance = TIM2; htim2.Init.Prescaler = 72-1; // 1MHz计数频率 htim2.Init.Period = 50-1; // 20kHz HAL_TIM_PWM_Init(&htim2); sConfig.OCMode = TIM_OCMODE_PWM1; sConfig.Pulse = 0; // 初始0%占空比 sConfig.OCPolarity = TIM_OCPOLARITY_LOW; // 反相,低电平有效 HAL_TIM_PWM_ConfigChannel(&htim2, &sConfig, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); } // 设置占空比(0~100) void PWM_SetDuty(uint8_t duty) { __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, duty*50/100); } ``` ### 5. OLED显示 使用SSD1306库,显示目标温度、实际温度、PID输出和状态。 ```c void OLED_Display(float target, float actual, float duty) { char buf[20]; OLED_Clear(); OLED_ShowString(0, 0, "Smart Temp Ctrl"); sprintf(buf, "Target: %.1f C", target); OLED_ShowString(0, 2, buf); sprintf(buf, "Actual: %.1f C", actual); OLED_ShowString(0, 4, buf); sprintf(buf, "PWM: %.0f%%", duty); OLED_ShowString(0, 6, buf); OLED_Refresh(); } ``` ## 主程序与PID参数整定 主循环每200ms读取温度、计算PID并更新PWM。按键中断调整目标温度。 ```c int main(void) { HAL_Init(); SystemClock_Config(); // 初始化各模块... PID_TypeDef pid; PID_Init(&pid, 20, 0.5, 5); // 初始参数 float target = 50.0; while (1) { float temp = Temperature_Filter(DS18B20_ReadTemp()); float duty = PID_Calc(&pid, target, temp); PWM_SetDuty((uint8_t)duty); OLED_Display(target, temp, duty); HAL_Delay(200); } } ``` **参数整定经验**: - 先设Ki=Kd=0,增大Kp直到系统振荡,记录临界Kp和振荡周期Tu。 - 然后按Ziegler-Nichols法:Kp=0.6*Kp_crit,Ki=2*Kp/Tu,Kd=Kp*Tu/8。 - 微调:若超调大,减小Kp或增大Kd;若稳态误差大,增大Ki。 ## 注意事项 - **安全第一**:加热棒接220V,务必使用SSR隔离,并加装保险丝和过热保护。 - **DS18B20时序**:单总线对延时敏感,建议使用定时器或DWT精确延时,避免被中断干扰。 - **PID输出限幅**:防止积分饱和,增量式已天然抗饱和,但输出仍需限幅。 - **电源隔离**:数字电路与加热电路分开供电,避免干扰。 - **调试技巧**:通过串口打印温度与PWM值,用上位机绘制曲线,便于观察响应。 ## 总结 通过本实战,你已掌握智能温控器的完整设计流程。从传感器驱动到PID算法,再到PWM控制与显示,每个环节都至关重要。你可以进一步扩展:加入WiFi远程监控、模糊PID自适应、或改用更高级的加热方式。动手实践吧,让温度控制变得精准而智能!