基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)实物图、仿真工程、源代码

基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)
源代码
仿真工程
实物图
原理图
PCB图基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)实物图、仿真工程、源代码_第1张图片
基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)实物图、仿真工程、源代码_第2张图片
基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)实物图、仿真工程、源代码_第3张图片
基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)实物图、仿真工程、源代码_第4张图片
基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)实物图、仿真工程、源代码_第5张图片
基于单片机PID算法的恒温控制系统仿真与程序源码设计(DS18B20传感器)实物图、仿真工程、源代码_第6张图片

#include 
#include 
#include 
#include 
struct PID { 
unsigned int SetPoint; // 设定目标 Desired Value 
unsigned int Proportion; // 比例常数 Proportional Const 
unsigned int Integral; // 积分常数 Integral Const 
unsigned int Derivative; // 微分常数 Derivative Const 
unsigned int LastError; // Error[-1] 
unsigned int PrevError; // Error[-2] 
unsigned int SumError; // Sums of Errors 
}; 
struct PID spid; // PID Control Structure 
unsigned int rout; // PID Response (Output) 响应输出
unsigned int rin; // PID Feedback (Input)//反馈输入
 unsigned char high_time,low_time,count=0;//占空比调节参数 
#define uchar unsigned char
#define uint unsigned int

sbit output=P1^0;
sbit ds=P3^2;
sbit DQ=P3^2;//ds18b20与单片机连接口
sbit lcden=P2^7;//LCE使能引脚
sbit lcdrs=P2^5;
sbit lcdrw=P2^6;
sbit ledred=P1^6;
sbit ledgreen=P1^7;

sbit key0=P2^0;//按键引脚 
sbit key1=P2^1;

uchar set[2]={0};
uchar code str1[]="now temp:      C";
uchar code str2[]="set temp:      C";
uchar code table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
uchar n,num;
int set_temper=30,temper,temp; //温度变量定义
unsigned int s;
float 	f_temp;//转换后的温度

uint tvalue;         
uchar tflag;//温度正负标志

void delay(i)//延时函数
{
	uint j;
	for(i;i>0;i--)
	for(j=110;j>0;j--);
}


void wr_com(uchar ml)//写命令
{
	lcdrs=0;
	P0=ml;
	delay(5);
	lcden=1;
	delay(5);
	lcden=0;

}



void wr_data(uchar shuju)//写数据
{
	lcdrs=1;
	//lcden=1;
	P0=shuju;
	delay(5);
	lcden=1;
	delay(5);
	lcden=0;

}

void init()  //按照时序操作的初始化
{	
	lcdrw=0;
	wr_com(0x38);//显示模式设置,设置为16*2显示,5*7点阵,八位数据口
	wr_com(0x0c);//开显示,但不开光标,光标不闪
	wr_com(0x06);//显示光标移动设置
	wr_com(0x01);// 清屏
	wr_com(0x80);	// 数据指针初始化
	for(num=0;num<16;num++)
		{
			wr_data(str1[num]);//now temp
		}
	wr_com(0x80+0x40); //地址初始化
	for(num=0;num<16;num++)
		{
			wr_data(str2[num]);//set temp
		}	 
}

/*************************DS1820程序****************************/
void delay_18B20(unsigned int i)//延时1微秒
{
   while(i--);
}

void ds1820rst(void)/*ds1820复位*/
{ 
	unsigned char x=0;
	DQ = 1;          //DQ复位
	delay_18B20(4); //延时
	DQ = 0;          //DQ拉低
   TR0=0;
	delay_18B20(100); //精确延时大于
   TR0=1;
	DQ = 1;          //拉高
	delay_18B20(40); 
} 

uchar ds1820rd(void)/*读数据*/
{ 
	unsigned char i=0;
	unsigned char dat = 0;
   TR0=0;
	for (i=8;i>0;i--)
	{   
		DQ = 0; //给脉冲信号
		dat>>=1;
		DQ = 1; //给脉冲信号
		if(DQ)
		dat|=0x80;
		delay_18B20(10);
	}
   return(dat);
}

void ds1820wr(uchar wdata)/*写数据*/
{
	unsigned char i=0;
   TR0=0;
   for (i=8; i>0; i--)
   { 
		DQ = 0;
		DQ = wdata&0x01;
		delay_18B20(10);
		DQ = 1;
		wdata>>=1;
   }
}



uint get_temper()//获取温度
{  
     
	uchar a,b;

	ds1820rst();    
	ds1820wr(0xcc);//*跳过读序列号*/
	ds1820wr(0x44);//*启动温度转换*/
	ds1820rst();    
	ds1820wr(0xcc);//*跳过读序列号*/ 
	ds1820wr(0xbe);//*读取温度*/ 
	a=ds1820rd();
	b=ds1820rd();
   
	tvalue=b;
	tvalue<<=8;
	tvalue=tvalue|a;
   TR0=1;
   if(tvalue<0x0fff)   tflag=0;
   else {tvalue=~tvalue+1;tflag=1;}
	tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
	temp=tvalue;
	return temp;
}


void dis_temp(int t)//显示温度
{
	uchar d0,d1,d2,d3;
	//t=26;
	if(tflag==0)
	{
		d0=t/1000+0x30;
		d1=t%1000/100+0x30;
		d2=t%100/10+0x30;
		d3=t%10+0x30;
		if(d0==0x30)
		{
			wr_com(0x80+9);
			wr_data(d1);
			wr_com(0x80+10);
			wr_data(d2);
			wr_com(0x80+11);
			wr_data(0x2e);
			wr_com(0x80+12);
			wr_data(d3);
		}
		else
		{
			wr_com(0x80+9);
			wr_data(d0);
			wr_com(0x80+10);
			wr_data(d1);
			wr_com(0x80+11);
			wr_data(d2);
			wr_com(0x80+12);
			wr_data(' ');
		}
		
	}
	else
	{
		wr_com(0x80+9);
		wr_data('-');
		wr_com(0x80+10);
		wr_data(d1);
		wr_com(0x80+11);
		wr_data(d2);
		wr_com(0x80+12);
		wr_data(' ');
		//wr_com(0x80+12);
		//wr_data(d3);
	}
	wr_com(0x80+14);
	wr_data(0xdf);
	temper=t/10;
}



