8.2.1 按键识别与键盘定义子程序
(1) 键值计算方法

本节给出键盘编程实例,其中涉及到如何扫描键盘取得键值、中断获取键值、键盘编码等问题。
键盘与单片机接线见图8-5,图8-6给出了键的定义符号“0”-“9”、“A”-“D”、“*”、“#”等。如何识别“1”键呢?这里将列线n1-n4分别接PTA4-PTA7,且编程时将PTA4-PTA7定义为输入并有内部上拉电阻,行线m1-m4分别接PTA0-PTA3,且编程时将PTA0-PTA3定义为输出,那么“1”键对应于:PTA7~PTA0=11101110,即$EE;“2”键对应于:PTA7~PTA0=11011110,即$DE;……;“D”键对应于:PTA7~PTA0=01110111,即$77。前者是我们的定义符号,后者是“键值”,这种情况“键值”是一个字节。这样,按图8-5的接法可以得出键值表,见图8-6。键值可以通过扫描法获得,由键值通过查表法编程得到定义值。

(2) 键盘编程汇编语言子程序
下面给出有关键盘编程的汇编语言子程序。它们是:键盘中断初始化子程序、扫描法读取键值子程序、键值转为定义值子程序。即使不使用中断方式识别按键,三个子程序仍然需要使用。只不过键盘中断初始化子程序中改为不允许中断进入。扫描法读取键值与键值转为定义值两个子程序在键盘编程中通常需要使用的。
①键盘子程序头文件KB.h
//[KB.h]键盘子程序定义头文件-----------------------------
//键盘控制引脚定义
KB_P = PTA //键盘接在PTA口上
KB_D = DDRA //相应的方向寄存器
KB_PUE = PTAPUE //相应的上拉电阻允许寄存器
②键盘子程序文件KB.s
//[KB.s]键盘子程序定义----------------------------------*
//本文件包含: *
// (1)KBInit:初始化键盘控制及中断的相关寄存器 *
// (2)KBScan:扫描4*4键盘,读取键值->A *
// (3)KBDef:键值转为定义值 *
//硬件连接: *
// PTA7-4接键盘4根列线,PTA3-0接键盘4根行线 *
//------------------------------------------------------*
.include "KB.h" //该头文件包含键盘控制引脚定义
//KBInit:键盘初始化子程序-------------------------------*
//功能:初始化键盘控制及中断的相关寄存器,但未开放键盘中断*
//入口:无 *
//出口:无 *
//堆栈深度:2 + 1 = 3 *
//------------------------------------------------------*
KBInit::
PSHA //[A进栈](保护寄存器A)
//复位相应寄存器
LDA #$00
STA KB_P
LDA #%00001111 //使列线(7-4位)为输入
STA KB_D //使行线(3-0位)为输出
LDA #%11110000 //输入引脚(列线)有内部上拉电阻
STA KB_PUE
BSET #1,INTKBSCR //屏蔽键盘中断(IMASKK=1)
LDA #%11110000 //允许输入引脚的中断可进入
STA INTKBIER
BSET #2,INTKBSCR //清除键盘中断请求(ACKK=1)
PULA //[A出栈](恢复寄存器A)
RTS
//KBScan:扫描读取键值子程序-----------------------------*
//功能:扫描4*4键盘,读取键值->A,若无按键,$FF->A *
//入口:无 *
//出口:A = 键值 *
//堆栈深度:2 + 2 = 4 *
//------------------------------------------------------*
KBScan::
AIS #-2 //开辟临时变量
KBScan_1:
LDA #%11111110 //使第一根行线为0(低电平)
STA 1,SP
LDA #$04 //最多将扫描4根行线
STA 2,SP
KBScan_2:
//当前扫描的一行,输出低电平
LDA KB_P
ORA #%00001111
AND $1,SP
STA KB_P
//等待键按下
NOP
NOP
LDA KB_P
//通过观察4根列线中是否出现低电平
//来判断当前行有无按键
AND #%11110000 //仅保留列线的值
CBEQA #$F0,KBScan_3 //当前行无按键,转KBScan_3
//当前行有按键
LDA KB_P //A中存入按键值
BRA KBScan_Exit
KBScan_3:
//准备扫描下一行
SEC //C=1
ROL 1,SP //使下一根行线输出低电平
DBNZ 2,SP,KBScan_2 //没有扫到按键且没有扫完4行
//4行扫完仍未扫到按键(认为无按键)
LDA #$FF
KBScan_Exit:
AIS #2 //释放临时变量
RTS
//KBDef:键值转为定义值子程序----------------------------*
//功能:键值转为键盘定义值 *
//入口:A = 键值 *
//出口:A = 键定义值 *
//堆栈深度:2+3=5 *
//------------------------------------------------------*
KBDef::
PSHH //[HX进栈](保护寄存器HX)
PSHX
AIS #-1 //开辟临时变量
STA 1,SP //键值存入[SP+1]
LDHX #KBTable //取键盘定义表首地址
KBDef_1:
//在键盘定义表中搜索欲转换的键值,直至表尾($00)
LDA ,X
CMP #$00
BEQ KBDef_3 //表已搜完,表中无对应的键值定义
//表未搜完
CMP 1,SP //表中当前键值与欲转换键值相比较
BNE KBDef_2 //未找到对应键值,转KBDef_2
//找到对应键值
AIX #1 //取相应定义值->A,并完成转换
LDA ,X
BRA KBDef_Exit
KBDef_2:
AIX #2 //指向下一个表中键值
BRA KBDef_1 //继续判断
KBDef_3:
LDA #$FF //表中无对应的键值定义$FF->A
KBDef_Exit:
AIS #1 //释放临时变量
PULX //[HX出栈](恢复寄存器HX)
PULH
RTS
//键盘定义表
KBTable::
.byte $EE,'1',$DE,'2',$BE,'3',$7E,'A'
.byte $ED,'4',$DD,'5',$BD,'6',$7D,'B'
.byte $EB,'7',$DB,'8',$BB,'9',$7B,'C'
.byte $E7,'*',$D7,'0',$B7,'#',$77,'D'
.byte $00
8.2.2 键盘中断编程举例
下面给出的实例程序的功能是,当按下键盘上任何一个键,产生键盘中断,在键盘中断程序中,通过串行口发送“键值”及“键定义值”。PC机用7.5.4节介绍的串口调试器,接收并显示。键盘中断汇编工程文件组织如表8-1所示。

