機(jī)電之家資源網(wǎng)
單片機(jī)首頁(yè)|單片機(jī)基礎(chǔ)|單片機(jī)應(yīng)用|單片機(jī)開發(fā)|單片機(jī)文案|軟件資料下載|音響制作|電路圖下載 |嵌入式開發(fā)
培訓(xùn)信息
贊助商
C51編程幾個(gè)有用的模塊-鍵盤掃描模塊
C51編程幾個(gè)有用的模塊-鍵盤掃描模塊
 更新時(shí)間:2008-7-27 15:59:30  點(diǎn)擊數(shù):4
【字體: 字體顏色

鍵盤掃描模塊有兩種工作方式, 一種為自動(dòng)的由時(shí)鐘模塊調(diào)用, 另一種是由程序員自行調(diào)用。

1) 由時(shí)鐘模塊自動(dòng)調(diào)用的方式

    將時(shí)鐘模塊實(shí)現(xiàn)文件(Timer.h)及鍵盤掃描模塊的實(shí)現(xiàn)文件(KBScan。c)包含進(jìn)工程, 在Config.h 文件中添加TIMER_KBSCANDELAY宏。 時(shí)鐘模塊自動(dòng)對(duì)時(shí)鐘中斷進(jìn)行計(jì)數(shù), 當(dāng)達(dá)到TIMER_KBSCANDELAY宏所定義的值后, 自動(dòng)調(diào)用鍵盤掃描模塊中的函數(shù)KBScanProcess()進(jìn)行鍵盤掃描,也就是說(shuō),這個(gè)宏的值可以決定按鍵消抖動(dòng)的時(shí)間。

    用戶應(yīng)該提供兩個(gè)回調(diào)函數(shù)OnKBScan()及onKeysPressed()。 在函數(shù)OnKBScan中進(jìn)行鍵盤掃描, 并返回掃描碼。 掃描碼的類型缺省為BYTE, 當(dāng)鍵盤規(guī)模較大時(shí), BYTE不能夠完全包含鍵盤信息時(shí), 可在Config.h文件中重定義宏KBVALUE, 如下:
#define KBVALUE      WORD

    這樣, 就可以使用16位的鍵盤掃描碼, 如果此時(shí)還達(dá)不到要求, 可以將鍵盤掃描碼定義成一個(gè)結(jié)構(gòu), 但這樣做將會(huì)增加代碼量及消耗更多的RAM資源, 故不推薦。
  掃描模塊調(diào)用OnKBScan取得掃描碼, 并調(diào)用用戶可以重定義的宏IsNoKeyPressed來(lái)判斷是否有鍵按下, 缺省的IsNoKeyPressed實(shí)現(xiàn)如下:

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

    即認(rèn)為OnKBScan返回0掃描碼時(shí)為沒有鍵按下, 如果掃描函數(shù)返回其它非零掃描碼做為無(wú)鍵按下的掃描碼時(shí), 可以在Config.h文件中重定義IsNoKeyPressed宏的實(shí)現(xiàn)。

  8位鍵盤掃描碼(缺省值)時(shí), 相應(yīng)的掃描函數(shù)為:

BYTE OnKBScan()

  當(dāng)掃描模塊經(jīng)過(guò)軟件消抖動(dòng)之后, 發(fā)現(xiàn)有鍵按下, 就會(huì)調(diào)用另一個(gè)回調(diào)函數(shù)onKeysPressed。 函數(shù)的聲明應(yīng)該如下:

void onKeyPressed(BYTE byKBValue, BYTE byState)

    其中中的參數(shù)byKBValue的類型為BYTE, 此為缺省值, 如果使用其它類型的掃描碼, 就將此參數(shù)變?yōu)橄鄳?yīng)類型。 這個(gè)值由OnKBScan返回。 另一個(gè)參數(shù)byState在通常情況下為零。 但當(dāng)用戶在Config.h中定義宏KBSCAN_BRUSTCOUNT, 同時(shí)鍵盤上的某鍵被按住不放時(shí), 掃描模塊對(duì)它自己的調(diào)用(注意這里和TIMER_KBSCANDELAY宏不同, TIMER_KBSCANDELAY是時(shí)鐘中斷足夠的次數(shù)后調(diào)用掃描模塊, 而KBSCAN_BRUSHCOUNT為掃描模塊自身的被調(diào)用次數(shù))進(jìn)行計(jì)數(shù),當(dāng)達(dá)到KBSCAN_BRUSTCOUNT時(shí),掃描模塊調(diào)用onKeysPressed,此時(shí)第一個(gè)參數(shù)的含義不變, 而byState變成1, 同時(shí)計(jì)數(shù)器復(fù)位,又經(jīng)過(guò)一段時(shí)間后,用值為3的byState 調(diào)用onKeysPressed。 這樣就可以很方便的實(shí)現(xiàn)多功能鍵或者檢測(cè)某鍵的長(zhǎng)時(shí)間被按下。

