单片机C语言之学习矩阵按键

新手记录学习:单片机C语言之矩阵按键

一、先画好原理图,了解基本原理:

二、再构思一下基本的程序思路:

矩阵按键扫描思路:

1、如单个IO检测按键,IO口要检测到高低电平变化,才能检测到按键;那么矩阵按键也一样。

2、先检测第1个按键(按键1),那么需要列1的IO口输出高电平,行1的IO口做输入(内部下拉,不能做高阻输入,IO没有内部下拉,就需要接外部下拉)检测,或者列1的IO口做输入,行1的IO做输出。先以列的IO做输出,行的IO口做输入(内部下拉)检测按键

3、检测设置与判断:当列1的IO输出高的时候(其它列的IO设置高阻输入),4个行的IO口做输入,有按键按下了,所在行的IO会有高电平。读取该行IO的电平,就可以判断有无按键,假如按键1按键,那么行1的IO就会有高电平,读取到了高电平,进行消抖确认后,就判断为有按键,其它按键依此类推。

4、 扫描完列_1,下一个2MS扫描列_2的IO上的按键,此时列_2的IO输出高,其它列的IO设置高阻输入,读取行IO有无按键,再间隔2毫秒扫描切换一个列输出(4个行IO做输入),来识别不同的按键

5、无按键判断,采用计数的方式,连续5个2MS无按键,则判断为无按键,有按键计数清0,按键状态标志位清0, 有按键时,无按键计数变量清0

三、画个流程图,把程序架构理顺一下:

五、开始写代码。

5.1、先初始化定时器和IO口。定时器0定时2ms中断一次,IO口P04~P07设置为输入带下拉模式:

		P0=B00000000;			//P0[7:0] 端口数据寄存器	P0^0 口输出高电平	
		P0M0 =0xC0;			//推挽输出
		P0M1 =0xC0;			//推挽输出
		P0M2 =0xC0;			//推挽输出
		P0M3 =0xC0;			//推挽输出
		P0M4 =0x58;			//施密特数字带下拉输入 
		P0M5 =0x58;			//施密特数字带下拉输入
		P0M6 =0x58;			//施密特数字带下拉输入
		P0M7 =0x58;			//施密特数字带下拉输入

5.2、定义IO口脚位配置和标志位 .h文件配置如下:

#ifndef     _matrix_key_H_
#define     _matrix_key_H_


/*********************** 函数声明 ************************************/
void matrix_key();
void key_check();
void key_press();
void key_release();

/******************声明全局字节变量*********************************/

extern unsigned char bdata key_flag0;
extern unsigned char bdata key_flag1;

/********************声明全局位变量*********************************/

extern	bit F_KeyScan_2ms;			// 按键扫描2ms标志位
extern  bit F_Key_state; 			//按键状态标志位 1=有按键  0=无按键
extern  bit	F_SW_1;				//按键1标志位
extern  bit	F_SW_2;				//按键2标志位
extern  bit	F_SW_3;				//按键3标志位
extern  bit	F_SW_4;				//按键4标志位
extern  bit	F_SW_5;				//按键5标志位
extern  bit	F_SW_6;				//按键6标志位
extern  bit	F_SW_7;				//按键7标志位
extern  bit	F_SW_8;				//按键8标志位
extern  bit	F_SW_9;				//按键9标志位
extern  bit	F_SW_10;				//按键10标志位
extern  bit	F_SW_11;				//按键11标志位
extern  bit	F_SW_12;				//按键12标志位
extern  bit	F_SW_13;				//按键13标志位
extern  bit	F_SW_14;				//按键14标志位
extern  bit	F_SW_15;				//按键15标志位
extern  bit	F_SW_16;				//按键16标志位

/********************功能声明与定义*********************************/
sbit	IO_Lie_1	=P0^3;
sbit	IO_Lie_2	=P0^2;
sbit	IO_Lie_3	=P0^1;
sbit	IO_Lie_4	=P0^0;

