C51编程几个有用的模块-键盘扫描模块

来源:本站
导读:目前正在解读《C51编程几个有用的模块-键盘扫描模块》的相关信息,《C51编程几个有用的模块-键盘扫描模块》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《C51编程几个有用的模块-键盘扫描模块》的详细说明。
简介:文章主要介绍C51编程几个有用的模块-键盘扫描模块。

键盘扫描模块有两种工作方式, 一种为自动的由时钟模块调用, 另一种是由程序员自行调用。

1) 由时钟模块自动调用的方式

将时钟模块实现文件(Timer.h)及键盘扫描模块的实现文件(KBScan。c)包含进工程, 在Config.h 文件中添加TIMER_KBSCANDELAY宏。 时钟模块自动对时钟中断进行计数, 当达到TIMER_KBSCANDELAY宏所定义的值后, 自动调用键盘扫描模块中的函数KBScanProcess()进行键盘扫描,也就是说,这个宏的值可以决定按键消抖动的时间。

用户应该提供两个回调函数OnKBScan()及onKeysPressed()。 在函数OnKBScan中进行键盘扫描, 并返回扫描码。 扫描码的类型缺省为BYTE, 当键盘规模较大时, BYTE不能够完全包含键盘信息时, 可在Config.h文件中重定义宏KBVALUE, 如下:

#define KBVALUEWORD

这样, 就可以使用16位的键盘扫描码, 如果此时还达不到要求, 可以将键盘扫描码定义成一个结构, 但这样做将会增加代码量及消耗更多的RAM资源, 故不推荐。

扫描模块调用OnKBScan取得扫描码, 并调用用户可以重定义的宏IsNoKeyPressed来判断是否有键按下, 缺省的IsNoKeyPressed实现如下:

#define IsNoKeyPressed(x)((x) == 0x00)

即认为OnKBScan返回0扫描码时为没有键按下,如果扫描函数返回其它非零扫描码做为无键按下的扫描码时, 可以在Config.h文件中重定义IsNoKeyPressed宏的实现。

8位键盘扫描码(缺省值)时, 相应的扫描函数为:

BYTE OnKBScan()

当扫描模块经过软件消抖动之后, 发现有键按下, 就会调用另一个回调函数onKeysPressed。 函数的声明应该如下:

void onKeyPressed(BYTE byKBValue, BYTE byState)

其中中的参数byKBValue的类型为BYTE, 此为缺省值, 如果使用其它类型的扫描码, 就将此参数变为相应类型。 这个值由OnKBScan返回。 另一个参数byState在通常情况下为零。 但当用户在Config.h中定义宏KBSCAN_BRUSTCOUNT, 同时键盘上的某键被按住不放时, 扫描模块对它自己的调用(注意这里和TIMER_KBSCANDELAY宏不同, TIMER_KBSCANDELAY是时钟中断足够的次数后调用扫描模块, 而KBSCAN_BRUSHCOUNT为扫描模块自身的被调用次数)进行计数,当达到KBSCAN_BRUSTCOUNT时,扫描模块调用onKeysPressed,此时第一个参数的含义不变, 而byState变成1, 同时计数器复位,又经过一段时间后,用值为3的byState 调用onKeysPressed。 这样就可以很方便的实现多功能键或者检测某键的长时间被按下。

2)由用户自行调用

由用户自行在程序中调用扫描模块,而不是由时钟中断自行调用。其它与方式1相同。

注意:

1) 函数KBScanProcess为非阻塞函数,它将在很快的时间内返回,等待再次分配给它执行的机会。

2) 函数KBScanProcess是在时钟中断外部运行的,它的过程可以被任何中断打断,但不影响系统运行。

3) byState的最大值为250,之后被复位为零。

现在来举例说明上述几个模块的使用方法。

硬件环境描述:

为了控制一盏灯,需要单片机提供一个做控制功能的开关量,这里不描述外部接口电路,只说明当单片机的P10脚为高电平时,灯灭,当P10脚为低电平时,灯亮。

可以通过计算机由串口发送命令来控制,或通过一个按键(pushbutton不是自锁式的按键)来手动控制(按键接在P11脚上,当键没有按下时,P11电平为高,键按下时,引脚电平被接低),当使用按键手动控制的时候,需要给计算机发送通知。

设定串口通讯指令如下:

数据包由0xff做包头,4个字节长,第二个字节为命令代码,第三个字节为数据,最后一个字节为校验位。

命令和数据代码有如下组合:

(计算机发给单片机)

0x100x01:计算机控制灯亮。(数据位是非零值即可)

0x100x00:计算机控制灯灭。

(单片机发给计算机)

0x110x01:单片机正常执行控制指令,返回。(数据位是非零值即可)

