STC15实现温控闭环控制,数码管显示温度,按键调节温度,PID控制

STC15实现温控闭环控制,数码管显示温度,按键调节温度,PID控制

1.控温系统的PWM控制方案
① 加热元件和驱动电路设计
② 控温的工作原理及加热元件的数学模型,特别是模型参数的确定
③ PCA、PWM波形产生方法
ⅰ) 寄存器配置及编程
ⅱ) 8位PWM与16位PWM产生方法
2.温度采样原理与实现方法
① 温度传感器工作原理与输出关系
② 放大电路设计
③ A/D转换程序设计
3.温度控制闭环系统结构图与数学模型建立,以及与MCU的关系(参考下图设计出本系统结构)

① PID数字控制与编程方法
② PID参数整定
4.温度设定与显示
① LED数码管显示的电路设计及相关计算
② 数码管控制方案与温度显示的编程方法
③ 键盘设置的电路设计与编程方法

#include "STC15.H"
#include "intrins.h"

#define display P2 
typedef unsigned char uchar;
typedef unsigned int uint;

sbit Led_CS1 = P0^0;	   	//位定义
sbit Led_CS2 = P0^1;
sbit Led_CS3 = P0^2;
sbit Led_CS4 = P0^3;
sbit Key_Tup = P0^4;
sbit Key_Tdown = P0^5;
sbit Key_Confirm = P0^6;
							//数码管数值码表	共阳极接法
uchar code TABLE[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90};
char SetT = 40;   			//设定温度初始化为 40 摄氏度
float RealT = 25;  			//实际温度初始化为 25 摄氏度
float Error = 0;  			//当前误差
float ErrorInt = 0;	  		//累积误差			设定温度太大可能溢出
float Kp = 25,Ki = 0.5e-3;	//PID参数
float u;		  			//控制量
float pwmduty;	  			//PWM波占空比
//uint ADCRESValue;			//ADC10位采样值	  	调试实际温度数码管闪烁时用

void IO_Init();	  			//IO端口初始化
void AD_Init();	  			//AD模块初始化
void PWM_Init();  			//PWM模块初始化
							
void SetTemperature();		//设定温度
void KeyScan();	  			//按键扫描
void SetTdisp();   			//设定温度显示
void RealTdisp();			//实际温度显示
void getRealT();  			//测温
void PIDControl();			//PID调节
void PWMOutput(); 			//PWM/DA输出
//void ADCRESshow();		//AD采样后,寄存器值显示	调试实际温度数码管闪烁时用
void delay1ms();
void delay5ms();

void main()
{						  	
	IO_Init();				//与数码管段选、片选以及按键有关的Io端口初始化
	AD_Init();				//AD模块初始化
	PWM_Init();				//PWM模块初始化


	while(1)
	{
		SetTemperature();	//设定温度
		
		getRealT();			//测温

		PIDControl();		//PID调节
		
		PWMOutput();		//PWM/DA输出
				
		SetTdisp();			//设定温度显示
		RealTdisp();		//实际温度显示
		
//		ADCRESshow();		//AD采样后,寄存器值显示	调试实际温度数码管闪烁时用
	}

	return;
}

void IO_Init()		    //与数码管段选、片选以及按键有关的Io端口初始化
{
	
	P0M1 = 0xF0;		// P0.0~P0.3 初始化为输出;P0.4~P0.7初始化为输入
	P0M0 = 0x0F;
	
	P2M1 = 0x00;	   	// P2口初始化为输出
	P2M0 = 0xFF;	

	return;
}

void AD_Init()			//AD模块初始化
{
	P1ASF = 0x01;		//设定 P1.0 作为AD使用

	ADC_CONTR = 0x60;	//关闭ADC电源;90个时钟周期转换1次
						//结束标志位、启动控制位清零;输入通道选择 P1.0
	CLK_DIV &= 0xDF;	//ADRJ:ADC转换结果存放位置调整

	EA = 1;				//CPU开放中断;禁止AD转换中断
	EADC = 0;

	PADC = 1;		   	//AD转换中断为最高优先级

	return;
}

