功能介绍:
0本系统采用STC89C52作为单片机
1液晶实时显示当前温度和设定温度值
2可通过旋钮设定温度,设定范围30~80℃
3当温度超出设定温度±1.5℃时,蜂鸣器报警提醒
4按键可设定PID参数
5.采用DC002作为电源接口可直接输入5V给整个系统供电
原理图:
PCB :
主程序:
#include "reg52.h"
#include "tlc0832.h"
#include "delay.h"
#include "math.h"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define T25 (273.15+25) //T25
#define Bx (4050.0) //B值
#define Ka (273.15) //绝对零度
#define Rp (10000.0) //ntc串联电阻
#define ntcR25 (10000.0) //25度时电阻
/*****************引脚定义*********************************/
// 继电器控制
sbit RELAY_HEAT = P1^3;
sbit RELAY_COOL = P1^4;
/********************************/
// lcd液晶
sbit LCD_RS = P3^5;
sbit LCD_EN = P3^6;
/********************************/
//蜂鸣器
sbit SPEAKER = P3^7;
/*****************变量定义(声明)*********************************/
int freq = 500, pwm = 0;
uchar setflag = 0, pageflag = 0, ok = 0;
float set_temp = 0;
float KP = 100, KI = 10, KD = 0;
uint pul_count = 0;
float ek = 0, ek1 = 0, ek2 = 0;
float keytemp = 0;
uchar code str[16] = " welcome! ";
uchar code str1[16] = " temperature PID";
uchar code str2[16] = "set-T now-T ";
uchar code str3[16] = "P: I: D:";
uchar code str4[16] = "set-P: ";
uchar code str5[16] = "set-I: ";
uchar code str6[16] = "set-D: ";
void Init(void); //初始化函数
float ReadTemp(void); //读取温度
void delay(uint n);
void writecom(uchar com); //LCD写命令
void writedata(uchar date); //LCD写数据
void initlcd(); //初始化LCD
float keyscan(void); //按键扫描
//uchar keyscans(void);
void lcdnumdisplay(uchar pos, double f); //LCD显示
void lcdnumdisplays(uchar pos, double f); //LCD显示
//uint read_pul();
void mypid(float Kp, float Ki, float Kd, uint count, uint point); //PID
void main()
{
uchar i;
float scantemp;
float adnum0 = 0;
float temperature = 0;
bit init0, init1, init2, init3, init4;
Init();
initlcd();
writecom(0x80);
for (i = 0; i < 16; i++)
writedata(str[i]);
writecom(0x80 + 0x40);
for (i = 0; i < 16; i++)
writedata(str1[i]);
delay(2000);
while (1)
{
if (setflag == 0) //
{
adnum0 = ReadADC(AIN1_GND); //读取AD值
temperature = ReadTemp(); //读取温度
if (init0 == 0)
{
initlcd();
writecom(0x80);
for (i = 0; i < 16; i++)
writedata(str2[i]); //显示温度
init0 = 1;
init1 = 0;
init2 = 0;
init3 = 0;
init4 = 0;
}
lcdnumdisplays(0x80 + 0x40, (float)set_temp); // set_temp
lcdnumdisplays(0x80 + 0x4a, (float)temperature);
}
if (setflag != 0 && pageflag == 0) //显示PID参数
{
if (init1 == 0)
{
initlcd();
writecom(0x80);
for (i = 0; i < 16; i++)
writedata(str3[i]);
init0 = 0;
init1 = 1;
init2 = 0;
init3 = 0;
init4 = 0;
}
lcdnumdisplays(0x80 + 0x40, KP);
lcdnumdisplays(0x80 + 0x46, KI);
lcdnumdisplays(0x80 + 0x4D, KD);
}
if (setflag != 0 && pageflag == 1) //设置P
{
if (init2 == 0)
{
initlcd();
writecom(0x80);
for (i = 0; i < 16; i++)
writedata(str4[i]);
init0 = 0;
init1 = 0;
init2 = 1;
init3 = 0;
init4 = 0;
}
lcdnumdisplays(0x80 + 0x40, scantemp);
if (ok == 1)
{
KP = scantemp;
ok = 0;
}
}
if (setflag != 0 && pageflag == 2) //设置I
{
if (init3 == 0)
{
initlcd();
writecom(0x80);
for (i = 0; i < 16; i++)
writedata(str5[i]);
init0 = 0;
init1 = 0;
init2 = 0;
init3 = 1;
init4 = 0;
}
lcdnumdisplays(0x80 + 0x40, scantemp);
if (ok == 1)
{
KI = scantemp;
ok = 0;
}
}
if (setflag != 0 && pageflag == 3) //设置D
{
if (init4 == 0)
{
initlcd();
writecom(0x80);
for (i = 0; i < 16; i++)
writedata(str6[i]);
init0 = 0;
init1 = 0;
init2 = 0;
init3 = 0;
init4 = 1;
}
lcdnumdisplays(0x80 + 0x40, scantemp);
if (ok == 1)
{
KD = scantemp;
ok = 0;
}
}
set_temp = 100 * (float)(adnum0) / 255 - 20;
// pwm=set_temp;
mypid(KP, KI, KD, temperature, set_temp);
if (temperature >= set_temp - 1.5 && temperature <= set_temp + 1.5) //在温度范围以内,关闭蜂鸣器
{
SPEAKER = 1;
}
else //否则开启蜂鸣器
{
SPEAKER = 0; //蜂鸣器报警
}
scantemp = keyscan();
}
}
float ReadTemp(void)
{
float current = 0;
float Rt = 0;
float f_tempVolt = 0; //温度对应电压
float f_temp = 0;
f_tempVolt = 5 * (float)ReadADC(AIN0_GND) / 255; //读取电压
current = (5 - f_tempVolt) / Rp; //计算电流值
Rt = f_tempVolt / current; //计算电阻值
f_temp = ((Bx * T25) / (T25 * (log(Rt) - log(ntcR25)) + Bx)) - Ka;
delay(5);
return f_temp;
}
void mypid(float Kp, float Ki, float Kd, uint count, uint point)
{
static float Uk;
ek = point - count;
// if(ek>=5&&ek<=-5) //积分分离
{
Uk = Kp * (ek - ek1) + Ki * ek + Kd * (ek - 2 * ek1 + ek2);
}
// else
// Uk=Kp*ek;
pwm = Uk;
// lcdnumdisplays(0x80+0x4a,(float)pwm);
if (pwm > freq)
pwm = freq;
if (pwm <= 0)
{
pwm = 0;
RELAY_HEAT = 1;
RELAY_COOL = 0;
}
if (pwm > 0)
{
RELAY_HEAT = 0;
RELAY_COOL = 1;
}
ek2 = ek1;
ek1 = ek;
}
//uint read_pul()
//{
// uint t1, th1, th2;
// uint val;
// while (1)
// {
// th1 = TH1;
// t1 = TL1;
// th2 = TH1;
// if (th1 == th2)
// break;
// }
// val = th1 * 256 + t1;
// return val;
//}
void delay(uint n)
{
uint i, j;
for (i = n; i > 0; i--)
for (j = 1; j > 0; j--)
;
}
void Init(void) //初始化函数
{
TMOD = 0x51;
TH0 = (65536 - 10) / 256;
TL0 = (65536 - 10) % 256;
EA = 1;
ET0 = 1;
TR0 = 1;
TH1 = 0;
TL1 = 0;
TR1 = 1;
}
void Timer_0(void) interrupt 1 //中断
{
// static ulong t_count = 0;
static uint num_count = 0;
TR0 = 0;
TH0 = (65536 - 10) / 256;
TL0 = (65536 - 10) % 256;
TR0 = 1;
num_count++;
// t_count++;
// if(t_count==2320)
// {
// t_count=0;
// TR1=0;
// pul_count=read_pul();
// TH1=0;
// TL1=0;
// TR1=1;
// }
if (num_count > freq)
num_count = 0; // 1khz;
}
// lcd写命令
void writecom(uchar com)
{
LCD_RS = 0;
P0 = com;
delay(1);
LCD_EN = 1;
delay(1);
LCD_EN = 0;
}
// lcd写数据
void writedata(uchar date)
//初始化lcd
{
LCD_RS = 1;
P0 = date;
delay(1);
LCD_EN = 1;
delay(1);
LCD_EN = 0;
}
// LCD初始化
void initlcd()
{
writecom(0x38);
delay(1);
writecom(0x0c);
delay(1);
writecom(0x06);
delay(1);
writecom(0x01);
delay(5);
}