单元训练07:矩阵键盘的基本操作

蓝桥杯 小蜜蜂 单元训练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();
    }
}

  • 10
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值