📄 温度pid控制.c
字号:
#include <reg51.h>
#include <intrins.h>
/******************************与编译器无关的数据类型定义*********************************/
typedef unsigned char uint8; // 无符号8位整型变量
typedef signed char int8; // 有符号8位整型变量
typedef unsigned short uint16; // 无符号16位整型变量
typedef signed short int16; // 有符号16位整型变量
typedef unsigned long uint32; // 无符号32位整型变量
typedef signed long int32; // 有符号32位整型变量
typedef float fp32; // 单精度浮点数(32位长度)
typedef double fp64; // 双精度浮点数(64位长度)
/********************************MPU管脚定义***********************************************/
#define LCD_DATA P2 //LCD控制引脚定义
sbit LCD_SEL = P3^6;
sbit LCD_WR = P3^7;
sbit AD_CS = P0^7; //TLC2543控制引脚定义
sbit AD_CLOCK = P0^4;
sbit AD_DATAIN = P0^5;
sbit AD_DATAOUT = P0^6;
sbit PWM = P1^4; //PWM脉冲产生引脚
sbit STA = P1^0; //加热冷凝状态控制引脚
/******************************全局常量变量定义***********************************************/
#define T_high 950 //定义高温值
#define T_low 550 //定义低温值
#define Kp 45 //定义PID比例系数
#define Ki 0 //定义PID积分系数
#define Kd 0 //定义PID微分系数
#define Kc 1 //定义PID维持功率项系数
uint16 T_target; //目标温度寄存器
uint16 T_true; //当前温度寄存器
int16 T_diff; //当前温差寄存器
uint8 duty_cycle; //PWM占空比,1% ~ 100%
uint16 count1=0,count2=0,count3=0; //软件计数寄存器
uint8 DATA1,DATA2,DATA3; //10进制数据缓存
uint8 DATA_T1_1,DATA_T1_2,DATA_T1_3; //T1显示数据缓存
uint8 DATA_T2_1,DATA_T2_2,DATA_T2_3; //T2显示数据缓存
uint8 DATA_pwm_1,DATA_pwm_2,DATA_pwm_3; //pwm显示数据缓存
uint8 DATA_sta_1,DATA_sta_2,DATA_sta_3,DATA_sta_4; //加热制冷状态显示数据缓存
uint8 code Tab[40]={0x54,0x31,0x3A,0x20,0x20,0x20,0x20,0xEF,0x43,0x20, 0x20,0x50,0x57,0x4D,0x3A,0x20,0x20,0x20,0x25,0x20,
0x54,0x32,0x3A,0x20,0x20,0x20,0x20,0xEF,0x43,0x20,
0x20,0x20,0x20,0x20,0x20,0x69,0x6E,0x67,0x20,0x20}; //LCD初始化数据表
/********************************************************************************************
* 函数名称:Delay()
* 功 能:软件延时
* 入口参数:count 延时参数,值越大,延时越长
* 出口参数:无
*********************************************************************************************/
void Delay(uint16 count)
{
uint8 i;
while(--count!=0)
{
for(i=0;i<125;i++); // i 从0加到125,在12M晶体下CPU大概耗时1毫秒
}
}
/********************************************************************************************
* 函数名称:LCD_write()
* 功 能:向LCD屏幕写入1Byte数据
* 入口参数:DATA 要写入的1Byte数据
* 出口参数:无
*********************************************************************************************/
void LCD_write(uint8 DATA)
{
LCD_SEL =1;
LCD_WR =1;
LCD_DATA =DATA;
LCD_SEL =0;
LCD_WR =0;
LCD_WR =1;
LCD_SEL =1;
Delay(2);
}
/********************************************************************************************
* 函数名称:TLC2543()
* 功 能:TLC2543的12位A/D转换
* 入口参数:SELECT 1Byte配置数据(****0010),需默认12位输出,LSB前导,单极性
* 出口参数:AD_data 16位数,高4位补零
*********************************************************************************************/
uint16 TLC2543(uint8 select)
{
uint16 AD_data=0,a=1;
uint8 i,b=128;
AD_CLOCK =0;
AD_CS =1;
AD_CS =0;
for(i=0;i<12;i++)
{
if(AD_DATAOUT==1)
{
AD_data=AD_data+a;
}
AD_DATAIN=0;
if(i<8)
{
if((select&b)!=0)
{
AD_DATAIN=1;
}
}
AD_CLOCK =1;
AD_CLOCK =0;
a=a<<1;
b=b>>1;
}
return AD_data;
}
/********************************************************************************************
* 函数名称:D16to10()
* 功 能:将双字节16进制数转换成10进制数,取低3位存入数据缓存:DATA1,DATA2,DATA3
* 入口参数:DATA 要转换的16进制数据
* 出口参数:无
*********************************************************************************************/
void D16to10(uint16 DATA)
{
DATA3=DATA%10;
DATA3=DATA3|0x30;
DATA2=(DATA/10)%10;
DATA2=DATA2|0x30;
DATA1=(DATA/100)%10;
DATA1=DATA1|0x30;
}
/********************************************************************************************
* 函数名称:DATA_change()
* 功 能:将T1,T2,PWM数据转成10进制,STA转为相应代码存显示缓存
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void DATA_change(void)
{
D16to10(T_target); //温度设置值转换
DATA_T2_1=DATA1; //数值存显示缓存
DATA_T2_2=DATA2;
DATA_T2_3=DATA3;
D16to10(T_true); //温度当前值转换
DATA_T1_1=DATA1; //数值存显示缓存
DATA_T1_2=DATA2;
DATA_T1_3=DATA3;
D16to10(duty_cycle); //pwm占空比转换
DATA_pwm_1=DATA1; //数值存显示缓存
DATA_pwm_2=DATA2;
DATA_pwm_3=DATA3;
if(STA==1) //STA为1,冷凝状态
{
DATA_sta_1=0x43; //代码存显示缓存
DATA_sta_2=0x6F;
DATA_sta_3=0x6F;
DATA_sta_4=0x6C;
}
else //STA为0,加热状态
{
DATA_sta_1=0x48; //代码存显示缓存
DATA_sta_2=0x65;
DATA_sta_3=0x61;
DATA_sta_4=0x74;
}
}
/********************************************************************************************
* 函数名称:Display()
* 功 能:将显示数据在LCD屏幕上显示
* 入口参数:无
* 出口参数:无
* ********************************************************************************************/
void Display(void)
{
LCD_write(0x10); //光标移至T1位置
LCD_write(0x03);
LCD_write(DATA_T1_1); //写入T1数据
LCD_write(DATA_T1_2);
LCD_write(0x2E);
LCD_write(DATA_T1_3);
LCD_write(0x10); //光标移至T2位置
LCD_write(0x17);
LCD_write(DATA_T2_1); //写入T2数据
LCD_write(DATA_T2_2);
LCD_write(0x2E);
LCD_write(DATA_T2_3);
LCD_write(0x10); //光标移至PWM位置
LCD_write(0x0F);
LCD_write(DATA_pwm_1); //写入PWM数据
LCD_write(DATA_pwm_2);
LCD_write(DATA_pwm_3);
LCD_write(0x10); //光标移至state位置
LCD_write(0x1F);
LCD_write(DATA_sta_1); //写入state数据
LCD_write(DATA_sta_2);
LCD_write(DATA_sta_3);
LCD_write(DATA_sta_4);
}
/********************************************************************************************
* 函数名称:display_init()
* 功 能:LCD屏幕初始化
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void display_init(void)
{
uint8 i;
LCD_write(0x14); //消隐光标
LCD_write(0x18); //字符库设置
for(i=0;i<39;i++) //初始化LCD屏幕数据
{
LCD_write(Tab[i]);
}
}
/********************************************************************************************
* 函数名称:Time0_init()
* 功 能:定时器T0初始化
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void Time0_init(void)
{
TMOD=0x02; //定时器T0设置(方式2)
TL0=163; //置定时器T0初值
TH0=163; //定时100 uS(晶振11.0592M)
EA=1; //开CPU中断
ET0=1; //允许T0中断
TR0=1; //启动T0
}
/********************************************************************************************
* 函数名称:T_set()
* 功 能:温度循环设置函数
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void T_set(void)
{
if(count3==120) //判断高温时间到没
{
T_target=T_low; //是则温度切换到低温
}
if(count3==240) //判断循环周期到没
{
T_target=T_high; //是则温度切换回高温
count3=0; //count3清零,开始下一轮温度循环
}
}
/********************************************************************************************
* 函数名称:pwm()
* 功 能:与定时器T0中断结合产生PWM脉冲,频率100Hz
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void pwm(void)
{
if(count1==duty_cycle) //判断一个脉宽时间到没
{
PWM=1; //是则PWM脚置0
}
if(count1==100) //判断一个PWM周期到没
{
PWM=0; //是则PWM脚置1
count1=0; //count1清零,开始下个PWM周期
}
}
/********************************************************************************************
* 函数名称:PID()
* 功 能:温度调节PID算法
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void PID(void)
{
static int16 diff[20];
static int16 sum_diff=0;
static uint8 n=0;
int16 p_out,i_out,d_out,c_out,pid_out;
n++;
if(n>=20)
{
n=0;
}
sum_diff=sum_diff-diff[n]+T_diff; //循环数值积分
diff[n]=T_diff; //更新温差数据
p_out=(Kp/10)*diff[n]+(Kp%10)*diff[n]/10; //比例项输出
i_out=Ki*sum_diff/100; //积分项输出
d_out=Kd*(diff[n]-diff[n-1]); //微分项输出
c_out=Kc*T_target/100; //维持功率项
pid_out=p_out+i_out+d_out+c_out; //PID输出
if(T_diff<-10) //温差低于-1℃
{
STA=1; //降温
pid_out=-pid_out;
}
else
{
STA=0; //升温
}
if(pid_out<1) //PID输出调整为1~100
{
pid_out=1;
}
else if(pid_out>=100)
{
pid_out=100;
}
duty_cycle=(uint8)pid_out; //由PID输出调整占空比
}
/********************************************************************************************
* 函数名称:Timer0()
* 功 能:定时器T0中断服务程序
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void Timer0(void) interrupt 1
{
count1++;
count2++;
pwm(); //产生PWM脉冲
}
/********************************************************************************************
* 函数名称:main()
* 功 能:主程序
* 入口参数:无
* 出口参数:无
*********************************************************************************************/
void main(void)
{
uint8 i;
display_init(); //显示初始化
Time0_init(); //定时器T0初始化
T_target=T_high; //温度设置初始化为高温
duty_cycle=100; //PWM占空比初始化为100
PWM=1; //PWM脚置1,脉宽状态
STA=0; //STA脚置0,加热状态
while(1)
{
if(count2==5000) //判断0.5S时间到没
{
count2=0; //count2清零,重新计时
count3++;
T_set(); //温度循环设置
T_true=0;
for(i=0;i<4;i++) //连续采集4次数据取平均;
{
T_true+=TLC2543(0x42);
}
T_true =T_true>>2;
T_true =T_true*3/10+T_true*1/100+T_true*6/1000+153;
T_diff=(int16)(T_target-T_true);
PID(); //PID调节
DATA_change(); //更新显示缓冲
Display(); //重新写入显示数据
}
}
}
*****************************************exp666*********************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -