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

📄 88888pid.c

📁 基于AT89s51的温湿度检测报警程序
💻 C
📖 第 1 页 / 共 3 页
字号:
//********************************
//max6675 温度采集
//lp      2007.12.06         
//********************************
#include <AT89x52.h>
#include <intrins.h>
#include <string.h>
#include "stdio.h"
//#include "sio.h"
#include "stc89c58_eeprom.h"			
#define  uchar unsigned char
#define  uint unsigned int
//********************
//模拟串口
#define  RXD   P2_7
#define  TXD   P2_6
//********************************
//      164显示用的变量
data 	uchar	dis_data0=10;
data	uchar	dis_data1=10;
data	uchar	dis_data2=10;
data	uchar	dis_data3=10;
data	uchar	dis_data4=10;
data	uchar	dis_data5=10;
data	uchar	dis_data6=10;
data	uchar	dis_data7=10;
data	uchar	dis_data8=10;
data	uchar	dis_data9=10;
data	uchar	dis_data10=10;
data	uchar	dis_data11=10;
data	uchar	dis_data12=10;
data	uchar	dis_data13=10;
data	uchar	dis_data14=10;
data	uchar	dis_data15=10;		
data	uint 	disp_cx=200;				//计数到显示标志树起
bit		DISP_FLAG=1;				//显示标志
//********************************
//串口通信用
float lnwd;
float cywd;
float czhi;
float eczhi;
float EII;
float EI=0;
//float bzhi;
uint  yxsj;
//********************************
//		按键用的变量
data	uchar	key_data;key_state=0xff;
bit   sk_flag=0;
bit		KEY_FLAG=1;					//按键抖动标志
data	uchar 	KeyFunIndex=0;				//状态号
bit		SERRIES_FLAG;				//连加时间计数
bit		SCANKEY_FLAG=1;				//10ms 中断树标志 进入按键扫描程序
data	uchar	key_long_cx=0;key_serries_cx=0;//长按键、连加时间计数用
//********************************
uchar code led_segment[12]={0x21,0xF9,0x45,0x51,0x99,0x13,0x03,0xF1,0x01,0x11,0xff,0xdf}  ;	
//********************************
//热电偶数字转换器MAX6675
sbit SCK=P1^0;
sbit CS=P1^1;
sbit SO=P1^2;
sbit out=P1^3; 					    //pwm输出	
bit	 COV_FLAG=1; 					//转换标志
uint  aver0,aver1=0,aver2=0;		//采样后求平均得到的温度也扩大了十倍 aver0 当前的 aver1 前一次 aver2 前二次的
uint  samping_temper;				//采样的温度扩大了十倍
int   s_t0,	s_t1=0;					//计算理论温度当前的和前一次的 也扩大了十倍	 
uchar data pmw_out=0; 					
uchar data pmw_cx=0;
bit	  SAVE_FLAG=1,SET_FLAG=0,PID_FLAG=0;
uint  a[7];						    //软件滤波用
//********************************
bit		SEC5_FLAG=0;				//按键是否是由5-0mode 标志
int		set_temper=25;				//设定温度
char	set_hour=0;set_min=0;       //设定时间
data int 	temper1;temper2;temper3;temper4;temper5;
data char	hour1;min1;hour2;min2;hour3;min3;hour4;min4;hour5;min5;
uint  min_cx=0;					//分计数
uint  ln_min;
//uint  xs_xs=20;
//uint  xsxs;
uint  cjsj=0;
bit   jr_flag;
uint 	min=0;						//分钟
char    sect=0;						//设置段数
uint 	t0;						    //保存开始的温度
//********************************
typedef struct						//多级菜单
{
	uchar KeyStateIndex;          	//index
	uchar KeyCrState;				//mode
	uchar KeyUpState;				//up
	uchar KeyDnState;				//down
	uchar KeyBackState;				//enter
	void  (*CurrentOperate)();
}KbdTabStruct;
//********************************
//函数申明:

