基于蓝桥杯的单片机模块练习——矩阵键盘算法

基于蓝桥杯的单片机模块练习——矩阵键盘算法

功能概述

通过矩阵键盘控制8个数码管同时显示一个字符。

C代码

#include "stc15f2k60s2.h"
//行
sbit R1 = P3^0;
sbit R2 = P3^1;
sbit R3 = P3^2;
sbit R4 = P3^3;
//列
sbit C1 = P4^4;
sbit C2 = P4^2;
sbit C3 = P3^5;
sbit C4 = P3^4;

unsigned char code SMG_duanma[] = {0xc0,0xf9,0xa4,0xb0,
                                   0x99,0x92,0x82,0xf8,
                                   0x80,0x90,0x88,0x83,
                                   0xc6,0xa1,0x86,0x8e,
                                   0xbf,0x7f};
void ScanKey();
void DisplayAll(unsigned char num);
void SystemInit();
void SelectHC573(unsigned channel);
void Timer0_Init();	
void KeyAction(unsigned char KeyCode);
																	 
void main()
{
	SystemInit();
	Timer0_Init();	
	while(1)
	{
		ScanKey();
	}
	
}

void SelectHC573(unsigned channel)
{
	switch(channel)
	{
		case 0 : P2 = (P2 & 0X1F) | 0X00;break;
		case 4 : P2 = (P2 & 0X1F) | 0X80;break;
		case 5 : P2 = (P2 & 0X1F) | 0XA0;break;
		case 6 : P2 = (P2 & 0X1F) | 0XC0;break;
		case 7 : P2 = (P2 & 0X1F) | 0XE0;break;
	}
}

void SystemInit()
{
	SelectHC573(5);
	P0 = 0x00;
	SelectHC573(0);
	P0 = 0xff;
	
}

void DisplayAll(unsigned char num)
{
	
	SelectHC573(6);
	P0 = 0xff;
	SelectHC573(7);
	P0 = SMG_duanma[num];
	
}
unsigned char KeyStat[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};//经消抖之后的键值
//矩阵按键编号的映射表,按照键盘标号映射.比如S7就映射0x07
unsigned char code KeyCodeMap[4][4] = {{0x07,0x11,0x15,0x19},
                                       {0x06,0x10,0x14,0x18},
																			       {0x05,0x09,0x13,0x17},
																			 {0x04,0x08,0x12,0x16}
};
void KeyAction(unsigned char KeyCode)//对照着映射表完成相应按键的动作
{
	switch(KeyCode)
	{
		case 0x04 : DisplayAll(4);break;
		case 0x05 : DisplayAll(5);break;
		case 0x06 : DisplayAll(6);break;
		case 0x07 : DisplayAll(7);break;
		case 0x08 : DisplayAll(8);break;
		case 0x09 : DisplayAll(9);break;
		case 0x10 : DisplayAll(10);break;
		case 0x11 : DisplayAll(11);break;
		case 0x12 : DisplayAll(12);break;
		case 0x13 : DisplayAll(13);break;
		case 0x14 : DisplayAll(14);break;
		case 0x15 : DisplayAll(15);break;
		case 0x16 : DisplayAll(16);break;
		case 0x17 : DisplayAll(17);break;
		case 0x18 : DisplayAll(17);break;
		case 0x19 : DisplayAll(17);break;
	}
}
void ScanKey()
{
	unsigned char i,j;
	static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};储存上一次的键值
		for(i = 0; i<4; i++)
		{
			for(j = 0; j<4;j++)
			{
				if(backup[i][j] != KeyStat[i][j])
				{
					if(backup[i][j] == 0)//松手检测,松开按键后动作
					{
						KeyAction(KeyCodeMap[i][j]);
					}
					backup[i][j] = KeyStat[i][j];
				}
			}
		}
}
void Timer0_Init()
{
	TMOD = 0X00;
	TH0 = (65536 - 1000) / 256;
	TL0 = (65536 - 1000) % 256;
	EA = 1;
	ET0 = 1;
	TR0 = 1;
}

void Timer0_Service() interrupt 1
{
    unsigned char i;
    static unsigned char keyout = 0;  //矩阵按键扫描输出索引
    static unsigned char Keybuf[4][4] = {  //矩阵按键扫描缓冲区
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF}
    };
    
    //将一行的4个按键值移入缓冲区
    Keybuf[keyout][0] = (Keybuf[keyout][0] << 1) | C1;
    Keybuf[keyout][1] = (Keybuf[keyout][1] << 1) | C2;
    Keybuf[keyout][2] = (Keybuf[keyout][2] << 1) | C3;
    Keybuf[keyout][3] = (Keybuf[keyout][3] << 1) | C4;
    //消抖后更新按键状态
    for (i=0; i<4; i++)  //每行4个按键,所以循环4次
    {
        if ((Keybuf[keyout][i] & 0x0F) == 0x00)
        {   //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
            KeyStat[keyout][i] = 0;
        }
        else if (( Keybuf[keyout][i] & 0x0F) == 0x0F)
        {   //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
            KeyStat[keyout][i] = 1;
        }
    }
    //执行下一次的扫描输出
    keyout++;                //输出索引递增
    keyout = keyout & 0x03;  //索引值加到4即归零
    switch (keyout)          //根据索引,释放当前输出引脚,拉低下次的输出引脚
    {
        case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
        case 1: R1 = 1; R2 = 0; break;
        case 2: R2 = 1; R3 = 0; break;
        case 3: R3 = 1; R4 = 0; break;
        
    }
}


