時間:2018-01-02 10:46:39來源:網(wǎng)絡(luò)轉(zhuǎn)載
結(jié)合按鍵程序,我們設(shè)計這樣一個功能程序:按數(shù)字鍵1~9,控制電機(jī)轉(zhuǎn)過1~9圈;配合上下鍵改變轉(zhuǎn)動方向,按向上鍵后正向轉(zhuǎn)1~9圈,向下鍵則反向轉(zhuǎn)1~9圈;左鍵固定正轉(zhuǎn)90度,右鍵固定反轉(zhuǎn)90;Esc鍵終止轉(zhuǎn)動。通過這個程序,我們也可以進(jìn)一步體會到如何用按鍵來控制程序完成復(fù)雜的功能,以及控制和執(zhí)行模塊之間如何協(xié)調(diào)工作,而你的編程水平也可以在這樣的實踐練習(xí)中得到鍛煉和提升。
#include
sbitKEY_IN_1=P2^4;
sbitKEY_IN_2=P2^5;
sbitKEY_IN_3=P2^6;
sbitKEY_IN_4=P2^7;
sbitKEY_OUT_1=P2^3;
sbitKEY_OUT_2=P2^2;
sbitKEY_OUT_3=P2^1;
sbitKEY_OUT_4=P2^0;
unsignedcharcodeKeyCodeMap[4][4]={//矩陣按鍵編號到標(biāo)準(zhǔn)鍵盤鍵碼的映射表
{0x31,0x32,0x33,0x26},//數(shù)字鍵1、數(shù)字鍵2、數(shù)字鍵3、向上鍵
{0x34,0x35,0x36,0x25},//數(shù)字鍵4、數(shù)字鍵5、數(shù)字鍵6、向左鍵
{0x37,0x38,0x39,0x28},//數(shù)字鍵7、數(shù)字鍵8、數(shù)字鍵9、向下鍵
{0x30,0x1B,0x0D,0x27}//數(shù)字鍵0、ESC鍵、回車鍵、向右鍵
};
unsignedcharKeySta[4][4]={//全部矩陣按鍵的當(dāng)前狀態(tài)
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};
signedlongbeats=0;//電機(jī)轉(zhuǎn)動節(jié)拍總數(shù)
voidKeyDriver();
voidmain(){
EA=1;//使能總中斷
TMOD=0x01;//設(shè)置T0為模式1
TH0=0xFC;//為T0賦初值0xFC67,定時1ms
TL0=0x67;
ET0=1;//使能T0中斷
TR0=1;//啟動T0
while(1){
KeyDriver();//調(diào)用按鍵驅(qū)動函數(shù)
}
}
/*步進(jìn)電機(jī)啟動函數(shù),angle-需轉(zhuǎn)過的角度*/
voidStartMotor(signedlongangle){
//在計算前關(guān)閉中斷,完成后再打開,以避免中斷打斷計算過程而造成錯誤
EA=0;
beats=(angle*4076)/360;//實測為4076拍轉(zhuǎn)動一圈
EA=1;
}
/*步進(jìn)電機(jī)停止函數(shù)*/
voidStopMotor(){
EA=0;
beats=0;
EA=1;
}
/*按鍵動作函數(shù),根據(jù)鍵碼執(zhí)行相應(yīng)的操作,keycode-按鍵鍵碼*/
voidKeyAction(unsignedcharkeycode){
staticbitdirMotor=0;//電機(jī)轉(zhuǎn)動方向
//控制電機(jī)轉(zhuǎn)動1-9圈
if((keycode>=0x30)&&(keycode<=0x39)){
if(dirMotor==0){
StartMotor(360*(keycode-0x30));
}else{
StartMotor(-360*(keycode-0x30));
}
}elseif(keycode==0x26){//向上鍵,控制轉(zhuǎn)動方向為正轉(zhuǎn)
dirMotor=0;
}elseif(keycode==0x28){//向下鍵,控制轉(zhuǎn)動方向為反轉(zhuǎn)
dirMotor=1;
}elseif(keycode==0x25){//向左鍵,固定正轉(zhuǎn)90度
StartMotor(90);
}elseif(keycode==0x27){//向右鍵,固定反轉(zhuǎn)90度
StartMotor(-90);
}elseif(keycode==0x1B){//Esc鍵,停止轉(zhuǎn)動
StopMotor();
}
}
/*按鍵驅(qū)動函數(shù),檢測按鍵動作,調(diào)度相應(yīng)動作函數(shù),需在主循環(huán)中調(diào)用*/
voidKeyDriver(){
unsignedchari,j;
staticunsignedcharbackup[4][4]={//按鍵值備份,保存前一次的值
{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};
for(i=0;i<4;i++){//循環(huán)檢測4*4的矩陣按鍵
for(j=0;j<4;j++){
if(backup[i][j]!=KeySta[i][j]){//檢測按鍵動作
if(backup[i][j]!=0){//按鍵按下時執(zhí)行動作
KeyAction(KeyCodeMap[i][j]);//調(diào)用按鍵動作函數(shù)
}
backup[i][j]=KeySta[i][j];//刷新前一次的備份值
}
}
}
}
/*按鍵掃描函數(shù),需在定時中斷中調(diào)用,推薦調(diào)用間隔1ms*/
voidKeyScan(){
unsignedchari;
staticunsignedcharkeyout=0;//矩陣按鍵掃描輸出索引
staticunsignedcharkeybuf[4][4]={//矩陣按鍵掃描緩沖區(qū)
{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}
};
//將一行的4個按鍵值移入緩沖區(qū)
keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KEY_IN_1;
keybuf[keyout][1]=(keybuf[keyout][1]<<1)|KEY_IN_2;
keybuf[keyout][2]=(keybuf[keyout][2]<<1)|KEY_IN_3;
keybuf[keyout][3]=(keybuf[keyout][3]<<1)|KEY_IN_4;
//消抖后更新按鍵狀態(tài)
for(i=0;i<4;i++){//每行4個按鍵,所以循環(huán)4次
if((keybuf[keyout][i]&0x0F)==0x00){
//連續(xù)4次掃描值為0,即4*4ms內(nèi)都是按下狀態(tài)時,可認(rèn)為按鍵已穩(wěn)定的按下
KeySta[keyout][i]=0;
}elseif((keybuf[keyout][i]&0x0F)==0x0F){
//連續(xù)4次掃描值為1,即4*4ms內(nèi)都是彈起狀態(tài)時,可認(rèn)為按鍵已穩(wěn)定的彈起
KeySta[keyout][i]=1;
}
}
//執(zhí)行下一次的掃描輸出
keyout++;//輸出索引遞增
keyout=keyout&0x03;//索引值加到4即歸零
//根據(jù)索引,釋放當(dāng)前輸出引腳,拉低下次的輸出引腳
switch(keyout){
case0:KEY_OUT_4=1;KEY_OUT_1=0;break;
case1:KEY_OUT_1=1;KEY_OUT_2=0;break;
case2:KEY_OUT_2=1;KEY_OUT_3=0;break;
case3:KEY_OUT_3=1;KEY_OUT_4=0;break;
default:break;
}
}
/*電機(jī)轉(zhuǎn)動控制函數(shù)*/
voidTurnMotor(){
unsignedchartmp;//臨時變量
staticunsignedcharindex=0;//節(jié)拍輸出索引
unsignedcharcodeBeatCode[8]={//步進(jìn)電機(jī)節(jié)拍對應(yīng)的IO控制代碼
0xE,0xC,0xD,0x9,0xB,0x3,0x7,0x6
};
if(beats!=0){//節(jié)拍數(shù)不為0則產(chǎn)生一個驅(qū)動節(jié)拍
if(beats>0){//節(jié)拍數(shù)大于0時正轉(zhuǎn)
index++;//正轉(zhuǎn)時節(jié)拍輸出索引遞增
index=index&0x07;//用&操作實現(xiàn)到8歸零
beats--;//正轉(zhuǎn)時節(jié)拍計數(shù)遞減
}else{//節(jié)拍數(shù)小于0時反轉(zhuǎn)
index--;//反轉(zhuǎn)時節(jié)拍輸出索引遞減
index=index&0x07;//用&操作同樣可以實現(xiàn)到-1時歸7
beats++;//反轉(zhuǎn)時節(jié)拍計數(shù)遞增
}
tmp=P1;//用tmp把P1口當(dāng)前值暫存
tmp=tmp&0xF0;//用&操作清零低4位
tmp=tmp|BeatCode[index];//用|操作把節(jié)拍代碼寫到低4位
P1=tmp;//把低4位的節(jié)拍代碼和高4位的原值送回P1
}else{//節(jié)拍數(shù)為0則關(guān)閉電機(jī)所有的相
P1=P1|0x0F;
}
}
/*T0中斷服務(wù)函數(shù),用于按鍵掃描與電機(jī)轉(zhuǎn)動控制*/
voidInterruptTimer0()interrupt1{
staticbitp=0;
TH0=0xFC;//重新加載初值
TL0=0x67;
KeyScan();//執(zhí)行按鍵掃描
//用一個靜態(tài)bit變量實現(xiàn)二分頻,即2ms定時,用于控制電機(jī)
p=~p;
if(p==1){
TurnMotor();
}
}這個程序是第8章和本章知識的一個綜合——用按鍵控制步進(jìn)電機(jī)轉(zhuǎn)動。程序中有這么幾點值得注意,我們分述如下:
針對電機(jī)要完成正轉(zhuǎn)和反轉(zhuǎn)兩個不同的操作,我們并沒有使用正轉(zhuǎn)啟動函數(shù)和反轉(zhuǎn)啟動函數(shù)這么兩個函數(shù)來完成,也沒有在啟動函數(shù)定義的時候增加一個形式參數(shù)來指明其方向。我們這里的啟動函數(shù)voidStartMotor(signedlongangle)與單向正轉(zhuǎn)時的啟動函數(shù)唯一的區(qū)別就是把形式參數(shù)angle的類型從unsignedlong改為了signedlong,我們用有符號數(shù)固有的正負(fù)特性來區(qū)分正轉(zhuǎn)與反轉(zhuǎn),正數(shù)表示正轉(zhuǎn)angle度,負(fù)數(shù)就表示反轉(zhuǎn)angle度,這樣處理是不是很簡潔又很明了呢?而你對有符號數(shù)和無符號數(shù)的區(qū)別用法是不是也更有體會了?
針對終止電機(jī)轉(zhuǎn)動的操作,我們定義了一個單獨的StopMotor函數(shù)來完成,盡管這個函數(shù)非常簡單,盡管它也只在Esc按鍵分支內(nèi)被調(diào)用了,但我們?nèi)匀话阉鼏为毺岢鰜碜鳛榱艘粋€函數(shù)。而這種做法就是基于這樣一條編程原則:盡可能用單獨的函數(shù)來完成硬件的某種操作,當(dāng)一個硬件包含多個操作時,把這些操作函數(shù)組織在一起,形成一個對上層的統(tǒng)一接口。這樣的層次化處理,會使得整個程序條理清晰,既有利于程序的調(diào)試維護(hù),又有利于功能的擴(kuò)充。
中斷函數(shù)中要處理按鍵掃描和電機(jī)驅(qū)動兩件事情,而為了避免中斷函數(shù)過于復(fù)雜,我們就又分出了按鍵掃描和電機(jī)驅(qū)動兩個函數(shù)(這也同樣符合上述2的編程原則),而中斷函數(shù)的邏輯就變得簡潔而清晰了。這里還有個矛盾,就是按鍵掃描我們選擇的定時時間是1ms,而本章之前的實例中電機(jī)節(jié)拍持續(xù)時間都是2ms;很顯然,用1ms的定時可以定出2ms的間隔,而用2ms的定時卻得不到準(zhǔn)確的1ms間隔;所以我們的做法就是,定時器依然定時1ms,然后用一個bit變量做標(biāo)志,每1ms改變一次它的值,而我們只選擇值為1的時候執(zhí)行一次動作,這樣就是2ms的間隔了;如果我要3ms、4ms??呢,把bit改為char或int型,然后對它們遞增,判斷到哪個值該歸零,就可以了。這就是在硬件定時器的基礎(chǔ)上實現(xiàn)準(zhǔn)確的軟件定時,其實類似的操作我們在講數(shù)碼管的時候也用過了,回想一下吧。
標(biāo)簽:
中國傳動網(wǎng)版權(quán)與免責(zé)聲明:凡本網(wǎng)注明[來源:中國傳動網(wǎng)]的所有文字、圖片、音視和視頻文件,版權(quán)均為中國傳動網(wǎng)(m.u63ivq3.com)獨家所有。如需轉(zhuǎn)載請與0755-82949061聯(lián)系。任何媒體、網(wǎng)站或個人轉(zhuǎn)載使用時須注明來源“中國傳動網(wǎng)”,違反者本網(wǎng)將追究其法律責(zé)任。
本網(wǎng)轉(zhuǎn)載并注明其他來源的稿件,均來自互聯(lián)網(wǎng)或業(yè)內(nèi)投稿人士,版權(quán)屬于原版權(quán)人。轉(zhuǎn)載請保留稿件來源及作者,禁止擅自篡改,違者自負(fù)版權(quán)法律責(zé)任。
產(chǎn)品新聞
更多>以簡驅(qū)繁,精準(zhǔn)智控 | 維智S1系列新一代...
2024-11-01
2024-10-31
2024-10-31
2024-10-31
2024-10-31
2024-10-29
推薦專題
更多>