 |
【接線】

|
 |
【程序】 #include <stm32f10x.h> // 共陽數碼管段碼表 unsigned char table[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e, 0xbf}; // 用於按鍵延時 void delay(void) { uint16_t i; for (i = 0; i < 20000; i++); } // 在數碼管上顯示指定段碼 void display(uint8_t n) { GPIO_ResetBits(GPIOB, 0xff00); GPIO_SetBits(GPIOB, n << 8); } int main(void) { GPIO_InitTypeDef init; uint8_t i, temp; uint8_t keycode; // 同時開啟PA和PB的時鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); // PB8~15用作數碼管顯示,為輸出 init.GPIO_Mode = GPIO_Mode_Out_PP; init.GPIO_Pin = 0xff00; init.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &init); // PA0~7用作矩陣鍵盤 init.GPIO_Pin = 0x0f; GPIO_Init(GPIOA, &init); // 行線為輸出 init.GPIO_Mode = GPIO_Mode_IPU; // 沒有信號輸入時,視為輸入了高電平 init.GPIO_Pin = 0xf0; GPIO_Init(GPIOA, &init); // 列線為輸入 display(0xbf); // 默認顯示'-' while (1) { GPIO_ResetBits(GPIOA, 0x0f); // 行線輸出0 temp = GPIO_ReadInputData(GPIOA) & 0xf0; // 讀列線。如果按鍵沒有按下,則沒有信號輸入(引腳懸空);如果有按鍵按下,則輸入的是按鍵對面輸出的0 // 如果讀出來列線中有為0的位,則表明有按鍵按下 if (temp != 0xf0) { // 按鍵消抖 delay(); temp = GPIO_ReadInputData(GPIOA) & 0xf0; if (temp != 0xf0) { // 如果確實按下了按鍵 // 行掃描 for (i = 0; i < 4; i++) { GPIO_SetBits(GPIOA, 0x0f); // 行線全設為1 GPIO_ResetBits(GPIOA, 1 << i); // 將要檢查的行設為0 temp = GPIO_ReadInputData(GPIOA) & 0xf0; // 按同樣的方法讀列線 if (temp != 0xf0) // 如果不全為1, 則表明該行有按鍵按下 { // 根據temp和i的值計算鍵碼 temp = ~temp >> 4 & 0x0f; keycode = i * 4; if (temp == 8) keycode += 3; else keycode += temp >> 1; // keycode為最終計算出來的鍵碼, 取值範圍是0~15 // 可在這裡進行按鍵處理 // 顯示鍵碼並退出行掃描 display(table[keycode]); break; } } // 等待按鍵釋放 while ((GPIO_ReadInputData(GPIOA) & 0xf0) != 0xf0); } } } }
|
 |
【電路圖】 
|
 |
【原理講解】 
|
 |
在行掃描循環中,當1 << i == 二進位的1101時,i = 2 此時讀列線為二進位的1101????,取反後右移四位並屏蔽掉高4位: temp = ~temp >> 4 & 0x0f;
得:temp = 二進位00000010 = 2 keycode = i * 4 + (temp >> 1) = 8 + 1 = 9 因此按下的鍵為9
|