(1) 键盘中断编程汇编主程序
//------------------------------------------------------*
//工 程 名:KeyBoard_Int.prj *
//硬件连接: *
// (1)MCU的A口接键盘(见"KB.s"文件中的说明) *
//程序描述:按下键盘按键,串口发送对应的键值 *
//目 的:键盘中断,键盘扫描,键值识别,键值转换 *
//注 意:如果键盘插在实验板的上排插孔,无须连线,若插在 *
// 下排插孔,需手工接线 *
//日 期:2007.07 *
//--------清华2007版《嵌入式技术基础与实践》实例--------*
//头文件
.include "Includes.h" //总头文件
//主程序
.area flash(abs)
.org FlashStartAddr
MainInit:: //复位后从此处执行(见Vectors08.s文件末尾处)
SEI //关总中断
//1.堆栈初始化为RAM最高端
LDHX #RAMendAddr + 1 //HX = #RAMendAddr + 1
TXS //HX - 1 -> SP
//2.系统初始化
JSR MCUinit //初学时跳过此处
//3.串行口初始化
JSR SCIinit
//4.键盘初始化
JSR KBinit
JSR EnableKBint //开放键盘中断
CLI //开总中断
//程序总循环入口
MainLoop:
NOP
NOP
BRA MainLoop
//包含本工程的其他文件-----------------------------------
.include "MCUinit.s" //芯片初始化
.include "SCI.s" //串行通信
.include "KB.s" //键盘子程序
.include "EnDisInt.s" //允许/禁止MCU各模块中断
//包含中断处理子程序与中断向量表文件"Vectors08.s"--------
//注意:这个包含语句的存放位置必须放在最后
.include "Vectors08.s" //中断处理子程序与中断向量表
(2) 键盘中断处理程序
//[Vectors08.s]中断处理子程序与中断向量表---------------*
//功能: *
// (1)定义中断处理子程序 *
// (2)放置中断向量表 *
//本文件包含: *
// (1)键盘中断处理函数 *
// (2)未定义的中断处理函数 *
//说明:该文件与芯片具体型号有关 *
// (1)芯片型号MC68HC908GP32 *
// (2)注意本文件内容的顺序不能变动 *
//------------------------------------------------------*
//isrKeyBoard:键盘中断处理程序--------------------------*
//功能:识别按键并发送键值,把键值转换成对应的定义值,再从 *
// 串口发送出去 *
//调用子程序: *
// (1)扫描法读取键值子程序(KBScan) *
// (2)键值转为定义值子程序(KBDef) *
//------------------------------------------------------*
isrKeyBoard::
SEI //关总中断
PSHH //[H进栈](保护寄存器H)
BSET #1,INTKBSCR //禁止键盘中断
JSR KBScan //扫描键盘,读取键值->A
JSR SCISend1 //发送键值
JSR KBDef //转成相应的定义值->A
JSR SCISend1 //发送定义值
JSR KBInit //键盘初始化
BCLR #1,INTKBSCR //开放键盘中断(IMASKK = 0)
PULH //[H出栈](恢复寄存器H)
CLI //开总中断
RTI
//未定义的中断处理子程序,本子程序不能删除
isrDummy::
RTI
//中断矢量表,用户若需开放某中断,可修改下表中的相应项目
//(interrupt service routine,isr 中断处理程序)
.area memory(abs)
.org 0xffdc //中断向量表起始地址(注意:与芯片型号有关)
vectab::
//…………省略其他未使用的中断向量定义
.word isrKeyBoard //键盘中断
//…………省略其他未使用的中断向量定义
(3) 键盘中断编程的PC机方程序
利用串口调试工具,接收按键后的键值,通过它可以清楚地知道定义值与键值的对应关系,若显示不对,可以修改键值转为定义值子程序中的键值表。


