单片机键盘输入编程(C语言)


学习过单片机技术的人都知道,单片机的按键输入一般可分 为简单的独立式按键输入及行列式键盘输入两种。图1为简 单的独立式键盘输入示意图,独立式键盘输入适合于按键输 入不多的情况(<5个按键) ,具有占用口线较少、软件编写 简单容易等特点。

图2为行列式键盘输入示意图,列线接 P1.0~P1.3,行线 接 P1.4~P1.7。行列式键盘输入适合于按键输入多的情况, 如有16个按键输入, 用简单按键输入用要占用2个输入口 (共 16位) ,而使用行列式键盘输入只需占用一个输入口(8位) 。 但行列式键盘输入软件编写较复杂,对初学者而言有一定的 难度。

以上略谈了一下按键输入的情况。在很多状态下,按键 输入的值要同时要在 LED 数码管上显示出来。如一个按键设 计为输入递增(加法)键,可以设计成每点按一下,数值递 增加1,同时在 LED 数码管上显示出来;也可设计成持续按 下时,数值以一定时间间隔(如0.3秒)累加。但是当欲输 入值较大时(如三位 LED 数码管作输入显示时的输入值最大 为999) ,则可能按下键的时间太长(最长达300秒) ,看来这 种方式只适用于一位或至多两位数值(最大99)的输入。当 然你也可多设几个键,每个键只负责一位数值的输入,但这 样会占用较多的口线,浪费宝贵的硬件资源。 大家可能见到过,一些进口的温度控制器(如日本 RKC INSTRUMENT INC. 生产的 REX_C700温控器)的面板设计为: 温度测量值用4位 LED 数码管显示,输入设定值显示也用4位

LED 数码管,输入按键只有4个,一个为“模式设定键”,一个 为“左移键”,另两个为“加法键”、“减法键”。欲输入设定值 (温控值)时,按一下“模式设定键”,程序进入设定状态, 此时输入设定值显示的4位 LED 数码管中, 个位显示最亮 (稳 定显示) ,而十、百、千位显示较暗(有闪烁感) ,说明可对 个位进行输入。按下“加法键”或“减法键”,即可输入个位数 的值;点按一下“左移键”,变为十位显示最亮,而个、百、 千位显示较暗,说明可对十位进行输入。按下“加法键”或“减 法键”, 即可输入十位数的值; ……这样可完成4位数的输入。 完成输入后, 再按一下“模式设定键”, 程序即退出设定状态, 进入工作运行。用这种输入方法,不仅输入4位数用4个键即 可,再多位(5位至24位)的输入也用这4个键就够了。 大家了解了这种新颖的按键输入方式后,一定很感兴 趣,也想掌握设计方法。为了便于大家理解,这里结合笔者 设计的一款“节能时控器”,详细进行讲解。“节能时控器”用 于定时控制大功率电器工作,因现采用分时计费方法,可起 到节约开支的作用,对工业生产成效显著。 图3为“节能时控器”硬件构成原理图。 “节能时控器”共有 4个输入按键:set--模式设定键,left--左移键,up—加法 键, on/off--定时1、 2启动/关闭键。 单片机 IC1 (AT89C2051) 只有15条 I/O 线,由于受 I/O 线数量限制,因此 P1口中的 P1.0~P1.3既作为驱动4位 LED 数码管的数据输出一部分,同

时也用作按键的输入。 无疑, 这种方式大大节约了硬件的 I/O 线,但也给编程者提出了更高的技术要求。限于篇幅,我们 只对要详解的按键输入程序进行分析,其它部分只略作介 绍。如读者需“节能时控器”详细的源程序,可以 Email:xuyuandz@163.com 与作者联系。

图4为主程序状态流程图。可见主程序只负责进行走时 或调整时间的运算及显示, 而判断按键输入则放在 T1定时中 断(10mS)服务子程序中。T0作为走时的基准被设置为100mS 定时中断。这种设计的优点是大大简化了主程序设计,并且 CPU 会定时关心键盘,只要定时中断时间足够短(如为几十 mS) ,就不会漏掉每一次的按键输入。

