STM32F429-DISCO 学习之FreeRTOS系统中断

/ 0评 / 0

只要在一个完善的系统上,必然会有中断,比如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是允许在阻塞状态的,他有效后,就可以开始执行代%