c语言嵌入式开发键盘,C语言嵌入式系统编程修炼之键盘操作篇

功能键的问题在于,用户界面并非固定的,用户功能键的选择将使屏幕画面处于不同的显示状态下。

处理功能键

功能键的问题在于,用户界面并非固定的,用户功能键的选择将使屏幕画面处于不同的显示状态下。例如,主画面如图1:

ET65309201008081336551201106082009126411.jpg

图1 主画面

当用户在设置XX上按下Enter键之后,画面就切换到了设置XX的界面,如图2:

ET65309201008081336552201106082009126412.jpg

图2 切换到设置XX画面

程序如何判断用户处于哪一画面,并在该画面的程序状态下调用对应的功能键处理函数,而且保证良好的结构,是一个值得思考的问题。

让我们来看看WIN32编程中用到的"窗口"概念,当消息(message)被发送给不同窗口的时候,该窗口的消息处理函数(是一个callback函数)最终被调用,而在该窗口的消息处理函数中,又根据消息的类型调用了该窗口中的对应处理函数。通过这种方式,WIN32有效的组织了不同的窗口,并处理不同窗口情况下的消息。

我们从中学习到的就是:

(1)将不同的画面类比为WIN32中不同的窗口,将窗口中的各种元素(菜单、按钮等)包含在窗口之中;

(2)给各个画面提供一个功能键"消息"处理函数,该函数接收按键信息为参数;

(3)在各画面的功能键"消息"处理函数中,判断按键类型和当前焦点元素,并调用对应元素的按键处理函数。

/* 将窗口元素、消息处理函数封装在窗口中 */

struct windows

{

BYTE currentFocus;

ELEMENT element[ELEMENT_NUM];

void (*messageFun) (BYTE keyValue);

};

/* 消息处理函数 */

void messageFunction(BYTE keyValue)

{

BYTE i = 0;

/* 获得焦点元素 */

while ( (element [i].ID!= currentFocus)&& (i < ELEMENT_NUM) )

/* "消息映射" */

if(i < ELEMENT_NUM)

{

switch(keyValue)

{

case OK:

element[i].OnOk();

break;

}

}

}

在窗口的消息处理函数中调用相应元素按键函数的过程类似于"消息映射",这是我们从WIN32编程中学习到的。编程到了一个境界,很多东西都是相通的了。其它地方的思想可以拿过来为我所用,是为编程中的"拿来主"。

在这个例子中,如果我们还想玩得更大一点,我们可以借鉴MFC中处理MESSAGE_MAP的方法,我们也可以学习MFC定义几个精妙的宏来实现"消息映射"。

处理数字键

用户输入数字时是一位一位输入的,每一位的输入都对应着屏幕上的一个显示位置(x坐标,y坐标)。此外,程序还需要记录该位置输入的值,所以有效组织用户数字输入的最佳方式是定义一个结构体,将坐标和数值捆绑在一起:

/* 用户数字输入结构体 */

typedef struct tagInputNum

{

BYTE byNum; /* 接收用户输入赋值 */

BYTE xPos; /* 数字输入在屏幕上的显示位置x坐标 */

BYTE yPos; /* 数字输入在屏幕上的显示位置y坐标 */

}InputNum, *LPInputNum;

那么接收用户输入就可以定义一个结构体数组,用数组中的各位组成一个完整的数字:

InputNum inputElement[NUM_LENGTH]; /* 接收用户数字输入的数组 */

/* 数字按键处理函数 */

extern void onNumKey(BYTE num)

{

if(num==0|| num==1) /* 只接收二进制输入 */

{

/* 在屏幕上显示用户输入 */

DrawText(inputElement[currentElementInputPlace].xPos, inputElement[currentElementInputPlace].yPos, "%1d", num);

/* 将输入赋值给数组元素 */

inputElement[currentElementInputPlace].byNum = num;

/* 焦点及光标右移 */

moveToRight();

}

}

将数字每一位输入的坐标和输入值捆绑后,在数字键处理函数中就可以较有结构的组织程序,使程序显得很紧凑。

整理用户输入

继续第2节的例子,在第2节的onNumKey函数中,只是获取了数字的每一位,因而我们需要将其转为有效数据,譬如要转为有效的XXX数据,其方法是:

/* 从2进制数据位转为有效数据:XXX */

void convertToXXX()

{

BYTE i;

XXX = 0;

for (i = 0; i < NUM_LENGTH; i++)

{

XXX += inputElement[i].byNum*power(2, NUM_LENGTH - i - 1);

}

}

反之,我们也可能需要在屏幕上显示那些有效的数据位,因为我们也需要能够反向转:

/* 从有效数据转为2进制数据位:XXX */

void convertFromXXX()

{

BYTE i;

XXX = 0;

for (i = 0; i < NUM_LENGTH; i++)

{

inputElement[i].byNum = XXX / power(2, NUM_LENGTH - i - 1) % 2;

}

}

当然在上面的例子中,因为数据是2进制的,用power函数不是很好的选择,直接用"<< >>"移位操作效率更高,我们仅是为了说明问题的方便。试想,如果用户输入是十进制的,power函数或许是唯一的选择了。

总结