相关知识点

keyout = keyout & 0x03; //加到4即归零
keyout = keyout & 0x01; //加到2即归零
keyout = keyout & 0x07; //加到8即归零
keyout = keyout & 0x0f; //加到16即归零

拓展功能

长、短按键的算法

void KeyScan()
{
	unsigned char i,j;
	static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
	for(i=0; i<4; i++)
	{
		for(j=0; j<4; j++)
		{
			if(backup[i][j] != KeySta[i][j])
			{
				lkey_flag = 0;
		        count_key = 0;
				while(KeySta[i][j]==0);
				if(backup[i][j] == 1)
				{
					if(lkey_flag)
					KeyAction(KeyCodemap[i][j]);//长按键
					else
					KeyAction(255 - KeyCodemap[i][j]);//短按键
				}
				backup[i][j] = KeySta[i][j];
			}
		}
	}
}
//****************在中断里的计时判断**********
//count_key每1ms自加一
if(count_key == 1000)
	{
		lkey_flag = 1;
		count_key = 0;
	}
//*******************************************

哪位大佬有没有更高级的长短按键判断的算法,告诉兄弟一下。抱拳了!!!
按下某按键时不立刻操作,到它弹起后一段时间才进行动作

//只需修改此函数,其余部分和长短按键相同
void KeyScan()
{
	unsigned char i,j;
	static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
	for(i=0; i<4; i++)
	{
		for(j=0; j<4; j++)
		{
			if(backup[i][j] != KeySta[i][j])
			{
				lkey_flag = 0;
		        count_key = 0;
				while((KeySta[i][j]==1)&&(lkey_flag==0)); 
				if(backup[i][j] == 0)
				{
					if(lkey_flag)
					KeyAction(KeyCodemap[i][j]);	
				}
				backup[i][j] = KeySta[i][j];
			}
		}
	}
}
  switch (keyout)          //根据索引,释放当前输出引脚,拉低下次的输出引脚
    {
        case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
        case 1: R1 = 1; R2 = 0; break;
        case 2: R2 = 1; R3 = 0; break;
        case 3: R3 = 1; R4 = 0; break;
        
    }

这部分代码在用到串口通讯时需要修改,不能再对R1和R2进行操作

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
蓝桥杯单片机矩阵键盘是一种常见的输入设备,它可以通过按下不同的按键来输入不同的信息。下面是蓝桥杯单片机矩阵键盘的工作原理和实现方法: 1.工作原理: 蓝桥杯单片机矩阵键盘的工作原理是基于按键扫描的。按键扫描的思路是,按键是连接行和列的桥梁,如果往某行或者某列输入低电平,其他行或列为高电平,我们只需要检测所有列或者行是否有低电平即可。因此,我们可以通过按下按键来改变行列的电平状态,从而检测出按下的按键。 2.实现方法: 蓝桥杯单片机矩阵键盘的实现方法如下: (1)将矩阵键盘的行和列分别连接到单片机的IO口上。 (2)设置行为输出,列为输入。 (3)将所有列的电平设置为高电平。 (4)循环扫描每一行,将该行的电平设置为低电平,然后检测所有列的电平状态,如果有低电平,则说明该行对应的按键被按下。 (5)重复步骤(4),直到检测完所有行。 下面是一个简单的蓝桥杯单片机矩阵键盘的实现代码: ```c #include <reg52.h> sbit row1 = P1^0; sbit row2 = P1^1; sbit row3 = P1^2; sbit row4 = P1^3; sbit col1 = P1^4; sbit col2 = P1^5; sbit col3 = P1^6; sbit col4 = P1^7; void main() { while(1) { row1 = 0; row2 = 1; row3 = 1; row4 = 1; if(col1 == 0) { /* 检测到第1个按键被按下 */ } if(col2 == 0) { /* 检测到第2个按键被按下 */ } if(col3 == 0) { /* 检测到第3个按键被按下 */ } if(col4 == 0) { /* 检测到第4个按键被按下 */ } row1 = 1; row2 = 0; row3 = 1; row4 = 1; if(col1 == 0) { /* 检测到第5个按键被按下 */ } if(col2 == 0) { /* 检测到第6个按键被按下 */ } if(col3 == 0) { /* 检测到第7个按键被按下 */ } if(col4 == 0) { /* 检测到第8个按键被按下 */ } row1 = 1; row2 = 1; row3 = 0; row4 = 1; if(col1 == 0) { /* 检测到第9个按键被按下 */ } if(col2 == 0) { /* 检测到第10个按键被按下 */ } if(col3 == 0) { /* 检测到第11个按键被按下 */ } if(col4 == 0) { /* 检测到第12个按键被按下 */ } row1 = 1; row2 = 1; row3 = 1; row4 = 0; if(col1 == 0) { /* 检测到第13个按键被按下 */ } if(col2 == 0) { /* 检测到第14个按键被按下 */ } if(col3 == 0) { /* 检测到第15个按键被按下 */ } if(col4 == 0) { /* 检测到第16个按键被按下 */ } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ღ 金龍戲水 ღ

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值