您好,欢迎访问三七文档
/*****************************************************//*采用AT89C51为主控制芯片*//*P0口为数码管的段选口,P2.4~P2.7为位选口*//*DS18B20的DQ接P2.3,12MHZ晶振*//*P2^2,PWM控制脚*//*****************************************************/#includereg51.h#defineKp1//比例系数#defineKi0.25//积分系数#defineKd1//微分系数unsignedcharm,n,p;//温度的十位个位小数unsignedchartest_temp;//温度检定标志unsignedcharkey_set_flag;//按键设定进入标志unsignedcharkey_hold;//按键保持标志unsignedcharChange_step=1;//温度设置步进intReal_temp;//实际温度值intSet_temp;//设置温度intDisp_temp;//显示温度intlast_error;//上次误差floatI_term;//前面温差和intPID_MAX;unsignedintout,PWMT,counter;inttime;//可控硅脉冲触发时刻sbitDQ=P2^3;//定义DS18b20的管脚sbitL1=P2^7;//定义控制数码管的管脚sbitL2=P2^6;sbitL3=P2^5;sbitL4=P2^4;sbitPWM=P2^2;//PWM控制脚unsignedchartable[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x7F,0xbF,0xC6};//0-9数字,后面为.-C/*****延时子程序*****/voiddelay(unsignedintt){for(;t0;t--);}voiddelay_50us(unsignedintt){unsignedcharj;for(;t0;t--)for(j=19;j0;j--);}/*****初始化DS18B20*****/unsignedcharInit_DS18B20(void){unsignedcharx=0;DQ=1;//DQ复位delay(8);//稍做延时DQ=0;//单片机将DQ拉低delay(80);//精确延时,大于480usDQ=1;//拉高总线delay(8);x=DQ;//稍做延时后,如果x=0则初始化成功,x=1则初始化失败delay(4);returnx;}/*****读一个字节*****/unsignedcharReadOneChar(void){unsignedchari=0;unsignedchardat=0;for(i=8;i0;i--){DQ=0;//给脉冲信号dat=1;DQ=1;//给脉冲信号if(DQ)dat|=0x80;delay(4);}return(dat);}/*****写一个字节*****/voidWriteOneChar(unsignedchardat){unsignedchari=0;for(i=8;i0;i--){DQ=0;DQ=dat&0x01;delay(4);DQ=1;dat=1;}delay(4);}/*****读取温度*****/intReadTemperature(void){unsignedchara=0;unsignedcharb=0;unsignedintt=0;t=Init_DS18B20();if(t)returnReal_temp;WriteOneChar(0xCC);//跳过读序号列号的操作WriteOneChar(0x44);//启动温度转换//delay(10);t=Init_DS18B20();if(t)returnReal_temp;WriteOneChar(0xCC);//跳过读序号列号的操作WriteOneChar(0xBE);//读取温度寄存器a=ReadOneChar();//读低8位b=ReadOneChar();//读高8位t=b;t=8;t=t|a;if(t=0||t0x900)returnReal_temp;return(t);}voiddisplay(signedintdd)//数码管扫描函数{inttt=0;tt=(unsignedint)(dd*0.625+0.5);//放大10倍输出并四舍五入m=tt/100;//分离出十位n=(tt%100)/10;//分离出个位p=tt%10;//分离出小数位P0=table[m];L1=1;//暂未1,如用三极管驱动要改为0delay(300);L1=0;//后关闭显示P0=table[n];//P1=table[10];//第二位后显示中间点L2=1;delay(300);L2=0;P0=table[10];L2=1;delay(300);L2=0;P0=table[p];//小数部分L3=1;delay(300);L3=0;P0=table[12];L4=1;delay(300);L4=0;}voidkey_set(void){unsignedcharkey_value;key_value=P1;key_value&=0x07;//提取按键键值if(key_value!=7)//按键按下{if(!key_hold)//按键第一次按下{key_hold=1;//标志按键处于保持按下状态switch(key_value){//set键按下case6:{if(key_set_flag==0)//首次进入温度设置{key_set_flag=1;//标志温度设定状态Disp_temp=Set_temp;//显示温度值为原设定温度}else{Set_temp=Disp_temp;//新设定温度为当前显示温度key_set_flag=0;//清温度设定标志Change_step=1;//恢复缺省设定步进值}break;}//+键按下case5:{if(key_set_flag)Disp_temp+=Change_step;break;}//-键按下case3:{if(key_set_flag)Disp_temp-=Change_step;break;}//其他组合按键可以扩充,现暂未设置default:break;}}elseif(key_set_flag){//按键处于一直按下状态key_hold++;if(key_hold20)//按键计数超过设定时长{Change_step=16;//设定步长按1度步进key_hold=0;//清按键保持状态,可进入加减按键功能}}}elseif(key_hold){key_hold=0;//标志按键松开状态Change_step=1;}}intPID(intSet_value,intReal_value)//标准PID温度控制算法{interror;floatP_term,D_term;intpid_out;error=Set_value-Real_value;//误差量P_term=Kp*error;//比例量I_term+=Ki*error;//积分量if(I_termPID_MAX)I_term=PID_MAX;//限定积分量上限elseif(I_term0)I_term=0;//限定积分量下限D_term=Kd*(error-last_error);//微分量last_error=error;//缓存当前误差量pid_out=(signedint)(P_term+I_term+D_term);//PID控制量计算if(pid_outPID_MAX)pid_out=PID_MAX;//控制量上限=PID_MAXelseif(pid_out0)pid_out=0;//控制量下限=0return(pid_out);}voidInit0(void)interrupt0{TH0=time8;TL0=time&0x00FF;TF0=0;ET0=1;counter++;}voidT0_int(void)interrupt1{TH0=0xFF;TL0=0x80;if(PWM){PWM=0;TH0=0xDA;TL0=0x00;}elsePWM=1;}voidmain(){PWMT=128;//128级步进PWM控制PID_MAX=PWMT;counter=0;out=0;PWM=0;I_term=0;last_error=0;Set_temp=41;//初始设定温度为41度Set_temp=4;Real_temp=Set_temp;Init_DS18B20();WriteOneChar(0xCC);//跳过读序号列号的操作WriteOneChar(0x44);//启动温度转换delay_50us(15000);//等待温度测量TMOD=0x01;//定时器0模式1TH0=0xFD;//初始计数字用于780us定时TL0=0x00;TR0=1;ET0=1;IT0=1;EX0=1;EA=1;while(1){if(counter=5){test_temp=1;//5*20ms=100ms进行一次温度检定counter=0;}if(test_temp)//温度检定标志置位,进入温度PID调节{Real_temp=ReadTemperature();//采集当前实际温度out=PID(Set_temp,Real_temp);//PID程序time=~((9500/PID_MAX)*(PID_MAX-out)+250);//可控硅触发时刻计数test_temp=0;//检定完成,清温度检定标志}//Real_temp=ReadTemperature();//读取当前温度//out=PID(Set_temp,Real_temp);//PID程序//显示温度(设定状态显示设定温度,非设定状态显示实际温度)if(!key_set_flag)Disp_temp=Real_temp;display(Disp_temp);key_set();//按键温度设置}
本文标题:最简单的PID
链接地址:https://www.777doc.com/doc-2319031 .html