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

📄 module.c

📁 一个锅炉温度控制程序
💻 C
字号:
/* module.c
* main program   新驱动(2路7703加2块继电器)					2003/1/11
*/
#include "absacc.h"
#include "math.h"
#include "sja.h"
#include "jdq.h"
#include "pid.h"
#include <reg52.h>
#include <intrins.h>
#include <string.h>
#include "link.h"
#include "ad7703_2.h"
#include "watchdog.h"
#include "delay.h"
#include "exp.h"
#include "L8279.h"
#include "XData.h"
//#include "PinAlarm.h"
/*==================================================================
								Main
==================================================================*/
/*
2003-2-27   王嵩
1加入模块PID控制,并有多种算法选择;
2断开模块PID时,由上位机给出控制量;
3上位机能直接控制继电器;
4若无阀位反馈,可用灵敏度法控制;
5新增定时器0中断;
6上位机可优化模块PID各参数;
7实时采集温度数据;
8可一次1帧或5帧收发数据;
*/
/*数据采集双缓冲
采集数据ad_val和cool_temp,外部读取ad_val_bk和cool_temp_bk*/

/*
*		修改:王占成
*		zcwang@mail.ustc.edu.cn
*		2003.4.29
*		加入键盘和显示器部分
*
*/

/***************************************************************/
/**********外部变量***************/
BYTE RXdata[11];
BYTE TXdata[11];
idata BYTE nr_frame;
idata BYTE TempTimes;
idata BYTE PIDTimes;
idata BYTE OnNewData;
idata BYTE NewLEDStatus;
idata BYTE TFlag;
idata BYTE DispTtime;
idata BYTE DispTFlag;

idata UINT cool_temp;
idata UINT cool_temp_bk;
idata UINT ad_val_bk[2];
idata UINT SP_nCount = 0;

BYTE p0val;


void data_sample()/*采集AD7703温度角度数据和室温数据*/
{	
	ad_val00 = read_ad_1();	ad_val10 = read_ad_2();
	ad_val01 = read_ad_1();	ad_val11 = read_ad_2();
	ad_val02 = read_ad_1();	ad_val12 = read_ad_2();
	ad_val03 = read_ad_1();	ad_val13 = read_ad_2();
	
	cool_temp = read_ds_data();
	clear_watchdog();
	return;
}
void order(UINT * table,BYTE size)/*排序   put the max into ad_val_0[4]*/
{
	BYTE i,j;
	UINT tmp;
	for(i=size-1;i>=1;i--){/*共比较(size-1)轮*/
		clear_watchdog();
		for(j=0;j<i;j++){
			if(table[i] < table[j]){
				tmp = table[j];
				table[j] = table[i];
				table[i] = tmp;			
				}
		}
	}
	return;
}
void cp_temp()/*处理7703采集的数据*/
{
	EA=0;
	order((UINT *)XAD0,4);/*将ad_val[i]去掉1个最大值,1个最小值,剩余2个求平均*/
	order((UINT *)XAD1,4);
	ad_val_bk[0] = (ad_val01+ad_val02)>>1;
	ad_val_bk[1] = (ad_val11+ad_val12)>>1;
	cool_temp_bk = cool_temp & 0x7FF;
	EA=1;
	clear_watchdog();
	return;
}

void PinAlarm()   /***++=蜂鸣器报警程序++=***/
{  BYTE i;
  for(i=0;i<500;i++){    /***产生500Hz方波,持1秒***/
     P2=0x28;           /***选通Y1***/
     delay1ms();
     P2=0xF8;
     delay1ms();
   }
   clear_watchdog();
   AlarmFlag = 0;
}

