?这是本人在校作品,也是第一次做,还有很多瑕疵,但能够基本实现温控,下文基本是从报告中摘取出来的,报告也挺水的(滑稽)。
摘 要
随着科学的进步,社会的不断发展,智能控制系统已经成为了一种常用的技术,应用在各行各业中,其中恒温控制在工业生产过程中举足轻重,温度的控制直接影响着工业生产的质量。本文聚焦于恒温控制设计出一款恒温箱并通过PID算法来满足系统设计的要求,可以较为精准的实现温度控制功能。设计过程主要有:分析恒温箱的背景;了解其工作原理;主要元器件的选取;总电路图的设计;软件程序的编写;焊接电路;调试运行。主要结构是基于单片机的智能恒温箱,采用STMF103C8T6单片机为主控芯片;DS18B20进行温度检测;OLED显示屏显示系统的信息;通过PID算法调控温度;采用220V?60W白炽灯作为热源,最终达到恒温的功能。
关键字:STM32;DS18B20;PID;恒温控制
1.2 硬件结构框图
?
1.3 电路设计说明
本项目的电路主要组成部分有可控硅控制电路、过零检测电路、DS18B20温度传感器、STM32F103C8T6控制器、变压器、OLED显示屏、电源、灯泡等组成。
可控硅控制电路:可控硅控制电路基本原理是通过控制可控硅的导通角来控制通过加热元件的电流大小。当可控硅导通时,加热元件两端的电压和电流增大,从而产生更多的热量;当可控硅截止时,加热元件两端的电压和电流减小,从而减少热量产生。可控硅控制电路的作用是根据箱内温度的变化来控制加热元件的功率,从而实现箱内温度的稳定控制。当箱内温度低于设定温度时,可控硅控制电路会使加热元件产生更多的热量,从而提高箱内温度;当箱内温度高于设定温度时,可控硅控制电路会使加热元件产生更少的热量,从而降低箱内温度。总之,可控硅控制电路是恒温箱中非常重要的组成部分,它可以实现箱内温度的精确控制和快速调整,从而保证恒温箱的正常工作。
过零检测电路:过零检测电路的基本原理是通过检测交流电源的电压和电流相位差来确定过零点的位置。具体来说,当交流电源的电压和电流相位差为零时,即电压和电流同相位时,称为过零点。在过零点时,交流电源的电压和电流都为零,此时可以进行温度采样和控制信号的传输,从而避免干扰和误差。过零检测电路可以用于温度采样和控制信号的传输。当过零检测电路检测到交流电源的过零点时,它会输出一个信号给控制电路,控制电路会根据这个信号进行温度采样和控制信号的传输,从而实现对箱内温度的精确控制。此外,过零检测电路还可以用于检测交流电源的频率和相位,从而保证恒温箱的正常工作。
?
2.2 硬件电路详图
图2.1 硬件电路链接图
?
软件设计主要逻辑为通过外部中断检测过零点,触发外部中断后将PID输出值写入到计数器并同时使能定时器;定时器设置为采用内部时钟,720分频,计数到1000即总计10ms触发定时器中断,输出一个脉冲信号来导通可控硅从而控制热源并最终实现恒温控制。其中
PID目标值:需要达到的温度
PID反馈值:实时的温度
PID输出值:时间参数,给到计数器。
给出部分主要代码
主函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "DS18B20.h"
#include "PID.h"
#include "Timer.h"
#include "exit.h"
/*
外部电路需要5V供电
外部中断调控定时器中断是否使能
过零检测电路,即外部中断 --PA0
可控硅控制电路,即定时器中断 --PA1
DS18B20 --PB14
OLED SCL --PB8
SDA --PB9
*/
int Temp; //读取的温度参数
float ST=30; //设定温度
int i=0; //标志位
int FLAG=1; //标志位
int main(void)
{
PID_Init();
OLED_Init( );
OLED_ShowChinese(4,1,2);
OLED_ShowChinese(4,2,3);
OLED_ShowString(4, 5, ":");
OLED_ShowNum(4,6,ST,2);
OLED_ShowChinese(2,1,0);
OLED_ShowChinese(2,2,4);
OLED_ShowString(2, 5, ":");
OLED_ShowString(3, 1, "PID:");
DS18B20_Init();
FLAG=DS18B20_Reset();
Delay_s(1);
while(1)
{
if(FLAG==0)
{
OLED_ShowChinese(1,1,0);
OLED_ShowChinese(1,2,1);
Temp=DS18B20_ReadTemp();
if(i==0)
{
PID_Count(Temp/10.0,ST); //传入温度参数!!!并初始化一次
Exit_Init();
Timer_Init();
}
i++;
if(flag==1)
{
OLED_ShowString(1, 5, ":-");
OLED_ShowString(1, 10, ".");
OLED_ShowNum(1,7,Temp/10%100,3);
OLED_ShowNum(1,11,Temp%10,1);
}
else
{
OLED_ShowString(1, 5, ":+");
OLED_ShowString(1, 10, ".");
OLED_ShowNum(1,7,Temp/10%100,3);
OLED_ShowNum(1,11,Temp%10,1);
}
if(i==6)
{
i=1;
PID_Count(Temp/10.0,ST);
}
Delay_ms(10); //50ms计算一次PID
}
else
{
OLED_ShowString(1,1,"No sensor ");
Delay_ms(5);
}
}
}
PID.c:
#include "stm32f10x.h" // Device header
#include "PID.h"
#include "OLED.h"
PID_InitStruct PID;
int PID_OUT = 0;
float PID_OUT_old=0,PID_OUT_new=0;
void PID_Init(void)
{
PID.P= 400; //比例系数 未超调
PID.I= 5; //积分系数
PID.D= 0; //微分系数 不同环境下需要更改
}
void PID_Count(float T, float SetTemp)
{
PID.Last_err=PID.err;
PID.err=SetTemp-T; //计算误差
PID.sum+=PID.err; //积分 误差累计
PID_OUT_old=PID_OUT_new; //上一次输出计算值
PID_OUT_new=PID.P*PID.err+PID.I*PID.sum+PID.D*(PID.err-PID.Last_err);//本次输出计算值
PID.OUT=0.6*PID_OUT_new+(1-0.6)*PID_OUT_old; //加权
if(PID.OUT>999) //周期是10ms 计数1000 999是最大极限
{
PID.OUT=999;
}
else if(PID.OUT<300) //与理论值0~1000有差别 200基本为最低导通亮度 300微亮但0也会亮(未知)
{
PID.OUT=300;
}
OLED_ShowNum(3,5,PID.OUT,3);
OLED_ShowFNum(2,6,PID.err,4,2);
PID_OUT=PID.OUT/1;
}
void EXTI0_IRQHandler(void) //5、中断函数配置 特定名字(在start文件中) 无参无返回 自动触发
{
if(EXTI_GetITStatus(EXTI_Line0)==SET)//判断中断标志位是否触发
{
// TIM_SetCounter(TIM2,0);
TIM_SetCounter(TIM2,PID_OUT); //设置计数器值
TIM_Cmd(TIM2,ENABLE); //使能定时器
EXTI_ClearITPendingBit(EXTI_Line0);//清除中断标志位 否则会一直卡在中断
}
}
?测试过程:
?
?