void PWM_Init()		    //PWM模块初始化
{
	P1M1 &= 0xFD;		//P1.1设为输出
	P1M0 |= 0x02;	

	CMOD = 0x80; 		//空闲模式下计数器停止计数;时钟源输入选择 SYSCLK/12
						//禁止计数器溢出中断
	CCON = 0x00;		//溢出标志位CF清零;运动控制位清零;
						//PCA模块0、1、2中断标志清零
	CCAPM0 = 0x42;		//PCA模块0工作于PWM模式;禁止CCF0中断

	PCA_PWM0 = 0x00;	//8位PWM功能;EPC0H = EPC0L = 0

	P_SW1 &= 0xCF;		//CCP切换为P1

	CH = 0x00;			//PCA装载值清零
	CL = 0x00;
	
	CCAP0H = 0xFF;		//捕获寄存器值,初始化占空比为 1/256
	CCAP0L = 0xFF;		
	
	CCON |= 0x40;		//启动PWM输出
	
	return;	
}

void SetTemperature()					//设定温度
{
	if( !(Key_Tup & Key_Tdown) )	 	//检测 升温/降温 按键是否按下
	{									//进入设定温度过程
		uchar i,j;
		do
		{
			KeyScan();				   	//按键扫描

			getRealT();					//测温

			for(i=0;i<2;i++)			//设定温度闪烁显示,用来指示设定温度过程
			{							//实际温度常量

				if( i==0 )				//设定温度显示
					for(j=0;j<20;j++)
					{
						SetTdisp();
						RealTdisp();
					}
				
				if( i==1 )			   	//设定温度不显示
					for(j=0;j<20;j++)
					{
						delay5ms();
						delay5ms();
						RealTdisp();
					}
							
			}

		}while(Key_Confirm);			//直到确认键按下,退出设定温度过程

	}

	return;
}

void KeyScan()						 	//按键扫描
{
	static uchar flag = 0;			   	//设置标志位

	if( !(Key_Tup & Key_Tdown) )	   	//检测 升温/降温 按键是否按下
	{
		if(!flag)					   	//标志位为0时才进行 升温/降温,产生延时效果
		{							   	//防止按键按下过程中	升温/降温 多次,同时不占用CPU
			if(!Key_Tup)			   	//升温
			{
				SetT++;
				if(SetT > 99)
					SetT = 0;
			}

			if(!Key_Tdown)			   	//降温
			{
				SetT--;
				if(SetT < 0)
					SetT = 0;
			}
		}
		
		flag++;							//标志位加一

		if(flag == 15);					//标志位加到15清零
			flag = 0;
	}			 
	else								//无按键按下,标志位清零
		flag = 0;

	return;
}
										
void SetTdisp()							//设定温度显示
{

	Led_CS1 = 0;
	Led_CS2 = 1;
	Led_CS3 = 1;
	Led_CS4 = 1;
	display = TABLE[SetT/10];
	delay5ms();

	Led_CS1 = 1;
	Led_CS2 = 0;
	Led_CS3 = 1;
	Led_CS4 = 1;
	display = TABLE[SetT%10];
	delay5ms();

	Led_CS1 = 1;
	Led_CS2 = 1;
	Led_CS3 = 1;
	Led_CS4 = 1;

	return;
}

void RealTdisp()						//实际温度显示
{
	uchar T = (uchar) RealT;

	Led_CS1 = 1;
	Led_CS2 = 1;
	Led_CS3 = 0;
	Led_CS4 = 1;
	display = TABLE[T/10];
	delay5ms();

	Led_CS1 = 1;
	Led_CS2 = 1;
	Led_CS3 = 1;
	Led_CS4 = 0;
	display = TABLE[T%10];
	delay5ms();

	Led_CS1 = 1;
	Led_CS2 = 1;
	Led_CS3 = 1;
	Led_CS4 = 1;

	return;
}

