日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FreeRTOS协程

發(fā)布時間:2025/3/15 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FreeRTOS协程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

FreeRTOS的協(xié)程,實(shí)際上是線程并發(fā)出來的。從協(xié)程控制塊中沒有棧空間就能夠知道,每個線程并發(fā)出來的協(xié)程共用一個棧空間。

/* 協(xié)程控制塊 */ typedef struct corCoRoutineControlBlock {crCOROUTINE_CODE pxCoRoutineFunction; /* 協(xié)程函數(shù)指針 */ListItem_t xGenericListItem; /* 狀態(tài)列表項 */ListItem_t xEventListItem; /* 事件列表項 */UBaseType_t uxPriority; /* 協(xié)程優(yōu)先級 */UBaseType_t uxIndex; /* 協(xié)程ID,區(qū)別不同協(xié)程調(diào)用相同函數(shù) */uint16_t uxState; /* 協(xié)程狀態(tài) */ }CRCB_t;

?

?

創(chuàng)建協(xié)程

/* 創(chuàng)建協(xié)程 */ BaseType_t xCoRoutineCreate(crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex) {BaseType_t xReturn;CRCB_t *pxCoRoutine;/* 為協(xié)程控制塊申請內(nèi)存空間 */pxCoRoutine = (CRCB_t *)pvPortMalloc(sizeof(CRCB_t));if(pxCoRoutine){/* 當(dāng)前協(xié)程為空 */if(pxCurrentCoRoutine == NULL){/* 將該協(xié)程設(shè)為當(dāng)前協(xié)程 */pxCurrentCoRoutine = pxCoRoutine;/* 初始化協(xié)程列表 */prvInitialiseCoRoutineLists();}/* 初始化協(xié)程優(yōu)先級 */if(uxPriority >= configMAX_CO_ROUTINE_PRIORITIES){uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;}/* 協(xié)程狀態(tài) */pxCoRoutine->uxState = corINITIAL_STATE;/* 協(xié)程優(yōu)先級 */pxCoRoutine->uxPriority = uxPriority;/* 協(xié)程ID */pxCoRoutine->uxIndex = uxIndex;/* 協(xié)程函數(shù)指針 */pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;/* 初始化協(xié)程狀態(tài)列表項 */vListInitialiseItem(&(pxCoRoutine->xGenericListItem));/* 初始化協(xié)程事件列表項 */vListInitialiseItem(&(pxCoRoutine->xEventListItem));/* 將協(xié)程狀態(tài)列表項所屬協(xié)程設(shè)為該協(xié)程 */listSET_LIST_ITEM_OWNER(&(pxCoRoutine->xGenericListItem), pxCoRoutine);/* 將協(xié)程事件列表項所屬協(xié)程設(shè)為該協(xié)程 */listSET_LIST_ITEM_OWNER(&(pxCoRoutine->xEventListItem), pxCoRoutine);/* 設(shè)置協(xié)程事件列表項值為協(xié)程優(yōu)先級 */listSET_LIST_ITEM_VALUE(&(pxCoRoutine->xEventListItem), ((TickType_t)configMAX_CO_ROUTINE_PRIORITIES - (TickType_t)uxPriority));/* 將協(xié)程掛接到就緒協(xié)程列表中 */prvAddCoRoutineToReadyQueue(pxCoRoutine);/* 返回成功 */xReturn = pdPASS;}/* 內(nèi)存不足 */else{xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;}return xReturn; }

?

?

協(xié)程調(diào)度

從代碼中可以看出,調(diào)度協(xié)程本質(zhì)上就是查找超時的協(xié)程將其轉(zhuǎn)為就緒,然后調(diào)用協(xié)程。

也就是說vCoRoutineSchedule函數(shù)應(yīng)該被任務(wù)循環(huán)調(diào)用。