下面为判断按键输入的 T1定时中断服务子程序, 序号为解释 方便而加。 /*10mS 定时中断服务子函数*/ 序号 1:void zd1(void) interrupt 3 2:{ 3:uchar i,j;i=P1;j=P3; 4:TH1=-(5000/256); 5:TL1=-(5000%256); 6:if(m==1)n++;

7:if(n>=30){n=0;m=0;} 8:P3_7=0; 9:P1=0xff; 10:if(P1!=0xff) 11:{ 12:if(n==0)m=1; 13:{if(n==1) 14:{ 15:if(P1_0==0){set++;left=0;} 16:if(set>=4)set=0; 17:if(set==1)flag=0x55; 18:if(P1_1==0)left++; 19:if(left>=4)left=0; 20:if(P1_2==0){up++; 21:switch(left) 22:{ 23:case 0:{if(up>=10)up=0;}break; 24:case 1:{if(up>=6)up=0;}break; 25:case 2:{if(up>=10)up=0;}break; 26:case 3:{if(up>=3)up=0;}break; 27:default:break; 28:}

29:} 30:if(P1_2==0){ 31:switch(set) 32:{case 0:break; 33:case 1:x[left]=up;break; 34:case 2:{y[left]=up;if(P1_3==0)o_f1=!o_f1;}break; 35:case 3:{z[left]=up;if(P1_3==0)o_f2=!o_f2;}break; 36:default:break; 37:} }

38:else { 39:switch(set) 40:{case 0:break; 41:case 1:up=x[left];break; 42:case 2:{up=y[left];if(P1_3==0)o_f1=!o_f1;}break; 43:case 3:{up=z[left];if(P1_3==0)o_f2=!o_f2;}break; 44:default:break;} 45 :}} 46:}}

47:P1=i;P3=j; 48:} 序号1(程序解释,以下同) :声明定时1中断函数。 序号2:定时1中断函数开始。 序号3:定义 i、j 为无符号字符型局部变量。将当时的 P1口、P3口状态送 i、j 暂存。 序号4、5:定时器 T1重新载入10mS 初值。 序号6:如变量 m 等于1,则变量 n 递增。说明:m、n 为 整个程序开始时定义的无符号字符型全局变量。 序号7:如变量 n 大于等于30,则 m、n 清零。 序号8:P3.7置0,准备读取按键输入。 序号9:P1口置全1,准备读取按键输入。 序号10: 如果 P1口不等于全1, 说明4个按键中有键按下。 序号11:进入 if(P1!=0xff)语句范围。 序号12:如果 n 等于0,进入 if(n==0)语句,m 置1。 序号13:如果 n 等于1,进入 if(n==1)语句,同时进 行下面的具体判断按键语句。作用效果为:开始时 m、n 均 赋0,一旦有键按下,第一次中断产生时 m 赋1;第二次中断 产生时 n 递增。当 n 等于1时(第二次中断产生)进入下面 的具体判断按键语句。若持续按下键,则第三次中断产生~ 第三十一次中断产生时,程序不进入具体的判断按键语句过 程(因这时 n 不等于1) 。由于中断每10mS 产生一次,这样可

实现每0.31秒 (31x10=0.31秒) 进行一次加法或移位的操作, 与人眼的视觉特性相吻合。 序号14:进入具体判断按键语句范围。 序号15:如果 P1.0等于0(即电路中的 set 键按下) ,变 量 set 递增,变量 left 清0。说明:set、left 是为了判断 模式设定及左移而在整个程序开始时定义的无符号字符型 全局变量。 序号16:如果 set 大于等于4,则 set 清0。说明:set 值只能在0~3间变化,只有4种工作模式(走时及输出控制模 式、走时调整模式、定时1调整模式、定时2调整模式) 。 序号17:在 set 等于1时,向 RAM 区标志变量 flag 写入 55H。说明:flag 是在整个程序开始时定义的无符号字符型 全局变量,用作判断 RAM 区是否受干扰的依据。 序号18:如果 P1.1等于0(即电路中的 left 键按下) , 变量 left 递增。 序号19: 如果 left 大于等于4, left 清0。 则 说明: left 值只能在0~3间变化,LED 数码管只有4位显示。 序号20:如果 P1.2等于0(即电路中的 up 键按下) ,进 入 if(P1_2==0)语句,变量 up 递增。说明:up 是为了判 断数值增量而在整个程序开始时定义的无符号字符型全局 变量。 序号21:随即进入 switch(left)开关语句。