2)由用戶自行調(diào)用

    由用戶自行在程序中調(diào)用掃描模塊,而不是由時(shí)鐘中斷自行調(diào)用。其它與方式1相同。

注意:

    1) 函數(shù)KBScanProcess為非阻塞函數(shù),它將在很快的時(shí)間內(nèi)返回,等待再次分配給它執(zhí)行的機(jī)會(huì)。

    2) 函數(shù)KBScanProcess是在時(shí)鐘中斷外部運(yùn)行的,它的過(guò)程可以被任何中斷打斷,但不影響系統(tǒng)運(yùn)行。

    3) byState的最大值為250,之后被復(fù)位為零。

現(xiàn)在來(lái)舉例說(shuō)明上述幾個(gè)模塊的使用方法。

硬件環(huán)境描述:

    為了控制一盞燈,需要單片機(jī)提供一個(gè)做控制功能的開關(guān)量,這里不描述外部接口電路,只說(shuō)明當(dāng)單片機(jī)的P10腳為高電平時(shí),燈滅,當(dāng)P10腳為低電平時(shí),燈亮。

    可以通過(guò)計(jì)算機(jī)由串口發(fā)送命令來(lái)控制,或通過(guò)一個(gè)按鍵(push button不是自鎖式的按鍵)來(lái)手動(dòng)控制(按鍵接在P11腳上,當(dāng)鍵沒有按下時(shí),P11電平為高,鍵按下時(shí),引腳電平被接低),當(dāng)使用按鍵手動(dòng)控制的時(shí)候,需要給計(jì)算機(jī)發(fā)送通知。
設(shè)定串口通訊指令如下:

    數(shù)據(jù)包由0xff做包頭,4個(gè)字節(jié)長(zhǎng),第二個(gè)字節(jié)為命令代碼,第三個(gè)字節(jié)為數(shù)據(jù),最后一個(gè)字節(jié)為校驗(yàn)位。

    命令和數(shù)據(jù)代碼有如下組合:
(計(jì)算機(jī)發(fā)給單片機(jī))
0x10 0x01: 計(jì)算機(jī)控制燈亮。(數(shù)據(jù)位是非零值即可)
0x10 0x00: 計(jì)算機(jī)控制燈滅。
(單片機(jī)發(fā)給計(jì)算機(jī))
0x11 0x01:?jiǎn)纹瑱C(jī)正常執(zhí)行控制指令,返回。(數(shù)據(jù)位是非零值即可)
0x11 0x00: 單片機(jī)不能夠正常執(zhí)行控制指令,或控制指令錯(cuò)(不明含義的數(shù)據(jù)包或校驗(yàn)錯(cuò)等)。
0x12 0x01:手動(dòng)控制燈亮。(數(shù)據(jù)位是非零值即可)
0x12 0x00: 手動(dòng)控制燈滅。

建立工程:

    在硬盤上建立文件夾Projects,在Projects下建立Common文件夾及Example文件夾。將各模塊的頭文件及實(shí)現(xiàn)文件拷貝到Common文件夾下(推薦使用這樣的文件組織結(jié)構(gòu),其它工程也可以建立在Projects下,各工程共享Common文件夾中的代碼)。
啟動(dòng)KeilC的IDE,在Example下建立新工程,將各模塊的實(shí)現(xiàn)文件包含進(jìn)工程。

    在Example文件夾下建立Output文件夾,更改工程設(shè)置,將Output作為輸出文件和List文件的輸出文件夾(推薦使用這樣的結(jié)構(gòu),當(dāng)保存工程文件時(shí),可以簡(jiǎn)單的刪除Output文件夾中的內(nèi)容而不會(huì)誤刪有用的工程文件)。

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

輸入代碼:

代碼的具體編寫過(guò)程略。下面是最后的Config.h文件及Example.c文件。
//
// file: Config.h
//
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include <Atmel/At89x52.h> // 使用AT89C52做控制
#include “../Common/Common.h” // 使用自定義的數(shù)據(jù)類型
#define TIMER_RELOAD 922 // 11.0592MHz晶振,1ms中斷周期
#define TIMER_KBSCANDELAY 40 // 40ms重檢測(cè)按鍵狀態(tài),即40ms消抖
#define SCOMM_AsyncInterface // 使用異步通訊服務(wù)
#define IsPackageHeader(x) ((x) == 0xff) // 判斷包頭是不是0xff
#define IsPackageTailer(x, y, z) ((y) <= (z)) // 判斷包的長(zhǎng)度是不是足夠
#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”

BIT gbitLampState = 1 ; // 燈的狀態(tài),缺省為off

static void Initialize()
{
InitTimerModule() ; // 初始化時(shí)鐘模塊
InitSCommModule(0xfd, TRUE) ; // 初始化通訊模塊,11.0592MHz晶振,
// 波特率為19200
EA = 1; // 開中斷
}