#define	IO_Lie_1_outport	{P0M3=0xC0; IO_Lie_1=1;}		//输出模式,输出高
#define	IO_Lie_2_outport	{P0M2=0xC0; IO_Lie_2=1;}		//输出模式,输出高
#define	IO_Lie_3_outport	{P0M1=0xC0; IO_Lie_3=1;}		//输出模式,输出高
#define	IO_Lie_4_outport	{P0M0=0xC0; IO_Lie_4=1;}		//输出模式,输出高

#define	IO_Lie_1_intport	{IO_Lie_1=0;P0M3=0x00; }		//模拟高阻输入
#define	IO_Lie_2_intport	{IO_Lie_2=0;P0M2=0x00; }		//模拟高阻输入
#define	IO_Lie_3_intport	{IO_Lie_3=0;P0M1=0x00; }		//模拟高阻输入
#define	IO_Lie_4_intport	{IO_Lie_4=0;P0M0=0x00; }		//模拟高阻输入

#define	KeyScan_Lie_1		{IO_Lie_1_outport; IO_Lie_2_intport; IO_Lie_3_intport; IO_Lie_4_intport;} //扫描列1上的按键设置
#define	KeyScan_Lie_2		{IO_Lie_1_intport; IO_Lie_2_outport; IO_Lie_3_intport; IO_Lie_4_intport;} //扫描列2上的按键设置
#define	KeyScan_Lie_3		{IO_Lie_1_intport; IO_Lie_2_intport; IO_Lie_3_outport; IO_Lie_4_intport;} //扫描列3上的按键设置
#define	KeyScan_Lie_4		{IO_Lie_1_intport; IO_Lie_2_intport; IO_Lie_3_intport; IO_Lie_4_outport;} //扫描列4上的按键设置

#endif

 5.3、定义IO口脚位配置和标志位 .C文件配置如下:

/*********************** 包含的头文件 ******************************/
#include "my_HC89F0541.H"
#include "matrix_key.H"


/******************声明全局字节变量********************************/
static unsigned char data r_KeyScan_cnt=0;	//按键扫描计数变量
static unsigned char data r_key_t1 =0;         //有按键计数(消抖)变量

static unsigned char data r_key_hang =0;		// 按键行变量,低四位有效
static unsigned char data r_NoKey_cnt=0;		//无按键计数变量

/********************声明全局位变量********************************/

bit F_KeyScan_2ms=0;			// 按键扫描2ms标志位
bit F_Key_state=0; 			//按键状态标志位 1=有按键  0=无按键

unsigned char bdata key_flag0 =0;
sbit	F_SW_1 =key_flag0^0;				//按键1标志位
sbit	F_SW_2 =key_flag0^1;				//按键2标志位
sbit	F_SW_3 =key_flag0^2;				//按键3标志位
sbit	F_SW_4 =key_flag0^3;				//按键4标志位
sbit	F_SW_5 =key_flag0^4;				//按键5标志位
sbit	F_SW_6 =key_flag0^5;				//按键6标志位
sbit	F_SW_7 =key_flag0^6;				//按键7标志位
sbit	F_SW_8 =key_flag0^7;				//按键8标志位

unsigned char bdata key_flag1 =0;
sbit	F_SW_9  =key_flag1^0;				//按键9标志位
sbit	F_SW_10 =key_flag1^1;				//按键10标志位
sbit	F_SW_11 =key_flag1^2;				//按键11标志位
sbit	F_SW_12 =key_flag1^3;				//按键12标志位
sbit	F_SW_13 =key_flag1^4;				//按键13标志位
sbit	F_SW_14 =key_flag1^5;				//按键14标志位
sbit	F_SW_15 =key_flag1^6;				//按键15标志位
sbit	F_SW_16 =key_flag1^7;				//按键16标志位


/********************功能声明与定义********************************/

5.4、矩阵扫描主程序如下:

/**********************************************************************
函 数:matrix_key() ---> 矩阵扫描按键程序
输 入:无
输 出:无
返 回:无
说 明:
1、
***********************************************************************/
void	matrix_key()
{
		if (F_KeyScan_2ms) 			//每2ms进来扫描一次按键
		{
			F_KeyScan_2ms=0;
			if (++r_KeyScan_cnt>4) 
			{
				r_KeyScan_cnt=1;		//扫描完4列后,从第1列开始
			}
			switch(r_KeyScan_cnt)
			{
				case 1:
					{
						KeyScan_Lie_1;		//第1列准备
						key_check();		//扫描第1列上的按键
						
					};break;
				case 2:
					{
						KeyScan_Lie_2;
						key_check();
						
					};break;
				case 3:
					{
						KeyScan_Lie_3;
						key_check();
						
					};break;
				case 4:
					{
						KeyScan_Lie_4;
						key_check();
					};break;										
					
			}
		}
	
}

