新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32 uCOS_II 實踐 之 外部中斷事件 及 系統運行過程

        STM32 uCOS_II 實踐 之 外部中斷事件 及 系統運行過程

        作者: 時間:2016-12-03 來源:網絡 收藏
        在進行uCOSII的程序之前先來復習下,裸機平臺下stm32的外部中斷的操作。

        大概可以分作4個步驟:1-配置相應管腳為浮空輸入;2-配置相應管腳為外部中斷口并設定其中斷屬性及參數;3-配置NVIC相關寄存器,設定中斷優先級;4-編寫中斷服務函數。廢話不說直接上代碼:

        本文引用地址:http://www.104case.com/article/201612/325150.htm

        第一步:配置相應管腳為浮空輸入,來自文件Key.c

        voidKey_Port_Configuration(void)
        {
        GPIO_InitTypeDefGPIO_InitStructure_EXTI_KEY_PORTE;

        GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_4;// 端口4
        GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING;// 浮空輸入
        GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz;// 口線翻轉速度為50MHz
        GPIO_Init(GPIOE,&GPIO_InitStructure_EXTI_KEY_PORTE);// 端口初始化

        GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_3;// 端口3
        GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING;// 浮空輸入
        GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz;// 口線翻轉速度為50MHz
        GPIO_Init(GPIOE,&GPIO_InitStructure_EXTI_KEY_PORTE);// 端口初始化
        }

        第二步:配置相應管腳為外部中斷口并且設定其中斷屬性及參數,來自文件EXTIG.c

        voidEXTI_PORTE_Configuration(void)
        {
        EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE4;
        EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE3;

        /* Connect EXTI Line4,3 to PE4,PE3 */
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);// 配置 管腳PE4用作外部中斷線路
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);// 配置 管腳PE3用作外部中斷線路

        /* Configure EXTI Line4 to generate an interrupt on falling edge */
        EXTI_InitStructure_EXTI_LINE4.EXTI_Line=EXTI_Line4;//配置 使能或失能的外部線路
        EXTI_InitStructure_EXTI_LINE4.EXTI_Mode=EXTI_Mode_Interrupt;//配置 EXTI線路為中斷請求 (或者是事件請求)
        EXTI_InitStructure_EXTI_LINE4.EXTI_Trigger=EXTI_Trigger_Falling;//配置 使能線路的觸發邊沿 -- 下降沿觸發中斷
        EXTI_InitStructure_EXTI_LINE4.EXTI_LineCmd=ENABLE;//配置 狀態為使能
        EXTI_Init(&EXTI_InitStructure_EXTI_LINE4);// 初始化外部中斷線路4

        /* Configure EXTI Line3 to generate an interrupt on falling edge */
        EXTI_InitStructure_EXTI_LINE3.EXTI_Line=EXTI_Line3;//配置 使能或失能的外部線路
        EXTI_InitStructure_EXTI_LINE3.EXTI_Mode=EXTI_Mode_Interrupt;//配置 EXTI線路為中斷請求 (或者是事件請求)
        EXTI_InitStructure_EXTI_LINE3.EXTI_Trigger=EXTI_Trigger_Falling;//配置 使能線路的觸發邊沿 -- 下降沿觸發中斷
        EXTI_InitStructure_EXTI_LINE3.EXTI_LineCmd=ENABLE;//配置 狀態為使能
        EXTI_Init(&EXTI_InitStructure_EXTI_LINE3);// 初始化外部中斷線路3

        /* Generate software interrupt: simulate a falling edge applied on EXTI line 13 */
        EXTI_GenerateSWInterrupt(EXTI_Line4);//線路4產生一個軟件中斷
        EXTI_GenerateSWInterrupt(EXTI_Line3);//線路3產生一個軟件中斷
        }

        第三步:配置NVIC相關寄存器,設定中斷優先級,來自文件SysInit.c

        voidNVIC_Configuration(void)
        {
        NVIC_InitTypeDefNVIC_InitStructure_EXTI_LINE;

        /* ================ NVIC-EXTI-PORTE ================= */
        /* Configure one bit for preemption priority */
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);// 配置優先級分組長度

        /* Enable the EXTI15_10 Interrupt */
        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI4_IRQn;// 配置使能指定的IRQ(Interrupt ReQuest中斷請求)通道
        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0;// 配置IRQ的 組 優先級
        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0;// 配置IRQ的 從 優先級
        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE;// 配置IRQ 使能
        NVIC_Init(&NVIC_InitStructure_EXTI_LINE);// 初始化 IRQ

        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI3_IRQn;// 配置使能指定的IRQ(Interrupt ReQuest中斷請求)通道
        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0;// 配置IRQ的 組 優先級
        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0;// 配置IRQ的 從 優先級
        NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE;// 配置IRQ 使能
        NVIC_Init(&NVIC_InitStructure_EXTI_LINE);// 初始化 IRQ
        }

        第四步:編寫中斷服務程序,來自文件stm32f10x_it.c

        voidEXTI3_IRQHandler(void)
        {
        if(EXTI_GetITStatus(EXTI_Line3)==SET)// 讀取中斷狀態
        {
        LED1_LOW;
        EXTI_ClearITPendingBit(EXTI_Line3);// 清除標志位
        }
        }
        voidEXTI4_IRQHandler(void)
        {
        if(EXTI_GetITStatus(EXTI_Line4)==SET)// 讀取中斷狀態
        {
        LED1_HIGH;
        EXTI_ClearITPendingBit(EXTI_Line4);// 清除標志位
        }
        }


        下面就要說說在uCOSII里的時候了。

        首先把上面所述步驟1,步驟2和步驟4的代碼放到KEY.C文件內,然后把步驟3的代碼加入SysInit.C文件內的 NVIC_Configuration()函數。步驟1,步驟2,和步驟3與沒有操作系統的代碼一致,都是最底層的東西。步驟4需要符合ucos的代碼規范,也要用到ucos的系統函數,如下面代碼:

        /*******************************************************************************
        * Function Name : Interrupt_Handle_KEY2
        * Description : 按鍵2中斷服務函數
        * Input : None
        * Output : None
        * Return : None
        *******************************************************************************/
        voidInterrupt_Handle_KEY2(void)
        {
        OSIntEnter();
        OSSemPost(Sem_Task_LED2);// 發送信號量,這個函數并不會引起系統調度,所以中斷服務函數一定要簡潔。
        EXTI_ClearITPendingBit(EXTI_Line4);// 清除標志位
        OSIntExit();
        }


        如代碼所示黃色高亮部分就是進入中斷和出中斷的ucos部分的代碼,在出中斷的時候會引起系統調度,然后最高優先級的任務會先執行,保證了系統的實時性。

        步驟1~3的代碼和上面類似就不一一列舉,系統運行過程如下:

        首先系統建立一個起始任務START,這個任務的優先級最低為10,他主要是做系統心跳的顯示,另外把其他需要的任務初始化。在例程里有另外兩個任務,分別是KEY1任務(優先級為9)和LED2任務(優先級為5)。先初始化KEY1任務,初始化函數結束后就跳到KEY1任務代碼處執行,當遇到OSTimeDlyHMSM()函數時,會引發系統調度,此時就兩個任務,所以肯定會回到起始任務START,然后初始化LED2任務,初始化函數結束后就跳到LED2任務代碼處執行,在這個任務中有等待信號量的函數,所以系統會自己掛起任務,系統再進行調度的時候也會執行這個掛起任務里的代碼。這時候如果按下按鍵,就會觸發中斷,在中斷函數里會有信號量發出來,在結束中斷的時候會有系統調度,此時系統會跳到請求信號量的斷點處去執行代碼,這一點體現了ucos的搶占性的特點,就是中斷的優先級都是凌駕與非中斷任務的,所以中斷里發出的信號量一定是要先相應的。然后系統就會遵循優先級高低進行系統調度。

        在這個例程里還有一個新的知識點就是計數信號量的使用。

        使用時分為4個步驟:

        1. 定義信號量指針void*Sem_Task_LED2;
        2. 創建信號量 Sem_Task_LED2 = OSSemCreate(0); // 函數里參數是指信號量的初始值
        3. 設置等待信號量 OSSemPend(Sem_Task_LED2,0,&err);
        4. 設置發送信號量OSSemPost(Sem_Task_LED2);

        這里創建信號量和設置等待信號量都是在任務LED2里,設置發送信號量在中斷服務函數里。見代碼:

        /*******************************************************************************
        * Function Name : Task_LED2
        * Description : LED2任務
        * Input : None
        * Output : None
        * Return : None
        *******************************************************************************/
        voidTask_LED2(void*p_arg)
        {
        (void)p_arg;
        Sem_Task_LED2=OSSemCreate(0);
        while(1)
        {
        OSSemPend(Sem_Task_LED2,0,&err);// 等待信號量
        LED2_HIGH;
        OSTimeDlyHMSM(0,0,1,0);
        LED2_LOW;
        OSTimeDlyHMSM(0,0,1,0);// 延時,用來給其他任務留有運行的時間
        }
        }

        這里要說一下注意點,首先定義的信號量指針是一個全局變量,需要在相應的頭文件里進行extern聲明,在這里是把他放在task.c文件里的。另外創建信號量和設置等待信號量函數都放在具體的任務中,因為在邏輯上,創建信號量和等待信號量函數肯定要早與發送信號量函數執行,因此在設置等待信號量之前去創建信號量是完全合適的,并且把創建信號量函數放在具體任務的while(1)上面,在創建函數的時候信號量就已經被創建了,然后代碼執行到等待信號量的時候任務就會被掛起,除非時間到或者有信號量來的話才會被執行。最后設置發送信號量,在這里發送信號量函數是放在中斷服務程序里的,因為發送信號量函數的執行并不會引起系統調度,只有在中斷服務函數執行完畢,出中斷函數的執行才會引發系統調度,所以中斷服務函數里的內容一定要精簡,否則就會影響系統的實時性。



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 慈溪市| 彰武县| 建德市| 浙江省| 大余县| 措美县| 鹿泉市| 福鼎市| 宕昌县| 南郑县| 类乌齐县| 苏尼特右旗| 洞口县| 龙里县| 宾川县| 巴林左旗| 佛教| 林西县| 阿荣旗| 潞西市| 灵宝市| 达尔| 获嘉县| 萍乡市| 鄂托克旗| 四川省| 靖江市| 江安县| 乌拉特前旗| 宣威市| 胶南市| 仁布县| 综艺| 原平市| 文登市| 海南省| 勐海县| 高雄县| 工布江达县| 阳泉市| 新平|