9 8 實用的電機控制程式

2021-09-11 04:39:53 字數 3323 閱讀 7529

上面我們雖然完成了用中斷控制電機轉動的程式,但實際上這個程式還是沒多少實用價值的,我們不能每次想讓它轉動的時候都上下電啊,是吧。還有就是它不但能正轉還得能反轉啊,也就是說不但能轉過去,還得能轉回來呀。好吧,我們就來做乙個例項程式吧,結合第 8 章的按鍵程式,我們設計這樣乙個功能程式:按數字鍵 1~9,控制電機轉過 1~9 圈;配合上下鍵改變轉動方向,按向上鍵後正向轉 1~9 圈,向下鍵則反向轉 1~9 圈;左鍵固定正轉 90 度,右鍵固定反轉 90;esc 鍵終止轉動。通過這個程式,我們也可以進一步體會到如何用按鍵來控制程式完成複雜的功能,以及控制和執行模組之間如何協調工作,而你的程式設計水平也可以在這樣的實踐練習中得到鍛鍊和提公升。

#include sbit key_in_1 = p2^4;

sbit key_in_2 = p2^5;

sbit key_in_3 = p2^6;

sbit key_in_4 = p2^7;

sbit key_out_1 = p2^3;

sbit key_out_2 = p2^2;

sbit key_out_3 = p2^1;

sbit key_out_4 = p2^0;

unsigned char code keycodemap[4][4] = , //數字鍵 1、數字鍵 2、數字鍵 3、向上鍵

, //數字鍵 4、數字鍵 5、數字鍵 6、向左鍵

, //數字鍵 7、數字鍵 8、數字鍵 9、向下鍵

//數字鍵 0、esc 鍵、 回車鍵、 向右鍵

};unsigned char keysta[4][4] = , , ,

};signed long beats = 0; //電機轉動節拍總數

void keydriver();

void main()

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

void startmotor(signed long angle)

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

void stopmotor()

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

void keyaction(unsigned char keycode)else

}else if (keycode == 0x26)else if (keycode == 0x28)else if (keycode == 0x25)else if (keycode == 0x27)else if (keycode == 0x1b)

}/* 按鍵驅動函式,檢測按鍵動作,排程相應動作函式,需在主迴圈中呼叫 */

void keydriver(), , ,

};for (i=0; i<4; i++)

backup[i][j] = keysta[i][j]; //重新整理前一次的備份值}}

}}/* 按鍵掃瞄函式,需在定時中斷中呼叫,推薦呼叫間隔 1ms */

void keyscan(), ,

, };

//將一行的 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++)else if ((keybuf[keyout][i] & 0x0f) == 0x0f)

}//執行下一次的掃瞄輸出

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

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

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

switch (keyout)

}/* 電機轉動控制函式 */

void turnmotor();

if (beats != 0)else

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

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

tmp = tmp | beatcode[index]; //用|操作把節拍**寫到低 4 位

p1 = tmp; //把低 4 位的節拍**和高 4 位的原值送回 p1

}else

}/* t0 中斷服務函式,用於按鍵掃瞄與電機轉動控制 */

void interrupttimer0() interrupt 1

}

這個程式是第 8 章和本章知識的乙個綜合——用按鍵控制步進電機轉動。程式中有這麼幾點值得注意,我們分述如下:

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

針對終止電機轉動的操作,我們定義了乙個單獨的 stopmotor 函式來完成,儘管這個函式非常簡單,儘管它也只在 esc 按鍵分支內被呼叫了,但我們仍然把它單獨提出來作為了乙個函式。而這種做法就是基於這樣一條程式設計原則:盡可能用單獨的函式來完成硬體的某種操作,當乙個硬體包含多個操作時,把這些操作函式組織在一起,形成乙個對上層的統一介面。這樣的層次化處理,會使得整個程式條理清晰,既有利於程式的除錯維護,又有利於功能的擴充。

中斷函式中要處理按鍵掃瞄和電機驅動兩件事情,而為了避免中斷函式過於複雜,我們就又分出了按鍵掃瞄和電機驅動兩個函式(這也同樣符合上述 2 的程式設計原則),而中斷函式的邏輯就變得簡潔而清晰了。這裡還有個矛盾,就是按鍵掃瞄我們選擇的定時時間是 1ms,而本章之前的例項中電機節拍持續時間都是 2ms;很顯然,用 1ms 的定時可以定出 2ms 的間隔,而用 2ms 的定時卻得不到準確的 1ms 間隔;所以我們的做法就是,定時器依然定時 1ms,然後用乙個 bit 變數做標誌,每 1ms 改變一次它的值,而我們只選擇值為 1 的時候執行一次動作,這樣就是 2ms 的間隔了;如果我要 3ms、4ms„„呢,把 bit 改為 char 或 int 型,然後對它們遞增,判斷到哪個值該歸零,就可以了。這就是在硬體定時器的基礎上實現準確的軟體定時,其實類似的操作我們在講數碼管的時候也用過了,回想一下吧。

瓦力視覺控制程式

上位機是採用了aforge.net framework 2.2.3和ez b sdk windows v2011.11.09.00的結合。aforge真的很強大,不過沒有涉及到控制這塊,ezb就有現成的參考,但ezb沒有提供核心部分的 而它只支援本地攝像頭,所以我只能反編譯獲取需要的 移植到afor...

瓦力視覺控制程式

2012 01 30 上位機是採用了aforge.net framework 2.2.3和ez b sdk windows v2011.11.09.00的結合。aforge真的很強大,不過沒有涉及到控制這塊,ezb就有現成的參考,但ezb沒有提供核心部分的 而它只支援本地攝像頭,所以我只能反編譯獲取...

Access使用巨集控制程式

巨集是指乙個或多個www.cppcns.com操作的集合,其中每個操作實現特定的功能,例如開啟某個窗體或列印某個報表。巨集可以使某些普通的任務自動完成。例如,可設定某個巨集,在使用者單擊某個命令程式設計客棧按鈕cvpbmstdwj時執行該巨集,以開啟某個窗體程式設計客棧。巨集可以是包含操作序列的乙個...