网上有很多wince中断处理的过程讲解,内容虽然充实,但是不免有些枯燥。本文将以实例的方式讲解wince6.0的中断处理过程。让初学者像学51中断一样简单明了。 看完wince中断的过程我们有了一个大致的了解,从结构上看,可分为4层硬件层、内核层、OAL层、IST处理层。 ① 硬件层就是我们GPIO引脚设计 ② 内核层就内核处理层 ③ OAL层其实就是一个中转层 ④ IST层是实际我们去处理中断事件的层 从程序上分可以分为如下几部: 1. 初始化GPIO口
2、 创建事件
3、 获取IRQ的系统中断号
4、 创建挂起的中断服务线程IST
5、 调用InterruptInitialize以创建IRQ与事件之间的关联。(创建未挂起的中断服务线程有可能导致InterruptInitialize函数调用失败,因为该事件已经处于等待状态)
6、 调用CeSetThreadPriority函数设置IST的优先级
7、 启动IST线程
在这里我就不再创建一个新的驱动了,因为前面也应有过创建新驱动的步骤。我将以led的驱动为前提进行修改,最后可以用一个按键控制一盏灯的亮灭. 首先我们打开飞凌提供的bsp,打开led.cpp。 1.在头文件与驱动入口函数之间加上如下代码: HANDLE KeyThread[6]; //声明按键线程可以声明6个 HANDLE KeyEvent[6]; //声明的按键事件,为6个 UINT32 g_KeySysIntr[6]; //按键逻辑中断号 UCHAR flag_led = 0; //led亮灭标志位 // GPIO virtual address static volatile S3C6410_GPIO_REG *v_pIOPregs ; static volatile S3C6410_VIC_REG *g_pVIC0Reg; 2.写初始化gpio的代码: BOOL KeyGpioInit() { RETAILMSG(1,(TEXT("Key_Gpio_Setting----\r\n"))); v_pIOPregs->GPNPUD &= ~(0x0fff); //设置按键的各个gpio为中断 v_pIOPregs->GPNCON &= ~(0x0fff); v_pIOPregs->GPNCON |= 0xaaa; v_pIOPregs->EINT0CON0 &= ~(0x0fff); v_pIOPregs->EINT0CON0 |= ~(0x0222); //使能按键中断位 v_pIOPregs->EINT0MASK &= ~(0x3f); return 1; } 根据6410数据手册,给下列各个寄存器赋值,如果初学者不能很好的掌握寄存器的控制,可以用RETAILMSG(1,(TEXT("******* v_pIOPregs->GPNCON = %x\r\n"),v_pIOPregs->GPNCON )); 这个函数可与打印出该寄存器的值。 3.物理中断映射成系统中断号,创建中断事件及中断处理线程: 在led—init函数中加上如下代码: DWORD threadID[6]; g_pVIC0Reg=(volatileS3C6410_VIC_REG*)DrvLib_MapIoSpace(S3C6410_BASE_REG_PA_VIC0,sizeof(S3C6410_VIC_REG),FALSE); KeyGpioInit() ; //创建IST线程 KeyThread[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FLKProcessThread0, 0, 0, &threadID[0]); if (NULL == KeyThread[0] ) { RETAILMSG(1,(TEXT("ERROR: failed to Create Key Thread!\r\n"))); return FALSE; }
创建总线程:总线程名称必须和上面创建线程的名称一致,下面各个函数用户可以上网查看,特别是各个参数的意思。 DWORD FLKProcessThread0(void) { UINT32 IRQ; //创建事件,后面与中断关联 KeyEvent[0] = CreateEvent(NULL, FALSE, FALSE, NULL); if (!KeyEvent[0]) { RETAILMSG(1, (TEXT("ERROR: FLK: Failed to create event.\r\n"))); return FALSE; } //动态申请外部中断 IRQ = IRQ_EINT0; //物理中断号 if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &IRQ, sizeof(UINT32), &g_KeySysIntr[0], sizeof(UINT32), NULL)) { RETAILMSG(1, (TEXT("ERROR: kEYBD: Failed to request sysintr value.\r\n"))); return FALSE; } //初始化中断,关联逻辑中断号与事件 if (!InterruptInitialize(g_KeySysIntr[0], KeyEvent[0], NULL, 0)) { RETAILMSG(1,(TEXT("Fail to initialize userkey interrupt event\r\n"))); return FALSE; } while(1) { //等待事件发生 WaitForSingleObject(KeyEvent[0], INFINITE); //处理外部中断 if (flag_led == 0) { v_pIOPregs->GPMCON&=(~(0x0f<<4)); v_pIOPregs->GPMCON|=0x1<<4; v_pIOPregs->GPMDAT|=(0x01<<1); OutputDebugString(L"Led1 Open- LED IO Control\n"); } else { v_pIOPregs->GPMCON&=(~(0x0f<<4)); v_pIOPregs->GPMCON|=0x1<<4; v_pIOPregs->GPMDAT&=~(0x01<<1); OutputDebugString(L"Led1 Close- LED IO Control\n"); } flag_led = !flag_led; InterruptDone(g_KeySysIntr[0]);//完成中断 } } 4.保存led.cpp,然后右击led工程文件选择 rebuild,从新烧写,成功后,就可以看到,当按下按键后,led灯亮了。剩下的几个按键用户可以自己去试着做! |