⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 温度pid控制.c

📁 51单片机实现温度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 + -