#include<reg52.h> #include<stdio.h> #define uchar unsigned char #define uint unsigned int uchar code Duan[]={0x3F, 0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//共陰極數碼管0-9段碼表,高電平導通數碼管段顯示,低電平導通數碼管位顯示。 uchar Data_Buffer[8]={0,0,0,0,0,0,0,0};//聲明數據緩存變量 sbit PWM_FC=P1^0;//位定義脈沖寬度輸入端口 sbit AddSpeed=P1^1;//位定義加速按鍵端口 sbit SubSpeed=P1^2;//位定義減速按鍵端口 sbit qiting=P1^3;//位定義啟停按鍵端口 sbit led0=P1^4;//位定義啟停led指示燈 sbit IN1=P3^4;//L298輸入端1 sbit IN2=P3^5;//L298輸入端2 uchar qitingnum;//聲明啟停次數變量 int e ,e1 ,e2 ;//聲明當前偏差值變量、之后偏差值變量、再后偏差值變量 int out=0;//PID調節后輸出偏差值變量 uint SetSpeed=0;//聲明設定速度變量 uint ActualSpeed=0;//聲明實際速度變量 uint cnt=0;//定時器1中斷次數變量 uint Inpluse=0;//聲明脈沖計數變量、 uint PWMTime=100;//聲明脈沖寬度時間變量 float uk ,uk1 ,duk ;//聲明目前總偏差值變量、之后偏差值總變量、偏差值總變量 float Kp=0.36,Ki=0.05,Kd=0.016;//聲明比例系數、積分系數、微分系數 void PIDControl();//PID控制函數 void SystemInit();//系統初始化函數 void delay(uchar x);//延時函數 void PWMOUT();//脈沖寬度輸出函數 void SpeedSet();//設定速度函數 void SegRefre();//數碼管顯示刷新函數 /**************主函數************/ void main() { SystemInit();//系統初始化函數 while(1) { SpeedSet();//設定速度函數 SegRefre();//數碼管顯示刷新函數 PWMOUT();//脈沖寬度輸出函數 } } void delay(uchar x)//延時函數 { uint i,j; for(i=x;i>0;i--) for(j=50;j>0;j--); } void PIDControl()//PID控制函數 { e=SetSpeed-ActualSpeed;//計算當前偏差值變量 duk=(Kp*(e-e1)+Ki*e+Kd*(e-2*e1+e2));//PID連續系統離散化增量型PID算法,算出總偏差值變量。 uk=duk+uk1;//計算偏差值總變量加上之后偏差值總變量之和賦給目前總偏差值變量 out=(int)uk;//強制類型轉化為整數型的目前總偏差值變量賦給PID調節后輸出偏差值變量 if(out>100)//判斷PID調節后輸出偏差值變量是否大於100 { out=100;//PID調節后輸出偏差值變量為100 } else if(out<0)//判斷PID調節后輸出偏差值變量是否小於0 { out=0;//PID調節后輸出偏差值變量為0 } uk1=uk;//目前總偏差值變量賦給之后偏差值總變量 e2=e1;//之前偏差值變量賦給之后偏差值變量 e1=e;//當前偏差值變量賦給之前偏差值變量 PWMTime=out;//PID調節后輸出偏差值變量賦給脈沖寬度時間變量 } void PWMOUT()//脈沖寬度輸出函數 { if(cnt<PWMTime)//判斷定時器1中斷次數變量是否小於脈沖寬度時間變量 { PWM_FC=1;//脈沖寬度輸入端口輸出高電平 } else { PWM_FC=0;//脈沖寬度輸入端口輸出低電平 } if(cnt>100)//判斷定時器1中斷次數變量是否大於100 cnt=0;//定時器1中斷次數變量歸0 } void SystemInit()//系統初始化函數 { TMOD=0X21;//定時器0方式1,定時器1方式2。 TH0=0xf8;//初裝定時器0高八位寄存器定時數值 TL0=0x50 ;//初裝定時器0低八位寄存器定時數值,即2毫秒。 TH1=0xC0;//初裝定時器1高八位寄存器定時數值 TL1=0XC0;//初裝定時器1低八位寄存器定時數值,即16毫秒。 EA=1;//開總中斷 EX0=1;//開外部中斷0 IT0=1;//外部中斷0下降沿觸發 ET0=1;//開定時器0中斷允許 ET1=1;//開定時器1中斷允許 TR0=1;//開定時器0中斷 TR1=1;//開定時器1中斷 e =0;//偏差值變量為0 e1=0;//之后偏差值變量為0 e2=0;//再后偏差值變量為0 IN1=1; IN2=1; } void SpeedSet()//設定速度函數 { if(qiting==0) { delay(200); if(qiting==0) { IN1=0; IN2=1; qitingnum++; while(qiting==1); } } if(qitingnum==1) { led0=0;if(AddSpeed==0)//判斷加速鍵是否按下 { delay(200);//延時 if(AddSpeed==0)//再次判斷加速鍵是否按下 { SetSpeed+=10;//設定速度變量每次加10 if(SetSpeed>3500)//判斷設定速度變量是否大於3500 { SetSpeed=3500;//設定速度變量歸為3500 } } } if(SubSpeed==0)//判斷減速鍵是否按下 { delay(200);//延時 if(SubSpeed==0)//再次判斷減速鍵是否按下 { SetSpeed-=10;//設定速度變量每次減10 if(SetSpeed<0)//判斷設定速度變量是否小於0 SetSpeed=0;//設定速度變量歸0 } } } if(qitingnum==2) { qitingnum=0; IN1=1; IN2=1; led0=1; } } void SegRefre()//數碼管顯示刷新函數 { Data_Buffer[0]=SetSpeed/1000;//設定速度變量千位數 Data_Buffer[1]=SetSpeed%1000/100;//設定速度變量百位數 Data_Buffer[2]=SetSpeed%100/10;//設定速度變量十位數 Data_Buffer[3]=SetSpeed%10;//設定速度變量個位數 Data_Buffer[4]=ActualSpeed/1000;//實際速度變量千位數 Data_Buffer[5]=ActualSpeed%1000/100;//實際速度變量百位數 Data_Buffer[6]=ActualSpeed%100/10;//實際速度變量十位數 Data_Buffer[7]=ActualSpeed%10;//實際速度變量個位數 } void int0() interrupt 0//外部中斷0函數 { Inpluse++;//脈沖計數變量加加 } void Time0() interrupt 1//定時器0中斷服務函數 { static uchar Bit=0;//數碼管位碼靜態變量,退出程序,其數值保留。 static uint time=0;//轉速測量周期變量 TH0=0xf8;//重裝定時器0高八位寄存器計數值 TL0=0x50 ;//重裝定時器0低八位寄存器計數值,即2毫秒。 time++;//轉速測量周期變量加加 if(time>500)//判斷轉速測量周期變量是否大於500,等於500就是500x2毫秒=1000毫秒,也就是1s。 { time=0;//轉速測量周期變量歸0 ActualSpeed=Inpluse;//脈沖計數變量表示實際速度變量 Inpluse=0;//脈沖計數變量歸0 PIDControl();//PID控制函數 } PWMOUT();//脈沖寬度輸出函數 Bit++;//數碼管位碼選擇位變量 if(Bit>8)//判斷數碼管位碼選擇位變量是否大於8 Bit=0;//數碼管位碼選擇位變量歸0 P0=0xff;//數碼管位碼顯示關閉 P2=Duan[Data_Buffer[Bit]];//數碼管段碼顯示 switch(Bit)//數碼管位碼變量選擇位 { case 0: P0=0X7F;//實際速度變量千位 break; case 1: P0=0XBF;//實際速度變量百位 break; case 2: P0=0XDF;//實際速度變量十位 break; case 3: P0=0XEF;//實際速度變量個位 break; case 4: P0=0XF7;//設定速度變量千位 break; case 5: P0=0XFB;//設定速度變量百位 break; case 6: P0=0XFD;//設定速度變量十位 break; case 7: P0=0XFE;//設定速度變量個位 break; } } void Timer1() interrupt 3//定時器1中斷服務函數 { cnt++;//定時器1中斷次數變量 }



