設計中采用了專門的芯片組成了PWM信號的發生系統并且對PWM信號的原理、產生方法以及如何通過軟件編程對PWM信號占空比進行調節從而控制其輸入信號波形等均作了詳細的闡述。另外本系統中使用了紅外對管對直流電機的轉速進行測量,經過整形電路后將測量值送到單片機,并且最終作為反饋值輸入到單片機進行PID運算從而實現了對直流電機速度的控制。在軟件方面,文章中詳細介紹了PID運算程序初始化程序等的編寫思路和具體的程序實現。
1 單片機最小系統:單片機最小系統由51單片機,晶振電路,復位電路,電源組成。大家都比較熟悉,這里不再贅述。 2 四位數碼管顯示:在應用系統中,設計要求不同,使用的LED顯示器的位數也不同,因此就生產了位數,尺寸,型號不同的LED顯示器供選擇,在本設計中,選擇4位一體的數碼型LED顯示器,簡稱“4-LED”。本系統中前三位顯示電壓的整數位,最后一位顯示轉速的小數位。4-LED顯示器引腳如圖2所示,是一個共陰極接法的4位LED數碼顯示管,其中a,b,c,e,f,g為4位LED各段的公共輸出端,1、2、3、4分別是每一位的位數選端,dp是小數點引出端,4位一體LED數碼顯示管的內部結構是由4個單獨的LED組成,每個LED的段輸出引腳在內部都并聯后,引出到器件的外部。 3 電機驅動電路:電機驅動電中是采用ULN2003來驅動。ULN2003是高耐壓、大電流達林頓陳列,由七個硅NPN達林頓管組成。該電路的特點:ULN2003的每一對達林頓都串聯一個2.7K的基極電阻,在5V的工作電壓下它能與TTL和CMOS電路直接相連,可以直接處理原先需要標準邏輯緩沖器來處理的數據,輸入5VTTL電平,輸出可達500mA/50V。ULN2003的引腳圖,其中IN1~IN7為輸入控制端;OUT1~OUT7為輸出端;8腳為芯片的接地端;9腳為公共端,該腳是內部7個續流二極管負極的公共端,各二極管的正極分別接各達林頓管的集電極。用于感性負載時,該腳接負載電源正極,實現續流作用。如果該腳接地,實際上就是達林頓管的集電極對地接通。 當P1.0中為高電平時,其內部三極管導通,使電機轉動。當P1.0為低電平時,內部三極管截止,電路斷開,電機停止轉動。所以在程序中可以利用P1.0口輸出PWM波來控制電機的轉速。 4 紅外測速電路:發射管工作時發出紅外線,當接收管收到紅外信號時,其電阻變小(本設計相當于從無窮大變到1k左右)。利用其電阻變化,改變接收管分壓情況。擋片是利用圓盤上剪四個孔,當擋片隨電機轉動時,接收管兩端電平發生變化,產生脈沖。 5 整形電路:本設計的整形電路是用555定時器接成的施密特觸發器。
6 源程序: - #include "reg52.h"
- #define uchar unsigned char
- #define uint unsigned int
- uchar code table[10]={0x3f,0x06,0x5b,
- 0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共陰數碼管顯示碼(0-9)
- sbit xiaoshudian=P0^7;
- sbit wei1=P2^4; //數碼管位選定義
- sbit wei2=P2^5;
- sbit wei3=P2^6;
- sbit wei4=P2^7;
- sbit beep=P2^3; //蜂鳴器控制端
- sbit motor = P1^0; //電機控制
- sbit s1_jiasu = P1^4; //加速按鍵
- sbit s2_jiansu= P1^5; //減速按鍵
- sbit s3_jiting=P1^6; //停止/開始按鍵
- uint pulse_count; //INT0接收到的脈沖數
- uint num=0; //num相當于占空比調節的精度
- uchar speed[3]; //四位速度值存儲
- float bianhuasudu; //當前速度(理論計算值)
- float reallyspeed; //實際測得的速度
- float vv_min=0.0;vv_max=250.0;
- float vi_Ref=60.0; //給定值
- float vi_PreError,vi_PreDerror;
- uint pwm=100; //相當于占空比標志變量
- int sample_time=0; //采樣標志
- float v_kp=1.2,v_ki=0.6,v_kd=0.2; //比例,積分,微分常數
- void delay (uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for (y=20;y>0;y--);
- }
- void time_init()
- {
- ET1=1; //允許定時器T1中斷
- ET0=1; //允許定時器T0中斷
- TMOD = 0x15; //定時器0計數,模式1;定時器1定時,模式1
- TH1 = (65536-100)/256; //定時器1值,負責PID中斷 ,0.1ms定時
- TL1 = (65536-100)%6;
- TR0 = 1; //開定時器
- TR1 = 1;
- IP=0X08; //定時器1為高優級
- EA=1; //開總中斷
- }
- void keyscan()
- {
- float j;
- if(s1_jiasu==0) //加速
- {
- delay(20);
- if(s1_jiasu==0)
- vi_Ref+=10;
- j=vi_Ref;
- }
- while(s1_jiasu==0);
- if(s2_jiansu==0) //減速
- {
- delay(20);
- if(s2_jiansu==0)
- vi_Ref-=10;
- j=vi_Ref;
- }
- while(s2_jiansu==0);
- if(s3_jiting==0)
- {
- delay(20);
- motor=0;
- P1=0X00;
- P3=0X00;
- P0=0x00;
- }
- while(s3_jiting==0);
- }
- float v_PIDCalc(float vi_Ref,floatvi_SpeedBack)
- {
- register floaterror1,d_error,dd_error;
- error1=vi_Ref-vi_SpeedBack; //偏差的計算
- d_error=error1-vi_PreError; //誤差的偏差
- dd_error=d_error-vi_PreDerror; //誤差變化率
- vi_PreError=error1; //存儲當前偏差
- vi_PreDerror=d_error;
- bianhuasudu=(v_kp*d_error+v_ki*vi_PreError+v_kd*dd_error);
- return (bianhuasudu);
- }
- void v_Display()
- {
- uint sudu;
- sudu=(int)(reallyspeed*10); //乘以10之后強制轉化成整型
- speed[3]=sudu/1000; //百位
- speed[2]=(sudu00)/100; //十位
- speed[1]=(sudu0)/10; //個位
- speed[0]=sudu; //小數點后一位
- wei1=0; //第一位打開
- P0=table[speed[3]];
- delay(5);
- wei1=1; //第一位關閉
- wei2=0;
- P0=table[speed[2]];
- delay(5);
- wei2=1;
- wei3=0;
- P0=table[speed[1]];
- xiaoshudian=1;
- delay(5);
- wei3=1;
- wei4=0;
- P0=table[speed[0]];
- delay(5);
- wei4=1;
- }
- void BEEP()
- {
- if((reallyspeed)>=vi_Ref+5||(reallyspeed
- {
- beep=~beep;
- delay(4);
- }
- }
- void main()
- {
- time_init();
- motor=0;
- while(1)
- {
- v_Display();
- BEEP();
- }
- if(s3_jiting==0) //對按鍵3進行掃描,增強急停效果
- {
- delay(20);
- motor=0;
- P1=0X00;
- P3=0X00;
- P0=0x00;
- }
- while(s3_jiting==0);
- }
- void timer0() interrupt 1
- {
- }
- void timer1() interrupt 3
- {
- TH1 = (65536-100)/256; //1ms定時
- TL1 = (65536-100)%6;
- sample_time++;
- if(sample_time==5000) //采樣時間0.1ms*5000=0.5s
- {
- TR0=0; //關閉定時器0
- sample_time=0;
- pulse_count=TH0*255+TL0; //保存當前脈沖數
- keyscan(); //掃描按鍵
- reallyspeed=pulse_count/(4*0.6); //計算速度
- pwm=pwm+v_PIDCalc(vi_Ref,reallyspeed);
- if(pwm
- if(pwm>100)pwm=100;
- TH0=TL0=0;
- TR0=1; //開啟定時器0
- }
- num++;
- if(num==pwm) //此處的num值,就是占空比
- {
- motor=0;
- }
- if(num==100) //100相當于占空比調節的精度
- {
- num=0;
- motor=1;
- }
- }
復制代碼
|