第十一集 矩阵键盘 Ai8051U实验箱
1 代码部分
io.h
- #ifndef __IO_H
- #define __IO_H
-
- #include "config.h"
-
- #define ROW1 P06
- #define ROW2 P07
- #define COL1 P00
- #define COL2 P01
- #define COL3 P02
- #define COL4 P03
-
- #define HC595_SER P34
- #define HC595_RCK P35
- #define HC595_SCK P32
-
- extern u8 key_num;
-
- #define WASH_OFF 0
- #define WASH_STANDBY 1
- #define WASH_RUNNING 2
-
- extern u8 wash_state;
- extern u8 wash_mode;
- extern u16 wash_countdown;
-
- void Key_Task(void);
- void SEG_Task(void);
- void Init_595(void);
- void Wash_Key_Task(void);
- void Wash_Timer_Task(void);
- void Wash_Display_Update(void);
-
- #endif
复制代码
io.c
- #include "io.h"
-
- u8 SEG_NUM[] = {
- 0x3F, /*'0', 0*/
- 0x06, /*'1', 1*/
- 0x5B, /*'2', 2*/
- 0x4F, /*'3', 3*/
- 0x66, /*'4', 4*/
- 0x6D, /*'5', 5*/
- 0x7D, /*'6', 6*/
- 0x07, /*'7', 7*/
- 0x7F, /*'8', 8*/
- 0x6F, /*'9', 9*/
- 0x77, /*'A', 10*/
- 0x7C, /*'B', 11*/
- 0x39, /*'C', 12*/
- 0x5E, /*'D', 13*/
- 0x79, /*'E', 14*/
- 0x71, /*'F', 15*/
- 0x40, /*'-', 16*/
- 0x00, /*' ', 17*/
- 0x80, /*'.', 18*/
- };
-
- u8 T_NUM[8] = {0X01, 0X02, 0X04, 0X08, 0X10, 0X20, 0X40, 0X80};
-
- void Init_595(void) {
- HC595_SER = 0;
- HC595_RCK = 0;
- HC595_SCK = 0;
- }
-
- void Send_595(u8 dat) {
- u8 i;
-
- for (i = 0; i < 8; i++) {
- dat <<= 1; // CY
- HC595_SER = CY;
- HC595_SCK = 1;
- HC595_SCK = 0;
- }
- }
-
- void Display_Seg(u8 HC595_1, u8 HC595_2) {
- Send_595(HC595_1); // segment data
- Send_595(HC595_2); // digit select
-
- HC595_RCK = 1; // latch output
- HC595_RCK = 0;
- }
-
- u8 key_num = 0xff;
-
- void Key_Task(void) {
- // Step 1: Set COL low, ROW high, check which row is pressed
- COL1 = 0;
- COL2 = 0;
- COL3 = 0;
- COL4 = 0;
- ROW1 = 1;
- ROW2 = 1;
-
- if ((ROW1 == 0) || (ROW2 == 0)) {
- // Only one row should be pressed
- if (((ROW1 == 1) && (ROW2 == 0)) || ((ROW1 == 0) && (ROW2 == 1))) {
-
- if (ROW1 == 0)
- key_num = 0;
- else if (ROW2 == 0)
- key_num = 4;
-
- // Step 2: Set ROW low, COL high, check which column is pressed
- COL1 = 1;
- COL2 = 1;
- COL3 = 1;
- COL4 = 1;
- ROW1 = 0;
- ROW2 = 0;
-
- if (COL1 == 0) {
- // key_num unchanged
- } else if (COL2 == 0) {
- key_num = key_num + 1;
- } else if (COL3 == 0) {
- key_num = key_num + 2;
- } else if (COL4 == 0) {
- key_num = key_num + 3;
- }
- }
- COL1 = 0;
- COL2 = 0;
- COL3 = 0;
- COL4 = 0;
- ROW1 = 1;
- ROW2 = 1;
- } else {
- key_num = 0xff;
- }
- }
-
- u8 seg_buf[8] = {16, 16, 16, 16, 16, 16, 16, 16};
-
- u8 seg_index = 0;
- void SEG_Task(void) {
- u8 num = 0;
- if (seg_index == 0) {
- Display_Seg(SEG_NUM[seg_buf[0]], ~T_NUM[0]);
- } else if (seg_index == 1) {
- Display_Seg(SEG_NUM[seg_buf[1]], ~T_NUM[1]);
- } else if (seg_index == 2) {
- Display_Seg(SEG_NUM[seg_buf[2]], ~T_NUM[2]);
- } else if (seg_index == 3) {
- Display_Seg(SEG_NUM[seg_buf[3]], ~T_NUM[3]);
- } else if (seg_index == 4) {
- Display_Seg(SEG_NUM[seg_buf[4]], ~T_NUM[4]);
- } else if (seg_index == 5) {
- Display_Seg(SEG_NUM[seg_buf[5]], ~T_NUM[5]);
- } else if (seg_index == 6) {
- Display_Seg(SEG_NUM[seg_buf[6]], ~T_NUM[6]);
- } else if (seg_index == 7) {
- Display_Seg(SEG_NUM[seg_buf[7]], ~T_NUM[7]);
- } else {
- }
- seg_index++;
- if (seg_index > 7)
- seg_index = 0;
- }
-
- // ========== Washing Machine Panel ==========
-
- u8 wash_state = WASH_OFF; // Current state: OFF/STANDBY/RUNNING
- u8 wash_mode = 1; // Current wash mode (1~5)
- u16 wash_countdown = 0; // Countdown in seconds
-
- // Wash time for each mode (seconds), index 1~5
- u8 wash_times[] = {0, 10, 15, 20, 25, 30};
-
- u8 key_cnt = 0;
- u8 key_lock = 0; // Prevent key repeat while held
-
- //========================================================================
- // Function: Wash_Display_Update
- // Description: Update display buffer (seg_buf[]) according to wash state.
- // WASH_OFF: all digits blank
- // WASH_STANDBY: first digit shows current mode (1-5)
- // WASH_RUNNING: first two digits show countdown (tens + ones)
- //========================================================================
- void Wash_Display_Update(void) {
- u8 i;
- // Clear all digits to blank
- for (i = 0; i < 8; i++) {
- seg_buf[i] = 17; // blank
- }
-
- switch (wash_state) {
- case WASH_STANDBY:
- // Show current mode number on the rightmost digit
- seg_buf[7] = wash_mode;
- break;
-
- case WASH_RUNNING:
- // Show countdown right-aligned on the last 2 digits
- seg_buf[6] = wash_countdown / 10; // tens
- seg_buf[7] = wash_countdown % 10; // ones
- break;
-
- case WASH_OFF:
- default:
- // All blank (already cleared)
- break;
- }
- }
-
- //========================================================================
- // Function: Wash_Key_Task
- // Description: Handle key input for the washing machine panel.
- // Called every 10ms.
- // Key 0: Power ON/OFF toggle
- // Key 1~5: Select wash mode (only in STANDBY state)
- // Key 6: Start washing (only in STANDBY state)
- //========================================================================
- void Wash_Key_Task(void) {
- if (key_num < 0xff) {
- key_cnt++;
- if (key_cnt == 5 && !key_lock) { // 50ms debounce + edge detect
- key_lock = 1;
-
- if (key_num == 0) {
- // Power button: toggle ON/OFF
- if (wash_state == WASH_OFF) {
- wash_state = WASH_STANDBY;
- wash_mode = 1; // Default to mode 1
- } else {
- wash_state = WASH_OFF;
- wash_countdown = 0;
- }
- Wash_Display_Update();
- } else if (key_num >= 1 && key_num <= 5) {
- // Mode select: only valid in STANDBY
- if (wash_state == WASH_STANDBY) {
- wash_mode = key_num;
- Wash_Display_Update();
- }
- } else if (key_num == 6) {
- // Start: only valid in STANDBY
- if (wash_state == WASH_STANDBY) {
- wash_state = WASH_RUNNING;
- wash_countdown = wash_times[wash_mode];
- Wash_Display_Update();
- }
- }
- }
- } else {
- key_cnt = 0;
- key_lock = 0; // Key released, reset for next press
- }
- }
-
- //========================================================================
- // Function: Wash_Timer_Task
- // Description: Countdown timer, called every 1000ms (1 second).
- // Decrements countdown each second during RUNNING state.
- // When countdown reaches 0, turns off (WASH_OFF state).
- //========================================================================
- void Wash_Timer_Task(void) {
- if (wash_state == WASH_RUNNING) {
- if (wash_countdown > 0) {
- wash_countdown--;
- }
- if (wash_countdown == 0) {
- wash_state = WASH_OFF; // Wash complete, turn off
- }
- Wash_Display_Update();
- }
- }
复制代码
task.c/Task_Comps[]
- static TASK_COMPONENTS Task_Comps[] = {
- // 状态 计数 周期 函数
- {0, 10, 10, Key_Task}, // 按键扫描: 每10ms
- {0, 1, 1, SEG_Task}, // 数码管扫描: 每1ms
- {0, 10, 10, Wash_Key_Task}, // 洗衣机按键处理: 每10ms
- {0, 1000, 1000, Wash_Timer_Task}, // 倒计时: 每1秒
- };
复制代码
2 代码学习
矩阵键盘获取按键
- void Key_Task(void) {
- // 第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。
- COL1 = 0;
- COL2 = 0;
- COL3 = 0;
- COL4 = 0;
- ROW1 = 1;
- ROW2 = 1;
-
- if ((ROW1 == 0) || (ROW2 == 0)) {
- // 如果有按键按下,而且只有一颗
- if (((ROW1 == 1) && (ROW2 == 0)) || ((ROW1 == 0) && (ROW2 == 1))) {
-
- if (ROW1 == 0)
- key_num = 0;
- else if (ROW2 == 0)
- key_num = 4;
-
- // 第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。
- COL1 = 1;
- COL2 = 1;
- COL3 = 1;
- COL4 = 1;
- ROW1 = 0;
- ROW2 = 0;
-
- if (COL1 == 0) {
- key_num = key_num;
- } else if (COL2 == 0) {
- key_num = key_num + 1;
- } else if (COL3 == 0) {
- key_num = key_num + 2;
- } else if (COL4 == 0) {
- key_num = key_num + 3;
- }
- }
- COL1 = 0;
- COL2 = 0;
- COL3 = 0;
- COL4 = 0;
- ROW1 = 1;
- ROW2 = 1;
- } else {
- key_num = 0xff;
- }
- }
复制代码
3 Ai8051U实验箱展示
|