仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png (64.31 KB, 下載次數: 59)
下載附件
2019-6-29 17:31 上傳
0.png (44.24 KB, 下載次數: 56)
下載附件
2019-6-29 17:31 上傳
- 設計直流電機驅動。
- 設計液晶屏(LCD1602)顯示電路和獨立鍵盤輸入電路。
- 能準確顯示電機狀態及轉速。
- 能通過按鍵控制電機狀態及轉速。
2.1 設計方案方案一:單片機的四組并行口(P0、P1、P2、P3)在復位時是高電平,那么在設計按鍵接口時可以設計為低電平有效。當低電平時判斷按鍵被按下去,執行相關的操作。 按鍵按下去會存在抖動現象。如果對按鍵進行計數,會發現雖然只按下去一次,所計的數卻不一致。這樣會導致錯誤的操作。因此需要對按鍵進行消抖,按鍵接口只是執行單純的被檢測功能,需要特殊的功能寄存器,所以使用P1口。 顯示模塊采用LCD1602液晶屏,使用單片機的P0口。P0比較特殊,需要外接上拉電阻才能正常進行輸出。考慮到簡化仿真圖的設計,故使用P0口作為LCD1602液晶屏是數據端口。 由于需要對電機進行測速和狀態測,P3存在一些特殊寄存器可以使用,故保留P3口。其它接口均接在除P3口以外的接口。 直流電機的轉速與正向電流持續時間成正比,使用PWM方式產生脈沖,電機轉速進行調節。具體如何產生則使用定時器T0產生中斷。 測速則使用T1定時器、外中斷INT1組合測量。通過外中斷INT1的負跳變來開啟T1計時器,通過測量兩次負脈沖的時間間隔即可得到轉速(電機轉動一圈發出一定時長的高電平)。 狀態的測量則在再次使用外中斷0、1來完成。狀態測量采用這樣的測量方式只需要測量一次即可,占用時間很短,并且準確。 方案二:對方案一的部分進行修改。按鍵部分為了響應準確,采用外接高電平的方法。 電機測速模塊:仍然不變。 狀態測量改成通過內部編程完成測量,不需要外中斷0、1的參與。 方案三:仍然對方案一進行修改。按鍵部分為確保準確性,按鍵外部接上高電平。 PWM波形產生模塊使用數據選擇器對電機的正反轉進行控制,降低編程難度。 2.2 方案選擇方案一過于追求準確性,編程復雜,過多的開啟中斷實現功能與其它方案是一樣的,但是大量標志位的開啟需要特別注意,同時要小心時序問題。對編程能力、協調有比較高的要求。 方案二準確的提高了按鍵的準確性部分,通過仔細考慮,與開外中斷測量比較,編程變簡單。全部實現比較容易,但為保證準確性、需要通過編程進行調整。 方案三經過仔細考慮,使用數據選擇器雖然降低了變成難度,在選擇芯片、了解芯片可能需要多花時間。 最終認為方案二比較可行。 2.3 系統框圖整個系統以單片機為核心,處理信息。 - 鍵盤:有7個鍵盤,每個鍵盤有不同的功能。鍵盤的輸入信號流入單片機需要進行消抖,避免產生預期外的結果。
- STC89C51:負責整個系統的信息處理。包括鍵盤的輸入信號處理、根據鍵盤的信號發出電機驅動信號、對電機的速度和轉向進行測量、測量完成將信息送給顯示。
- 電機驅動芯片:電機所需要的驅動電流相對于STC89C51直接輸出的電流要打的多,對電機的控制不理想。反過來同樣會影響到單片機的正常工作。所以需要通過驅動芯片來驅動直流電機。
- 電機:電機為MOTOR-ENCODER,有五條線。其中的兩條用來輸入電流驅動電機,剩余的三條為電機的編碼輸出。中間的線輸出特征為電機轉動一圈輸出一個正脈沖。邊上兩個根線輸出的脈沖可調,脈沖的相位相差90度,反應了電機的正反轉。
- 顯示:顯示所用器件為LCD1602顯示器,顯示電機轉速,正反轉狀態。
3.1 總體硬件設計總體硬件分為:晶體振蕩器電路、復位電路、按鍵輸入模塊、顯示電路、電機驅動電路、電機模塊。如下圖 3.1?1所示 圖 3.1?1 3.2 晶體振蕩器電路晶振X1采用11.0592MHZ,電容C1、C2采用典型值22pF。如圖 3.2?1。該電路的功能是為單片機提供11.0529MHZ的時鐘。 圖 3.2?1 3.3 復位電路電路圖 3.3?1如所示。復位電路電源為+5V、電容(極性電容)C3采用典型值10uF、電阻R7為820歐姆、按鍵。該電路為單片機復位端口提供一定時間的高電平,當單片機發生異常時可以通過按鍵使單片機復位。然后正常運行。其中EA/引腳在此電路中不需要使用,只是接上去了而已。 圖 3.3?1 3.4 按鍵輸入電路電路圖如圖 3.4?1所示。按鍵共有6個,分別有不同的功能。按鍵的功能在圖上已經標出。圖中的六個電阻阻值為1K歐姆,為限流電阻、還有降壓的作用。電壓沒有標出統一為+5V。只有按下按鍵1才能啟動其他按鍵。 圖 3.4?1 3.5 顯示電路電路圖如圖 3.5?1所示。液晶顯示模塊數據口與單片機的P0口連接,其它端口通過標號與P2.0、P2.1連接。P0口與液晶顯示模塊交換信息、P2.0、P2.1口對液晶進行讀寫、使能控制。 圖 3.5?1 3.6 電機驅動電路電路圖如圖 3.6?1所示。驅動芯片型號為L298其驅動能力很強。VCC為芯片的電源+5V、VS為電機驅動電壓,最高為45V。IN1、IN2接TTL電平、與單片機標號為ON、OFF的端口(電機控制流的輸出端口)連接,ON、OFF端口如圖 3.4?1所示。ENA、ENB為芯片的使能端,高電平時芯片工作。ENA控制端口IN1、IN2、OUT1、OUT2。低電平時端口無法工作,無法控制電機。OUT1、OUT2接直流電機輸入端。圖中接地的端口在圖中用不到。 圖 3.6?1 3.7 電機模塊電路圖如圖 3.7?1所示。電機的輸入端口為1、2。1為高電平時,電機正轉2為高電平時,電機反轉。1、2同為高或者低電平則不轉,ENA低電平也不轉。電機的A、B與單片機的A、B連接,用于電機狀態的測量。IN1與單片機的IN1相連,用于測速。具體連接與標號在圖中已標注。 圖 3.7?1 4.1 圖形界面設計4.1.1 按鍵界面設計如圖 4.1?1所示
按鍵掃描模塊中有6個按鍵,每個按鍵會調動相應的模塊。并對數據處理。 4.1.2 LCD1602模塊界面界面設計如圖 4.1?2所示: 顯示模塊會顯示電機的相關信息(正轉、反轉、速度、可以加上電機是否加速的、減速的測試、以及顯示),顯示前將依據按鍵輸入的信號進行運算,處理后送入液晶中。 5.1 程序流程圖主程序流程圖如圖 5.1?1所示。
6.1 硬件調試在確定方案后,便開始搭建硬件。從難易程度來看,該課題是比較簡單的所以硬件部分搭建容易,搭建完成即可。開始方案是選擇方案一,需要使用多個中斷,需要修改的僅僅是電路的連接。后面發現方案一過于復雜,改用方案二,對需要修改的連接電路增加標號即可。 6.2 程序調試由于是自己寫程序,經驗不足、速度慢,容易出現問題。為了保證每一個環節到位,采用邊寫程序、邊調試的方法。 最先開始的模塊是顯示模塊。顯示模塊使用器件為LCD1602,在單片機的課程中學過做過關于這個器件的實驗,對器件了解有一些,但不是很熟悉。對原來的程序沒有進行封裝,最開始出現數據送入位置錯誤,造成預期之外的結果。而后通過仔細查看課本上的資料,通過位置對照,修改后,液晶顯示模塊初步沒有問題。 電機控制模塊:對電機控制需要使用中斷、在中斷里面產生方波信號,并且方波的占空比可調,電機控制流輸出通道選擇也在這個模塊。在這個模塊完成前需要完成一部分鍵盤掃描函數的設計。當以上程序完成并運行后,通道選擇和占空比都出現了問題。最開始是無論按什么鍵電機都不轉,于是乎調整程序,首先發現單片機四組端口復位后輸出為高電平,即表示電機停轉,需要對電機輸出端口初始化,都為低電平。然后進行控制。脈沖波形的占空比的調節,設立多個全局變量,設置上下限,這樣波形占空比調節沒有問題。電機輸出信號通道選擇,由于寫程序經驗不足,邏輯上出現了錯誤,導致想要外接數據選擇器來調節信號輸出,進而控制電機正反轉。最后經過實驗發現這個方法實現起來比較困難,思路沒有。還是從中斷里面進行調節好一些。最終實現了電機的調節。 電機轉向測量模塊:此模塊完成后在多次的調試過程中發現使用while語句莫名奇妙對電極控制模塊產生了影響。為了保證電機控制模塊沒有問題,對轉向模塊重新進行了設計,理論分析。但是由于時間問題,沒能完成。 測速模塊的調節:測速模塊需要定時器1和外中斷1完成。測速模塊完成后需要與顯示模塊共同完成。由于此前在選擇方案的時候,過分依賴中斷和定時器,進行了較長時間的論證,電機控制模塊的調試由于是個人編程思想和能力問題導致花費了大量的時間。測速模塊雖然完成,但是沒有時間調試。 6.3 心得體會在一周的實訓中,發現了很多的問題,也收獲了很多。最開始是方案的確定很困難,方案的確定需要對單片機的各個資源非常了解。這從側面反映了個人對單片機不熟悉,以及特點的不了解,最終方案的敲定花費了大量的時間,導致后面編程、其它問題的解決時間不足。 從定時器T0的編程中發現自身的寫程序能力非常薄弱,程序的結構很亂,在一定程度上來說完全是想到什么就寫什么,毫無章法。更沒有將程序封裝起來、留做下次便以稍加修改即可使用。 總之,在這次實訓中讓我看到了自己各個方面的不足,這些不足通過平時的鍛煉是可以補起來的,反映出學習方法存在問題,需要加以改進。通過實訓,對單片機的部分硬件有了進一步的了解、熟悉。單片機實訓是一個比較綜合的課程,結合了C語言、單片機常識、模擬電路、數字電路、硬件設計、軟件的使用、軟件設計。對培養獨立解決問題的能力、自主學習能力、創新思維能力有較大影響。
單片機源程序如下:
- #include <reg52.h>
- #include<string.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
-
- sbit lcdrs=P2^0; //寄存器選擇,0:數據寄存器。1:為狀態/命令寄存器
- sbit lcden=P2^1; //--LCD控制引腳
- sbit speed=P3^2; //測速端口
- sbit ENA=P2^2; //電機使能控制端
- sbit key1=P1^0; //啟動按鍵
- sbit key2=P1^1; //正轉按鍵
- sbit key3=P1^2; //反轉按鍵
- sbit key4=P1^3; //加速按鍵
- sbit key5=P1^4; //減速按鍵
- sbit key6=P1^5; //停止按鍵
- sbit Zheng=P1^6; //正轉輸出端口
- sbit Fan=P1^7; //反轉輸出端口
- uchar Timer0_flag=4;
- uchar Timer0_BiaoZhi=0;//初始化占空比為1:3(高:低)
- uchar gewei;
- uchar shiwei;
- uchar baiwei;
- /******標志位設置*****/
- uchar KEY1=0;//優先級標志
- uchar KEY2=0;//加速標志
- uchar INT1_FLAG=0;
- uchar COUNTER_high=0;
- uchar COUNTER_low=0;
- uchar SUM=0;
- uint TIMER1_COUNTER=0;
- uint INT1_tingzhi=0; //在要測速時置0
- /****面板顯示****/
- uchar code lcd_desktop11[]="stop";//停止
- uchar code lcd_desktop12[]="ford";//正轉
- uchar code lcd_desktop13[]="fanz";//反轉
- uchar code lcd_desktop21[]="speedup";//加速
- uchar code lcd_desktop22[]="speeddn";//減速
- uchar code num[]={'0','1','2','3','4','5','6','7','8','9'};//要顯示的轉速數字。
- //-----lcd液晶屏頭文件-----//
- /**延時函數**/
- void delayms(uchar xms)
- {
- uchar i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--);
- }
- /****LCD寫命令******/
- void write_command(uchar com)//com寫入命令
- {
- lcdrs=0;
- P0=com;
- delayms(2);
- lcden=1;
- delayms(2);
- lcden=0;
- }
- /**************LCD寫數據*********/
- void write_data(uchar date)//數據為DATA
- {
- lcdrs=1;
- P0=date;
- delayms(2);
- lcden=1;
- delayms(2);
- lcden=0;
- }
- /********LCD初始化****************/
- void lcd_init()//顯示模式設置
- {
- lcden=0;
- write_command(0x38);
- write_command(0x0c);
- write_command(0x06);
- write_command(0x01);
- }
- /**電機初始化函數**/
- void motor_init(void)
- {
- ENA=0; // 停止
- }
- void ZhongDuanKaiQi(void)
- {
- EA=1;
- ET0=1; //計時器0允許中斷。產生脈沖。
- ET1=1; //計時器1允許中斷。對低電平進行計時。
- //EX1=1; //INT0允許中斷。測速。由外部來啟動。
- IT1=1; //低電平觸發。
- PX1=0; //低級中斷。
- PT0=1;
- PT1=0;
- TMOD=0x12;//定時器工作方式控制
- }
- /***定時器T1初始化!!!等待外部脈沖的到來***/
- void Timer1_init(void)
- {
- TH1=0;
- TL1=0; //等待外部脈的到來。INT1
- }
- /*****定時T0初始化*****/
- void Timer0_init(void)
- {
- TH0=0;
- TL0=0;
- TR0=1;
- }
- /********測速模塊,顯示速度*******/
- void speed_test(void)
- {
- // TIMER1_COUNTER;
- COUNTER_high=TH1;
- COUNTER_low=TL1;
- SUM=COUNTER_high*256+COUNTER_low+TIMER1_COUNTER*65536;//得到的是多少us。
- SUM=SUM/1000; //化為毫秒。
- SUM=1000/SUM; //圈每秒。
- SUM=SUM*60; //圈每分鐘;三位數。
- gewei=SUM%10;
- shiwei=SUM/10%10;
- baiwei=SUM/100;
- write_command(0xc0);
- write_data(baiwei);
- write_command(0xc1);
- write_data(shiwei);
- write_command(0xc2);
- write_data(gewei);
- SUM=0;
- TIMER1_COUNTER=0;
- }
- /********外中斷1函數**********/
- void INT1_QIDONG() interrupt 2
- {
- INT1_tingzhi++;
- if(INT1_tingzhi==5)
- {
- INT1_tingzhi=5;EX1=0;//關閉中斷。
- }
- if(INT1_tingzhi<=4)
- {
- INT1_FLAG++;
- if(INT1_FLAG==2)
- {
- INT1_FLAG=0;TR1=0;speed_test();
- }
- else
- {
- Timer1_init();
- TR1=1;
- }
- }
- }
- /******定時器T1計數*******/
- void Timer1_QIDONG() interrupt 3
- {
- TIMER1_COUNTER++;
- }
- /**相位測量并輸出!!!!!出現問題???**/
- void xiangwei_test(void)
- {
- uchar i=0,j=0;
- //while((P2^3==0)&&(P2^4==0));
- //if((P2^3==0)&&(P2^4==0))
- {
- //delayms(5);
- if(P2^3==1)
- {
- write_command(0x01);
- write_command(0x80);for(i=0;i<=3;i++) write_data(lcd_desktop13[i]);//反轉。
- j++;//反轉
- }
-
- if(P2^4==1)
- {
- write_command(0x01);
- write_command(0x80);for(i=0;i<=3;i++) write_data(lcd_desktop12[i]);//正轉。
- j++;
- }
- }
- }
- /****T0中斷發出信號并進行通道選擇****/
- void Timer0() interrupt 1
- {
- Timer0_flag--;
- if((Timer0_BiaoZhi)>=(Timer0_flag))
- {
- if(KEY2==0)
- {
- Zheng=1;Fan=0;
- }
- else
- {
- Zheng=0;Fan=1;
- }
- }
- else
- {
- Zheng=0;Fan=0;
- }
- if(Timer0_flag==0) Timer0_flag=5;
- }
- void Guan(void)
- {
- ET0=0;
- EX1=0;
- ET1=0;
- }
- void keyscan() //按鍵掃描函數
- {
- uint i=0;
- if(key1==0) //按鍵K1啟動按鈕。只有該位啟動時,后面的幾位才有效。啟動T0計數開始發出脈沖。
- {
- delayms(10);
- if(key1==0)
- {
- while(!key1);
- KEY1=5;
- Fan=0;
- Zheng=0;
- ENA=1;
- KEY2=0;//初始化為正轉。
- Timer0_BiaoZhi=0;
- Timer0_flag=4;
-
- ZhongDuanKaiQi();//開啟中斷
- Timer0_init();// 初始化并開始發出脈場外中斷已經開啟。
- EX1=1; //外中斷開啟;測速,顯示速度。五次后結束關閉外中斷1。出現問題!!!
-
- write_command(0x80);
- for(i=0;i<strlen(lcd_desktop11);i++)//顯示正轉。
- write_data(lcd_desktop12[i]);
- }
- }
-
- if((key2==0)&&(KEY1=5)) //按鍵K2按下,(正轉)只改變轉向(標志位改變輸出端口)
- {
- delayms(10);
- if(key2==0)
- {
- while(!key2);
- KEY2=0; //正轉標志,電機正向旋轉。
- //KEY2=(~1);
- xiangwei_test();
- KEY1=5;
- }
- }
-
- if((key3==0)&&(KEY1=5)) //按鍵K3按下,(反轉)只改變轉向
- {
- delayms(10);
- if(key3==0)
- {
- while(!key3);
- KEY2=~0; //反轉標志。
- //KEY2=(~0);
- xiangwei_test();
- KEY1=5;
- }
- }
- if((key4==0)&&(KEY1==5)) //按鍵K4按下,(加速)改變裝入的數值?循環次數?執行if里面的語句,通過size++來改變幅值的頻率
- {
- delayms(10);
- if(key4==0)
- {
- while(!key4);
- if(Timer0_BiaoZhi<4)
- {
- Timer0_BiaoZhi++;
- }
- else
- {
- Timer0_BiaoZhi=4;
- }
- EX1=1;
- KEY1=5;
- }
-
- }
-
- if((key5==0)&&(KEY1==5)) //按鍵K5按下,(減速)對其它標志位沒有影響。
- {
- delayms(5);
- if(key5==0)
- {
- while(!key5);
- if(Timer0_BiaoZhi==0)
- {
- Timer0_BiaoZhi=0;
- }
- else
- {
- Timer0_BiaoZhi--;
- }
- EX1=1;
- KEY1=5;
- }
- }
- if((key6==0)&&(KEY1==5))//按鍵K6按下,電機停止轉動使能端和計數啟動關閉,計數器工作否?設立標志位。此按鍵按下后除K1外無法啟動
- {
- delayms(5);
- if(key6==0)
- {
- while(!key6);
- //置位,保證后續操作正常。
-
-
-
- EA=0; //總中斷關
- motor_init(); //電機關
- Guan();
-
- }
- }
- }
-
- /*主函數*/
- void main()
- {
- ZhongDuanKaiQi();//初始化
- motor_init(); //電機停止
- lcd_init();
- while(1)
- {
- keyscan();
-
- }
- }
復制代碼
0.png (9.27 KB, 下載次數: 44)
下載附件
2019-6-29 17:27 上傳
所有資料51hei提供下載:
直流電機驅動.7z
(2.63 MB, 下載次數: 173)
2022-4-19 02:15 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|