【教程】STM32 FreeRTOS實(shí)時(shí)系統(tǒng)移植系列1:FreeRTOS 二值信號(hào)量

1.寫(xiě)在前面:
?
本文章為《STM32MP157開(kāi)發(fā)教程之FreeRTOS操作系統(tǒng)篇》系列中的一篇,筆者使用的開(kāi)發(fā)平臺(tái)為華清遠(yuǎn)見(jiàn)FS-MP1A開(kāi)發(fā)板(STM32MP157開(kāi)發(fā)板)。stm32mp157是ARM雙核,2個(gè)A7核,1個(gè)M4核,A7核上可以跑Linux操作系統(tǒng),M4核上可以跑FreeRTOS、RT-Thread等實(shí)時(shí)操作系統(tǒng),STM32MP157開(kāi)發(fā)板所以既可以學(xué)嵌入式linux,也可以學(xué)stm32單片機(jī)。
針對(duì)FS-MP1A開(kāi)發(fā)板,除了FreeRTOS操作系統(tǒng)篇外,還包括其他多系列教程,包括Cortex-A7開(kāi)發(fā)篇、Cortex-M4開(kāi)發(fā)篇、擴(kuò)展板驅(qū)動(dòng)移植篇、Linux應(yīng)用開(kāi)發(fā)篇、Linux系統(tǒng)移植篇、Linux驅(qū)動(dòng)開(kāi)發(fā)篇、硬件設(shè)計(jì)篇、人工智能機(jī)器視覺(jué)篇、Qt應(yīng)用編程篇、Qt綜合項(xiàng)目實(shí)戰(zhàn)篇等。歡迎關(guān)注,更多stm32mp157開(kāi)發(fā)教程及視頻,可加技術(shù)交流Q群459754978,感謝關(guān)注。
FS-MP1A開(kāi)發(fā)板詳情介紹:https://item.taobao.com/item.htm?id=622457259672
2.FreeRTOS 二值信號(hào)量
2.1二值信號(hào)量簡(jiǎn)介
信號(hào)量實(shí)際上就是一個(gè)值,這個(gè)值被用來(lái)解決臨界區(qū)問(wèn)題以及實(shí)現(xiàn)進(jìn)程在多處理器環(huán)境下的進(jìn)程同步。
其中,兩個(gè)最重要的信號(hào)量為二進(jìn)制信號(hào)量和計(jì)數(shù)信號(hào)量,計(jì)數(shù)信號(hào)量可以表示為非負(fù)的整數(shù)而二進(jìn)制信號(hào)量只存在0和1兩個(gè)值。
二值信號(hào)量通常用于互斥訪問(wèn)或同步,二值信號(hào)量和互斥信號(hào)量非常類似,但是還是有一些細(xì)微的差別,互斥信號(hào)量擁有優(yōu)先級(jí)繼承機(jī)制,二值信號(hào)量沒(méi)有優(yōu)先級(jí)繼承。因此二值信號(hào)量更適合用于同步(任務(wù)與任務(wù)或任務(wù)與中斷的同步),
2.2二值信號(hào)量函數(shù)
2.2.1 創(chuàng)建信號(hào)量
對(duì)于二值信號(hào)量,若想使用,必須先創(chuàng)建二值信號(hào)量,在新版FreeRTOS中,一般使用xSemaphoreCreateBinary()函數(shù)動(dòng)態(tài)創(chuàng)建二值信號(hào)量。此函數(shù)是個(gè)宏,具體創(chuàng)建工程是由函數(shù)xQueueGenericCreate()完成。其函數(shù)原型如下:
SemaphoreHandle_t xSemaphoreCreateBinary(void)
參數(shù): 無(wú)
返回值:
NULL:二值信號(hào)量創(chuàng)建失敗
其他值:創(chuàng)建成功的二值信號(hào)量的句柄
2.2.2 釋放信號(hào)量
釋放信號(hào)量的函數(shù)有兩個(gè),分別如下:
任務(wù)級(jí)信號(hào)量釋放函數(shù) xSemaphoreGive(),此函數(shù)是個(gè)宏,可以用于釋放二值信號(hào)量、計(jì)數(shù)型信號(hào)量或互斥信號(hào)量,其函數(shù)原型如下:
BaseType_t xSemaphoreGive(xSemaphore)
參數(shù):
xSemaphore:要釋放的信號(hào)量句柄
返回值:
PdPASS:釋放信號(hào)量成功
PdQUEUE_FULL:釋放信號(hào)量失敗
中斷級(jí)信號(hào)量釋放函數(shù) xSemaphoreGiveFromISR(),此函數(shù)也是個(gè)宏,只能用來(lái)釋放二值信號(hào)量和計(jì)數(shù)型信號(hào)量,其函數(shù)原型如下:
BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t* pxHigherPriorityTaskWoken)
參數(shù):
xSemaphore:要釋放的信號(hào)量句柄
pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)以后是否進(jìn)行任務(wù)切換
返回值:
PdPASS:釋放信號(hào)量成功
PdQUEUE_FULL:釋放信號(hào)量失敗
2.2.3 獲取信號(hào)量
獲取信號(hào)量的函數(shù)也有兩個(gè),分別如下:
任務(wù)級(jí)信號(hào)量獲取函數(shù)xSemaphoreTake(),此函數(shù)也是個(gè)宏,可以獲取二值信號(hào)量、計(jì)數(shù)型信號(hào)量和互斥信號(hào)量,其函數(shù)原型如下:
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,
TickType_t xBlockTime)
參數(shù):
xSemaphore:要獲取的信號(hào)量句柄
xBlockTime:阻塞時(shí)間
返回值:
pdTRUE:獲取信號(hào)量成功
pdFALSE:超時(shí),獲取信號(hào)量失敗
中斷級(jí)信號(hào)量獲取函數(shù) xSemaphoreTakeFromISR(),此函數(shù)也是個(gè)宏,只能獲取二值信號(hào)量和計(jì)數(shù)型信號(hào)量,其函數(shù)原型如下:
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t* pxHigherPriorityTaskWoken)
參數(shù):
xSemaphore:要獲取的信號(hào)量句柄
pxHigherPriorityTaskWoken:標(biāo)記退出此函數(shù)以后是否進(jìn)行任務(wù)切換
返回值:
PdPASS:獲取信號(hào)量成功
pdFALSE:獲取信號(hào)量失敗
2.3操作實(shí)驗(yàn)
2.3.1實(shí)驗(yàn)設(shè)計(jì)
二值信號(hào)量可以實(shí)現(xiàn)任務(wù)與任務(wù)之間或者任務(wù)與中斷之間的同步,在本節(jié)實(shí)驗(yàn)中,通過(guò)按鍵中斷來(lái)控制LED燈的亮滅來(lái)實(shí)現(xiàn)任務(wù)與中斷之間的同步。
在本實(shí)驗(yàn)中,共創(chuàng)建了兩個(gè)任務(wù),其中一個(gè)任務(wù)每隔一秒讓LED3電平翻轉(zhuǎn),來(lái)表示程序可以正常運(yùn)行,另外一個(gè)任務(wù)根據(jù)中斷中傳來(lái)的指令來(lái)控制不同LED燈的亮滅。
當(dāng)按鍵按下時(shí),進(jìn)入中斷,在中斷中同時(shí)同時(shí)釋放二值信號(hào)量,任務(wù)StartTask02()會(huì)一直嘗試獲取二值信號(hào)量,當(dāng)獲取到信號(hào)量后就會(huì)根據(jù)中斷中的指令進(jìn)而控制不同的LED燈發(fā)生亮滅。
任務(wù)及其功能如下:
StartDefaultTask():控制LED3閃爍,提示系統(tǒng)正在運(yùn)行。
StartTask02():進(jìn)行指令處理,根據(jù)接收的指令控制不同的LED燈。
2.3.2實(shí)驗(yàn)過(guò)程與分析
首先,根據(jù)之前幾章內(nèi)容配置好KEY、UART4、LED燈,切換到中間件“Middleware”的“FREERTOS”,默認(rèn)自動(dòng)勾選給M4了,然后接口“Interface”選擇“CMSIS_V2”。初次接觸,下面的參數(shù)大部分默認(rèn)即可,為了運(yùn)行其它任務(wù),這里需要切換到“Tasks and Queues”標(biāo)簽,可以看到默認(rèn)有個(gè)“defaultTask”任務(wù),我們?cè)冱c(diǎn)擊“Add”再新增一個(gè)任務(wù),如所示。