void keyscan()//键盘扫描
{  

   if(key0==0)
   { 
		delay(1);
		if(key0==0)
		{
			while(!key0);
			delay(1);
			while(!key0);
			set_temper++;

		}

		set[0]=set_temper/10;	//获得设置温度显示值
		set[1]=set_temper%10;
		wr_com(0x80+0x40+9);
		wr_data(table[set[0]]);
		delay(1);
		wr_com(0x80+0x40+10);
		wr_data(table[set[1]]);
		delay(1);
		//wr_com(0x80+0x40+11);
		//wr_data(0x2e);
		//wr_com(0x80+0x40+14);
		//wr_data(0xdf);
		delay(1);
	}
	if(key1==0)
   {
		delay(3);//延时去抖
		if(key1==0)
		{
			while(!key1);
			delay(3);
			while(!key1);
			set_temper--;//温度减
			if(set_temper==0)
			{set_temper=0;}
		}

	
		set[0]=set_temper/10;	//获得设置温度显示值
		set[1]=set_temper%10;
		wr_com(0x80+0x40+9);	//显示设置温度值
		wr_data(table[set[0]]);
		delay(1);
		wr_com(0x80+0x40+10);
		wr_data(table[set[1]]);
		delay(1);
		//wr_com(0x80+0x40+11);
		//wr_data(0x2e);
		wr_com(0x80+0x40+14);
		wr_data(0xdf);
		delay(1);
	}
}

void PIDInit (struct PID *pp) 
{ 
	memset ( pp,0,sizeof(struct PID)); //用参数0初始化pp
} 



unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint ) //PID计算
{ 
	unsigned int dError,Error; 
	Error = pp->SetPoint - NextPoint; // 偏差 
	pp->SumError += Error; // 积分 
	dError = pp->LastError - pp->PrevError; // 当前微分 
	pp->PrevError = pp->LastError; 
	pp->LastError = Error; 
	return (pp->Proportion * Error//比例
	+ pp->Integral * pp->SumError  //积分项
	+ pp->Derivative * dError); //   微分项 
} 
/*********************************************************** 
温度比较处理子程序 
***********************************************************/ 
void compare_temper(void) 
{ 
	unsigned char i; 
	if(set_temper>temper) 	//设置温度大于当前温度
	{ 
		ledred=0;
		ledgreen=1;
		if(set_temper-temper>1) 	//温度相差1度以上
		{	 
			high_time=100; 
			low_time=0;
		} 
		else 	//设置温度不大于当前温度
		{ 
			for(i=0;i<10;i++) 
			{ 
				get_temper(); 
				rin = s; // Read Input 
				rout = PIDCalc ( &spid,rin ); // Perform PID Interation 
			} 
			if (high_time<=100) 	high_time=(unsigned char)(rout/800); 
			else	high_time=100; 
			low_time= (100-high_time); 
		} 
	} 
	else if(set_temper<=temper) 	//设置温度不大于当前温度
	{ 
		ledred=1;
		ledgreen=0;
		if(temper-set_temper>0) //温度相差0度以上
		{ 
			high_time=0; 
			low_time=100; 
		} 
		else 
		{ 
			for(i=0;i<10;i++) 
			{ 
				get_temper(); 
				rin = s; // Read Input 
				rout = PIDCalc ( &spid,rin ); // Perform PID Interation 
			} 
			if (high_time<100) high_time=(unsigned char)(rout/10000); 
			else 	high_time=0; 
			low_time= (100-high_time); 
		} 
	} 
} 
/***************************************************** 
T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期 
******************************************************/ 
void serve_T0() interrupt 1 using 1 
{ 
	if(++count<=(high_time)) 	output=0;
	else if(count<=100) 
	{ 
		output=1; 
	} 
	else count=0; 
	TH0=0x2f; 
	TL0=0x40; 
} 


/***********主函数**********/
void main(void)
{
	unsigned char i;
	init();//LCD初始化
	TMOD=0x01;
	TH0=0x2f; 
	TL0=0x40;
	EA=1;
	ET0=1;
	TR0=1;
	high_time=50; 
	low_time=50; 
	PIDInit ( &spid ); // Initialize Structure 
	spid.Proportion= 10; // Set PID Coefficients 
	spid.Integral = 8; 
	spid.Derivative =6; 
	spid.SetPoint =100; // Set PID Setpoint 
	set[0]=set_temper/10;
	set[1]=set_temper%10;
	wr_com(0x80+0x40+9);	//显示设置温度
	wr_data(table[set[0]]);
   delay(1);
	wr_com(0x80+0x40+10);
	wr_data(table[set[1]]);
	delay(1);
	wr_com(0x80+0x40+14);	//显示温度符号
	wr_data(0xdf);
	delay(1);
	while(1)
	{
		keyscan(); 	//按键扫描
		for(i=0;i<10;i++)	//循环10次
		{
			dis_temp(get_temper());	//显示温度值
			if((key0==0)||(key1==0)) break;	//如果有按键退出显示循环
		}
		if((key0!=0)&&(key1!=0))		compare_temper(); 	//比较温度
	}
}

你可能感兴趣的:(单片机,算法,嵌入式硬件)