键盘作为收入设备,在嵌入式系统中应用广泛。它与PC键盘不同,嵌入式系统中的键盘千差万别,随实际应用的场景不同而不同。今天在这里介绍就是一种非标准键盘的驱动程序设计。在一些应用中,可能只会用到有限的几个按键。为了节省硬件成本,并充分利用既有的硬件资源,通常将这些按键连接到MCU的外部中断引脚上。如S3C2410有一百多个GPIO,几十个外部中断,我们就可以用几个外部中断来实现系统的按键功能。
虽然嵌入式系统中的键盘形形色色,各不相同,但驱动的框架基本一致。从工作模式的角度来看,一般有中断方式和扫描方式。在中断服务线程中读取按键的扫描码,并将其转换为虚拟按键信息发送给系统。采用扫描方式的过程与此类似。但如前所述的非标准键盘驱动就可不必采用该框架,而使用普通的中断处理方式,在中断服务线程中模拟相应的按键信息,调用函数keybd_event()即可。
下面以S3C2410的外部中断4为例,简单介绍一下整个处理过程。
Code
1UINT32 Irq1 = IRQ_EINT4;
2UINT32 SysIntr1 = SYSINTR_UNDEFINED;
3HANDLE IntrEvent1 = NULL;
4BOOL bThreadExit1 = FALSE;
5UINT IntrThreadProc1(LPVOID);
6//模拟按键
7void SimulateKey(BYTE bVk)
8{
9 keybd_event(bVk,0,0,0);
10 keybd_event(bVk,0,KEYEVENTF_KEYUP,0);
11}
12KEY_Init()中的关键代码:
13//初始化中断
14EnableInterrupt();
15//创建中断服务线程
16if(!CreateThread(0, 0, (LPTHREAD_START_ROUTINE)IntrThreadProc1,0,0,NULL))
17{
18 RETAILMSG(1, (TEXT("***KEYDrv: KEY_Init fail(1)。\r\n")));
19 return FALSE;
20}
21KEY_Deinit()中的关键代码:
22//设置退出线程的标志
23bThreadExit1 = TRUE;
24//模拟一个中断事件
25SetInterruptEvent(SysIntr1);
26//中断服务线程
27UINT IntrThreadProc1(LPVOID ptr)
28{
29 IntrEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
30
31 if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq1, sizeof(UINT32), &SysIntr1, sizeof(UINT32), NULL))
32 {
33 RETAILMSG(1, (TEXT("ERROR:IntrThreadProc1 Failed to request sysintr.\r\n")));
34 return(0);
35 }
36
37 //关联SYSINTR和之前创建的事件
38 if (!(InterruptInitialize(SysIntr1, IntrEvent1, 0, 0)))
39 {
40 RETAILMSG(1, (TEXT("ERROR: IntrThreadProc1 InterruptInitialize failed.\r\n")));
41 }
42
43 while(1)
44 {
45 WaitForSingleObject(IntrEvent1, INFINITE);
46
47 if(bThreadExit1)
48 {
49 break;
50 }
51
52 SimulateKey(VK_F1);
53 Sleep(1);
54 InterruptDone(SysIntr1);
55 }
56 //取消IRQ与SYSINTR之间的关联
57 KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR,&SysIntr1, sizeof(UINT32),NULL,0, NULL);
58 //取消Event与PwrButtonSysIntr之间的关联
59 InterruptDisable(SysIntr1);
60 CloseHandle(IntrEvent1);
61 RETAILMSG(1, (TEXT("IntrThreadProc1 IST Exit.\r\n")));