|
实验目的
①学习如何配置键盘控制器的寄存器
②掌握键盘扫描程序的实现过程
实验内容
①熟悉PXA270提供的键盘接口
②分析Eeliod实验平台的键盘原理图
③参考示例程序实现矩阵键盘扫描,利用数码管显示区分不同按键
④编译程序,下载执行,验证程序工作是否正常
实验原理
①键盘控制
矩阵键盘的扫描方式有多种,逐行扫描,翻转扫描等,本实验中由于PXA270自带了键盘控制器,且输入输出口是单向的,所以只能采用逐行扫描方式。本实验采用手动扫描,不利用中断,扫描控制方式与一般的矩阵键盘扫描方式一样,都是列线上逐位送出高电平,行线读取电平值,如果读取到高电平则说明在当前列线和读到的行线交叉点的按键被按下了。该实验主要工作是设置键盘控制器相应的寄存器和读取相应的寄存器。通过设置键盘接口寄存器KPC中相应的位来控制矩阵键盘4个列信号逐位为高,通过读取矩阵键盘寄存器KPMK中相应的位来判断矩阵键盘4个行信号的高低,进而根据当前的列信号状态来确定按键的物理坐标。
②数码管控制
数码管控制与实验一中的数码管控制方法一样。
实验步骤
第一步 分析代码
结合以上说明,对本实验提供的示例代码分析,深入理解针对具体的硬件实现,软件是如何配合工作的。
第二步 程序的编译和下载
利用ADS打开示例工程文件,执行Project→Make,编译、链接生成可执行映像文件
第三步 观察系统运行情况,对系统进行源码调试
程序说明
①键盘程序
键盘程序通过依次给出列线高电平读行线电平状态来判断当前按下的按键的位置,通过读写相应的寄存器即可,由于键盘实际连线对应的IO口实际上不是连续的,导致须通过4次判断来完成,而不是利用循环实现。
②数码管程序
数码管程序在实验一中已经写过,本次实验可以直接使用
③主程序
主程序为一死循环,通过触发手动键盘扫描函数,读取到键盘按下的按键,判断键值,进行相应的处理
程序源代码、注释
①键盘程序
1)MyKeypad.h
#ifndef __MyKeypad_h__
#define __MyKeypad_h__
extern unsigned char KeypadScan(void);
#endif
2)MyKeypad.c
#define KPC_VALUE (*((volatile unsigned int *)(0x41500000))) //键盘接口控制寄存器
#define KPMK_VALUE (*((volatile unsigned int *)(0x41500018))) //矩阵键盘寄存器,读取扫描的状态
//这句宏定义控制键盘扫描返回值,不注释时返回是4x4矩阵键盘的实际物理坐标,从上到下从左到右为0x00~0x0F
//注释掉后返回的是4x4矩阵键盘按键上印刷的ASCII字符
//#define KEYPAD_RETPHY
void Delay(unsigned int x)
{
unsignedint i, j, k;
for(i =0; i <=x; i++)
for (j = 0; j <0xff; j++)
for(k = 0; k <0xff; k++)
;
}
unsigned char KeypadScan(void)
{
unsignedshort int inRow;
//扫描第一列
KPC_VALUE&= 0xFFE01FFF; //先将列线全复位拉低
KPC_VALUE|= (0x01 << 13); //再将列线第一列置1
Delay(1);
inRow= KPMK_VALUE;
Delay(1);
if(inRow== KPMK_VALUE) //消抖后还相等表明确实有按键按下
{
switch(inRow & 0xFF)
{
#ifdefKEYPAD_RETPHY
//注意这里返回的是扫描到的按键的物理坐标,从键盘左上角到右下角分别为0x00~0x0F
case 0x01: return 0x00;
case 0x02: return 0x04;
case 0x04: return 0x08;
case 0x20: return 0x0C;
default:;
#else
//注意这里返回的是键盘上印刷的字符的ASCII
case 0x01: return '1';
case 0x02: return '4';
case 0x04: return '7';
case 0x20: return '*';
default:;
#endif
}
}
//扫描第二列
KPC_VALUE&= 0xFFE01FFF; //先将列线全复位拉低
KPC_VALUE|= (0x01 << 14); //再将列线第二列置1
Delay(1);
inRow= KPMK_VALUE;
Delay(1);
if(inRow== KPMK_VALUE) //消抖后还相等表明确实有按键按下
{
switch(inRow & 0xFF)
{
#ifdefKEYPAD_RETPHY
//注意这里返回的是扫描到的按键的物理坐标,从键盘左上角到右下角分别为0x00~0x0F
case 0x01: return 0x01;
case 0x02: return 0x05;
case 0x04: return 0x09;
case 0x20: return 0x0D;
default:;
#else
//注意这里返回的是键盘上印刷的字符的ASCII
case 0x01: return '2';
case 0x02: return '5';
case 0x04: return '8';
case 0x20: return '0';
default:;
#endif
}
}
//扫描第三列
KPC_VALUE&= 0xFFE01FFF; //先将列线全复位拉低
KPC_VALUE|= (0x01 << 15); //再将列线第三列置1
Delay(1);
inRow= KPMK_VALUE;
Delay(1);
if(inRow== KPMK_VALUE) //消抖后还相等表明确实有按键按下
{
switch(inRow & 0xFF)
{
#ifdefKEYPAD_RETPHY
//注意这里返回的是扫描到的按键的物理坐标,从键盘左上角到右下角分别为0x00~0x0F
case 0x01: return 0x03;
case 0x02: return 0x06;
case 0x04: return 0x0A;
case 0x20: return 0x0E;
default:;
#else
//注意这里返回的是键盘上印刷的字符的ASCII
case 0x01: return '3';
case 0x02: return '6';
case 0x04: return '9';
case 0x20: return '#';
default:;
#endif
}
}
//扫描第四列
KPC_VALUE&= 0xFFE01FFF; //先将列线全复位拉低
KPC_VALUE|= (0x01 << 19); //再将列线第四列置1
Delay(1);
inRow= KPMK_VALUE;
Delay(1);
if(inRow== KPMK_VALUE) //消抖后还相等表明确实有按键按下
{
switch(inRow & 0xFF)
{
#ifdefKEYPAD_RETPHY
//注意这里返回的是扫描到的按键的物理坐标,从键盘左上角到右下角分别为0x00~0x0F
case 0x01: return 0x03;
case 0x02: return 0x07;
case 0x04: return 0x0B;
case 0x20: return 0x0F;
default:;
#else
//注意这里返回的是键盘上印刷的字符的ASCII
case 0x01: return 'A';
case 0x02: return 'B';
case 0x04: return 'C';
case 0x20: return 'D';
default:;
#endif
}
}
return0xFF;
}
②数码管程序
本次实验使用的数码管程序为实验一中的数码管程序,可以直接使用。
③主函数
#include "SegLed.h"
#include "MyKeypad.h"
int main()
{
unsignedchar keyValue;
shorttempDisp = 0;
//这几句用于调试时单步执行查看结果
SegLedDispNum(123,DISP_BLANKING);
SegLedDispNum(23,DISP_BLANKING);
SegLedDispNum(3,DISP_BLANKING);
SegLedDispNum(0,DISP_BLANKING);
while(1)
{
//手动扫描一次矩阵键盘,得到按键的ASCII码
keyValue = KeypadScan();
switch(keyValue)
{
//普通数字键
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
{
tempDisp = tempDisp * 10 + keyValue - '0';
if(tempDisp > 9999)
tempDisp= 0;
SegLedDispNum(tempDisp, DISP_BLANKING);
break;
}
//取消键
case'*':
{
break;
}
//确认键
case'#':
{
break;
}
//清零键
case'A':
{
tempDisp = 0;
SegLedDispNum(tempDisp, DISP_BLANKING);
break;
}
//退位键
case'B':
{
tempDisp /= 10;
SegLedDispNum(tempDisp, DISP_BLANKING);
break;
}
case'C':
{
break;
}
case'D':
{
break;
}
default:
break;
} //endof switch(keyValue)
} //end of while(1)
} //endof main()
总结
在键盘程序中,在语句中间定义了变量,编译时提示错误,看错误的提示,没有发现问题,后来突然想到之前Keil中在语句中间定义变量C51的编译器也提示错误,将变量定义放在函数开头,果然编译正确。
|
|