void init_system()		/*系统初始化*/
{  
	BYTE baud;
	EA = 0;	/* 禁止中断 */
	
	/* 设置CPU寄存器 */
	
	IE=0x2F;	/*定时器0中断计算温度角度*/
				/*定时器1中断设定值曲线*/
				/*定时器2中断PID计算*/
				/*外部中断0收发数据*/
				/*外部中断1响应键盘中断*/
	
	IP=0x01;    /*外部中断0优先级最高*/
	
	TCON=0x01;  /*外部中断0下降沿触发,外部中断1低电平触发*/
	T2CON = 0x00; /*中断程序设置T2CON.7 = 0, T2CON.2 = 0 (stop counter) */
	T2MOD = 0x00; /*增计数*/ 
	RCAP2H = 0x9E;
	RCAP2L = 0x58;/*定时长度25ms*/
	TMOD=0x11;     /*定时器0,1工作在模式1,16位定时器*/
	TH0 = 0;      
	TL0 = 0;         /*定时器0定时长度65ms*/
	TH1 = 0x3c;
	TL1 = 0xaf;		/*定时器0定时长度50ms*/
	
	/* 读取模块地址 */
	
	P2 = 0x08;
	p0val = P0;			/*不要使用访问内存的方法读取*/
	P2 = 0xF8;
	
	/* 设置外设 */
	init_watchdog();  /*初始化看门狗*/  
	Init_8279();
	init_jdq();
	init_ad7703();    /* 4k Hz */
	
	switch(p0val&0xc0){
	case 0x00:		baud=0xc3;		break;
	case 0x40:		baud=0xc9;		break;
	case 0x80:		baud=0xd3;		break;
	case 0xc0:		baud=0xe7;		break;
	}
	
	clear_watchdog();
	init_sja(p0val&0x3f,baud);
	
	if((PIDIni != 0x01)&&(RFlag!=0xc5)) {    /***+++++ 上电复位时,初始化各PID参数++++****/
		Init_Para();
		PIDIni = 0x01;
	}
	

	     
	
	EA = 1;
	
	TR0 = 1;/*定时器0开*/
	TR2 = 1;/*定时器2开*/
	  if(RFlag==0xC5)
	      TR1 = 1;  /*定时器1开*/
	return;
}

void main()
{
	BYTE i;
	OnNewData = TRUE;
	NewLEDStatus = TRUE;
	ResetFlag=0;
	TempFlag=1;
	PIDFlag = 0; 
	TFlag = TRUE;
	DispTtime = 0;
	DispTFlag = TRUE;
	AlarmFlag = 0;                 /*+++++AlarmFlag = 0 不报警 **/     
	AlarmTime = 0;
	AutoFlag = 1;                  /***自动控制**/
	
	init_system();			/*系统初始化*/
	 
	     
	RFlag=0xC5;                    /**用于区分复位标志**/
	do{		
		if (ResetFlag == 1){
			init_system();
			ResetFlag=0;
		}
		
		if((TFlag == TRUE) && (DispTFlag == TRUE)){
			DispT();
			DispTFlag = FALSE;
		}
		
        if (TempFlag == 1){			 /*采样*/	
			data_sample();           /* 读取来自7703数据 */
			cp_temp();               /*AD7703采样数据处理*/		
			
            TempFlag=0;
			
			Yk=CalcTemp();          /*计算当前温度*/
			Angle=CalcAngle();      /*有反馈,计算当前阀位角度*/ 
		}	
		
		if(OnNewData == TRUE)	{		/*接受到了新帧*/
			Update_PID_Para();   /*更新PID参数,为测试用总更新*/
		}
		
		if((PIDFlag == 1)&&(AutoFlag == 1)){/*PID计算 每4秒钟执行一次PID控制*/ 
			
			if (EnablePID==1) {             /*由模块自身进行PID控制*/	
				PID();
				PIDFlag=0;
				
				/*=========================
				临时:自加标志
				=========================*/
				TempPIDUINT++;
				
			}
			
			else if( EnablePID == 0 ){ 	        /*上位机给出控制量*/		
				U=sPID.CalValue.sValue._UH+sPID.CalValue.sValue._UL/256.0;
				CheckU();
				if ((U-Angle)>Sens) {
					set_jdq_mode(2);
					MotorDir =2;
				}	/*正转*/
				else if ((U-Angle)<-Sens) {
					set_jdq_mode(1);
					MotorDir =1;
				}	/*反转*/	
				else {
					set_jdq_mode(0);
					MotorDir = 0;
				}   /*停转*/
			}			
			else if (EnablePID==2)  {              /*由上位机直接控制电机正反转*/
				set_jdq_mode(sPID.ReceiveValue.sValue.CMod.MotorDirec);
				MotorDir=sPID.ReceiveValue.sValue.CMod.MotorDirec;
			}
		}
		UpdateData();  	                    /*所有参数发送上位机,为测试用总更新*/    
		
	/****===============****/	
        if((AutoFlag==0)&&(Angle>0)){  /***==电机反转至关闭==>手动 ==***/
			set_jdq_mode(1);
            MotorDir =1;    
		}
	/***===++倒计时差1分钟时开始报警,定时器1修改AlarmFlag ++===***/
		if((AlarmFlag==1)&&(AutoFlag == 1)){
           PinAlarm();
		}
				
	}while(1);
}

