基于PID算法的水箱温度控制系统
1.概述本设计为基于STC89C52单片机的智能水温控制系统,控制对象以500mL陶瓷水箱为容器,并使用PID控制算法来调整水箱中500ml纯净水的温度。水温可以在一定范围内人为设定,并能实现在下限温度到上限温度之间对每个点温度的控制。主要的功能为:可以通过键盘自由设定上限温度和下限温度,通过12864液晶显示,显示的最小区分为1度可以通过DS18B20温度传感器测量水温并通过1286...
1. 概述
本设计为基于STC89C52单片机的智能水温控制系统,控制对象以500mL陶瓷水箱为容器,并使用PID控制算法来调整水箱中500ml纯净水的温度。水温可以在一定范围内人为设定,并能实现在下限温度到上限温度之间对每个点温度的控制。
主要的功能为:
- 可以通过键盘自由设定上限温度和下限温度,通过12864液晶显示,显示的最小区分为1度
- 可以通过DS18B20温度传感器测量水温并通过12864液晶显示水的实际温度,最小区分为0.1度
- 系统应具有在水温下限到水温上限全量程内的加热功能(当水温低于水温下限时开始加热,水温低于水温上限时自动断电停止加热)
- 使用PID控制算法,调节温度
- 存储设定的参数到EEEPROM中,并记录升温曲线(程序中使用DS1302,精确设定时间间隔,使用EEPROM记录升温曲线)
- 可以记录3组参数以及对应的3组升温曲线(每组250个温度数据)
2.硬件设计
本次设计的硬件电路是由STC89C52 单片机为控制核心,通过DS18B20温度传感器采集的温度,传送给单片机进行PID计算,将结果作为PWM的占空比来驱动加热棒;同时,通过LCD12864显示屏、按键和DS1302时钟芯片,可实现温度值的显示和目标温度的设置。整体硬件框图如图所示:
(1)12V转5V稳压电路
由于系统的供电电源采用了4节18650锂电池供电,需要使用LM2596-ADJ芯片进行稳压,转换成12V电压,作为加热棒的加热电源,并通过LM7805-5.0稳压芯片转换为5V电压,作为单片机和其他功能电路的工作电压。稳压芯片的电路可根据芯片技术手册中的参考电路来搭建,其电路图如图:
(2)按键电路
本次设置了4个控制按键,分别为设置键、增加键、减少键和OK键,通过这四个按键,可以根据用户的需求来调整相应的参数。
(3)DS1302时钟电路
DS1302时钟电路可以为系统提供实时年、月、日、星期、时、分、秒。
(4)加热控制电路
加热电路主要三极管及功率MOS管搭建而成的,3个三极管为MOS管的提供可靠的控制电平。如图所示,当单片机引脚为高电平时,三极管T3导通,T2导通,T1截止,从而MOS管的G极接地,MOS管截止;相反,当单片机引脚为低电平时,三极管T3截止,T2截止,T1导通,从而MOS管的G极接电源,MOS管导通,加热棒加热。
其他都相对简单,就不一一解释了。
(5)总体硬件电路图
3. 软件设计
系统软件所需实现的功能主要为:
- 按键输入与设置
- 显示屏界面显示
- PID算法调节
- 时钟读取及显示
(1)按键输入与设置
//*按键处理函数 KEY_Scan
uint8 KEY_Scan(uint8 mode)
{
static uint8 key_up = 1; //按键松开的标志
Button0 = 1;
Button1 = 1;
Button2 = 1;
Button3 = 1;
if(mode == 1)
{
key_up = 1;
}
if(key_up&&(Button0 == 0||Button1 == 0||Button2==0||Button3 == 0)) //第一次读取按键的状态
{
Delay1ms(3); //延时10MS,去抖动
if(key_up&&(Button0 == 0||Button1 == 0||Button2==0||Button3 == 0))//有按键按下
{
key_up = 0; //按键按下的标志
if(Button0 == 0) return Button0_value; //按键0按下
else if(Button1 == 0) return Button1_value; //按键1按下
else if(Button2 == 0) return Button2_value; //按键2按下
else if(Button3 == 0) return Button3_value; //按键2按下
}
}
else if(Button0==1&&Button1==1&&Button2==1&&Button3==1)
{
key_up = 1; //按键松开的标志
}
return 0;
}
/*******************************************************************************
* 函 数 名 : Exint0
* 函数功能 : 外部中断0中断服务函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Exint0 (void) interrupt 0 //外部中断0中断服务程序
{
if(KEY_Scan(1) == Button0_value) //按键0按下
{
LCD_cursor++; //移动光标
}
if(LCD_cursor >= 9)
{
LCD_cursor = 0;
}
if(KEY_Scan(1) == Button1_value)
{
(*Adjustable_Value[LCD_cursor]) ++; //光标对应的数++
//对应数据的限制
if(Low_temp >= High_temp - 1) Low_temp = High_temp-1;
if(Set_temp>=High_temp) Set_temp = High_temp;
if(Read_add>3) Read_add = 1;
if(Write_add>3) Write_add = 1;
}
if(KEY_Scan(1) == Button2_value)
{
(*Adjustable_Value[LCD_cursor]) --; //光标对应的数--
//对应数据的限制
if(High_temp <= Low_temp + 1) High_temp = Low_temp+1;
if(Set_temp<=Low_temp) Set_temp = Low_temp;
if(Write_add<1) Write_add = 3;
if(Read_add <1) Read_add = 3;
}
if(LCD_cursor == 0)
{
if(KEY_Scan(1) == Button3_value)
{
start_warm_flag = 1;
if(temp_save_flag == 1)
{
start_time=readtime[12]*10+readtime[13]; //记录开始时间
start_time = start_time%temp_cycle - 1;
}
}
}
if(LCD_cursor == 1)
{
if(KEY_Scan(1) == Button3_value)
{
start_warm_flag = 0;
temp_save_flag = 0;
}
}
if(LCD_cursor == 3) //光标指向横坐标所在数据时
{
if(KEY_Scan(1) == Button3_value)
{
temp_read_flag = 0;
}
}
if(LCD_cursor == 7) //光标指向读数据位置时
{
if(KEY_Scan(1) == Button3_value) //读按键按下
{
Read_EEPROM_Word(Adjustable_Value,Read_add);
Read_add = Write_add;
LCD12864_WriteCmd(0x01); //清屏
temp_save_flag = 0; //温度保存标志
temp_read_flag = 1; //阅读温度的标志
}
}
else if(LCD_cursor == 8) //光标指向写数据位置时
{
if(KEY_Scan(1) == Button3_value) //写按键按下
{
time = 0; //温度从零地址开始写
Write_Word_EEPROM(Adjustable_Value,Write_add);
temp_save_flag = 1;
temp_read_flag = 0; //温度保存标志
LCD12864_WriteCmd(0x01); //清屏
}
Clear_flag = 1; //清屏标志
}
if(LCD_cursor == 0 && Clear_flag == 1) //光标循环一圈时,清屏
{
LCD12864_WriteCmd(0x01);
Clear_flag = 0;
}
}
(2)PID算法调节
int16 Proportion = 64; // 比例常数 Proportional Const
int16 Integral = 0; // 积分常数 Integral Const
int16 Derivative = 54; // 微分常数 Derivative Const
float LastError; // Error[-1]
float PrevError; // Error[-2]
float SumError; // Sums of Errors
float Now_temp;
float Target_temp;
float Temp_Out;
float PID_Calc(float NextPoint ,float SetPoint)
{
float D_Error,Error;
float II;
Error = SetPoint-NextPoint; //偏差
SumError+=Error; // 积分
D_Error =LastError-PrevError; // 当前微分
PrevError = LastError;
LastError = Error;
II = Integral*SumError/10000.0; //积分缩小10000倍
if(II>30) //积分饱和限制
{
II=30;
}
return (Proportion*Error+II+Derivative*D_Error);
}
void Control_Temp(void)
{
Now_temp = Temp_numbe;
Target_temp = Set_temp;
if(Now_temp>High_temp)
{
PWM_duty = 0;
}
else
{
Temp_Out = PID_Calc(Now_temp,Target_temp);
if(Temp_Out >= 100) Temp_Out = 100;
else if(Temp_Out <=0) Temp_Out = 0;
//不同的温度设置不同的比例补偿热量损失
//Temp_Out = Temp_Out+Target_temp/80.0*20;
PWM_duty = (int)Temp_Out;
}
}
(3)主函数
void main(void)
{
int16 temp; //温度缓存值
System_Init(); //系统初始化
while (1)
{
LED2 = 0;
Ds1302_time();
real_time = readtime[12]*10+readtime[13]; //从1302中读取秒值
real_time = real_time%temp_cycle;
Temp_numbe = Temp_collect(); //采集温度
if(temp_save_flag == 1 && start_warm_flag == 1) //按下了存储按键
{
if((real_time == start_time)&&(real_time- last_real_time!=0)) //每隔10S记录一次时间
{
temp = (int16)(Temp_numbe*100+0.5); //将温度值增大100倍,保留两位小数
Write_DATA_EEPROM(temp,Write_add,time); //将温度写入EEPROM中保存
time++;
if(time >= 250) //最多记录250组的值
{
time = 250;
}
}
}
last_real_time = real_time;
if(start_warm_flag == 1)
{
Control_Temp(); //温度控制函数
}
else
{
PWM_duty = 0;
}
//上限报警
if(Temp_numbe > High_temp) LED0 = 0;
else LED0 = 1;
//下限报警
if(Temp_numbe < Low_temp) LED1 = 0;
else LED1 = 1;
Init_LCD12864_Set(); //LCD12864液晶显示数据的标识
LCD12864_Show_DATA(); //LCD12864液晶显示数据
UART_Send_temp(); //将采集温度并通过串口发送到上位机
//Uart_Send_time(); //将DS1302的时间发送给电脑
UART_Send_PWM(); //将控制加热棒的PEM占空比实时发送监控
UART_SendData('\n');
}
}
详细完整的程序,可下载源码。
源码+AD原理图 下载:关注公众号,首页回复“PID水温控制”获取资料
更多推荐
所有评论(0)