FreeRTOS系統-二值信號量的使用
提示:以下文章基於FreeRTOS全部移植完成,能夠正常運行.
文章目錄
前言
FreeRTOS系統的引入可以極大的提高程序的運行效率,搭建的框架也提高了程序的易寫性,提高編程效率.
在使用FreeRTOS系統的過程中,筆者發現GPIO觸發外部中斷,在中斷服務函數中做一個Delay_ms(20)的延時消抖時,會導致FreeRTOS系統停止工作,這樣會導致系統效率降低更嚴重的情況會導致一些需要實時性的功能斷層.
一、FreeRTOS系統的中斷管理?
configLIBRARY_LOWEST_INTERRUPT_PRIORITY]
這個宏是可以定義的中斷最低優先級,由於STM32中斷管理只用了4位來分配搶佔優先級和子優先級,並且FreeRTOS使用優先級分組4(沒有子優先級),所以該宏設爲15
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
這個宏是系統可管理的最高中斷優先級,即爲一個閾值,低於該值的可以調用一些fromISR的函數。高於該優先級的中斷則不響應打開和關斷中斷(一直都可以進行中斷操作)。
configKERNEL_INTERRUPT_PRIORITY
這個宏定義是( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
,實質上就是把15左移4位當作真正的優先級。(因爲第四位保留了)
configMAX_SYSCALL_INTERRUPT_PRIORITY
相當於( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
,原因與configKERNEL_INTERRUPT_PRIORITY
相同。
經過對上面configLIBRARY_LOWEST_INTERRUPT_PRIORITY]
與configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
的宏定義便確定了在這個優先級範圍內能夠調用FreeRTOS系統的API了。
這個優先級範圍的確定,接下來我們在外部中斷的優先級定義就必須在此範圍內,否則FreeRTOS的API的調用在中斷服務函數中卡死。
二、二值信號量
1.二值信號量介紹
二值型信號量可以理解爲任務與中斷間或者兩個任務間的標誌,該標誌非“滿”即“空”。Give操作相當把該標誌置“滿”,Take操作相關與把該標誌取"空",經過send和receive操作實現任務與中斷間或者兩任務的操作同步。
需要用到的頭文件
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
創建信號量
函數 | 描述 |
---|---|
xSemaphoreCreateBinary() | 動態創建二值信號量 |
vSemaphoreCreateBinaryStatic() | 靜態創建二值信號量 |
使用(示例):
SemaphoreHandle_t Semaphore_Exit1 = NULL;//聲明變量 用來接收創建二值信號量的句柄
Semaphore_Exit1 = xSemaphoreCreateBinary();//創建外部中斷1 二值信號量
釋放信號量
函數 | 描述 |
---|---|
xSemaphoreGive() | 任務級釋放二值信號量 |
xSemaphoreGiveFromISR() | 中斷中釋放二值信號量 |
以上兩個釋放二值信號量的函數,需用戶根據自己的使用環境進行選擇。在中斷服務函數中一定選擇 xSemaphoreGiveFromISR()
使用(示例):
//在外部1中釋放Semaphore_Exit1二值信號量
//參數1:傳入你要釋放的二值信號量的句柄,也就是你創建二值信號量的返回值
//參數2:默認NULL
void EXTI_1_Triggered_Mptor1_Stop(void)
{
xSemaphoreGiveFromISR( Semaphore_Exit1, NULL );//發送二值信號量
}
獲取信號量
函數 | 描述 |
---|---|
xSemaphoreTake() | 任務級獲得二值信號量 |
xSemaphoreTakeFromISR() | 中斷級獲得二值信號量 |
以上兩個獲取二值信號量的函數,需用戶根據自己的使用環境進行選擇,與釋放二值信號量配套使用。
使用(示例):
//創建一個任務進行對二值信號量的獲取判斷,獲取後進行操作,未獲取則進行等待,並釋放資源使其他任務繼續進行。
void Exit1_Irq_task(void *pvParameters)
{
while (1)
{
//參數1:需要獲取的二值信號量句柄
//參數2:等待時間 portMAX_DELAY爲永久等待
//返回值:成功返回1 失敗返回 0
if(pdTRUE == xSemaphoreTake(Semaphore_Exit1,portMAX_DELAY))//等待二值信號量 永久等待
{
vTaskDelay(20);//FreeRTOS的延時是一種阻塞態並不會佔用系統資源
/********/
省略代碼
/*******/
}
}
}
2.使用指南
思路說明:在一個外部中斷服務函數中釋放二值信號量,創建一個任務進行等待二值信號量的到來,在任務中進行操作,這樣極大的減少了在系統中斷中停留的時間。使得系統運行效率大大提高。
代碼如下(示例):
SemaphoreHandle_t Semaphore_Exit1 = NULL;//聲明變量 用來接收創建二值信號量的句柄
Semaphore_Exit1 = xSemaphoreCreateBinary();//創建外部中斷1 二值信號量
void FreeRTOS_Exec()
{
//創建二值信號量獲取後的處理任務
xTaskCreate((TaskFunction_t )Exit1_Irq_task,
(const char* )"Exit1_Irq_task",
(uint16_t )EXIT1_TRQ_STK_SIZE,
(void* )NULL,
(UBaseType_t )EXIT1_IRQ_TASK_PRIO,
(TaskHandle_t* )&Exit1_Irq_Task_Handler);
vTaskStartScheduler(); //開啓任務調度
}
//創建一個任務進行對二值信號量的獲取判斷,獲取後進行操作,未獲取則進行等待,並釋放資源使其他任務繼續進行。
void Exit1_Irq_task(void *pvParameters)
{
while (1)
{
//參數1:需要獲取的二值信號量句柄
//參數2:等待時間 portMAX_DELAY爲永久等待
//返回值:成功返回1 失敗返回 0
if(pdTRUE == xSemaphoreTake(Semaphore_Exit1,portMAX_DELAY))//等待二值信號量 永久等待
{
vTaskDelay(20);//FreeRTOS的延時是一種阻塞態並不會佔用系統資源
/********/
省略代碼
/*******/
}
}
}
//在外部中斷1中釋放Semaphore_Exit1二值信號量
//參數1:傳入你要釋放的二值信號量的句柄,也就是你創建二值信號量的返回值
//參數2:默認NULL
void EXTI_1_Triggered_Mptor1_Stop(void)
{
xSemaphoreGiveFromISR( Semaphore_Exit1, NULL );//發送二值信號量
}
總結
[1].任務的優先級以及分配的空間大小需要適合。
[2].中斷中發送信號量儘量使用xSemaphoreGiveFromISR。
[3]釋放信號量的中斷的優先級數值應大configMAX_SYSCALL_INTERRUPT_PRIORITY
。