合肥 網(wǎng)站平臺(tái)建設(shè)公司站長工具端口檢測
介紹
例程使用 SDCC 編譯、 stcgal 燒錄,如果你想要配置一樣的環(huán)境,可以參考本專欄的第一篇文章“51單片機(jī)開發(fā)環(huán)境搭建 - VS Code 從編寫到燒錄”,我的設(shè)備是 Windows 10,使用普中51單片機(jī)開發(fā)板(STC89C52RC)。
- 關(guān)于如何驅(qū)動(dòng)數(shù)碼管,推薦閱讀:驅(qū)動(dòng)多位數(shù)碼管
- 關(guān)于使用單片機(jī)接收來自微動(dòng)開關(guān)的輸入:獨(dú)立按鍵控制 LED
最后的程序?qū)崿F(xiàn)了按下一個(gè)微動(dòng)開關(guān)后,驅(qū)動(dòng)一位數(shù)碼管上顯示對(duì)應(yīng)的數(shù)字,顯示持續(xù)1秒后重新等待輸入。
矩陣鍵盤
如下圖所示,單片機(jī)的 P1_0 ~ P1_7
引腳剛好連接了一個(gè) 4x4 的矩陣鍵盤:

當(dāng)我們想要檢測第一列(S1/S5/S9/S13)是否被按下時(shí),可以置P1=1111 0111
,也就是除P13外,其它全輸出高電平,這時(shí)如果S1被按下,S1的高電平被拉低,就可以檢測到P1=0111 0111
,如果S9被按下,就是1101 0111
,所以可以通過掃描低4位(對(duì)低4位逐個(gè)置0),然后檢查高4位的電平變化,來交叉判斷是哪一個(gè)按鍵被按下了。
實(shí)現(xiàn)
可以使用逐個(gè)給 P1 賦值 0xf7、0xfb、0xfd… 然后判斷每一種情況的方法來實(shí)現(xiàn),缺點(diǎn)是代碼行數(shù)很多(case 數(shù)就等于按鍵的數(shù)量),可以利用循環(huán)和位運(yùn)算來大大縮短代碼量:
unsigned int get_keyboard_input() {unsigned int i = 0, j, t, mask = (1 << 4) - 1;while (1) { // 在有按鍵按下前一直掃描P1 = 0xFF ^ (1 << (3 - i));t = (P1 >> 4) ^ mask;if (t) {delay_10us(1000); // 去抖動(dòng)j = 4 - bit_length(t);while ((P1 >> 4) ^ mask); // 等待手指抬起delay_10us(1000); // 去抖動(dòng)return j * 4 + i;}i = (i + 1) % 4;}
}
其中:
mask
是 1111,用來取 P1 的低 4 位,以及對(duì)低 4 位進(jìn)行按位取反,i
代表列數(shù),在 while 循環(huán)中不斷的掃描第 0 列、第 1 列、第 2 列、第 3 列、第 0 列…j
代表行數(shù),檢查是第幾行的按鍵被按下了(也就是電平被下拉到 0 了)。
完整代碼:
#include <8051.h>#define decoder_in_1 P2_2 // 譯碼器的 3 位輸入,用于位選
#define decoder_in_2 P2_3
#define decoder_in_3 P2_4
#define NUMBER P0unsigned int LED_MAP[11] = {0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, 0x6f};void delay_10us(unsigned int n) {while(n--);
}void send_to_decoder(unsigned int position) { // position: 1 ~ 8 position--; // position: 0 ~ 7 (000 ~ 111)decoder_in_1 = position & 1; // low bit of position (position & 001)decoder_in_2 = position & 2; // middle bit of position (position & 010)decoder_in_3 = position & 4; // high bit of position (position & 100)
}void print_number(unsigned int n) { // 在最左邊的數(shù)碼管(8號(hào))顯示 nNUMBER = 0;send_to_decoder(8);NUMBER = LED_MAP[n];
}unsigned int bit_length(unsigned int n) {unsigned int x = 1;while (n >>= 1) x++;return x;
}unsigned int get_keyboard_input() {unsigned int i = 0, j, t, mask = (1 << 4) - 1;while (1) { // 在有按鍵按下前一直掃描P1 = 0xFF ^ (1 << (3 - i));t = (P1 >> 4) ^ mask;if (t) {delay_10us(1000); // 去抖動(dòng)j = 4 - bit_length(t);while ((P1 >> 4) ^ mask); // 等待手指抬起delay_10us(1000); // 去抖動(dòng)return j * 4 + i;}i = (i + 1) % 4;}
}void main() {NUMBER = 0;unsigned int num;while (1) {num = get_keyboard_input();print_number(num % 10);delay_10us(100000);NUMBER = 0;}
}