/* 協(xié)程調(diào)度器 */ void vCoRoutineSchedule(void) {/* 檢查掛起時進(jìn)入就緒的協(xié)程列表,并將協(xié)程轉(zhuǎn)移到就緒列表 */prvCheckPendingReadyList();/* 檢查延時列表,如果有協(xié)程超時則掛接到就緒列表 */prvCheckDelayedList();/* 檢查所有就緒列表,是否有協(xié)程就緒 */while(listLIST_IS_EMPTY(&(pxReadyCoRoutineLists[uxTopCoRoutineReadyPriority]))){/* 沒有協(xié)程就緒直接退出 */if(uxTopCoRoutineReadyPriority == 0){return;}--uxTopCoRoutineReadyPriority;}/* 取出最高優(yōu)先級的就緒協(xié)程 */listGET_OWNER_OF_NEXT_ENTRY(pxCurrentCoRoutine, &(pxReadyCoRoutineLists[uxTopCoRoutineReadyPriority]));/* 運(yùn)行協(xié)程 */(pxCurrentCoRoutine->pxCoRoutineFunction)(pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex);return; }

?

?

協(xié)程調(diào)用方式

協(xié)程調(diào)用是有一定格式的,主要有三個宏:crSTART、crEND和crDELAY

void vACoRoutine(CoRoutineHandle_t xHandle, UBaseType_t uxIndex) {static int32_t ulAVariable;static const TickType_t xDelayTime = 200 / portTICK_PERIOD_MS;crSTART(xHandle);for(;;){crDELAY(xHandle, xDelayTime);/* 應(yīng)用程序 */}crEND(); }

將宏展開,可以看出每次調(diào)用協(xié)程會先運(yùn)行應(yīng)用程序,然后將協(xié)程掛接到延時列表,最后退出協(xié)程

void vACoRoutine(CoRoutineHandle_t xHandle, UBaseType_t uxIndex) {static int32_t ulAVariable;static const TickType_t xDelayTime = 200 / portTICK_PERIOD_MS;switch(((CRCB_t *)(xHandle))->uxState) {case 0:;for(;;){/* 延時時間大于0 */if((xDelayTime) > 0){/* 將協(xié)程掛接到延時列表 */vCoRoutineAddToDelayedList((xDelayTime), NULL);}/* 設(shè)置協(xié)程狀態(tài) */((CRCB_t *)(xHandle))->uxState = (__LINE__ * 2); /* 退出協(xié)程,延時結(jié)束之后直接進(jìn)入應(yīng)用程序 */return;/* 應(yīng)用程序,運(yùn)行完之后因為for循環(huán)的存在,下一輪又開始延時 */case (__LINE__ * 2):;/* 應(yīng)用程序 */}}; }

?

?

協(xié)程間通信

同一任務(wù)并發(fā)出來的協(xié)程,直接使用全局變量即可,不存在共享數(shù)據(jù)的完整性問題。但是不同任務(wù)并發(fā)出來的協(xié)程之間,如果需要通信,則需要考慮共享數(shù)據(jù)的完整性問題。FreeRTOS為協(xié)程提供了專門的隊列通信API,只能用于協(xié)程之間通信,不能用于線程和協(xié)程之間通信。

發(fā)送隊列消息,是一個宏定義

/* 發(fā)送隊列消息 */ #define crQUEUE_SEND(xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult) \ { \*(pxResult) = xQueueCRSend((pxQueue), (pvItemToQueue), (xTicksToWait)); \if(*(pxResult) == errQUEUE_BLOCKED) \{ \crSET_STATE0((xHandle)); \*pxResult = xQueueCRSend((pxQueue), (pvItemToQueue), 0); \} \if(*pxResult == errQUEUE_YIELD) \{ \crSET_STATE1((xHandle)); \*pxResult = pdPASS; \} \ }

將宏定義完全展開