序号22:switch(left)开关语句开始。 序号23: left 值为0时, 如果 up 大于等于10, up 清0。 则 随即退出。说明:电子钟的个位可在0~9之间调整。 序号24:left 值为1时,如果 up 大于等于6,则 up 清0。 随即退出。说明:电子钟的十位可在0~5之间调整。 序号25: left 值为2时, 如果 up 大于等于10, up 清0。 则 随即退出。说明:电子钟的百位可在0~9之间调整。 序号26:left 值为3时,如果 up 大于等于3,则 up 清0。 随即退出。说明:电子钟的千位可在0~2之间调整。 序号27:若 left 为其它值,也退出。 序号28:switch(left)开关语句结束。 序号29:if(P1_2==0)语句结束。 序号30:如果 P1.2等于0(即电路中的 up 键按下时) , 进入 if(P1_2==0)语句,同时进入 switch(set)开关语 句。 序号31:switch(set)开关语句开始。 序号32:set 值为0时,退出。 序号33: 值为1时, set 将此时 up 值送入 X 数组的第 left 位。随即退出。说明:X 数组是显示走时缓存区。 序号34: 值为2时, set 将此时 up 值送入 Y 数组的第 left 位。若此时 P1.3等于0(即电路中的 on/off 键按下) ,则定 时1启停标志位 o_f1取反(启动/关闭) 。随即退出。说明:Y

数组是定时1记忆缓存区。o_f1是为了判断定时1启动/关闭 而在整个程序开始时定义的位标志。 序号35: 值为3时, set 将此时 up 值送入 Z 数组的第 left 位。若此时 P1.3等于0(即电路中的 on/off 键按下) ,则定 时2启停标志位 o_f2取反(启动/关闭) 。随即退出。说明:Z 数组是定时2记忆缓存区。o_f2是为了判断定时2启动/关闭 而在整个程序开始时定义的位标志。 序号36:若 set 为其它值,也退出。 序号37:switch(set)开关语句结束。if(P1_2==0) 语句结束。 序号38:else 语句开始。 序号39:又进入 switch(set)开关语句。说明:上一 个 switch(set)开关语句是将按键产生的 up 值送入 X、Y、 Z 数组存放,现在这个 switch(set)开关语句是调出 X、Y、 Z 数组内容至变量 up,以便在原来的基础上递增。例如:原 来的 X[0]值为5, 则在调整时个位 LED 数码管显示就从5开始 往上调,而不会产生从0或其它值开始上调的情况,适合人 的一般直觉。 序号40:set 值为0时,退出。 序号41:set 值为1时,将此时 X 数组的第 left 位值送 入变量 up。随即退出。 序号42:set 值为2时,将此时 Y 数组的第 left 位值送

入变量 up。 若此时 P1.3等于0 (即电路中的 on/off 键按下) , 则定时1启停标志位 o_f1取反(启动/关闭) 。随即退出。 序号43:set 值为3时,将此时 Z 数组的第 left 位值送 入变量 up。 若此时 P1.3等于0 (即电路中的 on/off 键按下) , 则定时2启停标志位 o_f2取反(启动/关闭) 。随即退出。 序号44:若 set 为其它值,也退出。 序号45:switch(set)开关语句结束。else 语句结束。 序号46:if(n==0)语句结束。if(P1!=0xff)语句结 束。 序号47:本次定时中断快结束时,将暂存于 i,j 的当 时 P1口、P3口状态还原。 序号48:定时1中断函数结束。 上面为按键输入程序设计的详细解释,按键输入时需将 当时状态实时显示出来,我们将显示走时、显示调整走时、 显示调整定时1、 显示调整定时2做成四个子程序, 分别由 set 为0、 2、 1、 3时散转后的“显示走时并判断定时1、 2到否程序”、 “显示调整走时程序”、“显示调整定时1程序”、“显示调整定 时2程序”进行调用。为达到需输入的某位显示最亮(稳定显 示) ,而其它三位显示较暗(有闪烁感)的视觉效显,让三 位需显示较暗的数码管每位点亮3mS,而显示最亮的那位数 码管点亮36mS 即可。限于篇幅,具体程序就不进行详解了, 读者朋友可自行编写。


相关文档

单片机C语言程序设计与应用
第3章 单片机C语言编程技术
单片机c语言编程经验
单片机C语言的编程探析
PIC单片机C语言程序设计(3)
单片机C语言编程常用语句课件
第7章单片机C语言程序设计
第4章单片机C语言程序设计
补充 单片机C语言程序设计【精选】
单片机第五章C语言程序设计分解
电脑版