0x110x00:单片机不能够正常执行控制指令,或控制指令错(不明含义的数据包或校验错等)。

0x120x01:手动控制灯亮。(数据位是非零值即可)

0x120x00:手动控制灯灭。

建立工程:

在硬盘上建立文件夹Projects,在Projects下建立Common文件夹及Example文件夹。将各模块的头文件及实现文件拷贝到Common文件夹下(推荐使用这样的文件组织结构,其它工程也可以建立在Projects下,各工程共享Common文件夹中的代码)。

启动KeilC的IDE,在Example下建立新工程,将各模块的实现文件包含进工程。

在Example文件夹下建立Output文件夹,更改工程设置,将Output作为输出文件和List文件的输出文件夹(推荐使用这样的结构,当保存工程文件时,可以简单的删除Output文件夹中的内容而不会误删有用的工程文件)。

建立工程配置头文件Config.h及工程主文件Example.c,并将Exmaple.c文件加入工程。

输入代码:

代码的具体编写过程略。下面是最后的Config.h文件及Example.c文件。

//

//file:Config.h

//

#ifndef_CONFIG_H_

#define_CONFIG_H_

#include<Atmel/At89x52.h>//使用AT89C52做控制

#include“../Common/Common.h”//使用自定义的数据类型

#defineTIMER_RELOAD922//11.0592MHz晶振,1ms中断周期

#defineTIMER_KBSCANDELAY40//40ms重检测按键状态,即40ms消抖

#defineSCOMM_AsyncInterface//使用异步通讯服务

#defineIsPackageHeader(x)((x)==0xff)//判断包头是不是0xff

#defineIsPackageTailer(x,y,z)((y)<=(z))//判断包的长度是不是足够

#endif//_CONFIG_H_

//

//file:Example.c

//

#include<Atmail/At89x52.h>

#include“../Common/Common.h”

#include“../Common/Timer.h”

#include“../Common/Scomm.h”

#include“../Common/KBScan.h”

BITgbitLampState=1;//灯的状态,缺省为off

staticvoidInitialize()

{

InitTimerModule();//初始化时钟模块

InitSCommModule(0xfd,TRUE);//初始化通讯模块,11.0592MHz晶振,

//波特率为19200

EA=1;//开中断

}

voidmain()

{

Initialize();//初始化

while(TRUE)//主循环

{

ImpTimerService();//实现时钟中断服务,如键盘扫描

AsyncRecePackage(4);//接收4个字节长的数据包

}

}

//在中断外部响应时钟中断事件

voidOnTimerEvent()

{

//donothing

}

//控制外部灯

staticvoidTriggerLamp(BITbEnable)

{

P10=~bEnable;//需要反相控制

}

//键扫描回调函数

BYTEKBScan()

{

BITb;

P11=1;//读之前拉高引脚电平

b=P11;//读入引脚状态

return~b;//数据反相做扫描码

}

//计算校验和

staticBYTECalcCheckSum(BYTE*pbyBuf,BYTEbyLen)

{

BYTEby,bySum=0;

for(by=0;by<byLen;by++)

bySum+=pbyBuf[by];

return0–bySum;

}

//接收到键盘消息回调函数

voidonKeyPressed(BYTEbyvalue,BYTEbyState)

{

BYTEby[4];

if(byState==0)

{

switch(byvalue)

{

case0x01:

gbitLampState=~gbitLampState;//灯状态取反

TriggerLamp(gbitLampState);//执行控制

by[0]=0xff;//构造数据包

by[1]=0x12;

by[2]=(BYTE)gbitLampState;

by[3]=CalcCheckSum(by,3);//求校验和

SendPackage(by,4);//发送数据包

break;

//处理其它扫描码

default:

break;

}

}

//接收到数据包回调函数

voidOnRecePackage(BYTE*pbyBuf,BYTEbyBufLen)

{

BYTEby[4];

by[0]=0xff;

by[1]=0x11;

if(byBufLen!=4||pbyBuf[3]!=CalcCheckSum(pbyBuf,3))

{

by[2]=0;

by[3]=CalcCheckSum(by,3);

SendPackage(by,4);//处理长度或校验和不正确

}

switch(pbyBuf[1])

{

case0x10:

gbitLampState=(BIT)pbyBuf[2];

TriggerLamp(gbitLampState);

by[2]=1;

by[3]=CalcCheckSum(by,3);

SendPackage(by,4);//发送成功执行通知

break;

default://不知道的命令

by[2]=0;

by[3]=CalcCheckSum(by,3);

SendPackage(by,4);//发送没有成功执行通知

break;

}

}

提醒:《C51编程几个有用的模块-键盘扫描模块》最后刷新时间 2024-03-14 01:02:32,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《C51编程几个有用的模块-键盘扫描模块》该内容的真实性请自行鉴别。