void set();							//按键用
void up();
void down();
void enter();

void normal();						//正常模式
void sec_1_temper();				//第一段的  设定温度
void sec_1_temper_up();				//第一段的  设定温度+
void sec_1_temper_down();			//第一段的  设定温度-
void sec_1_min();					//第一段的	设定时间min				
void sec_1_min_up();				//第一段的	设定时间min+
void sec_1_min_down();				//第一段的	设定时间min-													
void sec_1_hour();					//第一段的	设定时间hour				
void sec_1_hour_up();				//第一段的	设定时间hour+
void sec_1_hour_down();				//第一段的	设定时间hour-

void sec_2_temper();				//第2段的  	设定温度
void sec_2_temper_up();				//第2段的  	设定温度+
void sec_2_temper_down();			//第2段的  	设定温度-
void sec_2_min();					//第2段的	设定时间min				
void sec_2_min_up();				//第2段的	设定时间min+
void sec_2_min_down();				//第2段的	设定时间min-													
void sec_2_hour();					//第2段的	设定时间hour				
void sec_2_hour_up();				//第2段的	设定时间hour+
void sec_2_hour_down();				//第2段的	设定时间hour-

void sec_3_temper();				//第3段的  	设定温度
void sec_3_temper_up();				//第3段的  	设定温度+
void sec_3_temper_down();			//第3段的  	设定温度-
void sec_3_min();					//第3段的	设定时间min				
void sec_3_min_up();				//第3段的	设定时间min+
void sec_3_min_down();				//第3段的	设定时间min-													
void sec_3_hour();					//第3段的	设定时间hour				
void sec_3_hour_up();				//第3段的	设定时间hour+
void sec_3_hour_down();				//第3段的	设定时间hour-

void sec_4_temper();				//第4段的  	设定温度
void sec_4_temper_up();				//第4段的  	设定温度+
void sec_4_temper_down();			//第4段的  	设定温度-
void sec_4_min();					//第4段的	设定时间min				
void sec_4_min_up();				//第4段的	设定时间min+
void sec_4_min_down();				//第4段的	设定时间min-													
void sec_4_hour();					//第4段的	设定时间hour				
void sec_4_hour_up();				//第4段的	设定时间hour+
void sec_4_hour_down();				//第4段的	设定时间hour-

void sec_5_temper();				//第5段的  	设定温度
void sec_5_temper_up();				//第5段的  	设定温度+
void sec_5_temper_down();			//第5段的  	设定温度-
void sec_5_min();					//第5段的	设定时间min				
void sec_5_min_up();				//第5段的	设定时间min+
void sec_5_min_down();				//第5段的	设定时间min-													
void sec_5_hour();					//第5段的	设定时间hour				
void sec_5_hour_up();				//第5段的	设定时间hour+
void sec_5_hour_down();				//第5段的	设定时间hour-

void theory_count();
//********************************
//E_0: 当前测量值
//E_1: 前一次测量值
//E0 :当前理论值
//E1 :前一次理论值
//kp : 比例系数
//ki : 积分系数
//kd : 微分系数
//--------------------------------
//fun: PID计算输出
//********************************
char   kp;                     // pid 系数
char   ki;
char   kd;
bit	   CT_FLAG=0;
float  E_1=0,E_2=0;
char code  DKP[7][7]={{40,40, 40,40,40,40, 40},
					       {40,40, 40,40,40,40, 40},
					       {30,30, 30,30,30,30, 30},
					       {0,0, 0,0,0,0,0},
					       {-10,0,-10,-10,-10,-10,-10},
					       {-10,0,-10,-10,-10,-10,-10},
					       {-20,0,-20,-20,-30,-30,-30}};

char code  DKI[7][7]={{20,20, 20,20,20,20,20},
					       {20,20, 20,20,20,20,20},
					       {20,20, 20,20,20,20,20},
					       {20,20, 20,20,20,20,20},
					       {20,20, 20,20,5,5,5},
					       {5,5,5,5,5,5,5},
					       {0,0,0,0,0,0,0}};

