只要在一个完善的系统上,必然会有中断,比如GPIO中断啊,SPI中断啊,当然这些怎么处理,首先系统就有中断在上面,所以我们需要一个更高优先级的中断.也就是配置的中断要被configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY高,另外还需要开启SYSCFG的时钟,具体GPIO配置如下,首先是LED的,不修改,然后是PA0按键,修改成普通的边沿检测.
GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOG, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOG, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
在FreeRTOS里面,中断处理就像Linux内核一样,有上半部分和下半部分,上半部分主要是保存一下标志位,关键数据,清除中断标志.而下半部分可就厉害多了,把各种要处理的都得处理完,下半部分不是在中断里面,而是一个独立的任务,只是优先级一般比较高了.这个下半部分,比普通Task高,比ISR低.
如何通知ISR下半的任务,一般就用信号量,其实可以理解成只有一个Byte的队列,深度是1,而且只能写1或者0.通过xSemaphoreGiveFromISR可以让信号量填满,然后用xSemaphoreTake来查看数据时候来了.当然信号量要预先创建的.使用vSemaphoreCreateBinary.
SemaphoreHandle_t xSemaphore; int main(void) { MGPIO_Init(); xSemaphore = xSemaphoreCreateBinary(); xTaskCreate( vTask1, ( const char * ) "vTask1", 1000, NULL, 1, NULL ); vTaskStartScheduler(); for(;;); }
然后发生中断时候,使用xSemaphoreGiveFromISR方法,来填写信号量,如果中断外使用,就是xSemaphoreGive,队列函数,他都有FromISR的方法,发送的xQueueSendToFrontFromISR和xQueueSendToBackFromISR,接受同理,然后使用portYIELD_FROM_ISR请求一次上下文切换,通常的结构是这样的.
void EXTI0_IRQHandler(void) { static BaseType_t xHigherPriorityTaskWoken; if(EXTI_GetITStatus(EXTI_Line0) != RESET) { EXTI_ClearITPendingBit(EXTI_Line0); xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } }
而这个触发,会使得xSemaphoreTake触发有效,xSemaphoreTake是允许在阻塞状态的,他有效后,就可以开始执行代%