5.5、按键检测子程序如下:

void key_check()		
{
	r_key_hang=P0&0xF0;	//提取P0口高四位,检测4个行上的按键
	r_key_hang>>=4;		//行变量,左移4位,低4位有效
	if (r_key_hang==0) 
	{
		key_release();		//无按键子程序
	}
	else
	{
		key_press();		//有按键子程序
	}
}

5.6、有按键判断子程序如下:

/**********************************************************************
函 数:key_press() ---> 有按键子程序
输 入:无
输 出:无
返 回:无
说 明:
1、
***********************************************************************/
void key_press()				
{
	r_NoKey_cnt=0;				//无按键计数清0
	if(!F_Key_state)    				//按键状态标志位=1,不再重复进入判断短按
	{		
	   if(++r_key_t1&0x08)  		//递增后判断,消抖时间8*8ms
		{                   		    
			r_key_t1 = 0;   		//消抖计数清0
			F_Key_state = 1;	    //按键状态标志位=1

			switch(r_key_hang)			//按键标志位判断
			{
				case 1:				//第1行上的按键
				{
					switch(r_KeyScan_cnt)
					{
						case 1: F_SW_1=1; break;		//第1列扫描时第1行有按键 
						case 2: F_SW_2=1; break;		//第2列扫描时第1行有按键
						case 3: F_SW_3=1; break;		//第3列扫描时第1行有按键
						case 4: F_SW_4=1; break;		//第4列扫描时第1行有按键
					}		
				}; break;
				
				case 2:				//第2行上的按键
				{
					switch(r_KeyScan_cnt)
					{
						case 1: F_SW_5=1; break;		//第1列扫描时第2行有按键
						case 2: F_SW_6=1; break;      //第2列扫描时第2行有按键
						case 3: F_SW_7=1; break;      //第3列扫描时第2行有按键
						case 4: F_SW_8=1; break;		//第4列扫描时第2行有按键
					}	
				}; break;
				
				case 4:			//第3行上的按键
				{
					switch(r_KeyScan_cnt)
					{
						case 1: F_SW_9=1; break;
						case 2: F_SW_10=1; break;
						case 3: F_SW_11=1; break;
						case 4: F_SW_12=1; break;
					}	
				} ; break;
				
				case 8:			//第4行上的按键
				{
					switch(r_KeyScan_cnt)
					{
						case 1: F_SW_13=1; break;
						case 2: F_SW_14=1; break;
						case 3: F_SW_15=1; break;
						case 4: F_SW_16=1; break;
					}	
				} ; break;							
			}			
			
		}
		
	}
	
}

5.7、无按键时判断子程序如下:


/**********************************************************************
函 数:key_release() ---> 无按键子程序
输 入:无
输 出:无
返 回:无
说 明:
1、
***********************************************************************/
void key_release()		
{
	if (++r_NoKey_cnt>4) 
	{
		r_key_t1 =0;			//扫完一轮,没有按键,按键计数清0
		r_NoKey_cnt=0;		//无按键计数变量清0
		F_Key_state=0;			//按键状态标志位
	}
	
}

六、在主程序内搞个测试程序, 下载到芯片内测试OK。


void main()
{
	sys_init();             //系统初始化

	while(1)
	{	   
		WDTC |= 0x10;			//看门狗清0 
		matrix_key();			//按键扫描
		
		P10=~P10;
		
		if (key_flag0 | key_flag1) 	//查询按键标志位
		{
			P12=~P12;				// 按任意按键,IO口反转
			key_flag0=0;			// 按键标志位都清0
			key_flag1=0;			
			
		}

		
		sleep();				//睡眠
	}
}

7、有图有真相:

八、每天努力一点点,十年之功,必出大成果, 加油加油~!!

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值