switch(((CRCB_t *)(xHandle))->uxState) {case 0:;for(;;){ /這一段是展開//* 發(fā)送隊列消息 */*(pxResult) = xQueueCRSend((pxQueue), (pvItemToQueue), (xTicksToWait));/* 阻塞 */if(*(pxResult) == errQUEUE_BLOCKED){/* 設(shè)置協(xié)程狀態(tài) */((CRCB_t *)(xHandle))->uxState = (__LINE__ * 2); /* 退出協(xié)程,阻塞結(jié)束之后,直接進(jìn)入(__LINE__ * 2) */return;case (__LINE__ * 2):;/* 退出阻塞,意味著發(fā)送成功或者超時 */*pxResult = xQueueCRSend((pxQueue), (pvItemToQueue), 0);}/* 請求切換協(xié)程,也意味著發(fā)送成功 */if(*pxResult == errQUEUE_YIELD){/* 設(shè)置協(xié)程狀態(tài) */((CRCB_t *)(xHandle))->uxState = ((__LINE__ * 2)+1);/* 退出協(xié)程,下次直接進(jìn)入((__LINE__ * 2)+1),然后進(jìn)入應(yīng)用程序 */return; case ((__LINE__ * 2)+1):;*pxResult = pdPASS;}; //* 應(yīng)用程序 */} };

真正用于發(fā)送隊列消息的函數(shù)為xQueueCRSend

/* 協(xié)程發(fā)送隊列消息 */ BaseType_t xQueueCRSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait) {BaseType_t xReturn;Queue_t *const pxQueue = xQueue;/* 禁止中斷 */portDISABLE_INTERRUPTS();{/* 判斷隊列是否已滿,已滿 */if(prvIsQueueFull(pxQueue) != pdFALSE){/* 等待時間大于0 */if(xTicksToWait > (TickType_t)0){/* 將協(xié)程掛接到延時列表中 */vCoRoutineAddToDelayedList(xTicksToWait, &(pxQueue->xTasksWaitingToSend));/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();/* 返回阻塞 */return errQUEUE_BLOCKED;}/* 等待時間不大于0 */else{/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();/* 返回錯誤 */return errQUEUE_FULL;}}}/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();/* 運(yùn)行到這兒說明解除阻塞或者隊列中有位置 *//* 禁止中斷 */portDISABLE_INTERRUPTS();{/* 隊列項數(shù)小于隊列長度 */if(pxQueue->uxMessagesWaiting < pxQueue->uxLength){/* 將數(shù)據(jù)拷貝到隊列中 */prvCopyDataToQueue(pxQueue, pvItemToQueue, queueSEND_TO_BACK);/* 返回成功 */xReturn = pdPASS;/* 判斷是否存在因等待消息而阻塞的協(xié)程,有 */if(listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive)) == pdFALSE){/* 將協(xié)程從事件列表中移除 */if(xCoRoutineRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE){/* 請求切換協(xié)程 */xReturn = errQUEUE_YIELD;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}/* 隊列已滿 */else{/* 返回錯誤 */xReturn = errQUEUE_FULL;}}/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();return xReturn; }

?

接收隊列消息

/* 接收隊列消息 */ #define crQUEUE_RECEIVE(xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult) \ { \*(pxResult) = xQueueCRReceive((pxQueue), (pvBuffer), (xTicksToWait)); \if(*(pxResult) == errQUEUE_BLOCKED) \{ \crSET_STATE0((xHandle)); \*(pxResult) = xQueueCRReceive((pxQueue), (pvBuffer), 0); \} \if(*(pxResult) == errQUEUE_YIELD) \{ \crSET_STATE1((xHandle)); \*(pxResult) = pdPASS; \} \ }

將宏定義完全展開

switch(((CRCB_t *)(xHandle))->uxState) {case 0:;for(;;){/* 接收隊列消息 */*(pxResult) = xQueueCRReceive((pxQueue), (pvBuffer), (xTicksToWait));/* 阻塞 */if(*(pxResult) == errQUEUE_BLOCKED){/* 設(shè)置協(xié)程狀態(tài) */((CRCB_t *)(xHandle))->uxState = (__LINE__ * 2);/* 退出協(xié)程,解除阻塞之后直接進(jìn)入(__LINE__ * 2) */ return; case (__LINE__ * 2):;/* 運(yùn)行到這里說明接收到消息或超時 */*(pxResult) = xQueueCRReceive((pxQueue), (pvBuffer), 0);}/* 請求切換協(xié)程,也意味著接收到消息 */if(*(pxResult) == errQUEUE_YIELD){/* 設(shè)置協(xié)程狀態(tài) */((CRCB_t *)(xHandle))->uxState = ((__LINE__ * 2)+1);/* 退出協(xié)程,下一次直接接入((__LINE__ * 2)+1),然后運(yùn)行應(yīng)用程序 */return; case ((__LINE__ * 2)+1):;/* 接收到消息 */*(pxResult) = pdPASS;}; /* 應(yīng)用程序 */} };

真正用于接收隊列消息的函數(shù)為xQueueCRReceive

/* 協(xié)程接收隊列消息 */ BaseType_t xQueueCRReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) {BaseType_t xReturn;Queue_t *const pxQueue = xQueue;/* 禁止中斷 */portDISABLE_INTERRUPTS();{/* 隊列項數(shù)為0 */if(pxQueue->uxMessagesWaiting == (UBaseType_t)0){/* 等待時間大于0 */if(xTicksToWait > (TickType_t)0){/* 將協(xié)程加入?yún)f(xié)程延時列表 */vCoRoutineAddToDelayedList(xTicksToWait, &(pxQueue->xTasksWaitingToReceive));/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();/* 返回阻塞 */return errQUEUE_BLOCKED;}/* 等待時間不大于0 */else{/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();/* 返回錯誤 */return errQUEUE_FULL;}}else{mtCOVERAGE_TEST_MARKER();}}/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();/* 運(yùn)行到這兒說明,解除阻塞或者隊列中就有數(shù)據(jù) *//* 禁止中斷 */portDISABLE_INTERRUPTS();{/* 隊列項數(shù)大于0 */if(pxQueue->uxMessagesWaiting > (UBaseType_t)0){/* 將指針偏移到新的隊列項 */pxQueue->u.xQueue.pcReadFrom += pxQueue->uxItemSize;if(pxQueue->u.xQueue.pcReadFrom >= pxQueue->u.xQueue.pcTail){pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead;}else{mtCOVERAGE_TEST_MARKER();}/* 隊列項數(shù)減一 */--(pxQueue->uxMessagesWaiting);/* 將隊列項內(nèi)容拷貝出來 */(void)memcpy((void *)pvBuffer, (void *)pxQueue->u.xQueue.pcReadFrom, (unsigned)pxQueue->uxItemSize);/* 返回成功 */xReturn = pdPASS;/* 判斷是否有協(xié)程在等待發(fā)送 */if(listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend)) == pdFALSE){/* 將協(xié)程從事件列表中移除 */if(xCoRoutineRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) != pdFALSE){/* 請求切換協(xié)程 */xReturn = errQUEUE_YIELD;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}/* 隊列項為空 */else{/* 返回錯誤 */xReturn = pdFAIL;}}/* 恢復(fù)中斷 */portENABLE_INTERRUPTS();return xReturn; }

?

FreeRTOS還提供了帶中斷的隊列消息接收/發(fā)送函數(shù),原理大同小異,不再深入分析。

/* 帶中斷的發(fā)送隊列消息 */ #define crQUEUE_SEND_FROM_ISR(pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken) xQueueCRSendFromISR((pxQueue), (pvItemToQueue), (xCoRoutinePreviouslyWoken)) /* 帶中斷的接收隊列消息 */ #define crQUEUE_RECEIVE_FROM_ISR(pxQueue, pvBuffer, pxCoRoutineWoken) xQueueCRReceiveFromISR((pxQueue), (pvBuffer), (pxCoRoutineWoken))

?

總結(jié)

以上是生活随笔為你收集整理的FreeRTOS协程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。