新手记录学习:单片机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、有图有真相:
八、每天努力一点点,十年之功,必出大成果, 加油加油~!!