欧美一区二区三区,国内熟女精品熟女A片视频小说,日本av网,小鲜肉男男GAY做受XXX网站

單片機是如何控制步進電機扎旋轉的?

江奕云2年前15瀏覽0評論

結合按鍵程序,我們設計這樣一個功能程序:按數字鍵1~9,控制電機轉過1~9圈;配合上下鍵改變轉動方向,按向上鍵后正向轉1~9圈,向下鍵則反向轉1~9圈;左鍵固定正轉90度,右鍵固定反轉90;Esc鍵終止轉動。通過這個程序,我們也可以進一步體會到如何用按鍵來控制程序完成復雜的功能,以及控制和執行模塊之間如何協調工作,而你的編程水平也可以在這樣的實踐練習中得到鍛煉和提升。

#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]={//矩陣按鍵編號到標準鍵盤鍵碼的映射表

{0x31,0x32,0x33,0x26},//數字鍵1、數字鍵2、數字鍵3、向上鍵

{0x34,0x35,0x36,0x25},//數字鍵4、數字鍵5、數字鍵6、向左鍵

{0x37,0x38,0x39,0x28},//數字鍵7、數字鍵8、數字鍵9、向下鍵

{0x30,0x1B,0x0D,0x27}//數字鍵0、ESC鍵、回車鍵、向右鍵

};

unsignedcharKeySta[4][4]={//全部矩陣按鍵的當前狀態

{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}

};

signedlongbeats=0;//電機轉動節拍總數

voidKeyDriver();

voidmain(){

EA=1;//使能總中斷

TMOD=0x01;//設置T0為模式1

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

TL0=0x67;

ET0=1;//使能T0中斷

TR0=1;//啟動T0

while(1){

KeyDriver();//調用按鍵驅動函數

}

}

/*步進電機啟動函數,angle-需轉過的角度*/

voidStartMotor(signedlongangle){

//在計算前關閉中斷,完成后再打開,以避免中斷打斷計算過程而造成錯誤

EA=0;

beats=(angle*4076)/360;//實測為4076拍轉動一圈

EA=1;

}

/*步進電機停止函數*/

voidStopMotor(){

EA=0;

beats=0;

EA=1;

}

/*按鍵動作函數,根據鍵碼執行相應的操作,keycode-按鍵鍵碼*/

voidKeyAction(unsignedcharkeycode){

staticbitdirMotor=0;//電機轉動方向

//控制電機轉動1-9圈

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

if(dirMotor==0){

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

}else{

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

}

}elseif(keycode==0x26){//向上鍵,控制轉動方向為正轉

dirMotor=0;

}elseif(keycode==0x28){//向下鍵,控制轉動方向為反轉

dirMotor=1;

}elseif(keycode==0x25){//向左鍵,固定正轉90度

StartMotor(90);

}elseif(keycode==0x27){//向右鍵,固定反轉90度

StartMotor(-90);

}elseif(keycode==0x1B){//Esc鍵,停止轉動

StopMotor();

}

}

/*按鍵驅動函數,檢測按鍵動作,調度相應動作函數,需在主循環中調用*/

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++){//循環檢測4*4的矩陣按鍵

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

if(backup[i][j]!=KeySta[i][j]){//檢測按鍵動作

if(backup[i][j]!=0){//按鍵按下時執行動作

KeyAction(KeyCodeMap[i][j]);//調用按鍵動作函數

}

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

}

}

}

}

/*按鍵掃描函數,需在定時中斷中調用,推薦調用間隔1ms*/

voidKeyScan(){

unsignedchari;

staticunsignedcharkeyout=0;//矩陣按鍵掃描輸出索引

staticunsignedcharkeybuf[4][4]={//矩陣按鍵掃描緩沖區

{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},

{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}

};

//將一行的4個按鍵值移入緩沖區

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;

//消抖后更新按鍵狀態

for(i=0;i<4;i++){//每行4個按鍵,所以循環4次

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

//連續4次掃描值為0,即4*4ms內都是按下狀態時,可認為按鍵已穩定的按下

KeySta[keyout][i]=0;

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

//連續4次掃描值為1,即4*4ms內都是彈起狀態時,可認為按鍵已穩定的彈起

KeySta[keyout][i]=1;

}

}

//執行下一次的掃描輸出

keyout++;//輸出索引遞增

keyout=keyout&0x03;//索引值加到4即歸零

//根據索引,釋放當前輸出引腳,拉低下次的輸出引腳

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;

}

}

/*電機轉動控制函數*/

voidTurnMotor(){

unsignedchartmp;//臨時變量

staticunsignedcharindex=0;//節拍輸出索引

unsignedcharcodeBeatCode[8]={//步進電機節拍對應的IO控制代碼

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

};

if(beats!=0){//節拍數不為0則產生一個驅動節拍

if(beats>0){//節拍數大于0時正轉

index++;//正轉時節拍輸出索引遞增

index=index&0x07;//用&操作實現到8歸零

beats--;//正轉時節拍計數遞減

}else{//節拍數小于0時反轉

index--;//反轉時節拍輸出索引遞減

index=index&0x07;//用&操作同樣可以實現到-1時歸7

beats++;//反轉時節拍計數遞增

}

tmp=P1;//用tmp把P1口當前值暫存

tmp=tmp&0xF0;//用&操作清零低4位

tmp=tmp|BeatCode[index];//用|操作把節拍代碼寫到低4位

P1=tmp;//把低4位的節拍代碼和高4位的原值送回P1

}else{//節拍數為0則關閉電機所有的相

P1=P1|0x0F;

}

}

/*T0中斷服務函數,用于按鍵掃描與電機轉動控制*/

voidInterruptTimer0()interrupt1{

staticbitp=0;

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

TL0=0x67;

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

//用一個靜態bit變量實現二分頻,即2ms定時,用于控制電機

p=~p;

if(p==1){

TurnMotor();

}

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

針對終止電機轉動的操作,我們定義了一個單獨的StopMotor函數來完成,盡管這個函數非常簡單,盡管它也只在Esc按鍵分支內被調用了,但我們仍然把它單獨提出來作為了一個函數。而這種做法就是基于這樣一條編程原則:盡可能用單獨的函數來完成硬件的某種操作,當一個硬件包含多個操作時,把這些操作函數組織在一起,形成一個對上層的統一接口。這樣的層次化處理,會使得整個程序條理清晰,既有利于程序的調試維護,又有利于功能的擴充。

中斷函數中要處理按鍵掃描和電機驅動兩件事情,而為了避免中斷函數過于復雜,我們就又分出了按鍵掃描和電機驅動兩個函數(這也同樣符合上述2的編程原則),而中斷函數的邏輯就變得簡潔而清晰了。這里還有個矛盾,就是按鍵掃描我們選擇的定時時間是1ms,而本章之前的實例中電機節拍持續時間都是2ms;很顯然,用1ms的定時可以定出2ms的間隔,而用2ms的定時卻得不到準確的1ms間隔;所以我們的做法就是,定時器依然定時1ms,然后用一個bit變量做標志,每1ms改變一次它的值,而我們只選擇值為1的時候執行一次動作,這樣就是2ms的間隔了;如果我要3ms、4ms??呢,把bit改為char或int型,然后對它們遞增,判斷到哪個值該歸零,就可以了