|
事件標(biāo)志組 嵌入式事件標(biāo)志組是一種在嵌入式系統(tǒng)中廣泛使用的同步機(jī)制,主要用于實(shí)現(xiàn)多任務(wù)間的同步與通信。
事件標(biāo)志組是一組事件標(biāo)志位的集合,每個(gè)位代表一個(gè)事件是否發(fā)生。它允許任務(wù)等待特定的事件發(fā)生,當(dāng)事件發(fā)生時(shí),相關(guān)任務(wù)將被喚醒并執(zhí)行相應(yīng)的操作。
特點(diǎn) 靈活性:用戶可以根據(jù)需要自定義每個(gè)位事件的含義,如bit0表示按鍵是否按下。支持一對(duì)多、多對(duì)多的同步模式,即一個(gè)任務(wù)可以等待多個(gè)事件的發(fā)生,也可以是多個(gè)任務(wù)同步多個(gè)事件。高效性:使用位操作,效率高,占用資源少。擴(kuò)展性:雖然常用的是16位或32位無(wú)符號(hào)的數(shù)據(jù)類型來(lái)存儲(chǔ)事件標(biāo)志,但其中的高8位可能用作控制信息,低24位用作存儲(chǔ)事件標(biāo)志,因此可以存儲(chǔ)多個(gè)事件標(biāo)志。工作原理 等待事件:任務(wù)通過(guò)調(diào)用相應(yīng)的API函數(shù)(如FreeRTOS中的xEventGroupWaitBits)來(lái)等待一個(gè)或多個(gè)事件標(biāo)志位的發(fā)生?梢栽O(shè)置等待條件,如等待所有指定的事件標(biāo)志位都為1,或等待其中任意一個(gè)事件標(biāo)志位為1。觸發(fā)事件:當(dāng)事件發(fā)生時(shí),通過(guò)調(diào)用相應(yīng)的API函數(shù)(如FreeRTOS中的xEventGroupSetBits)來(lái)設(shè)置相應(yīng)的事件標(biāo)志位為1,從而觸發(fā)等待該事件的任務(wù)。喚醒所有符合條件的任務(wù),類似于“廣播”的作用。執(zhí)行任務(wù):被喚醒的任務(wù)根據(jù)事件標(biāo)志位的狀態(tài)執(zhí)行相應(yīng)的操作,并可以選擇是否清除事件標(biāo)志位。應(yīng)用場(chǎng)景 多任務(wù)同步:在需要多個(gè)任務(wù)協(xié)同工作的場(chǎng)景中,可以使用事件標(biāo)志組來(lái)同步這些任務(wù),但無(wú)數(shù)據(jù)傳輸。中斷處理:在中斷服務(wù)程序中設(shè)置事件標(biāo)志位,以通知主任務(wù)或其他任務(wù)進(jìn)行相應(yīng)的處理。狀態(tài)監(jiān)控:用于監(jiān)控系統(tǒng)的各種狀態(tài),如設(shè)備是否就緒、數(shù)據(jù)是否到達(dá)等。例子:在嵌入式系統(tǒng)中,處理USB數(shù)據(jù)的同步發(fā)送通常涉及多線程編程,并使用適當(dāng)?shù)耐綑C(jī)制來(lái)確保數(shù)據(jù)的一致性和完整性。在這種情況下,可以使用事件標(biāo)志和消息隊(duì)列來(lái)協(xié)調(diào)一個(gè)生產(chǎn)線程(生成USB數(shù)據(jù))和一個(gè)消費(fèi)線程(發(fā)送USB數(shù)據(jù))。
設(shè)計(jì)思路:
消息隊(duì)列:用于存儲(chǔ)從生產(chǎn)線程到消費(fèi)線程的數(shù)據(jù)。每個(gè)數(shù)據(jù)項(xiàng)可能是一個(gè)指向USB數(shù)據(jù)包緩沖區(qū)的指針或包含數(shù)據(jù)包信息的結(jié)構(gòu)體。事件標(biāo)志:用于通知消費(fèi)線程有新的數(shù)據(jù)可供處理,或者當(dāng)隊(duì)列為空時(shí)通知生產(chǎn)線程暫停生產(chǎn)。互斥鎖:保護(hù)消息隊(duì)列和事件標(biāo)志的訪問(wèn),防止競(jìng)態(tài)條件。
實(shí)現(xiàn)步驟:
1. 定義消息隊(duì)列和事件標(biāo)志使用RTOS提供的API來(lái)創(chuàng)建消息隊(duì)列和事件標(biāo)志。消息隊(duì)列應(yīng)能夠存儲(chǔ)指向USB數(shù)據(jù)包的指針或相關(guān)結(jié)構(gòu)體。2. 生產(chǎn)線程生產(chǎn)線程負(fù)責(zé)生成USB數(shù)據(jù),并將其放入消息隊(duì)列中。
void producer_thread(void *arg)
{
while (1)
{
// 生成USB數(shù)據(jù)包
usb_packet_t *packet = generate_usb_packet();
// 鎖定互斥鎖
rtos_mutex_lock(&mutex);
// 將數(shù)據(jù)包放入隊(duì)列
if (rtos_queue_send(&usb_queue, &packet, portMAX_DELAY) == pdPASS)
{
// 通知消費(fèi)線程有新數(shù)據(jù)
rtos_event_group_set_bits(&event_group, EVENT_BIT_DATA_READY);
}
// 解鎖互斥鎖
rtos_mutex_unlock(&mutex);
// 等待一段時(shí)間或根據(jù)其他條件繼續(xù)生成數(shù)據(jù)
vTaskDelay(pdMS_TO_TICKS(100));
}
}
3. 消費(fèi)線程消費(fèi)線程從消息隊(duì)列中取出數(shù)據(jù),并發(fā)送USB數(shù)據(jù)包。
void consumer_thread(void *arg)
{
usb_packet_t *packet;
while (1)
{
// 等待數(shù)據(jù)就緒事件
EventBits_t uxBits = xEventGroupWaitBits(
&event_group,
EVENT_BIT_DATA_READY,
pdTRUE,
pdFALSE,
portMAX_DELAY
);
if (uxBits & EVENT_BIT_DATA_READY)
{
// 鎖定互斥鎖
rtos_mutex_lock(&mutex);
// 從隊(duì)列接收數(shù)據(jù)包
if (rtos_queue_receive(&usb_queue, &packet, portMAX_DELAY) == pdPASS)
{
// 發(fā)送USB數(shù)據(jù)包
send_usb_packet(packet);
// 釋放數(shù)據(jù)包(如果需要)
free_usb_packet(packet);
}
// 解鎖互斥鎖
rtos_mutex_unlock(&mutex);
}
}
}
4. 初始化與啟動(dòng)創(chuàng)建消息隊(duì)列、事件標(biāo)志和互斥鎖,并啟動(dòng)生產(chǎn)者和消費(fèi)者線程。
void app_main(void)
{
// 初始化消息隊(duì)列、事件標(biāo)志和互斥鎖
rtos_queue_create(&usb_queue, ...);
rtos_event_group_create(&event_group);
rtos_mutex_create(&mutex);
// 創(chuàng)建并啟動(dòng)生產(chǎn)者和消費(fèi)者線程
xTaskCreate(producer_thread, "Producer", STACK_SIZE, NULL, PRIORITY, NULL);
xTaskCreate(consumer_thread, "Consumer", STACK_SIZE, NULL, PRIORITY, NULL);
// 其他初始化...
}
注意事項(xiàng) 在使用事件標(biāo)志組時(shí),需要注意避免競(jìng)態(tài)條件,確保任務(wù)間的同步與通信的正確性。合理安排事件標(biāo)志位的數(shù)量和使用方式,避免資源浪費(fèi)和效率低下。在設(shè)計(jì)系統(tǒng)時(shí),應(yīng)充分考慮任務(wù)間的依賴關(guān)系和同步需求,以選擇合適的同步機(jī)制。猜你喜歡:
WiFi6+藍(lán)牙+星閃,三合一開發(fā)板,真香!
Github上熱門 C 語(yǔ)言項(xiàng)目匯總!
嵌入式,可測(cè)試性軟件設(shè)計(jì)!
一些低功耗軟件設(shè)計(jì)的要點(diǎn)!
嵌入式 C 保護(hù)結(jié)構(gòu)體的方式
實(shí)用 | 10分鐘教你通過(guò)網(wǎng)頁(yè)點(diǎn)燈
談?wù)勄度胧杰浖募嫒菪裕?/strong>
分享一個(gè)嵌入式代碼生成器設(shè)計(jì)思路!
點(diǎn)擊閱讀原文,查看更多分享。 |
|