技術(shù)頻道

娓娓工業(yè)
您現(xiàn)在的位置: 中國(guó)傳動(dòng)網(wǎng) > 技術(shù)頻道 > 應(yīng)用方案 > 用單片機(jī)按鍵控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)的程序

用單片機(jī)按鍵控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)的程序

時(shí)間:2018-01-02 10:46:39來源:網(wǎng)絡(luò)轉(zhuǎn)載

導(dǎo)語:?結(jié)合按鍵程序,我們?cè)O(shè)計(jì)這樣一個(gè)功能程序:按數(shù)字鍵1~9,控制電機(jī)轉(zhuǎn)過1~9圈;

結(jié)合按鍵程序,我們?cè)O(shè)計(jì)這樣一個(gè)功能程序:按數(shù)字鍵1~9,控制電機(jī)轉(zhuǎn)過1~9圈;配合上下鍵改變轉(zhuǎn)動(dòng)方向,按向上鍵后正向轉(zhuǎn)1~9圈,向下鍵則反向轉(zhuǎn)1~9圈;左鍵固定正轉(zhuǎn)90度,右鍵固定反轉(zhuǎn)90;Esc鍵終止轉(zhuǎn)動(dòng)。通過這個(gè)程序,我們也可以進(jìn)一步體會(huì)到如何用按鍵來控制程序完成復(fù)雜的功能,以及控制和執(zhí)行模塊之間如何協(xié)調(diào)工作,而你的編程水平也可以在這樣的實(shí)踐練習(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]={//矩陣按鍵編號(hào)到標(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)動(dòng)節(jié)拍總數(shù)

voidKeyDriver();

voidmain(){

EA=1;//使能總中斷

TMOD=0x01;//設(shè)置T0為模式1

TH0=0xFC;//為T0賦初值0xFC67,定時(shí)1ms

TL0=0x67;

ET0=1;//使能T0中斷

TR0=1;//啟動(dòng)T0

while(1){

KeyDriver();//調(diào)用按鍵驅(qū)動(dòng)函數(shù)

}

}

/*步進(jìn)電機(jī)啟動(dòng)函數(shù),angle-需轉(zhuǎn)過的角度*/

voidStartMotor(signedlongangle){

//在計(jì)算前關(guān)閉中斷,完成后再打開,以避免中斷打斷計(jì)算過程而造成錯(cuò)誤

EA=0;

beats=(angle*4076)/360;//實(shí)測(cè)為4076拍轉(zhuǎn)動(dòng)一圈

EA=1;

}

/*步進(jìn)電機(jī)停止函數(shù)*/

voidStopMotor(){

EA=0;

beats=0;

EA=1;

}

/*按鍵動(dòng)作函數(shù),根據(jù)鍵碼執(zhí)行相應(yīng)的操作,keycode-按鍵鍵碼*/

voidKeyAction(unsignedcharkeycode){

staticbitdirMotor=0;//電機(jī)轉(zhuǎn)動(dòng)方向

//控制電機(jī)轉(zhuǎn)動(dòng)1-9圈

if((keycode>=0x30)&&(keycode<=0x39)){

if(dirMotor==0){

StartMotor(360*(keycode-0x30));

}else{

StartMotor(-360*(keycode-0x30));

}

}elseif(keycode==0x26){//向上鍵,控制轉(zhuǎn)動(dòng)方向?yàn)檎D(zhuǎn)

dirMotor=0;

}elseif(keycode==0x28){//向下鍵,控制轉(zhuǎn)動(dòng)方向?yàn)榉崔D(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)動(dòng)

StopMotor();

}

}

/*按鍵驅(qū)動(dòng)函數(shù),檢測(cè)按鍵動(dòng)作,調(diào)度相應(yīng)動(dò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)檢測(cè)4*4的矩陣按鍵

for(j=0;j<4;j++){

if(backup[i][j]!=KeySta[i][j]){//檢測(cè)按鍵動(dòng)作

if(backup[i][j]!=0){//按鍵按下時(shí)執(zhí)行動(dòng)作

KeyAction(KeyCodeMap[i][j]);//調(diào)用按鍵動(dòng)作函數(shù)

}

backup[i][j]=KeySta[i][j];//刷新前一次的備份值

}

}

}

}

/*按鍵掃描函數(shù),需在定時(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個(gè)按鍵值移入緩沖區(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個(gè)按鍵,所以循環(huán)4次

if((keybuf[keyout][i]&0x0F)==0x00){

//連續(xù)4次掃描值為0,即4*4ms內(nèi)都是按下狀態(tài)時(shí),可認(rèn)為按鍵已穩(wěn)定的按下

KeySta[keyout][i]=0;

}elseif((keybuf[keyout][i]&0x0F)==0x0F){

//連續(xù)4次掃描值為1,即4*4ms內(nèi)都是彈起狀態(tài)時(shí),可認(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)動(dòng)控制函數(shù)*/

voidTurnMotor(){

unsignedchartmp;//臨時(shí)變量

staticunsignedcharindex=0;//節(jié)拍輸出索引

unsignedcharcodeBeatCode[8]={//步進(jìn)電機(jī)節(jié)拍對(duì)應(yīng)的IO控制代碼

0xE,0xC,0xD,0x9,0xB,0x3,0x7,0x6

};

if(beats!=0){//節(jié)拍數(shù)不為0則產(chǎn)生一個(gè)驅(qū)動(dòng)節(jié)拍

if(beats>0){//節(jié)拍數(shù)大于0時(shí)正轉(zhuǎn)

index++;//正轉(zhuǎn)時(shí)節(jié)拍輸出索引遞增

index=index&0x07;//用&操作實(shí)現(xiàn)到8歸零

beats--;//正轉(zhuǎn)時(shí)節(jié)拍計(jì)數(shù)遞減

}else{//節(jié)拍數(shù)小于0時(shí)反轉(zhuǎn)

index--;//反轉(zhuǎn)時(shí)節(jié)拍輸出索引遞減

index=index&0x07;//用&操作同樣可以實(shí)現(xiàn)到-1時(shí)歸7

beats++;//反轉(zhuǎn)時(shí)節(jié)拍計(jì)數(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)動(dòng)控制*/

voidInterruptTimer0()interrupt1{

staticbitp=0;

TH0=0xFC;//重新加載初值

TL0=0x67;

KeyScan();//執(zhí)行按鍵掃描

//用一個(gè)靜態(tài)bit變量實(shí)現(xiàn)二分頻,即2ms定時(shí),用于控制電機(jī)

p=~p;

if(p==1){

TurnMotor();

}

}這個(gè)程序是第8章和本章知識(shí)的一個(gè)綜合——用按鍵控制步進(jìn)電機(jī)轉(zhuǎn)動(dòng)。程序中有這么幾點(diǎn)值得注意,我們分述如下:

針對(duì)電機(jī)要完成正轉(zhuǎn)和反轉(zhuǎn)兩個(gè)不同的操作,我們并沒有使用正轉(zhuǎn)啟動(dòng)函數(shù)和反轉(zhuǎn)啟動(dòng)函數(shù)這么兩個(gè)函數(shù)來完成,也沒有在啟動(dòng)函數(shù)定義的時(shí)候增加一個(gè)形式參數(shù)來指明其方向。我們這里的啟動(dòng)函數(shù)voidStartMotor(signedlongangle)與單向正轉(zhuǎn)時(shí)的啟動(dòng)函數(shù)唯一的區(qū)別就是把形式參數(shù)angle的類型從unsignedlong改為了signedlong,我們用有符號(hào)數(shù)固有的正負(fù)特性來區(qū)分正轉(zhuǎn)與反轉(zhuǎn),正數(shù)表示正轉(zhuǎn)angle度,負(fù)數(shù)就表示反轉(zhuǎn)angle度,這樣處理是不是很簡(jiǎn)潔又很明了呢?而你對(duì)有符號(hào)數(shù)和無符號(hào)數(shù)的區(qū)別用法是不是也更有體會(huì)了?

針對(duì)終止電機(jī)轉(zhuǎn)動(dòng)的操作,我們定義了一個(gè)單獨(dú)的StopMotor函數(shù)來完成,盡管這個(gè)函數(shù)非常簡(jiǎn)單,盡管它也只在Esc按鍵分支內(nèi)被調(diào)用了,但我們?nèi)匀话阉鼏为?dú)提出來作為了一個(gè)函數(shù)。而這種做法就是基于這樣一條編程原則:盡可能用單獨(dú)的函數(shù)來完成硬件的某種操作,當(dāng)一個(gè)硬件包含多個(gè)操作時(shí),把這些操作函數(shù)組織在一起,形成一個(gè)對(duì)上層的統(tǒng)一接口。這樣的層次化處理,會(huì)使得整個(gè)程序條理清晰,既有利于程序的調(diào)試維護(hù),又有利于功能的擴(kuò)充。

中斷函數(shù)中要處理按鍵掃描和電機(jī)驅(qū)動(dòng)兩件事情,而為了避免中斷函數(shù)過于復(fù)雜,我們就又分出了按鍵掃描和電機(jī)驅(qū)動(dòng)兩個(gè)函數(shù)(這也同樣符合上述2的編程原則),而中斷函數(shù)的邏輯就變得簡(jiǎn)潔而清晰了。這里還有個(gè)矛盾,就是按鍵掃描我們選擇的定時(shí)時(shí)間是1ms,而本章之前的實(shí)例中電機(jī)節(jié)拍持續(xù)時(shí)間都是2ms;很顯然,用1ms的定時(shí)可以定出2ms的間隔,而用2ms的定時(shí)卻得不到準(zhǔn)確的1ms間隔;所以我們的做法就是,定時(shí)器依然定時(shí)1ms,然后用一個(gè)bit變量做標(biāo)志,每1ms改變一次它的值,而我們只選擇值為1的時(shí)候執(zhí)行一次動(dòng)作,這樣就是2ms的間隔了;如果我要3ms、4ms??呢,把bit改為char或int型,然后對(duì)它們遞增,判斷到哪個(gè)值該歸零,就可以了。這就是在硬件定時(shí)器的基礎(chǔ)上實(shí)現(xiàn)準(zhǔn)確的軟件定時(shí),其實(shí)類似的操作我們?cè)谥v數(shù)碼管的時(shí)候也用過了,回想一下吧。

標(biāo)簽:

點(diǎn)贊

分享到:

上一篇:無線傳感器網(wǎng)絡(luò)的結(jié)構(gòu)和技術(shù)...

下一篇:大型風(fēng)力發(fā)電機(jī)組齒輪傳動(dòng)技...

中國(guó)傳動(dòng)網(wǎng)版權(quán)與免責(zé)聲明:凡本網(wǎng)注明[來源:中國(guó)傳動(dòng)網(wǎng)]的所有文字、圖片、音視和視頻文件,版權(quán)均為中國(guó)傳動(dòng)網(wǎng)(www.treenowplaneincome.com)獨(dú)家所有。如需轉(zhuǎn)載請(qǐng)與0755-82949061聯(lián)系。任何媒體、網(wǎng)站或個(gè)人轉(zhuǎn)載使用時(shí)須注明來源“中國(guó)傳動(dòng)網(wǎng)”,違反者本網(wǎng)將追究其法律責(zé)任。

本網(wǎng)轉(zhuǎn)載并注明其他來源的稿件,均來自互聯(lián)網(wǎng)或業(yè)內(nèi)投稿人士,版權(quán)屬于原版權(quán)人。轉(zhuǎn)載請(qǐng)保留稿件來源及作者,禁止擅自篡改,違者自負(fù)版權(quán)法律責(zé)任。

網(wǎng)站簡(jiǎn)介|會(huì)員服務(wù)|聯(lián)系方式|幫助信息|版權(quán)信息|網(wǎng)站地圖|友情鏈接|法律支持|意見反饋|sitemap

中國(guó)傳動(dòng)網(wǎng)-工業(yè)自動(dòng)化與智能制造的全媒體“互聯(lián)網(wǎng)+”創(chuàng)新服務(wù)平臺(tái)

網(wǎng)站客服服務(wù)咨詢采購(gòu)咨詢媒體合作

Chuandong.com Copyright ?2005 - 2024 ,All Rights Reserved 版權(quán)所有 粵ICP備 14004826號(hào) | 營(yíng)業(yè)執(zhí)照證書 | 不良信息舉報(bào)中心 | 粵公網(wǎng)安備 44030402000946號(hào)