蓝桥杯 小蜜蜂 单元训练07:矩阵键盘的基本操作
因为题目中要求(不做去抖动),所以代码没有添加定时器扫描,如果需要,可以自行添加。
#include "stc15f2k60s2.h"
typedef unsigned char uint8_t;
uint8_t timerCounter = 0;
uint8_t timerEnable = 0;
#define LED(X) \
{ \
P0 = X; \
P2 = (P2 & 0x1f | 0x80); \
P2 &= 0x1f; \
}
// 数码管
// 段选
#define COM(x) \
{ \
P0 = x; \
P2 = P2 & 0x1F | 0xc0; \
P2 &= 0x1F; \
}
// 位选
#define SEG(x) \
{ \
P0 = x; \
P2 = P2 & 0x1F | 0xE0; \
P2 &= 0x1F; \
}
code unsigned char Seg_Table[] =
{
0xc0, // 0
0xf9, // 1
0xa4, // 2
0xb0, // 3
0x99, // 4
0x92, // 5
0x82, // 6
0xf8, // 7
0x80, // 8
0x90, // 9
0x88, // A
0x83, // b
0xc6, // C
0xa1, // d
0x86, // E
0x8e // F
}; // 表不用记,官方提供资源包里面有。
// 数码管第一位显示
void DisplayNo1(uint8_t no)
{
COM(0x01);
SEG(Seg_Table[no]);
}
// 矩阵键盘 列
sbit col1 = P4 ^ 4;
sbit col2 = P4 ^ 2;
// col1 col2 col3 col4 row4 row3 row2 row1
// P44 P42 P35 P34 P33 P32 P31 P30 当成一个8位变量
// 通过不同按键产生不同状态来进行分辨,如同独立按键中if (key7 == 0)为按下状态
uint8_t GetPortState()
{
uint8_t portState;
portState = P3 & 0x3F; // 0x3F: 0011 1111
(col2) ? (portState |= 0x40) : (portState &= 0xbf); // 0x40: 0100 0000,0xbf:1011 1111
(col1) ? (portState |= 0x80) : (portState &= 0x7f); // 0x80: 1000 0000, 0x7f: 0111 1111
return portState;
}
void ClearRow()
{
P3 = 0xF0;
col2 = 1;
col1 = 1;
}
void ClearCol()
{
P3 = 0x0F;
col1 = 0;
col2 = 0;
}
// 从左到右,从上到下,依次显示0~F,定义一个二维数组,注意数组大小一定要写,不然会报销
code uint8_t ArrayNum[4][4] = {
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
{12, 13, 14, 15}};
uint8_t keyStatus;
uint8_t key_row; // 用于数组下标的按键行数,注意后面使用时要减1
uint8_t key_col; // 用于数组下标的按键列数,注意后面使用时要减1
void KeyScan()
{
switch (keyStatus)
{
case 0:
ClearCol(); // 这里换成ClearRow()也行
if (GetPortState() != 0x0f)
{
keyStatus = 1;
}
break;
case 1:
ClearCol();
if (GetPortState() == 0x0e)
{
key_row = 1;
keyStatus = 2;
}
else if (GetPortState() == 0x0d)
{
key_row = 2;
keyStatus = 2;
}
else if (GetPortState() == 0x0b)
{
key_row = 3;
keyStatus = 2;
}
else if (GetPortState() == 0x07)
{
key_row = 4;
keyStatus = 2;
}
break;
case 2:
ClearRow();
if (GetPortState() == 0x70)
{
key_col = 1;
keyStatus = 3;
}
else if (GetPortState() == 0xb0)
{
key_col = 2;
keyStatus = 3;
}
else if (GetPortState() == 0xd0)
{
key_col = 3;
keyStatus = 3;
}
else if (GetPortState() == 0xe0)
{
key_col = 4;
keyStatus = 3;
}
break;
case 3:
ClearRow();
if (GetPortState() == 0xf0)
keyStatus = 0;
break;
default:
keyStatus = 0;
break;
}
}
void SegShow()
{
KeyScan();
DisplayNo1(ArrayNum[key_row - 1][key_col - 1]);
}
void Timer0_Init(void) // 1毫秒@12.000MHz
{
AUXR |= 0x80; // 定时器时钟1T模式
TMOD &= 0xF0; // 设置定时器模式
TL0 = 0x20; // 设置定时初始值
TH0 = 0xD1; // 设置定时初始值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
ET0 = 1; // 使能定时器0中断
EA = 1;
}
void InitSys()
{
LED(0xff);
SEG(0xFF);
COM(0xFF);
}
void main()
{
InitSys();
while (1)
{
SegShow();
}
}