本篇给出了键盘操作所涉及的各个方面:功能键处理、数字键处理及用户输入整理,基本上提供了一个全套的按键处理方案。对于功能键处理方法,将LCD屏幕与Windows窗口进行类比,提出了较新颖地解决屏幕、键盘繁杂交互问题的方案。

计算机学的许多知识都具有相通性,因而,不断追赶时髦技术而忽略基本功的做法是徒劳无意的。我们最多需要"精通"三种语言(精通,一个在如今的求职简历里泛滥成灾的词语),最佳拍档是汇编、C、C++(或JAVA),很显然,如果你"精通"了这三种语言,其它语言你应该是可以很快"熟悉"的,否则你就没有"精通"它们。

c语言实现单片机的键盘程序 #include "SST89x5x4.H" #include #define uchar unsigned char #define uint unsigned int #define _Nop() _nop_() unsigned char code Key_Value_Table[16]={0xff,0x00,0x01,0xff,0x02,0xff,0xff,0xff, 0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; void Key_Init(void); unsigned char GetScanKey(void); unsigned char GetKey(void); void LCD_Init(void); void LCD_Init2(void); //void WriteW(uint a); void CheckBF(void); unsigned char Key_ASC2(unsigned char); void WritD(unsigned char); void Delay_ns(int i); void Delay_ms(int ms); unsigned char key; unsigned char key_asc2; unsigned char bKeyUp_Flag; uchar xdata *ptr; //函数功能描述:键盘初始化,将标志位置1; void Key_Init(void) { bKeyUp_Flag=1;//标志(全局变量)位置1 } //函数功能描述:键盘扫描函数,得到键的行列位置; unsigned char GetScanKey(void) { unsigned char key, i, temp; unsigned char xdata * ptr; key=0xff; for (i=1; i<0x10; i<<=1) //i的低4位为行数位,行依次检测 循环4次 { ptr=0x8fff; //数码管位选地址 * ptr =i; temp = * ptr; //取键盘IO口的值 temp &= 0x0f; //屏蔽高四位 if (temp!=0x00) //是否有有效键值 { key = i<<4; //取行数位的值并将其放入返回值高4位 key|=temp; //列数位的值放入返回值低4位 break; } } return key; //返回行位(高四)和列位(低四) } /*函数功能描述:取键值,长按无效; unsigned char code Key_Value_Table[16]={0xff,0x00,0x01,0xff,0x02,0xff,0xff,0xff, 0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; 说明:计算因子,定义在函数外部。此数组在计算键值的中间过程起作用。比如右下方键按下(行列值为0x88),通过查找数组得到行对应的中间值0x03,列对应的中间值0x03。 */ unsigned char GetKey(void) { unsigned char key, temp; if (!bKeyUp_Flag) //判断标志,是0执行 /*按键程序执行一次后会将bKeyUp_Flag标志位清零,执行此段程序,长按键无效返回无效值,直至按键无效返回无效按键值,置"1"标志位。按键输入恢复有效。屏蔽这部分则长按键有效*/ { key=GetScanKey(); if (key==0xff) //没有按键,置标志位 bKeyUp_Flag=1; else //保持按键 return 0xff; //因为0xff大于15,故为无效键值,实现长按键无效 } key=GetScanKey(); if (key==0xff) //没有按键 return key; else //有按键有效 temp=key; //取键值 Delay_ms(20); //延时20ms 消抖 key=GetScanKey(); //键盘扫描 if(key!=temp) //判断两次键值是否相同,排除干扰信号影响 确认有效信号 { key=0xff; return key; }
1.1. 具备多个可编程按键,一个多段可编程电子锁(具体数量依型号而定)。 1.2. 支持磁卡阅读和IC卡读写功能(两功能模块为可选)。 1.3. 能用专用软件对每个按键和电子锁位能进行多至十五层和每层255个字符的任意设定。能对磁卡数据输出前后缀进行自定义设置;能使用软件对任意磁道进行关闭或者开放。 1.4. 特别设计静电保护电路,并采用EPROM保存数据,无需电池,数据保存时间不少于100年。 1.5. 提供标准PS/2键盘接口,能外接标准键盘和标准条形码扫描枪。 1.6. 提供“TSL-True Status Lock”功能。能对任意一个键位和电子锁锁位进行包括Num lock、Caps lock、Scroll lock、Shift、Ctrl、Alt、Esc、F1等功能键在内的编程。 1.7. 能对Shift、Ctrl、Alt功能键通码和断码进行组合编码。 1.8. 提供“多层键”功能,可对键盘通过层的定义来配合POS管理软件进行权限分级管理、或扩展按键的数量与功能。每个键可多至定义15个切换层和一个默认层。 1.9. 提供延时功能,最多能延时255秒。 2. 键盘安装 2.1. 将可编程键盘用随机专用电缆连接至主机后面的PS/2接口。如果想使用标准键盘,则将标准键盘的PS/2插头与本键盘的电缆线6PIN母头对接。 2.2. 将随机光碟中的编程软件目录中的全部文件复制到硬盘中。 2.3. 运行WINKB.EXE对可编程键盘进行设置。 2.4. 至此可编程键盘即可正常使用。 2.5. 根据自己的需要,将随机光碟中的其它相关内容复制到硬盘中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值