char code  DKD[7][7]={ {7,-7,-21,-21,-21,-14,7},
      					  {7,-7,-21,-14,-14,-7,0 },
      					  {0,-7,-14,-14,-7,-7,0},
      					  {0,-7,-7,-7,-7,-7,0},
      					  {0,-7,-14,-14,-7,-7,0},
      					  {7,-7,-21,-14,-14,-7,0},
      					  {7,-7,-21,-21,-21,-14,7},};
       				
#define ENB -7    //N是负,B是很大,M是中等,S是很少
#define ENM -5    //P是正,EC是偏差变化率,E是偏差
#define ENS -1
//#define EZO  0
#define EPS  1
#define EPM  2
#define EPB  3


#define ECNB -3  
#define ECNM -2
#define ECNS -1
//#define ECZO  0
#define ECPS  1
#define ECPM  2
#define ECPB  3

float	pidprocess(int rn,yn)		//rn理论值,yn采样值
{	
	float	dp,di,dd,E_0,EC,kpp,kii,pdsj,ycjw;
	static float pidout=0;
	uchar i,j;
   ycjw=pdsj-rn;;
	E_0=rn-yn;						//当前偏差
   EI=EI+E_0;
//   if(E_0>8) {EI=0;}
   EII=EI/10.0;
   if(E_0==0){EII=0;}
   EC=E_0-E_1;			         //偏差的变化率
   eczhi=(E_0-E_1)/10.0;

	if(E_0<ENB)					{i=0;} //负的比较多 //负=超调
	else if(E_0>ENB&&E_0<ENM)	{i=1;} //负的中	
	else if(E_0>ENM&&E_0<ENS)	{i=2;} //负的比较小
	else if(E_0>ENS&&E_0<EPS)   {i=3;} // 0 
	else if(E_0>EPS&&E_0<EPM)	{i=4;} //正的比较小	//正超调
	else if(E_0>EPM&&E_0<EPB)	{i=5;} //正的比较中
	else 						{i=6;} //正的比较大	
	
	if(EC<ECNB)					{j=0;} //负的比较多 //负=下降趋势
	else if(EC>ECNB&&EC<ECNM)	{j=1;} //负的中	
	else if(EC>ECNM&&EC<ECNS)	{j=2;} //负的比较小
	else if(EC>ECNS&&EC<ECPS)   {j=3;} // 0 
	else if(EC>ECPS&&EC<ECPM)	{j=4;} //正的比较小	//正=上升趋势
	else if(EC>ECPM&&EC<ECPB)	{j=5;} //正的比较中
	else 						{j=6;} //正的比较大

	kp=(45-DKP[i][j]);
   if(rn<600){kp=kp-20-rn/100;}
   if(rn<700&&rn>600){kp=kp-10-rn/500;}
   if(rn<1200&&rn>700){kp=kp-5500/rn;}
   if(rn>1200&&rn<1500){kp=kp-1000/rn;}
   if(rn>1501&&rn<1800){kp=kp+rn/2000;}
   if(rn>1800){kp=kp+5+rn/450;}
   kpp=kp/10.0;	
	ki=(80-DKI[i][j]);
   kii=ki/100.0;		
	kd=(130-DKD[i][j]);

	dp=kpp*E_0;
	di=kii*EII;                          //(E_0-E_1);						
	dd=kd*EC;

	pidout=dp+di+dd+pidout;				//	对输出要累加

 // if(E_0>-3){pidout=0;}
   if(E_0<1){pidout=0;}

	E_2=E_1;
	E_1=E_0;
   pdsj=rn;
	if(pidout<0){pidout=0;}			   //输出限幅
	if(pidout>200){pidout=200;}		   //输出限幅

	dis_data4=dp/100;
	dis_data11=((int)dp%100 )/10;
	dis_data12=(int)dp%10;

	//dis_data13=(k%100)/10;	 		//个位
	//dis_data14=k%10;
	dis_data13=dd/100;
	dis_data14=((int)dd%100)/10;
	dis_data15=(int)dd%10;
	return  (pidout);
//   return   (EI);
}
//********************************
//fun:定时器0  1 ms  定时 初始化子程序
//********************************
void time0_init()
{
	TMOD=0x11;
	TH0 =(65536-1000)>>8;
    TL0 =(65536-1000)&0xff;
	EA=1;
	ET0=1;
	TR0=1;
}
//********************************
//fun:定时器1  50 ms  定时 初始化子程序
//********************************
void time1_init()
{
	TH1 =(65536-50000)>>8;
    TL1 =(65536-50000)&0xff;
	ET1=1;
	TR1=1;
}
//********************************
//fun:定时器2 设置单片机的频率
//********************************
void time2()
{
   T2CON=0x14;
   RCAP2H=0xff;
   RCAP2L=0xb4;
   SCON=0x7a;
 //  ET2=1;
 //  ES=1;
   EA=1;
   TI=1;
   printf("%.2f  ",lnwd);
   printf("%.2f  ",cywd);

 //  printf("%.2f  ",min);
 //  printf("%.2f  ",yxsj);
   printf("%.2f\n",czhi);
 //  printf("%d\n",yxsj);
   TI=0;
 //  ET2=0;
}
//********************************
//fun:  定时器0服务子程序
//********************************
void time0_sever() interrupt 1 using 1
{	
	//EA=0;	   	
    TH0 =(65536-10000)>>8;
    TL0 =(65536-10000)&0xff;
	SCANKEY_FLAG=1;				    //10ms 扫描按键1次
   sk_flag=1;
   disp_cx--;	
	if(disp_cx==0)
	{		
		disp_cx=100;
	 	DISP_FLAG=1;				//1秒显示标志树起
	   COV_FLAG=1;					//1秒转换标志树起
	}
	EA=1;
}
//********************************
//fun:  定时器1服务子程序
//********************************
void time1_sever() interrupt 3 
{
	//EA=0;	   	
    TH1 =(65536-49900)>>8;
    TL1 =(65536-49900)&0xff;
//--------------------------------
	min_cx+=1;
   cjsj+=1;
	if(min_cx==120)						//要改成1200(1 min);
{
		min_cx=0;						 //1分钟到计数清零
		min+=1;							//分钟计数
      yxsj=min;		
	{
	if(sect==1)							//sec 在按键设置的时候设为1 为0则不进行PID运算
		{}
	else if(sect==2)					//
		{min1=min2;hour1=hour2;}		// 计算理论温度时,计算理论温度的斜率要分段
	else if(sect==3)					//
		{min1=min3;hour1=hour3;}		//
	else if(sect==4)					//
		{min1=min4;hour1=hour4;}		//
	else if(sect==5)					//
		{min1=min5;hour1=hour5;}		//
	else 
		{
			sect=0;						// sect=0;表示不进行PID计算
			dis_data4=10;				//
			dis_data5=10;				//
			dis_data6=10;				//
			dis_data7=10;				//
			dis_data8=10;				//
			dis_data9=10;				//
			dis_data10=10;				//	
			out=1;
		}								
	}
}
	if(sect)
   {
   		theory_count();	
		if(min==min1*10+hour1*600)          //时间到进行第二段计算
		{			
	 		sect++;
			if(sect==6) sect=0;								
			min=0;						//时间清0
		}
		if(min%10==0)							//十分钟写保护
		{
			write_eeprom(SECT_ADDR,sect);
			write_eeprom(MIN_ADDR,min);
		}
	}
	 	
//--------------------------------	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
	if(sect)							//sect!=0 则有进行PWM输出		
{										//中断输出
	if(pmw_cx<pmw_out)					//加热时间到
	{									//输出加热
		out=0;
	}	
	else
	{
		if(pmw_cx<=200)					//不加热时间到
		{								//停止加热

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -