📄 采用18b20的温度pid控制程序.txt
字号:
采用18B20的温度PID控制程序(C51)
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
void sendbyte(char);
uchar timecnt=0;
/************************PID******************************/
bit dealCS=0;
uchar Ctrltab[20]={8,15,20,40,50,60,70,80,100,120,140,160,180,200};
//###########################
sbit PWM=P3^2;
#define tim0 65536-5000
#define tim1 65536-10000
uchar tm=0,tx=0; //记数两个定时中断的
enum{Y,U,R,Ts,Kd,Kp};//Y采集量 U控制量 R 设定量 Ts 采样时间 Kd 微分 Kp比例
int para[6],ptr,out; //out 是从PID()得到的控制量
int wd=300,r,kp,kd,ts,e2,e1,e0,u; //wd 是从DS18B20采到的数据
//###########################
void initTimer0_Timer1() //初始化定时器0,定时器1
{
TMOD=0x11;
TH0=tim0>>8; TL0=tim0;
TH1=tim1>>8; TL1=tim1;
TR0=1;
ET0=1;
TR1=1;
ET1=1;
EA=1;
}
void initPID() //初始化PID函参数
{
para[R]=40;
para[Kp]=200;
para[Kd]=3;
para[Ts]=10;
}
void PID() //PID服务程序
{
para[Y]=wd;
r=para[R];
e0=e1;e1=e2;e2=r-para[Y]/10;
kp=para[Kp]; kd=para[Kd]; ts=para[Ts];
u=r+kp*(e2+kd*(e2-e1));
if(u<0) u=0;
if(u>2559) u=2559;
para[U]=u/10;
out=para[U];
}
void PWM_timer0() interrupt 1 //定时器0中断服务子程序
{
TH0=tim0>>8; TL0=tim0;
if(tm++>out) PWM=1; //通过变量out控制PWM脉冲宽度
else PWM=0;
if(tm>255) tm=0; //通过变量tm控制PWM的周期
if(out<10)PWM=1;
if(timecnt++==180)
{
timecnt=0;
sendbyte(0xA5);
sendbyte(para[R]); //设定温度
sendbyte(wd/10); //当前温度
sendbyte(para[Kp]); //P
sendbyte(0xa5); //I 现在没有用、
sendbyte(para[Kd]); //D
sendbyte(0xCD);
}
}
int wdCtrl;
void timer1() interrupt 3 //定时器1中断服务子程序
{
TH1=tim1>>8; TL1=tim1;
if(dealCS==0) ///模糊控制
{
wdCtrl=para[R];
if((wdCtrl-wd/10)>10)out=225;
else if((wd/10-wdCtrl)>2)out=0;
else out=Ctrltab[wdCtrl+2-wd/10];
}
else if(tx++>=ts) //dealCS为1,选择的是PID();
{
PID();
tx=0;
}
}
/********************end PID******************************/
/****************LCD程序*******************/
#define dataport P0
sbit RS=P3^4;
sbit RW=P3^5;
sbit ET=P3^6;
void Wait() //延时程序
{uint j;
for(j=0;j<300;j++){;}
}
void WriCom(uchar comm) //发送命令字节到LCD
{ RS=0;
RW=0;
ET=0;
dataport=comm;
ET=1;
Wait();
ET=0;
}
void WriData(uchar wdata) //写数据到LCD
{
RS=1;
RW=0;
ET=0;
dataport=wdata;
ET=1;
Wait();
ET=0;
}
void InitLcd() //初始化LCD
{
Wait();
WriCom(0x38);
Wait();
WriCom(0x38);
Wait();
WriCom(0x38);
Wait();
WriCom(0x38);
Wait();
WriCom(0x08);
WriCom(0x01);
WriCom(0x06);
WriCom(0x0C);
}
void SetCursor(uchar row) //设置光标插入点(写入的数据插入点
{ if(row>15)
row+=(0x40-16);
WriCom(row | 0x80);
}
void ClrLCD() //清屏LCD
{
WriCom(0x01);
}
void WriStr(char *ch) //发送一串数据
{
while(*ch!='#')WriData(*ch++);
}
/*****************LCD程序END****************/
/*************************DS18B20 子程序 *********************/
sbit DQ=P2^4;
sbit DQ1=P2^5;
sbit DQ2=P3^3;
typedef unsigned char byte;
typedef unsigned int word;
void delay(word useconds) //延时
{
for(;useconds>0;useconds--);
}
byte ow_reset(void) //复位
{
byte presence;
DQ = 0; //pull DQ line low
delay(29); // leave it low for 480us
DQ = 1; // allow line to return high
delay(3); // wait for presence
presence = DQ; // get presence signal
delay(25); // wait for end of timeslot
return(presence); // presence signal returned
} // 0=presence, 1 = no part
byte read_byte(void) //从 1-wire 总线上读取一个字节
{
byte i;
byte value = 0;
for (i=8;i>0;i--)
{
value>>=1;
DQ = 0; // pull DQ low to start timeslot
DQ = 1; // then return high
delay(1); //for (i=0; i<3; i++);
if(DQ)value|=0x80;
delay(6); // wait for rest of timeslot
}
return(value);
}
void write_byte(char val) //向 1-WIRE 总线上写一个字节
{
byte i;
for (i=8; i>0; i--) // writes byte, one bit at a time
{
DQ = 0; // pull DQ low to start timeslot
DQ = val&0x01;
delay(5); // hold value for remainder of timeslot
DQ = 1;
val=val/2;
}
delay(5);
}
uchar Read_Temperature(void)//读取温度
{
union{
byte c[2];
uint X; // X的值为 FFFF xxxx_xxxx ZZZZ
// 其中 FFFF为符号位,xxxx_xxxx 为温度整数位,ZZZZ为小数部分,
// 小数值=ZZZZ*0.0625
}temp;
ow_reset();
write_byte(0xCC); // Skip ROM
write_byte(0xBE); // Read Scratch Pad
temp.c[1]=read_byte();
temp.c[0]=read_byte();
ow_reset();
write_byte(0xCC); //Skip ROM
write_byte(0x44); // Start Conversion
return temp.X>>4; //这里只取出温度整数部分
}
/********************************************************/
byte ow_reset1(void)
{
byte presence;
DQ1 = 0; //pull DQ line low
delay(29); // leave it low for 480us
DQ1 = 1; // allow line to return high
delay(3); // wait for presence
presence = DQ1; // get presence signal
delay(25); // wait for end of timeslot
return(presence); // presence signal returned
} // 0=presence, 1 = no part
byte read_byte1(void)//从 1-wire 总线上读取一个字节
{
byte i;
byte value = 0;
for (i=8;i>0;i--)
{
value>>=1;
DQ1 = 0; // pull DQ low to start timeslot
DQ1 = 1; // then return high
delay(1); //for (i=0; i<3; i++);
if(DQ1)value|=0x80;
delay(6); // wait for rest of timeslot
}
return(value);
}
void write_byte1(char val)//向 1-WIRE 总线上写一个字节
{
byte i;
for (i=8; i>0; i--) // writes byte, one bit at a time
{
DQ1 = 0; // pull DQ low to start timeslot
DQ1 = val&0x01;
delay(5); // hold value for remainder of timeslot
DQ1 = 1;
val=val/2;
}
delay(5);
}
uchar Read_Temperature1(void)//读取温度
{
union{
byte c[2];
uint X; // X的值为 FFFF xxxx_xxxx ZZZZ
// 其中 FFFF为符号位,xxxx_xxxx 为温度整数位,ZZZZ为小数部分,
// 小数值=ZZZZ*0.0625
}temp;
ow_reset1();
write_byte1(0xCC); // Skip ROM
write_byte1(0xBE); // Read Scratch Pad
temp.c[1]=read_byte1();
temp.c[0]=read_byte1();
ow_reset1();
write_byte1(0xCC); //Skip ROM
write_byte1(0x44); // Start Conversion
return temp.X>>4; //这里只取出温度整数部分
}
/********************************************************/
byte ow_reset2(void)
{
byte presence;
DQ2 = 0; //pull DQ line low
delay(29); // leave it low for 480us
DQ2 = 1; // allow line to return high
delay(3); // wait for presence
presence = DQ2; // get presence signal
delay(25); // wait for end of timeslot
return(presence); // presence signal returned
} // 0=presence, 1 = no part
byte read_byte2(void)//从 1-wire 总线上读取一个字节
{
byte i;
byte value = 0;
for (i=8;i>0;i--)
{
value>>=1;
DQ2 = 0; // pull DQ low to start timeslot
DQ2 = 1; // then return high
delay(1); //for (i=0; i<3; i++);
if(DQ2)value|=0x80;
delay(6); // wait for rest of timeslot
}
return(value);
}
void write_byte2(char val)//向 1-WIRE 总线上写一个字节
{
byte i;
for (i=8; i>0; i--) // writes byte, one bit at a time
{
DQ2 = 0; // pull DQ low to start timeslot
DQ2 = val&0x01;
delay(5); // hold value for remainder of timeslot
DQ2 = 1;
val=val/2;
}
delay(5);
}
uchar Read_Temperature2(void)//读取温度
{
union{
byte c[2];
uint X; // X的值为 FFFF xxxx_xxxx ZZZZ
// 其中 FFFF为符号位,xxxx_xxxx 为温度整数位,ZZZZ为小数部分,
// 小数值=ZZZZ*0.0625
}temp;
ow_reset2();
write_byte2(0xCC); // Skip ROM
write_byte2(0xBE); // Read Scratch Pad
temp.c[1]=read_byte2();
temp.c[0]=read_byte2();
ow_reset2();
write_byte2(0xCC); //Skip ROM
write_byte2(0x44); // Start Conversion
return temp.X>>4; //这里只取出温度整数部分
}
/*************************end DS18B20 子程序 ****************/
uchar funkey() //按键识别子程序
{
uint timecnt;
uint key;
P1=0xff;
key=P1;
if(key!=0xff)
{
for(timecnt=0;timecnt<200;timecnt++); //延时去抖
if(key!=0xff)
{
while(P1!=0xff); //等待键放开
return key;
}
return 0;
}
return 0;
}
uint key;
int wd1,wd2,wd3;
void sendbyte(char ch)
{
TI=0;
SBUF=ch;
while(TI==0);
TI=0;
}
void main(void) //主程序
{
//////////////////开串口中断
SCON=0X50;
T2CON=0X34; // RCLK=1; TCLK=1; TR2=1;
RCAP2H=0XFF; RCAP2L=0XDB; TR2=1; // 9600 b/s
EA=1;
//////////////////
InitLcd(); //初始化LCD
initTimer0_Timer1(); //初始化定时器0,定时器1
initPID(); //初始化PID 参数
ClrLCD(); //清屏LCD
{
SetCursor(0);
wd1=Read_Temperature()*10; //读温度
WriData(wd1/100+0x30);
WriData((wd1%100)/10+0x30);
WriData(' ');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -