概述 此系統(tǒng)采用IAP15F2K60S2單片機作為主控芯片,控制直流電機的轉(zhuǎn)動,帶動小車移動,使用超聲波傳感器來測量小車位移,實現(xiàn)小車行進指定位移的功能。顯示部分使用LCD1602液晶屏。
主要由單片機控制器、直流電機驅(qū)動電路、超聲波傳感器測距電路、顯示電路、鎖定裝置等部分組成。
核心在于如何能夠驅(qū)動電機穩(wěn)定又準確轉(zhuǎn)動,以及如何構(gòu)建適當?shù)姆答佅到y(tǒng)來確保小車位移的準確性。
反饋控制系統(tǒng)如圖2.1所示;系統(tǒng)通過按鍵模塊將目標位移值輸入反饋控制鏈中,當前位移值與目標值作差;控制系統(tǒng)對差值控制,在某一閾值之前,系統(tǒng)保持高速前進,到達閾值之后,使得小車能夠逐漸減速并且最終能夠在目標值處停下。其中使用超聲波測距作為負反饋,在密閉的空間內(nèi)能夠擁有很好地精度,也能確定小車當前的位移,是良好的反饋系統(tǒng)。
圖2.1 反饋控制系統(tǒng)框圖
圖2.2 系統(tǒng)連接框圖
以模型小車為載體,各個模塊都需要安裝在小車上。系統(tǒng)的連接如圖2.2所示,按鍵模塊對應(yīng)位移控制系統(tǒng)的輸入,CUP對應(yīng)著系統(tǒng)的程序部分,超聲波測距對應(yīng)著反饋部分。驅(qū)動部分接收來自MCU的命令,通過ENA的PWM的占空比以調(diào)節(jié)小車的行進。直流電機控制著傳動系統(tǒng),驅(qū)動小車的位移。具體的連線圖參考圖2.3.
按鍵模塊接收輸入信息和控制命令,系統(tǒng)通過測距模塊采集距離信息,經(jīng)過反饋算法之后,將通過ENA、IN1和IN2的狀態(tài)自動控制直流電機轉(zhuǎn)動等,最終使得小車的行進距離與輸入值相等。
圖2.3 電路連線圖
一、 電機驅(qū)動
1、 模塊簡介該模塊主控芯片為L298N,一種雙H橋電機驅(qū)動芯片,其中每個H橋可以提供2A的電流,功率部分的供電電壓范圍是2.5-48v,邏輯部分5v供電,接受5vTTL電平。其實質(zhì)類似于一個單刀雙擲開關(guān),不過能夠提供較大的電流。 該模塊共有13個接口,此次項目將會使用到的共有8個:兩個使能接口IN1、IN2,12V供電接口,GND接口,5V電源接口,驅(qū)動接口C、D,PWM控制接口ENA。本系統(tǒng)中12V供電接口接入的是9V電池,作為整個系統(tǒng)的供電;5V接口作為電源輸出為單片機及其它外設(shè)供電;C、D接口與直流電機相連,當IN1、IN2接口接入的數(shù)值是10時,電機正轉(zhuǎn),01電機反轉(zhuǎn),00及11電機不轉(zhuǎn)。 表3.1 L298N控制 2、功能實現(xiàn)控制小車行進速度的方法就是,通過調(diào)節(jié)控制接口ENA的PWM波占空比,來控制電機轉(zhuǎn)動與否以及時長,如此控制小車的勻速減速等工作狀態(tài)。 這里使用定時器來實現(xiàn)PWM波的輸出:每當定時時間來臨,計數(shù)單位加一,達到一百就置零;而當計數(shù)單位小于占空比時,PWM輸出口置1,否則清零。代碼參考附錄L298N.c。
二、 超聲波測距
1、模塊簡介選用常見的HC-SR04超聲波模塊,該模塊使用直流5.0V供電,可探測距離為2cm-450cm,精度能夠達到0.2cm,各參數(shù)基本符合此次項目的設(shè)計。該模塊共有四個接口,其中VCC、GND為電源接口,TRIG控制接口、Echo為數(shù)據(jù)接口。 使用步驟有三: (1) 觸發(fā)測距:IO口TRIG觸發(fā),至少給10us的高電平信號; (2) 模塊內(nèi)部自動發(fā)送8個40KHz的方波,自動檢測是否有信號返回; (3) 有信號返回,Echo輸出一個高電平,高電平持續(xù)的時間就是超聲波從發(fā)射到接收的時間。 可以根據(jù)超聲波傳輸?shù)臅r間計算出測量的距離: 2 t即為高電平持續(xù)的時間,c為聲速340m/s。 2、功能實現(xiàn)程序里,利用外部中斷來接受來自Echo的高電平,上升沿定時器1開始計數(shù),下降沿定時器計數(shù)結(jié)束。將計數(shù)時間乘以音速,再除以2便可得到測距的結(jié)果。 值得注意的是:此超聲波測距模塊測得的距離并不是那么準確,導(dǎo)致前后數(shù)據(jù)的差值較大。鑒于此,在獲得距離之前,先進行五次測距,取它們的平均值作為當前測得的距離。另外這部分的重要性是毋庸置疑的,在實驗過程之初,沒有進行均值濾波之前,小車在到達目標1cm左右的位置時,小車會來回的抖動。一方面是由于當時控制的頻率太高,而另一方面正是由于測得的距離有著十足的誤差。代碼請參考附錄wave.c。
三、 控制算法為了實現(xiàn)速度的閉環(huán)控制,這里使用了業(yè)內(nèi)常常使用到了PID算法來控制PWM波的占空比,通過對偏差的比例、積分、微分進行控制,使偏差趨于零的過程。 系統(tǒng)每隔1ms進行一次采樣,之后進行一次PID算法。 PID控制一般有兩種寫法,一個是位置式,另一個是增量式。位置式需要進行累加的操作,而此系統(tǒng)的主控芯片為IAP15F2K61S2,其存儲與計算能力一般,于是這里采用增量式。 增量式程序: //PID控制 //move 與 deta的關(guān)系,最終使得 move = objective if(caiyang_FLAG_) { deta_ID[2]=deta;//采樣 PWM_deta=Kp*(deta_ID[2]-deta_ID[1])+Ki*deta_ID[2]+Kd*(deta_ID[2]-2*deta_ID[1]+deta_ID[0]); PWM_ID[1]= PWM_ID[0]+PWM_deta; PWM=(uint)PWM_ID[1]; //準備下一輪控制 PWM_ID[0]=PWM_ID[1]; deta_ID[0]=deta_ID[1]; deta_ID[1]=deta_ID[2]; } if(deta>0) Z_F= 1; else Z_F= 2; mada(); 此外,為了解決系統(tǒng)到達位置之后的原地抖動問題,以及消除到達之后受到人為遮擋會引起小車強烈反應(yīng)的情況。又引入了消抖算法:小車位于指定位置±0.5cm的距離1秒鐘以上時,視為調(diào)節(jié)結(jié)束,小車停止運動。這里使用定時器來確定一秒的時間。 代碼如下: START是能直接控制小車是否運動的標志,STOP是記錄小車能否保持±0.5cm的標志。 if(deta<= 0.5 && deta >= -0.5) sanmiao = 1; //一旦deta的絕對值小于0.5,電機暫停控制 if(sanmiao == 1) { if(deta > 0.5 ||deta < -0.5) {//跳出暫停 STOP = 0; sanmiao_flag =0; sanmiao = 0; } else { STOP = 1; } } 定時器處理函數(shù)里面: if(sanmiao== 1 ) { if(sanmiao_flag++ == 10000) { sanmiao_flag = 0; sanmiao = 0; if(STOP == 1) START = 0; } } 四、 其他功能模塊1、4*4按鍵模塊:4*4矩陣功能如下: 1 2 3 A 4 5 6 B 7 8 9 C * 0 # D, 其中A按鍵控制讀入初始距離,B按鍵一鍵開始,C按鍵停止運動,D按鍵切換前進后退,*按鍵重新輸入,#按鍵確認輸入,各數(shù)字按鍵進行數(shù)字讀入。
2、 電源模塊由于小車需要移動,系統(tǒng)必須使用移動電源。而普通電池電量不夠充足,而且質(zhì)量太大,影響電機的運轉(zhuǎn)。故系統(tǒng)使用一節(jié)9V可充電電池供電,利用L298N的5V電源接口給單片機及其外設(shè)供電,電機驅(qū)動模塊使用9V供電。
3、 顯示模塊顯示部分使用LCD1602液晶顯示屏,也叫1602字符型液晶,它是一種專門用來顯示字母、數(shù)字、符號等的點陣型液晶模塊。它由若干個5X7或者5X11等點陣字符位組成。 共有16個接口,其中VSS、VDD、VO、A、K是電源接口,VSS、K接單片機的GND,VDD、A接單片機的VCC,VO接上變阻器;RS、RW、EN作為使能接口;其余8個引腳作為數(shù)據(jù)接口,以便顯示不同的ASCII或者自定義的字符。 實驗中顯示初始距離、設(shè)定位移、當前距離以及實時誤差。
單片機源程序如下:
- /*******
- 位移控制系統(tǒng)設(shè)計:小車
- 設(shè)計編寫:汪佳鋅
- 開始時間:2019/6/4
- 結(jié)束時間:2019/6/8
- 最終時間:2019/6/8
- 功 能:按鍵輸入指定位移,小于4米;
- 小車行進到指定距離(位置);
- 使用模塊:矩陣按鍵、超聲波、電機驅(qū)動、顯示模塊;
- KBD_key.c\wave.c\L298N.c\LCD1602.c
- 按鍵功能:按鍵A:位置初始化;
- 數(shù)字按鍵 1,2,3,4,5,6,7,8,9,0:輸入數(shù)字,百十個CM
- 按鍵#:確認輸入;
- 按鍵*:重新輸入;
- 按鍵A:位置初始化;
- 按鍵B:一鍵開始;
- 按鍵C:手動停止;
- 按鍵D: '+'/'-';
- 1、2、3、A
- 4、5、6、B
- 7、8、9、C
- *、0、#、D
- 顯示區(qū)域:1:
- 2:
- *******/
- #include <STC15F2K60S2.h>
- #include <intrins.h>
- #include "timer0.h"
- #include "L298N.h"
- #include "wave.h"
- #include "LCD1602.h"
- #include "KBD_keys.h"
- #define MAX 400
- //#ifndef uchar
- //typedef unsigned char uchar;
- //#endif
- //#ifndef uchar
- //typedef unsigned int uint;
- //#endif
- enum keyState {state0,state1,state2};
- bit key_FLAG_=1,mada_FLAG_=0,caiyang_FLAG_,wave_FLAG_,dsp_FLAG_,//定時器FLAG
- QJ_HT=1,//前進、后退
- sanmiao=1,//一秒消抖
- STOP=0, //一秒消抖就停止運動
- START=0; //開始、停止
- uint key_flag=0,countB=0,caiyang_flag,wave_flag,dsp_flag,
- sanmiao_flag,
- T; //超聲波測距返回的時間
- uchar Z_F, //馬達的狀態(tài):0代表停,1正轉(zhuǎn),2反轉(zhuǎn);
- key_value=44, //指按下了哪個按鍵;
- add=0, //按鍵的指針,三位數(shù) 150、010、007
- PWM=0; //0~100表示占空比
- uchar aim[]={0,0,0}; //按鍵的輸入
- float distance_caiyang=0,
- deta=20, // -------------------------- 墻壁
- //deta = 當前位置-目標位置,也是程序的控制對象 ---------------- d 終點 目標位置distance_aim
- distance=0, //當前位置 o d i
- distance_init=0, //初始位置 b eta s
- distance_aim=0, //目標位置=初始位置-目標位移 j ^--^ tance 現(xiàn)在 當前位置
- objective=0; //目的位移CM e |
- // ctive |
- //使用PID算法:P比例,I微分,D積分; -------------------------- 起點 初始位置distance_init
- float deta_ID[3]; //用于微分和積分
- float PWM_deta,Kp,Ki,Kd,zhongjian;
- uchar PWM_ID[2];
- void display(void);
- void control();
- void main()
- {
- uchar p=0;
-
- Kp = 0.06;
- Ki = 0.25;
- Kd = 0.01;
- deta_ID[0]=deta_ID[1]=0;
- PWM_ID[0]=0;
-
- Timer0_init();
- LCD_init();
- while(1)
- {
- //按鍵掃描,
- if(key_FLAG_)
- {
- key_FLAG_ = 0;
- key_value = key_scan();
- if(key_value != 44)
- {
- key_hand(key_value);
- }
- }
- //測距,六次取平均值
- if(wave_FLAG_)
- {
- wave_FLAG_ = 0;
- send_wave();
- zhongjian += distance_caiyang;
- if(p++ == 5)
- {
- distance=zhongjian/6;
- zhongjian = 0;
- p=0;
- }
- }
- //顯示
- if(dsp_FLAG_)
- {
- dsp_FLAG_ = 0;
- display();
- }
- //電機控制
- control();
- // PWM = 50;
- // Z_F = 1;
- mada();
- }
- }
- void control()
- {
- distance_aim = distance_init - objective;
- deta = distance-distance_aim;
- //deta = distance-distance_init+objective;
- if(START == 1 && objective <= MAX && objective >= -MAX)
- {
- //控制部分
- if(deta <= 0.5 && deta >= -0.5)
- sanmiao = 1;
- //一旦deta的絕對值小于0.5,電機暫停控制
- if(sanmiao == 1)
- {
- if(deta > 0.5 || deta < -0.5)
- {//跳出暫停
- STOP = 0;
- sanmiao_flag = 0;
- sanmiao = 0;
- }
- else
- {
- STOP = 1;
- }
- }
- else//
- {
- //分段控制
- if(deta >= 100)
- { PWM = 70;Z_F = 1;}
- else if(deta >= 50)
- { PWM = 50;Z_F = 1;}
- else if(deta >= 10)
- { PWM = 30;Z_F = 1;}
- else if(deta > 5)
- { PWM = 10;Z_F = 1;}
- else if(deta > 0.5)
- { PWM = 5;Z_F = 1;}
- else if(deta >= -0.5 && deta <= 0.5)
- { //START = 0;
- PWM = 0;Z_F = 0;}
- else if(deta >= -5)
- { PWM = 5 ;Z_F = 2;}
- else if(deta >= -10 && deta < -5)
- { PWM = 10;Z_F = 2;}
- else if(deta >= -50)
- { PWM = 30;Z_F = 2;}
- else if(deta >= -100)
- { PWM = 50;Z_F = 2;}
- else
- { PWM = 70;Z_F = 2;}
- //PID控制
- //move 與 deta的關(guān)系,最終使得 move = objective
- // if(caiyang_FLAG_)
- // {
- // deta_ID[2]=deta;//采樣
- //
- // PWM_deta=Kp*(deta_ID[2]-deta_ID[1])+Ki*deta_ID[2]+Kd*(deta_ID[2]-2*deta_ID[1]+deta_ID[0]);
- //
- // PWM_ID[1] = PWM_ID[0]+PWM_deta;
- // PWM=(uint)PWM_ID[1];
- // //準備下一輪控制
- // PWM_ID[0]=PWM_ID[1];
- // deta_ID[0]=deta_ID[1];
- // deta_ID[1]=deta_ID[2];
- // }
- // if(deta>0)
- // Z_F = 1;
- // else
- // Z_F = 2;
-
- }
- }
- else
- {
- Z_F = 0;
- ENB = 0;
- ENA = 0;
- }
- //一秒無變化,停止運動
-
- }
- void key_hand(uchar key_value)
- {
- switch(key_value)
- {
- case 1:
- case 2:
- case 3:aim[add]=key_value;add++;break;
- case 4:distance_init = distance;break;
-
- case 5:
- case 6:
- case 7:aim[add]=key_value-1;add++;break;
- case 8:START = 1;
- sanmiao = 0; //開始、停止
- objective = aim[0]*100+aim[1]*10+aim[2]; //確認輸入
- if(QJ_HT == 0)//后退
- {
- objective = -objective;}
- distance_init = distance; //位置初始化
- break;//
-
- case 9:
- case 10:
- case 11:aim[add]=key_value-2;add++;break;
- case 12:START = 0;
- break;
-
- case 13:aim[0]=aim[1]=aim[2]=0;add=0;QJ_HT = 1;break;//重新輸入
- case 14:aim[add]=0;add++;break;
- case 15:objective = aim[0]*100+aim[1]*10+aim[2];//確認輸入
- if(QJ_HT == 0)//后退
- { objective = -objective;}
- break;
- case 16:QJ_HT = ~QJ_HT;break; //輸入前進或后退
- default:break;
- }
- if(add == 3)
- add = 0;
- }
- void display()
- {
- LCD_write_com(0x80);
- if(START == 1)
- LCD_write_data('T');
- else
- LCD_write_data('P');
- LCD_write_data(':');
- display_32(distance_init);
- LCD_write_data(' ');
- if(QJ_HT == 1)
- LCD_write_data('+');
- else
- LCD_write_data('-');
- LCD_write_data('0'+aim[0]);
- LCD_write_data('0'+aim[1]);
- LCD_write_data('0'+aim[2]);
- LCD_write_data('C');
- LCD_write_data('M');
- Delayms(1);
-
- LCD_write_com(0x80+0x40);
- if(objective >MAX || objective < -MAX)
- {
- LCD_write_string(2,1,"INPUT ERROR! ");
- }
- else
- {
- display_32(distance);
- LCD_write_data(' ');
- display_32(deta);
- }
- Delayms(1);
- }
- void Timer0_handle(void) interrupt 1
- {
- if(sanmiao == 1 )
- {
- if(sanmiao_flag++ == 10000)
- {
- sanmiao_flag = 0;
- sanmiao = 0;
- if(STOP == 1)
- START = 0;
- else
- START = 1;
- }
- }
- if(dsp_flag++ == 30) //LCD顯示3ms
- {
- dsp_FLAG_=1;
- dsp_flag =0;
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復(fù)制代碼
0.png (9.29 KB, 下載次數(shù): 29)
下載附件
2019-6-20 04:10 上傳
所有資料51hei提供下載:
工程程序.rar
(65.19 KB, 下載次數(shù): 26)
2019-6-19 21:00 上傳
點擊文件名下載附件
工程程序 下載積分: 黑幣 -5
|