void getRealT()							//测温
{
	/*
	uint AD_Data = 0;
	uchar Temp = 0;

	ADC_CONTR |= 0x80;
	delay1ms();

	ADC_CONTR |= 0x08;
	while( !(ADC_CONTR & 0x10) );
	ADC_CONTR &= 0x67;
	 
//	AD_Data = ADC_RES;					//(1)无滤波
//	AD_Data <<= 2;
//	Temp = ADC_RESL;
//	Temp &= 0x03;
//	AD_Data |= Temp;
								   	
	ADC_RESL &= 0x03;					//(2)无滤波
	RealT = (uchar)((ADC_RES*4+ADC_RESL)/1023.0*100);	//出现bug,以后注意!!!
	*/

	
	uint temp = 0;				   		//(3)均值滤波	效果最好
	uchar i;
	ADC_CONTR |= 0x80;					//开电源
	delay1ms();							//延时1ms
	for(i = 0;i < 20;i++)				//采样20次
	{
		ADC_CONTR |= 0x08;				//开始采样
		while( !(ADC_CONTR & 0x10) );	//查询转换是否完成
		ADC_CONTR &= 0xE7;				//停止转换,清标志位
		ADC_RESL &= 0x03;				//计算10位采样值
		temp += ADC_RES*4+ADC_RESL;	
	}
	ADC_CONTR &= 0x7F;				   	//关电源

//	ADCRESValue = temp/20;				//计算20次10位采样值的平均值
										//调试实际温度数码管闪烁时用
	RealT = temp/20.0/1023.0*100;		//计算20次平均温度
	

	/*
	uint SampleValue[31] = {0},temp;	//(4)中值滤波	不太稳定	
	uchar i,j,k;
	ADC_CONTR |= 0x80;					//开电源
	delay1ms();							//延时1ms

	ADC_CONTR |= 0x08;					//采第一个值
	while( !(ADC_CONTR & 0x10) );
	ADC_CONTR &= 0xE7;

	ADC_RESL &= 0x03;
	SampleValue[0] = ADC_RES*4+ADC_RESL;

	for(i = 1;i < 31;i++)				//再采20个(共21个)	同时将21个值排序
	{
		ADC_CONTR |= 0x08;
		while( !(ADC_CONTR & 0x10) );
		ADC_CONTR &= 0xE7;

		ADC_RESL &= 0x03;
		temp = ADC_RES*4+ADC_RESL;
		for(j = 0;j < i;j++)
		{
			if(temp < SampleValue[j])
			{
				for(k = i;k > j;k--)
					SampleValue[k] = SampleValue[k-1];
				SampleValue[j] = temp;
				break;	
			}
		}
		if(j == i)
		{
			SampleValue[j] = temp;
		}
	}
	ADC_CONTR &= 0x7F;					//关电源

//	ADCRESValue = SampleValue[15];		//取中值	调试实际温度数码管闪烁时用

	RealT = (uchar)( SampleValue[15]/1023.0*100 ); 	//计算实际温度
	*/

	return;
}

void PIDControl()							//PID调节
{
	
	Error = (float)SetT - RealT;			//注意数据类型!!!
	ErrorInt += Error;
	u = Kp*Error + Ki*ErrorInt;
	
	return;
}

void PWMOutput()							//PWM/DA输出
{
	pwmduty = u/255;					   	//计算占空比

	if(pwmduty >0.9)		  				//占空比限幅
		pwmduty = 0.9;
	if(pwmduty < 0.1)
		pwmduty = 0.1;

	CCAP0H = (uchar)(256*(1-pwmduty));		//占空比调节

	return;
}

void delay1ms()   
{
    unsigned char a,b;
    for(b=4;b>0;b--)
        for(a=248;a>0;a--);
    _nop_();  //if Keil,require use intrins.h
}

void delay5ms()  
{
    unsigned char a,b;
    for(b=19;b>0;b--)
        for(a=130;a>0;a--);
}

//void ADCRESshow()						//AD采样后,寄存器值显示	
//{										//调试实际温度数码管闪烁时用
//
	ADCRESValue = ADC_RES*4+ADC_RESL;	//不使用滤波算法时使用
	ADCRESValue	= (uint)ErrorInt;		//可以观测误差变化
	ADCRESValue	= (uint)ErrorInt;		//可以观测误差累积的变化
//
//	Led_CS1 = 0;
//	Led_CS2 = 1;
//	Led_CS3 = 1;
//	Led_CS4 = 1;
//	display = TABLE[ADCRESValue/1000];
//	ADCRESValue -= (ADCRESValue/1000)*1000;
//	delay5ms();
//
//	Led_CS1 = 1;
//	Led_CS2 = 0;
//	Led_CS3 = 1;
//	Led_CS4 = 1;
//	display = TABLE[ADCRESValue/100];
//	ADCRESValue -= (ADCRESValue/100)*100;
//	delay5ms();
//
//
//	Led_CS1 = 1;
//	Led_CS2 = 1;
//	Led_CS3 = 0;
//	Led_CS4 = 1;
//	display = TABLE[ADCRESValue/10];
//	delay5ms();
//
//	Led_CS1 = 1;
//	Led_CS2 = 1;
//	Led_CS3 = 1;
//	Led_CS4 = 0;
//	display = TABLE[ADCRESValue%10];
//	delay5ms();
//
//	Led_CS1 = 1;
//	Led_CS2 = 1;
//	Led_CS3 = 1;
//	Led_CS4 = 1;
//
//	return;
//}
  • 3
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值