#include <reg52.h>
#include <intrins.h>
#include "disp.h"
#include "DELAY.H"
#include "DS18B20.H"
#include "PID.H"
#define uchar unsigned char
#define uint unsigned int
sbit Pwm_Out=P1^5; //输出端口
sbit Add_Tem_1 = P3^0; //加高设定温度,每按一次加 1℃
sbit Add_Tem_10 = P3^1; //加高设定温度,每按一次加 10℃
sbit Sub_Tem_1 = P3^2; //加高设定温度,每按一次减 1℃
sbit Sub_Tem_10 = P3^3; //加高设定温度,每按一次减 10℃
uint HL=50;//占空比显示单元,初始化为中间值
uint DS=100;//定时中断计数器
void timer0() interrupt 1 //T0定时中断子函数
{
TH0=60; //重置定时初值 ,(65536-50000)/256
TL0=176; //定时4毫秒,(65536-50000)%256
if( HL==DS )//占空比计数器等于定时中断计数器否
Pwm_Out=1; //开通输出
DS--;
if (DS==0)//定时中断计数器为0否
{ Pwm_Out=0;//关断输出
DS=100; //重置初始值 ,跟默认初装值相同
}
}
///////////////////////////////////////////////////////////////////////
void Break_Ini()//中断初始化程序
{
TMOD=0x01; //T0方式1计时
TH0=(65536-50000)/256;//定时4毫秒
TL0=(65536-50000)%256;
EA=1; //总中断开
ET0=1;//定时器0开
TR0=1;//启动定时器
}
void main()
{
uchar i;
uint T0_Data,T1_Data,te,Final_Tem=8000;
T1_Data=50;
Pwm_Out=1;
PID_Ini();
Break_Ini();
while(1)
{
if(i==0)
{
te=Read_Temperature();
T0_Data = PID_increment(te,Final_Tem);
T1_Data = PID_Action(T0_Data);
if(T1_Data<=0)
{
EA=0;
Pwm_Out=0;
}
else if(T1_Data>=100) //跟默认初装值相同
{
EA=0;
Pwm_Out=1;
}
else
{
EA=1;
HL=T1_Data;
}
i=50;
}
else
i--;
Disp_Break(te);
Disp_BingKOu();
if(Add_Tem_1==0)
{
if(Final_Tem<9900)
Final_Tem+=100;
Disp_Break(Final_Tem);
while(Add_Tem_1==0)
Disp_BingKOu();
}
else if(Add_Tem_10==0)
{
if(Final_Tem<8900)
Final_Tem+=1000;
Disp_Break(Final_Tem);
while(Add_Tem_10==0)
Disp_BingKOu();
}
else if(Sub_Tem_1==0)
{
if(Final_Tem>1900)
Final_Tem-=100;
Disp_Break(Final_Tem);
while(Sub_Tem_1==0)
Disp_BingKOu();
}
else if(Sub_Tem_10==0)
{
if(Final_Tem>2900)
Final_Tem-=1000;
Disp_Break(Final_Tem);
while(Sub_Tem_10==0)
Disp_BingKOu();
}
}
}
PID算法程序
#include<REG52.H>
#include<intrins.h>
#include"PID.H"
#include "DELAY.H"
#define uchar unsigned char
#define uint unsigned int
// uint PID_Ek,PID_Ek_Last,PID_Ei; //位置式PID算法的变量
int PID_P,PID_I,PID_D,PID_Yk0,PID_Yk1,PID_En0,PID_En1,PID_En2; //增量式PID算法的变量
float PID_Kp,PID_Ki,PID_Kd;
uint PID_Max,PID_Min;
void PID_Ini()
{
char Ti,Td,T; //Ti--积分时间常数(常为分钟),Td--微分时间常数(常为分钟),T--采样周期(秒)
PID_Kp = 5; //Kp——比例系数
T = 5; //应跟实际采样时间对应(秒)
Ti = 30; //测定PID_Kp时,Ti先取无穷大,即PID_Ki≈0 ;
Td = 15; //测定Ti时,Td先取0,即PID_Kd≈0
/**********位置式 算法 初始值************************************************************
PID_Ki =0; // PID_Ki = PID_Kp * T/Ti;
PID_Kd =0; // PID_Kd = PID_Kp * Td/T;
PID_Ek = 0;
PID_Ek_Last = 0;
PID_Ei = 0;
*********************************************************************************/
//**********位置式 算法 初始值************************************************************
PID_En1 = PID_En2 = 0 ;
PID_Ki = 0; // PID_Ki = T/Ti;
PID_Kd = Td/T; // PID_Kd = Td/T;
PID_Yk1 = 0; // PID_Yk1 = PID_Yk0;
//*********************************************************************************
PID_Max = (100 * PID_Kp); //最大温差(已扩大10倍) ;大于 最大温差 时全功率运行
PID_Min = (0 * PID_Kp); //最小温差(已扩大10倍) ;用于调整温度惯性
}
uint PID_increment(int Now_Tem,int Final_Tem)
{
int Add_Yk;
uint Temp;
Now_Tem = Now_Tem /10;
Final_Tem = Final_Tem /10;
PID_En0 = Final_Tem - Now_Tem;
PID_P = PID_Kp * (PID_En0 - PID_En1);
PID_I = PID_Ki * PID_En0;
if(PID_En0 > 500) //为克服积分饱和,采用积分分离法,选择PD运算,还是PID运算
PID_I = 0;
PID_D = PID_Kd * (PID_En0 - 2 * PID_En1 + PID_En2);
Add_Yk = PID_P + PID_I + PID_D;
PID_Yk0 = PID_Yk1 + Add_Yk;
PID_Yk1 = PID_Yk0;
PID_En2 = PID_En1;
PID_En1 = PID_En0;
if(PID_Yk1 < 0)
Temp = 0;
else
Temp = PID_Yk1;
return (Temp) ;
}
/*
uint PID_Location(int Now_Tem,int Final_Tem)
{
uint PID_Value;
if(Final_Tem > Now_Tem)
{
PID_Ek = Final_Tem - Now_Tem;
PID_Ei = PID_Ei + PID_Ek;
PID_Value = PID_Kp * PID_Ek + PID_Ki * PID_Ei + PID_Kd * (PID_Ek - PID_Ek_Last);
}
else
PID_Value = 0;
PID_Ek_Last = PID_Ek;
return (PID_Value) ;
}
*/
uint PID_Action(uint Control_Value)
{
float Out_Value;
uint T_Data;
Out_Value = Control_Value ; //缩小10倍以用于比较
if(Out_Value>=PID_Max) //完全导通
{
//point_on=0;
T_Data=100; //定时器的高电平持续时间100%;周期1ms时
}
else if(Out_Value<=PID_Min) //完全截至
{
//point_on=100;
T_Data = 0; //定时器的高电平持续时间0%;周期1ms时
}
else
{
//point_on=100*(PMAX-temp)/(PMAX-PMIN);
Out_Value=Out_Value/(PID_Max-PID_Min);
T_Data=100*Out_Value; //定时器的高电平持续时间0%~100%;周期1ms时
}
return (T_Data);
}
数字温度传感器DS18B20
#include "DS18B20.H"
#include <REG52.H> //单片机类型,默认为REG51.H
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P3^5; // ds18b20与单片机连接口,默认P3.3
//uchar data Tp[8]; // 温度显示数据
ds1820程序
***************************************/
//延时
void Delay_DS(uint useconds)//延时1微秒
{
while (useconds--);
}
/*****************************************************
void Ow_Reset()
{
DQ = 1; // DQ复位
Delay_DS(4); // 延时
DQ = 0; // DQ拉低
Delay_DS(100); // 精确延时大于480us
DQ = 1; // 拉高
Delay_DS(40);
}
*****************************************************/
uchar Read_byte()
{
uchar i = 0;
uchar value = 0;
for (i=8; i>0; i--)
{
DQ = 0; // 给脉冲信号
value >>= 1;
DQ = 1; // 给脉冲信号
if(DQ)
value |= 0x80;
Delay_DS(10);
}
return (value);
}
/*****************************************************
void Write_Byte(uchar val)
{
uchar i = 0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = val & 0x01;
Delay_DS(10);
DQ = 1;
val >>= 1;
}
}
/*****************************************************
uint Read_Temperature()
{
uchar a,b;
uchar tflag; // 温度正负标志
uint tvalue; // 温度值
Ow_Reset();
Write_Byte(0xcc); // 跳过读序列号******
Write_Byte(0x44); // 启动温度转换
Ow_Reset();
Write_Byte(0xcc); // 跳过读序列号
Write_Byte(0xbe); // 读取温度
a = Read_byte(); // 读出温度低8位
b = Read_byte(); // 读出温度高8位
tvalue = b;
tvalue <<= 8;
tvalue = tvalue | a;
if( tvalue < 0x0fff)
{
tflag = 0;
}
else
{
tvalue = ~tvalue + 1;
tflag = 1;
}
tvalue = tvalue*(6.25); // 温度值扩大100倍,精确到1位小数,根据分辨率调整6.25(即分辨率0.0625的100倍)
return (tvalue);