隨后生成初始化代碼,會(huì)彈出Systick被FreeRTOS占用,建議HAL庫(kù)時(shí)鐘基準(zhǔn)源換成其它。之后FreeRTOS實(shí)驗(yàn)?zāi)J(rèn)為此配置。
上述為新建工程配置過(guò)程,可參考12.3.2章節(jié)進(jìn)行導(dǎo)入已有工程,工程存放路徑【華清遠(yuǎn)見(jiàn)-FS-MP1A開(kāi)發(fā)資料\02-程序源碼\ARM體系結(jié)構(gòu)與接口技術(shù)\FreeRTOS\1_FS-MP1A-FreeRTOS】
生成代碼后,找到“main.c”,結(jié)尾部分會(huì)有兩個(gè)任務(wù)函數(shù),分別是“StartDefaultTask()”和“StartTask02()”。兩個(gè)任務(wù)宏觀看同時(shí)、獨(dú)立運(yùn)行,互不干擾。在“StartDefaultTask()”實(shí)現(xiàn)LED3每隔一秒閃爍,在“StartTask02()”中實(shí)現(xiàn)根據(jù)不同的指令控制不同LED燈亮滅。


在本次實(shí)驗(yàn)中,釋放信號(hào)量在中斷中進(jìn)行,每進(jìn)行一次按鍵按下,就釋放一次信號(hào)量。在StartTask02任務(wù)中循環(huán)檢測(cè)信號(hào)量,當(dāng)在中斷中釋放信號(hào)量以后,便可以獲取到信號(hào)量,然后根據(jù)指令進(jìn)行控制,按鍵1或按鍵2按下時(shí),分別控制LED1或LED2點(diǎn)亮,按鍵3按下時(shí),控制LED1和LED2熄滅。