void main()
{
Initialize() ; // 初始化
while(TRUE) // 主循環(huán)
{
ImpTimerService() ; // 實(shí)現(xiàn)時(shí)鐘中斷服務(wù),如鍵盤掃描
AsyncRecePackage(4) ; // 接收4個(gè)字節(jié)長(zhǎng)的數(shù)據(jù)包
}
}

// 在中斷外部響應(yīng)時(shí)鐘中斷事件
void OnTimerEvent() 
{
// do nothing
}

// 控制外部燈
static void TriggerLamp(BIT bEnable) 
{
P10 = ~bEnable ; // 需要反相控制
}

// 鍵掃描回調(diào)函數(shù)
BYTE KBScan() 
{
BIT b ;
P11 = 1 ; // 讀之前拉高引腳電平
b = P11 ; // 讀入引腳狀態(tài)
return ~b ; // 數(shù)據(jù)反相做掃描碼
}

// 計(jì)算校驗(yàn)和
static BYTE CalcCheckSum(BYTE* pbyBuf, BYTE byLen)
{
BYTE by, bySum = 0 ;
for(by = 0 ; by < byLen ; by++)
bySum += pbyBuf[by] ;
return 0 – bySum ;
}

// 接收到鍵盤消息回調(diào)函數(shù)
void onKeyPressed(BYTE byvalue, BYTE byState)
{
BYTE by[4] ;
if(byState == 0)
{
switch(byvalue)
{
case 0x01:
gbitLampState = ~g bitLampState ; // 燈狀態(tài)取反
TriggerLamp(gbitLampState) ; // 執(zhí)行控制
by[0] = 0xff ; // 構(gòu)造數(shù)據(jù)包
by[1] = 0x12 ;
by[2] = (BYTE)gbitLampState ;
by[3] = CalcCheckSum(by, 3) ; // 求校驗(yàn)和
SendPackage(by, 4) ; // 發(fā)送數(shù)據(jù)包
break ;
// 處理其它掃描碼
default:
break ;
}
}

// 接收到數(shù)據(jù)包回調(diào)函數(shù)
void OnRecePackage(BYTE* pbyBuf, BYTE byBufLen)
{
BYTE by[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) ; // 處理長(zhǎng)度或校驗(yàn)和不正確
}

switch(pbyBuf[1])
{
case 0x10:
gbitLampState = (BIT)pbyBuf[2] ;
TriggerLamp(gbitLampState) ;
by[2] = 1 ;
by[3] = CalcCheckSum(by, 3) ;
SendPackage(by, 4) ; // 發(fā)送成功執(zhí)行通知
break ;

default: // 不知道的命令
by[2] = 0 ;
by[3] = CalcCheckSum(by, 3) ;
SendPackage(by, 4) ; // 發(fā)送沒有成功執(zhí)行通知
break ;
}

 
  • 上一篇: C51語(yǔ)言應(yīng)用編程的若干問題
  • 下一篇: MSP430 按鍵程序范例(附原理圖)
  • 發(fā)表評(píng)論   告訴好友   打印此文  收藏此頁(yè)  關(guān)閉窗口  返回頂部
    熱點(diǎn)文章
     
    推薦文章
     
    相關(guān)文章
    網(wǎng)友評(píng)論:(只顯示最新5條。)
    關(guān)于我們 | 聯(lián)系我們 | 廣告合作 | 付款方式 | 使用幫助 | 機(jī)電之家 | 會(huì)員助手 | 免費(fèi)鏈接

    點(diǎn)擊這里給我發(fā)消息66821730(技術(shù)支持)點(diǎn)擊這里給我發(fā)消息66821730(廣告投放) 點(diǎn)擊這里給我發(fā)消息41031197(編輯) 點(diǎn)擊這里給我發(fā)消息58733127(審核)
    本站提供的機(jī)電設(shè)備,機(jī)電供求等信息由機(jī)電企業(yè)自行提供,該企業(yè)負(fù)責(zé)信息內(nèi)容的真實(shí)性、準(zhǔn)確性和合法性。
    機(jī)電之家對(duì)此不承擔(dān)任何保證責(zé)任,有侵犯您利益的地方請(qǐng)聯(lián)系機(jī)電之家,機(jī)電之家將及時(shí)作出處理。
    Copyright 2007 機(jī)電之家 Inc All Rights Reserved.機(jī)電之家-由機(jī)電一體化網(wǎng)更名-聲明
    電話:0571-87774297 傳真:0571-87774298
    杭州濱興科技有限公司提供技術(shù)支持

    主辦:杭州市高新區(qū)(濱江)機(jī)電一體化學(xué)會(huì)
    中國(guó)行業(yè)電子商務(wù)100強(qiáng)網(wǎng)站

    網(wǎng)站經(jīng)營(yíng)許可證:浙B2-20080178-1