分析:
51需要控制一个电热丝上的功率,根据加热预设温度和实际温度的误差做积分微分运算来控制加热温度。为了让现象明显,我们使用了固态继电器,这是一个双向可控硅器件,他的开关速率比机械继电器快,时延短,方便进行瞬时功率的控制。
源代码:
#include "uart.h"
//#include "pid.h"
#include "LQ12864.h"
#include "codetab.h"
#include "stdio.h"
#define MAX_PID_SIZE 8 //积分时间常量
#define ABS(a) (((a)>0)?(a):-(a))
char Kp;
char Ki;
char Kd;
int Ts;
int Ts_t;
unsigned int temp;
//#include "pid.h"
#include "LQ12864.h"
#include "codetab.h"
#include "stdio.h"
#define MAX_PID_SIZE 8 //积分时间常量
#define ABS(a) (((a)>0)?(a):-(a))
char Kp;
char Ki;
char Kd;
int Ts;
int Ts_t;
unsigned int temp;
//热电偶用的引脚
sbit SCK = P1^5;
sbit CS = P1^6;
sbit SO = P1^7;
sbit RELAY = P0^7; //////继电器
bit uart_flag = 0;
bit bit_send = 0;
unsigned char count;
unsigned char cap_sp = 0;
int pid_val;
unsigned int Itter;
char mode;
unsigned char det[MAX_PID_SIZE];
unsigned char sst;
unsigned int MAX6675_ReadReg(void);
void set_pid(void);
void calculate_pid(void);
void Tim0_Init(void); ////开启定时器
void delay_1(unsigned int ss);
void main()
{
char disp_str[18];
Kp = '0';
Ki = '0';
Kd = '0';
Ts = '0';
LCD_Init();
LCD_CLS();
Tim0_Init();
UART_Init();
mode =3;
receive = 0x99;
RELAY = 1;
while(1)
{
//UART_SentChar(0x34);
// for(i=0;i<255;i++)
// {
// UART_SentChar(i);
// delay(600);
// }
// delay(5);
// }
if( receive != 0x99) ///进入与从机通信的模式
{
switch(receive)
{
case SET_PID_VAL: TR0=0;RELAY =1;mode =1;set_pid();break;
case SET_START_DIGITAL:
UART_SentChar(SET_START_DIGITAL);
TR0 = 1;
count = 0;
mode =2; break;
case SET_STOP_DIGITAL:
UART_SentChar(SET_STOP_DIGITAL);
TR0 =0;RELAY=1;
mode = 3;break;
case ENFORCE_STOP:
if(mode !=1)
{
EA = 0;
sprintf(disp_str,"please restart");
LCD_P8x16Str(0,0,disp_str);
while(1);
}
break;
case 'o': if(mode ==2) UART_SentChar(sst);break;
default: break;
}
receive = 0x99;
LCD_CLS();
}
//LCD_CLS();
if(mode == 1)
{
sprintf(disp_str,"Ts:%d",Ts);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,0,disp_str);
// LCD_ShowNum(0,6,Kp,3); //(unsigned char x,unsigned char y,unsigned int num,unsigned char len)
sprintf(disp_str,"Kp:%d",Kp);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,2,disp_str);
sprintf(disp_str,"Ki:%d",Ki);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,4,disp_str);
sprintf(disp_str,"Kd:%d",Kd);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,6,disp_str);
delay_1(300);
}
else if(mode == 2)
{
temp= MAX6675_ReadReg();
if(!(temp &0x04))
{
// LCD_CLS();
temp =temp<<1;
temp = temp>>4;
temp =temp/4;
sst = (char)temp;
sprintf(disp_str,"temp:%d",temp);
LCD_P8x16Str(0,2,disp_str);
sprintf(disp_str,"pidval:%d",pid_val);
LCD_P8x16Str(0,0,disp_str);
sprintf(disp_str,"settemp:%d",Ts);
LCD_P8x16Str(0,6,disp_str);
delay_1(900);
}
else
{
sprintf(disp_str,"not connect");
LCD_P8x16Str(0,2,disp_str);
delay_1(300);
LCD_CLS();
}
if(temp <Ts)
{
calculate_pid();
}else{
pid_val = 0;
if(temp >Ts+50)
{
mode =50;
EA =0;
}
}
}
else if(mode ==3)
{
TR0 =0;
sprintf(disp_str,"stop");
LCD_P8x16Str(0,2,disp_str);
LCD_CLS();
delay_1(200);
}
}
if(mode == 50)
{
LCD_P8x16Str(0,6,"temp high");
LCD_CLS();
}
}
sbit SCK = P1^5;
sbit CS = P1^6;
sbit SO = P1^7;
sbit RELAY = P0^7; //////继电器
bit uart_flag = 0;
bit bit_send = 0;
unsigned char count;
unsigned char cap_sp = 0;
int pid_val;
unsigned int Itter;
char mode;
unsigned char det[MAX_PID_SIZE];
unsigned char sst;
unsigned int MAX6675_ReadReg(void);
void set_pid(void);
void calculate_pid(void);
void Tim0_Init(void); ////开启定时器
void delay_1(unsigned int ss);
void main()
{
char disp_str[18];
Kp = '0';
Ki = '0';
Kd = '0';
Ts = '0';
LCD_Init();
LCD_CLS();
Tim0_Init();
UART_Init();
mode =3;
receive = 0x99;
RELAY = 1;
while(1)
{
//UART_SentChar(0x34);
// for(i=0;i<255;i++)
// {
// UART_SentChar(i);
// delay(600);
// }
// delay(5);
// }
if( receive != 0x99) ///进入与从机通信的模式
{
switch(receive)
{
case SET_PID_VAL: TR0=0;RELAY =1;mode =1;set_pid();break;
case SET_START_DIGITAL:
UART_SentChar(SET_START_DIGITAL);
TR0 = 1;
count = 0;
mode =2; break;
case SET_STOP_DIGITAL:
UART_SentChar(SET_STOP_DIGITAL);
TR0 =0;RELAY=1;
mode = 3;break;
case ENFORCE_STOP:
if(mode !=1)
{
EA = 0;
sprintf(disp_str,"please restart");
LCD_P8x16Str(0,0,disp_str);
while(1);
}
break;
case 'o': if(mode ==2) UART_SentChar(sst);break;
default: break;
}
receive = 0x99;
LCD_CLS();
}
//LCD_CLS();
if(mode == 1)
{
sprintf(disp_str,"Ts:%d",Ts);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,0,disp_str);
// LCD_ShowNum(0,6,Kp,3); //(unsigned char x,unsigned char y,unsigned int num,unsigned char len)
sprintf(disp_str,"Kp:%d",Kp);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,2,disp_str);
sprintf(disp_str,"Ki:%d",Ki);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,4,disp_str);
sprintf(disp_str,"Kd:%d",Kd);
// UART_SentChar(disp_str);
LCD_P8x16Str(0,6,disp_str);
delay_1(300);
}
else if(mode == 2)
{
temp= MAX6675_ReadReg();
if(!(temp &0x04))
{
// LCD_CLS();
temp =temp<<1;
temp = temp>>4;
temp =temp/4;
sst = (char)temp;
sprintf(disp_str,"temp:%d",temp);
LCD_P8x16Str(0,2,disp_str);
sprintf(disp_str,"pidval:%d",pid_val);
LCD_P8x16Str(0,0,disp_str);
sprintf(disp_str,"settemp:%d",Ts);
LCD_P8x16Str(0,6,disp_str);
delay_1(900);
}
else
{
sprintf(disp_str,"not connect");
LCD_P8x16Str(0,2,disp_str);
delay_1(300);
LCD_CLS();
}
if(temp <Ts)
{
calculate_pid();
}else{
pid_val = 0;
if(temp >Ts+50)
{
mode =50;
EA =0;
}
}
}
else if(mode ==3)
{
TR0 =0;
sprintf(disp_str,"stop");
LCD_P8x16Str(0,2,disp_str);
LCD_CLS();
delay_1(200);
}
}
if(mode == 50)
{
LCD_P8x16Str(0,6,"temp high");
LCD_CLS();
}
}
void set_pid(void)
{
UART_SentChar(SET_PID_VAL);
uart_flag = 0; ///信号量清零
while(!uart_flag);
Kp = receive;
uart_flag =0;
while(!uart_flag);
Ki = receive;
uart_flag = 0;
while(!uart_flag)
Kd = receive;
uart_flag = 0;
while(!uart_flag);
Ts = receive;
{
UART_SentChar(SET_PID_VAL);
uart_flag = 0; ///信号量清零
while(!uart_flag);
Kp = receive;
uart_flag =0;
while(!uart_flag);
Ki = receive;
uart_flag = 0;
while(!uart_flag)
Kd = receive;
uart_flag = 0;
while(!uart_flag);
Ts = receive;
Ts_t = Ts * 1.1f;
}
}
/****
加热算法
根据预设温度和误差累加计算pid参数
计算值在0-100之间 为加热pwm控制的占空比
**w***/
void calculate_pid(void)
{
unsigned char i;
for(i=0;i< MAX_PID_SIZE;i++)
{
if(det[i] <0)
{
Itter+=0;
}
else
{
Itter += det[i];
}
}
Itter = Itter/MAX_PID_SIZE;
if(cap_sp !=0)
{
pid_val = Kp*det[cap_sp]/100 +Ki*Itter/100- Kd*ABS(det[cap_sp]-det[cap_sp-1]);
}
else
{
pid_val = Kp*det[cap_sp]/100 +Ki*Itter/100- Kd*ABS(det[cap_sp]-det[MAX_PID_SIZE-1]);
}
if(temp >Ts)
pid_val = 0;
if(pid_val<0)
pid_val = 0;
}
加热算法
根据预设温度和误差累加计算pid参数
计算值在0-100之间 为加热pwm控制的占空比
**w***/
void calculate_pid(void)
{
unsigned char i;
for(i=0;i< MAX_PID_SIZE;i++)
{
if(det[i] <0)
{
Itter+=0;
}
else
{
Itter += det[i];
}
}
Itter = Itter/MAX_PID_SIZE;
if(cap_sp !=0)
{
pid_val = Kp*det[cap_sp]/100 +Ki*Itter/100- Kd*ABS(det[cap_sp]-det[cap_sp-1]);
}
else
{
pid_val = Kp*det[cap_sp]/100 +Ki*Itter/100- Kd*ABS(det[cap_sp]-det[MAX_PID_SIZE-1]);
}
if(temp >Ts)
pid_val = 0;
if(pid_val<0)
pid_val = 0;
}
unsigned int MAX6675_ReadReg(void)
{
unsigned char i;
unsigned int dat;
i = 0;
dat = 0;
CS = 0;
SCK = 0;
for(i=0; i<16; i++) //get D15-D0 from 6675
{
SCK = 1;
dat = dat<<1;
if( SO==1 )
dat = dat|0x01;
SCK = 0;
}
CS = 1;
return dat;
}
{
unsigned char i;
unsigned int dat;
i = 0;
dat = 0;
CS = 0;
SCK = 0;
for(i=0; i<16; i++) //get D15-D0 from 6675
{
SCK = 1;
dat = dat<<1;
if( SO==1 )
dat = dat|0x01;
SCK = 0;
}
CS = 1;
return dat;
}
void Tim0_Init(void)
{
TMOD |= 0x01;
TH0 = 0xd8;
TL0 = 0xf0;
ET0 =1;
TR0 =1;
}
{
TMOD |= 0x01;
TH0 = 0xd8;
TL0 = 0xf0;
ET0 =1;
TR0 =1;
}
void delay_1(unsigned int ss)
{
unsigned int aa;
while(ss--)
{
for(aa=0;aa<100;aa++)
{
if(receive !=0x99)
{
break;
}
}
if(receive != 0x99)
{
break;
}
}
}
{
unsigned int aa;
while(ss--)
{
for(aa=0;aa<100;aa++)
{
if(receive !=0x99)
{
break;
}
}
if(receive != 0x99)
{
break;
}
}
}
void inttr1_timer() interrupt 1
{
TH0 =0xd8;
TL0 =0xf0;
if(++count == 100)
{
count = 0;
}
if(count < pid_val)
{
RELAY = 0;
}
else
{
RELAY = 1;
}
det[cap_sp++] = Ts_t - temp;
if(cap_sp >= MAX_PID_SIZE)
{
cap_sp = 0;
}
// RELAY =~RELAY;
}
{
TH0 =0xd8;
TL0 =0xf0;
if(++count == 100)
{
count = 0;
}
if(count < pid_val)
{
RELAY = 0;
}
else
{
RELAY = 1;
}
det[cap_sp++] = Ts_t - temp;
if(cap_sp >= MAX_PID_SIZE)
{
cap_sp = 0;
}
// RELAY =~RELAY;
}
#include <reg52.h>
#include <intrins.h>
#include "uart.h"
#define BAUDRATE 115200
#define FOSC 12000000
extern bit uart_flag;
#include <intrins.h>
#include "uart.h"
#define BAUDRATE 115200
#define FOSC 12000000
extern bit uart_flag;
unsigned char data receive;
unsigned char ii =0;
unsigned char ii =0;
void UART_Init()
{
/***
以12mhz的时钟 2400波特率启动串口 定时器1做串口波特率发生器
*****/
TMOD |= 0x21; //T1工作于方式2
{
/***
以12mhz的时钟 2400波特率启动串口 定时器1做串口波特率发生器
*****/
TMOD |= 0x21; //T1工作于方式2
// 配置 SCON
REN=1; //允许串口接收
SM0=0; //设定串口工作方式1
SM1=1; //设定串口工作方式1
// 根据系统晶振及波特率设置T1自动重装初始值
TH1 = TL1 = 0xf3; //Set auto-reload vaule
REN=1; //允许串口接收
SM0=0; //设定串口工作方式1
SM1=1; //设定串口工作方式1
// 根据系统晶振及波特率设置T1自动重装初始值
TH1 = TL1 = 0xf3; //Set auto-reload vaule
TR1 = 1; //启动定时器1
ES = 1;
EA = 1;
}
ES = 1;
EA = 1;
}
void UART_SentChar(unsigned char chr)
{
//发送一个字节
SBUF = chr;
while( TI == 0);
TI = 0;
}
{
//发送一个字节
SBUF = chr;
while( TI == 0);
TI = 0;
}
void UART_SendString(unsigned char *str)
{
while(*str != '\0')
{
UART_SentChar(*str++);
}
}
{
while(*str != '\0')
{
UART_SentChar(*str++);
}
}
unsigned char UART_RecChar(void)
{
unsigned char data recive1;
while(!RI);
RI = 0;
recive1 = SBUF;
RI = 0;
recive1 = SBUF;
return(recive1);
}
}
void serialget(void) interrupt 4
{
RI = 0;
receive = SBUF;
uart_flag = 1;
}
unsigned char UART_RecChar(void)
{
unsigned char data recive1;
{
RI = 0;
receive = SBUF;
uart_flag = 1;
}
#include <reg52.h>
#include <intrins.h>
#include "uart.h"
#define BAUDRATE 115200
#define FOSC 12000000
extern bit uart_flag;
#include <intrins.h>
#include "uart.h"
#define BAUDRATE 115200
#define FOSC 12000000
extern bit uart_flag;
unsigned char data receive;
unsigned char ii =0;
unsigned char ii =0;
void UART_Init()
{
/***
以12mhz的时钟 2400波特率启动串口 定时器1做串口波特率发生器
*****/
TMOD |= 0x21; //T1工作于方式2
{
/***
以12mhz的时钟 2400波特率启动串口 定时器1做串口波特率发生器
*****/
TMOD |= 0x21; //T1工作于方式2
// 配置 SCON
REN=1; //允许串口接收
SM0=0; //设定串口工作方式1
SM1=1; //设定串口工作方式1
// 根据系统晶振及波特率设置T1自动重装初始值
TH1 = TL1 = 0xf3; //Set auto-reload vaule
REN=1; //允许串口接收
SM0=0; //设定串口工作方式1
SM1=1; //设定串口工作方式1
// 根据系统晶振及波特率设置T1自动重装初始值
TH1 = TL1 = 0xf3; //Set auto-reload vaule
TR1 = 1; //启动定时器1
ES = 1;
EA = 1;
}
ES = 1;
EA = 1;
}
void UART_SentChar(unsigned char chr)
{
//发送一个字节
SBUF = chr;
while( TI == 0);
TI = 0;
}
{
//发送一个字节
SBUF = chr;
while( TI == 0);
TI = 0;
}
void UART_SendString(unsigned char *str)
{
while(*str != '\0')
{
UART_SentChar(*str++);
}
}
{
while(*str != '\0')
{
UART_SentChar(*str++);
}
}
unsigned char UART_RecChar(void)
{
unsigned char data recive1;
while(!RI);
RI = 0;
recive1 = SBUF;
RI = 0;
recive1 = SBUF;
return(recive1);
}
}
void serialget(void) interrupt 4
{
RI = 0;
receive = SBUF;
uart_flag = 1;
}
{
RI = 0;
receive = SBUF;
uart_flag = 1;
}