 |
線反轉法也是識別閉合鍵的一種常用方法,該法比行掃描速度快。 先將行線作為輸出線,列線作為輸入線,行線輸出全0信號,讀入列線的值,那麼在閉合鍵所在的列線上的值必為0;然後從列線輸出全0信號,再讀取行線的輸入值,閉合鍵所在的行線值必為0。這樣,當一個鍵被按下時,必定可讀到一對唯一的行列值。再由這一對行列值可以求出閉合鍵所在的位置。 
|
 |
【程序】 #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 in, out; uint8_t col, row; uint8_t i, keycode; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); // 默認輸入/輸出模式 in.GPIO_Mode = GPIO_Mode_IPU; out.GPIO_Mode = GPIO_Mode_Out_PP; out.GPIO_Speed = GPIO_Speed_2MHz; // PB8~15用作數碼管顯示,為輸出 out.GPIO_Pin = 0xff00; GPIO_Init(GPIOB, &out); display(0xbf); // 默認顯示'-' while (1) { // 第一步:和行掃描法一樣,先將行線作為輸出線, 列線作為輸入線 out.GPIO_Pin = 0x0f; GPIO_Init(GPIOA, &out); in.GPIO_Pin = 0xf0; GPIO_Init(GPIOA, &in); GPIO_ResetBits(GPIOA, 0x0f); // 行線全輸出0 col = GPIO_ReadInputData(GPIOA) & 0xf0; // 讀取列線的值 // 按鍵消抖 if (col != 0xf0) { delay(); col = GPIO_ReadInputData(GPIOA) & 0xf0; if (col != 0xf0) { // 第二步:從列線輸出全0信號,再讀取行線的輸入值 out.GPIO_Pin = 0xf0; GPIO_Init(GPIOA, &out); in.GPIO_Pin = 0x0f; GPIO_Init(GPIOA, &in); GPIO_ResetBits(GPIOA, 0xf0); row = GPIO_ReadInputData(GPIOA) & 0x0f; // 行線有非1值的情況下才繼續 // 防止出現按下了6顯示的卻是2的錯誤情況 if (row != 0x0f) { // 第三步:計算鍵碼 row = ~row & 0x0f; col = ~col >> 4 & 0x0f; keycode = 0; for (i = 0; i < 4; i++) { if (row & 1) { keycode = i * 4; break; } row >>= 1; } for (i = 0; i < 4; i++) { if (col & 1) { keycode += i; break; } col >>= 1; } display(table[keycode]); while ((GPIO_ReadInputData(GPIOA) & 0x0f) != 0x0f); } } } } }
|
 |
【技巧】 為了方便進行I/O口輸入輸出的切換,可以定義兩個GPIO_InitTypeDef結構體類型的變量:in和out,並給speed和mode成員賦初值。
普中開發板中自帶的矩陣鍵盤例程就顯得非常繁瑣:

|