本帖最后由 leonbaichi 于 2011-9-1 19:27 编辑
好几天没登论坛。学习还处在原地。在看了神农之前的讲课后,自己对GPIO做个理解。书写如下,我觉得对于像我一样的新手还是比较方便马上看懂的。
程序是BSP中的smpl_drGPIO
神农:其实M系列的芯片,每一个管脚都可以作为中断引脚。他在每一组的PORT中,有一个寄存器,它用来保护一组PORT的中断,出了两个口。
该寄存器是GPIOA_ISRC(可读可写,具体读写的含义不同,读是查询是否中断,写中断的那位是清中断)具体可以参考数据手册,这边不赘述。
NUC1xx的芯片,讲IO的中断分成了两个源头,将IO的中断分成了两个源头,GPAB_IRQHandler和GPCDE_IRQHandler。也就是说,如果我设置了PA1作为中断输入,实际上我是进入了GPAB_IRQHandler这个源头,同样CDE的管脚中断会进入GPCDE_IRQHandler这个源头。
void GPAB_IRQHandler(void)
{
volatile uint32_t u32GPAStatus, u32GPBStatus;
/* Keep the interrupt source */
u32GPAStatus = GPIOA->ISRC;
u32GPBStatus = GPIOB->ISRC;
/* Avoid to clear EINT0/EINT1 INT flag */
u32GPBStatus = u32GPBStatus & ~(0x3 << 14);
/* Clear the interrupt */
GPIOA->ISRC = u32GPAStatus;
GPIOB->ISRC = u32GPBStatus; //进入中断当然要清楚标志位了
/* Call the callback function of GPIOAB interrupt */
if ( _pfGPABCallback )
_pfGPABCallback(u32GPAStatus, u32GPBStatus);
}
其中在同一个DrvGPIO.c文件中定义了该函数指针
static void (*_pfGPABCallback)(uint32_t u32GPAStatus, uint32_t u32GPBStatus);
所以if语句判断为真,执行之。
具体执行的是哪个函数呢,请往下看
void GPABCallback(uint32_t u32GpaStatus, uint32_t u32GpbStatus)
{
printf("GPAB Interrupt ! GPA:0x%04x GPB:0x%04x. \n", u32GpaStatus, u32GpbStatus);
}
然后它传递的方式呢,是通过以下这个函数在MAIN中的执行来进行传递的
void DrvGPIO_SetIntCallback(GPIO_GPAB_CALLBACK pfGPABCallback,GPIO_GPCDE_CALLBACK pfGPCDECallback);
它的具体实现:
void DrvGPIO_SetIntCallback(GPIO_GPAB_CALLBACK pfGPABCallback, GPIO_GPCDE_CALLBACK pfGPCDECallback)
{
_pfGPABCallback = (void (*)(uint32_t, uint32_t))pfGPABCallback;
_pfGPCDECallback = (void (*)(uint32_t, uint32_t, uint32_t))pfGPCDECallback;
}
看到了吧
其中红色部分,在DrvGPIO.H的头文件中又定义了一个跟
(*_pfGPABCallback)函数格式相同的typedef
typedef void (*GPIO_GPAB_CALLBACK)(uint32_t u32GPAStatus, uint32_t u32GPBStatus);
就为了传递那个要执行的函数参数。
至此,中断的流程细节应该就交代清楚了,虽然好像有点乱,但是对照那个BSP中的例程还是很清楚的。
另外,经常出现的类似于E_GPA,E_GPB......
DrvGPIO_EnableDebounce(E_GPA, 11);
定义原型为:
typedef enum
{
E_GPA = 0,
E_GPB = 1,
E_GPC = 2,
E_GPD = 3,
E_GPE = 4
} E_DRVGPIO_PORT;
在实际使用中,会做一个相对地址到实际地址的转换。
int32_t DrvGPIO_DisableDebounce(E_DRVGPIO_PORT port, int32_t i32Bit)
{
volatile uint32_t u32Reg;
u32Reg = (uint32_t)&GPIOA->DBEN + (port*PORT_OFFSET); //这边进行了转换。
outpw(u32Reg, inpw(u32Reg) & ~(1<<i32Bit));
GPIO_DBNCECON->DBNCECON.ICLK_ON = 0;
return E_SUCCESS;
}
添加附件:
|