基于Atmega16的温度测控系统PID算法.docx
《基于Atmega16的温度测控系统PID算法.docx》由会员分享,可在线阅读,更多相关《基于Atmega16的温度测控系统PID算法.docx(20页珍藏版)》请在冰豆网上搜索。
![基于Atmega16的温度测控系统PID算法.docx](https://file1.bdocx.com/fileroot1/2022-11/21/55f33149-79fc-4c8b-92b0-67a18c8a03f3/55f33149-79fc-4c8b-92b0-67a18c8a03f31.gif)
基于Atmega16的温度测控系统PID算法
//编译器:
AVRStudio
头文件部分:
#include
#defineucharunsignedchar
#defineucharunsignedchar
#defineuintunsignedint
voidconvert(floatdata);
voidinit_1820(void);
voidwrite_1820(ucharx);
ucharread_1820(void);
floatread_temperature(void);
charkey_scan();
intlcd_bz();
voidlcd_wcmd(ucharcmd);
voidlcd_pos(ucharpos);
voidlcd_wdat(uchardat);
voidlcd_wstr(unsignedcharpos,unsignedchar*q);
voidlcd_init();
voidavr_init();
voiddelay(intus);
voiddelayl(intms);
voiddelay1(intms);
按键程序
#include
#include"headfile.h"
//............................按键.................................
charkey_scan()
{
inttemp=0,temp1,temp2;
charkey;
DDRA=0xf0;
PORTA&=0x0f;
delay1(3);
temp1=PINA&0x0f;
if(temp1!
=0x0f)
{
delay1(80);
temp1=PINA&0x0f;
if(temp1!
=0x0f)
{
DDRA=0x0f;
PORTA&=0xf0;
delay1(5);
temp2=PINA&0xf0;
if(temp2!
=0xf0)
{
temp=temp1+temp2;
}
}
}
switch(temp)
{
case0xee:
key='/';break;//7
case0xde:
key='*';break;//8
case0xbe:
key='-';break;//9
case0x7e:
key='+';break;//+
case0xed:
key='.';break;//4
case0xdd:
key='9';break;//5
case0xbd:
key='6';break;//6
case0x7d:
key='3';break;//-
case0xeb:
key='=';break;//1
case0xdb:
key='8';break;//2
case0xbb:
key='5';break;//3
case0x7b:
key='2';break;//*
case0xe7:
key='0';break;//0
case0xd7:
key='7';break;//.
case0xb7:
key='4';break;//=
case0x77:
key='1';break;///
default:
key=0;break;
}
returnkey;
}
1602显示程序
#include
//#include
#defineep_1(PORTB|=0x04)
#defineep_0(PORTB&=~0x04)
#definers_1(PORTB|=0x01)
#definers_0(PORTB&=~0x01)
#definerw_1(PORTB|=0x02)
#definerw_0(PORTB&=~0x02)
#defineucharunsignedchar
#defineuintunsignedint
//.....................LCD............................
//..............................测试LCD忙碌状态.........................................................................................................
intlcd_bz()
{
DDRC&=~0x80;
intresult=0;
rs_0;
rw_1;
ep_1;
result=(result||(PINC&0x80));
ep_0;
DDRC=0xff;
returnresult;
}
//.................................写入指令数据到LCD..............................................................................................................................
voidlcd_wcmd(ucharcmd)
{
while(lcd_bz());
rs_0;
rw_0;
ep_0;
PORTC=cmd;
ep_1;
ep_0;
delay(5);
}
//..........................设定显示位置........................................................................
voidlcd_pos(ucharpos)
{
lcd_wcmd(pos|0x80);
delay(5);
}
//...........................写入字符显示数据到LCD.........................................................
voidlcd_wdat(uchardat)
{
while(lcd_bz());
rs_1;
rw_0;
ep_0;
PORTC=dat;
ep_1;
ep_0;
}
//.........................写入字符显示数组到LCD.....................................
voidlcd_wstr(unsignedcharpos,unsignedchar*q)
{
//lcd_wcmd(0x01);//清屏
//delay(10);
unsignedchari=0x00;
lcd_pos(pos);
while(*q!
='\0')
{
lcd_wdat(*q);
q++;
i++;
if(i==(0x0F-pos+1))
lcd_pos(0x40);
delay(10);
}
}/**/
//........................LCD初始化设定.............................................
voidlcd_init()
{
lcd_wcmd(0x38);//functionset
delay(10);
lcd_wcmd(0x38);//functionset
delay(10);
lcd_wcmd(0x0c);//displayon/off
delay(10);
lcd_wcmd(0x06);//entrymodeset
delay(10);
lcd_wcmd(0x01);//清除LCD的显示内容
delay(10);
}
//........................avr初始化.................//
voidavr_init()
{
DDRC=0xFF;
DDRB=0x07;
}
18b20程序
#include
#defineucharunsignedchar
#defineucharunsignedchar
#defineuintunsignedint
//------------------------//
//.................convert:
datadisplay.............
voidconvert(floatdata)//实数在液晶上显示
{
inti=0;
intdata1=(int)data;
uchararray1[5]={0},array2[5]={0};
lcd_wcmd(0x01);
//lcd_wcmd(0x00);
lcd_pos(0x0B);
//
if(data1==0)
{
array1[0]=0;
lcd_wdat(48);
//delay1(5);
}
else
while(data1!
=0)
{
array1[i]=data1%10;
data1=data1/10;
i++;
}
for(--i;i>=0;i--)
{
lcd_wdat(array1[i]+48);
//delay1(5);
}//显示小数点前面
lcd_wdat(0x2E);//显示小数点
for(i=0;i<2;i++)//显示小数部分前两位
{
data=data*10;
array2[i]=((int)data)%10;
lcd_wdat(array2[i]+48);
//delay1(5);
}
}
//...................18B20......................
voidinit_1820(void)
{
intFlag_1820Error;
uchari;
uintj=0;
PORTD|=(1<<7);//PORTC|=(1<<7);//"1"
PORTD&=~(1<<7);//PORTC&=~(1<<7);//"0"
for(i=0;i<8;i++)delay(180);//delay_60us();//480us以上
PORTD|=(1<<7);//PORTC|=(1<<7);//"1"
DDRD&=~(1<<7);//DDRC&=~(1<<7);//"PINC7isINPUT"
delay(40);//delay_15us();//15~60us
delay(40);//delay_15us();
Flag_1820Error=0;
while(PIND&(1<<7))//while(PINC&(1<<7))
{delay(180);//delay_60us();
j++;
if(j>=18000){Flag_1820Error=1;break;}
}
DDRD|=(1<<7);//DDRC|=(1<<7);//PORTC7isOUTPUT
PORTD|=(1<<7);//PORTC|=(1<<7);//"1"
for(i=0;i<4;i++)delay(180);//delay_60us();//240us
}
/********************************/
/********************************/
voidwrite_1820(ucharx)
{
ucharm;
for(m=0;m<8;m++)
{
if(x&(1<{
PORTD&=~(1<<7);//PORTC&=~(1<<7);delay_5us();//"0",5us
PORTD|=(1<<7);//PORTC|=(1<<7);//write"1"
delay(40);//delay_15us();//15~45us
delay(40);//delay_15us();
delay(40);//delay_15us();
}
else
{
PORTD&=~(1<<7);//PORTC&=~(1<<7);delay_15us();//"0",15us
delay(40);//delay_15us();//write"0"
delay(40);//delay_15us();//15~45us
delay(40);//delay_15us();
PORTD|=(1<<7);//PORTC|=(1<<7);//"1"
}
}
PORTD|=(1<<7);//PORTC|=(1<<7);//"1"
}
/*******************************/
ucharread_1820(void)
{
uchartemp,k,n;
temp=0;
for(n=0;n<8;n++)
{
PORTD&=~(1<<7);//PORTC&=~(1<<7);//"0"
delay(13);//delay_5us();
PORTD|=(1<<7);//PORTC|=(1<<7);//"1"
delay(13);//delay_5us();
DDRD&=~(1<<7);//DDRC&=~(1<<7);//"PINC7isINPUT"
k=(PIND&(1<<7));//k=(PINC&(1<<7));//读数据,从低位开始
if(k)
temp|=(1<else
temp&=~(1<delay(40);//delay_15us();//45us
delay(40);//delay_15us();
delay(40);//delay_15us();
DDRD|=(1<<7);//DDRC|=(1<<7);//PORTC7isOUTPUT
}
return(temp);
}
/*************************************/
floatread_temperature(void)
{
floattemp;////////////
ucharteml=0,temh=0;
unsignedlongt=0;
init_1820();//复位18b20
write_1820(0xcc);//发出转换命令
write_1820(0x44);
//Delay_nms(100);
init_1820();
write_1820(0xcc);//发出读命令
write_1820(0xbe);
teml=read_1820();//读数据byte1
temh=read_1820();//byte2
t=temh;
t=t<<8;
t=t|teml;
temp=t*0.0625*260/286;
return(temp);
/*if(temh&0xf8)sign=0;
elsesign=1;
if(sign==0){temh=255-temh;teml=255-teml;}
temh=temh<<4;
temh|=(teml&0xf0)>>4;
teml=teml&0x0f;
teml=(teml*10)/16;
tempval=temh;e[0]=tempval/100;
tempval=temh;e[1]=(tempval/10)%10;
tempval=temh;e[2]=tempval%10;
tempval=teml;e[3]=tempval;*/
}
Main程序
#include
#include"headfile.h"
#include
#include
#include
#include
#include
unsignedcharkey[5];//按键数组
floatkeyvalue;//按键值
floatactual;//温度值
unsignedintflag=0;//判断按键标志
unsignedchardis1[]={"SET"};
unsignedchardis2[]={"NOW"};
unsignedchardis3[]={"00:
00"};
unsignedinth=0;//定时1S计时10000次
unsignedcount=0;//计算动态时间
floatPWM=0;
floatPWM1=0;
floatError1;//误差
unsignedintmaxminflag=0;//判断达到动态平衡标志
unsignedchartime[7];//存储动态时间
structPID
{
floatSetPoint;//设定目标DesiredValue
floatProportion;//比例常数ProportionalConst
floatIntegral;//积分常数IntegralConst
floatDerivative;//微分常数DerivativeConst
floatLastError;//Error1[‐1]
floatPrevError;//Error1[‐2]
};
structPIDspid;//PIDControlStructure
structPID*pp;
/***************PID结构体初始化*****/
voidPIDInit(structPID*pp)
{
memset(pp,0,sizeof(structPID));
}
/*****************PID参数设置******************/
voidsetPID(floata,floatb,floatc)
{
pp->Proportion=a;
pp->Integral=b;
pp->Derivative=c;
}
/***********PID计算部分***************************//////////////
floatPIDCalc(structPID*pp,floatNextPoint)
{
floatdError;
unsignedinta;
Error1=pp->SetPoint-NextPoint;//当前偏差
if(fabs(Error1)<10)a=1;
elsea=0;
dError=pp->Proportion*(Error1-pp->LastError)
+a*pp->Integral*pp->LastError
+a*pp->Derivative*(Error1-2*pp->LastError+pp->PrevError);
/*dError=pp->Proportion*Error1
-pp->Integral*pp->LastError
+pp->Derivative*pp->PrevError;
if(fabs(Error1)<=14)
a=1;
else
a=0;
dError=pp->Proportion*(Error1-pp->LastError)+a*pp->Integral*pp->LastError+
pp->Derivative*(Error1-2*pp->LastError+pp->PrevError);*/
pp->PrevError=pp->LastError;
pp->LastError=Error1;
return(dError);//微分项
}
/*********************PWM占空比设置/**********************/////////
voidsetPWM(floatdError)
{
if(fabs(Error1)<10)PWM+=4*dError;
elsePWM+=6*dError;
//PWM+=6*dError;
PWM1=1023-PWM;
if(PWM1<10)PWM1=10;
elseif(PWM1>1020)PWM1=1020;
OCR1BH=(int)(PWM1/256);
OCR1BL=(int)PWM1%256;
}
voidfactor(void)//确认按键值
{
unsignedchartmp;
inti=0;
inttemp1,temp2;
flag=0;
floatkey1=0,key2=0;
while(!
flag)
{
while(!
(tmp=key_scan()));
if(tmp=='*')flag=1;
elseif(tmp=='=')flag=2;
else
{
key[i]=tmp;
lcd_pos(0x03+i);
lcd_wdat(key[i]);
i++;
}
}
key[i]='\0';
keyvalue=(key[0]-48)*10+(key[1]-48)+(key[3]-48)*0.1+(key[4]-48)*0.01+0.5;//0.5是矫正
/*for(i=0;i<5;i++)
{
if(key[i]=='.')temp1=i;if(key[i]=='\0')temp2=i;
}
//if(temp1>=0&&temp1<=4)
for(i=temp
else1-1;i>=0;i--)
key1=key1+(key[i]-48)*pow(10,temp1-1-i);//10^(temp1-1-i)
for(i=temp1+1;ikey2=key2+(key[i]-48)*pow(10,temp1-i);//10^(temp1-i)
keyvalue=key1+key2;*/
pp->SetPoint=keyvalue;
}
/************从DS18B20获得实际温度值并设置显示位置*************