/* 定时器0中断服务子程序,控制主程序计算温度和角度*/
void timer0_int()  interrupt 1 using 1    
{
	EA=0;
	TR0=0;
	TempTimes++;
	DispTtime++;
	if(TempTimes >= 15)    /*1秒钟计算一次温度和角度*/
	{
		TempTimes = 0;
		TempFlag=1;	
	}
	
	if(DispTtime >= 46){   /*******++++++++++++++++++*******/
		DispTtime = 0;
		DispTFlag = TRUE;
	}
	
	TH0=0;
	TL0=0;/*定时周期65ms*/
    TR0=1;/*start timer*/
	EA=1;
	return;
}

/* 定时器1中断服务子程序,控制设定值*/
void Timer1_int() interrupt 3 using 1
{
	EA = 0;						/*关中断*/
	TR1 = 0;					/*停止计数*/
	if(SP_nCount >= 200){		/*每隔10s计数一次*/
		if(abs(SP2-Rk) >= SPOneStepVal){
			
			if(SPOneStepValSign == 1){
				SP_temp += SPOneStepVal;
			}
			else {
				SP_temp -= SPOneStepVal;
			}
			
			SP_nCount = 0;
			Rk = SP_temp;
		}					
	
		 /***+++++++++++++++++++++++***/ 
	     AlarmTime++;
	     if(SP1toSP2Time<=1)   /***倒计时差一分钟时报警***/
	         AlarmFlag = 1;
	}							
	SP_nCount++;
	
	if((AlarmTime>=6)&&(SP1toSP2Time>0)){       /***过了一分钟***/
       SP1toSP2Time--;   /*设定值1到设定值2之间的时间减一*/           
       AlarmTime=0;
	}
	
	TH1 = 0x3c;
	TL1 = 0xaf;					/*定时周50ms*/
	TR1 = 1;	
	EA = 1;
	return;
}

/* 定时器2中断服务子程序,控制计算PID*/
void timer2_int() interrupt 5 using 1
{
	EA = 0;
	TR2 = 0;				/*定时器2停止计数*/
	TF2 = 0;				/*清除定时器2中断标志位,防止反复中断请求*/
	PIDTimes++;
	if(PIDTimes > (Ts*50))
	{
		PIDFlag = 1;		/*每个采样周期计算PID,定时周期为20ms,所以乘以50*/	
		PIDTimes = 0;		
	}
	TR2 = 1;				/*定时器2开始计数*/
	EA = 1;
	return;
}

/*外部中断0 命令帧中断处理函数*/
void sja_receive_int() interrupt 0 using 0
{
	BYTE i;
    BYTE reg;
	BYTE can_status; 
	BYTE xdata* psb;
	EA = 0;
	
	reg=read_sja(4);
	write_sja(4,0x00);
	can_status=receive();
	read_sja(3);
	
	if(can_status==0x00){/* is command frame */
		for(i=0;i<=10;i++){
			TXdata[i]=RXdata[i];	
		}
		TXdata[1] += 0x40;
		TXdata[2] += QD;
		TXdata[3] += 0x40;/*封装返回帧头*/
		
		switch(RXdata[4]) {
		case 0x02:/* 获取AD7703数据及室温数据 */
			if(RXdata[3] >= 0x02)			
				break;
			TXdata[5] = ad_val_bk[RXdata[3]];
			TXdata[6] = _iror_(ad_val_bk[RXdata[3]],8);
			TXdata[7] = cool_temp_bk;
			TXdata[8] = _iror_(cool_temp_bk,8);
			btransmit();
			break;
			
		case 0x04:  /*上位机向模块写ControlMod*/ 
			sPID.ReceiveValue.sValue.CMod.Tsample = RXdata[10];
			sPID.ReceiveValue.sValue.CMod.MotorDirec = RXdata[9];	  /*电机正反停转,0停1反2正*/
			sPID.ReceiveValue.sValue.CMod.PIDNorP = RXdata[8];		 /*PID正作用P,1或负作用N,0*/
			sPID.ReceiveValue.sValue.CMod.Feedback = RXdata[7];		 /*判断有无阀位反馈*/
			sPID.ReceiveValue.sValue.CMod.PIDModel = RXdata[6];      /*不同PID选择*/
			sPID.ReceiveValue.sValue.CMod.EnPID = RXdata[5]; /* PID开断 */
			
			TXdata[5]=4;
			TXdata[6]=4;
			TXdata[7]=4;
			TXdata[8]=4;
			TXdata[9]=4;
			TXdata[10]=4;
			DataFrame = 2;	/*设置标志,供Update_pid_para用*/
			OnNewData = TRUE;
			btransmit();
			break;
			
		case 0x05:  /*上位机从模块读ControlMod*/ 
			TXdata[10] = sPID.ReceiveValue.sValue.CMod.Tsample;
			TXdata[9] = sPID.ReceiveValue.sValue.CMod.MotorDirec;	  /*电机正反停转,0停1反2正*/
			TXdata[8] = sPID.ReceiveValue.sValue.CMod.PIDNorP;		  /*PID正作用P,1或负作用N,0*/
			TXdata[7] = sPID.ReceiveValue.sValue.CMod.Feedback;			/*判断有无阀位反馈*/
			TXdata[6] = sPID.ReceiveValue.sValue.CMod.PIDModel;      /*不同PID选择*/
			TXdata[5] = sPID.ReceiveValue.sValue.CMod.EnPID;         /* PID开断 */
			btransmit();
			break;
			
		case 0x20:/* 上位机向模块写命令   一帧一帧数据发送*/
			i=RXdata[3];
			if ((i>=0)&&(i<=1)) {

				save_pid(i,RXdata+5);
				DataFrame=i;
				OnNewData = TRUE; 
				TXdata[5] = 1;     	/*发送成功消息给上位机*/
				btransmit();
			}
			else {
			    TXdata[5] = 0;   /*发送出错消息给上位机*/
				TXdata[6] = i;  /*丢失的帧号*/
				btransmit();		
			}
			break;

			
			
			
/*========================================================================
							临时:测试用
  =======================================================================*/
		case 0x08:
			TXdata[6] = TempPIDUINT;
			TXdata[5] = TempPIDUINT >> 8;
			
			/*测试temp值*/

			TXdata[10] = Ek;
			TXdata[9] = Ek >> 8;
			TXdata[8] = Ek >> 16;
			TXdata[7] = Ek >> 24;
					
			btransmit();
			delay(4);
			break;
		
			


		case 0x21:/* 上位机向模块读命令  一帧一帧数据接收*/
			psb = sPID.SendValue.bValue;
			if  ((RXdata[3]>=0)&&(RXdata[3]<=2)) {				
				i=RXdata[3];
				TXdata[3] = 0x40 + i;
				memcpy((BYTE*)(TXdata+5),psb+6*i,6);
				btransmit();
				delay(4);				
			}
			break;
		
		case 0x25:
			ResetFlag=1;			 /*init_system(); 软件重新初始化*/
			TXdata[5]=0x25;
			TXdata[6]=0x25;
			TXdata[7]=0x25;
			TXdata[8]=0x25;
			TXdata[9]=0x25;
			TXdata[10]=0x25;
			btransmit();
			break;
		
		case 0x26:		/*利用看门狗硬件复位*/
			TXdata[5]=0x26;
			TXdata[6]=0x26;
			TXdata[7]=0x26;
			TXdata[8]=0x26;
			TXdata[9]=0x26;
			TXdata[10]=0x26;
			btransmit();
			while(1) {;
			}			/*看门狗复位*/
			break;
		default:			
			break;
		}
	}
	write_sja(4,reg);
	EA = 1;
	return;
}

void KeyBoard_int() interrupt 2 using 0
{
	EA = 0;		/*关键盘中断*/
	ScanKey();		/*扫描键盘*/
	EA = 1;		/*开键盘中断*/
	return;
}

⌨️ 快捷键说明

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