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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

uC/OS-II源码分析(总体思路 三)

發(fā)布時(shí)間:2023/12/15 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uC/OS-II源码分析(总体思路 三) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

OSTimeDly

?

在Task中,一般執(zhí)行一段時(shí)間之后調(diào)用OSTimeDly推遲一段時(shí)間再繼續(xù)運(yùn)行,OSTimeDly將本進(jìn)程從Ready TCBList中刪除,然后將Delay的時(shí)間設(shè)置給OSTCBDly,最后調(diào)用OS_Sched進(jìn)行進(jìn)程調(diào)度。

void? OSTimeDly (INT16U ticks)

{

??? INT8U????? y;

??

??? if (ticks > 0) {????????????????????????????

??????? OS_ENTER_CRITICAL();

??????? y??????????? =? OSTCBCur->OSTCBY;???????

??????? OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;

??????? if (OSRdyTbl[y] == 0) {?

??????????? OSRdyGrp &= ~OSTCBCur->OSTCBBitY;

??????? }

??????? OSTCBCur->OSTCBDly = ticks;?????????????

??????? OS_EXIT_CRITICAL();

??????? OS_Sched();?????????????????????????????

??? }

}

如果ticks為零,說明不需延遲,則什么事情都不做。否則,調(diào)用OS_ENTER_CRITICAL進(jìn)入臨界段,將本進(jìn)程從Ready TCBList中刪除的代碼如下:

??????? y??????????? =? OSTCBCur->OSTCBY;???????

??????? OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;

??????? if (OSRdyTbl[y] == 0) {?

??????????? OSRdyGrp &= ~OSTCBCur->OSTCBBitY;

??????? }

y為當(dāng)前進(jìn)程所在Group,OSRdyTbl[y]為該Group所在字節(jié),&=~則將該字節(jié)中本進(jìn)程所占用的Bit清零。如果OSRdyTbl[y]為0,則說明這個(gè)Group中沒有進(jìn)程處于Ready狀態(tài),則將OSRdyGrp中該Group所占用的Bit清零。

然后將ticks保存在OSTCBDly中,每次OSTimeTick運(yùn)行時(shí)會(huì)將這個(gè)值減一直至為零。

調(diào)用OS_EXIT_CRITICAL離開臨界段,緊接著調(diào)用OS_Sched進(jìn)入調(diào)度例程。

?

OS_Sched

?

OS_Sched是進(jìn)程調(diào)度所使用的函數(shù),在這里面找到最高優(yōu)先級的進(jìn)程,然后切換到該進(jìn)程運(yùn)行。

void? OS_Sched (void)

{

??? INT8U????? y;

??? OS_ENTER_CRITICAL();

??? if (OSIntNesting == 0) {??????????????????????????

??????? if (OSLockNesting == 0) {?????????????????????

??????????? y???????????? = OSUnMapTbl[OSRdyGrp];?????

??????????? OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);

??????????? if (OSPrioHighRdy != OSPrioCur) {?????????

??????????????? OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

??????????????? OSCtxSwCtr++;?????????????????????????

??????????????? OS_TASK_SW();?????????????????????????

??????????? }

??????? }

??? }

??? OS_EXIT_CRITICAL();

}

OS_Sched不允許在中斷嵌套中調(diào)用,因此先判斷是否是中斷嵌套,并且是否限制進(jìn)程調(diào)度,這兩個(gè)條件都滿足之后,找到最高優(yōu)先級的進(jìn)程,如果這個(gè)進(jìn)程不是當(dāng)前進(jìn)程,則將新的進(jìn)程TCB指針保存到OSTCBHighRdy中,為調(diào)度計(jì)數(shù)器OSCtxSwCtr加一,然后調(diào)用宏OS_TASK_SW()進(jìn)行切換。

OS_TASK_SW()宏也是一個(gè)自定義的宏,uC/OS-II推薦使用軟中斷方式實(shí)現(xiàn)。

OSCtxSw是一個(gè)中斷響應(yīng)函數(shù),一般我們在初始化時(shí)將這個(gè)軟終端和OSCtxSw掛接好。在OSCtxSw中所需要做的事情就是將當(dāng)前寄存器的值保存到當(dāng)前堆棧中,然后切換堆棧到新進(jìn)程的堆棧,將寄存器的值出棧,然后調(diào)用中斷返回指令I(lǐng)RET就返回到新進(jìn)程中斷前的地方繼續(xù)執(zhí)行了。

?

定時(shí)中斷

?

uC/OS-II的定時(shí)中斷必須在OSStart之后初始化,而不能在OSStart之前,因?yàn)楹ε碌谝粋€(gè)TimeTick發(fā)生時(shí)第一個(gè)進(jìn)程還沒有開始運(yùn)行,而這時(shí)uC/OS是處于不可預(yù)期狀態(tài),會(huì)導(dǎo)致死機(jī)。

因此對于定時(shí)中斷,我一般是放在最高級進(jìn)程的初始化中進(jìn)行,然后將定時(shí)中斷和OSTickISR掛接。

OSTickISR也是一個(gè)用戶自定義函數(shù),所要完成的功能一個(gè)是保存當(dāng)前的寄存器到當(dāng)前堆棧將OSIntNesting加一,然后調(diào)用uC/OS提供的OSTimeTick函數(shù),然后調(diào)用OSIntExit()將OSIntNesting減一,最后將各寄存器值出棧,使用中斷返回指令I(lǐng)RET返回。

OSTimeTick在每個(gè)時(shí)鐘中斷中被調(diào)用一次,在該函數(shù)中會(huì)更新各個(gè)進(jìn)程TCB所對應(yīng)的OSTCBDly,如果該OSTCBDly減為0,則對應(yīng)的TCB就被放入Ready TCBList中。

??? OS_ENTER_CRITICAL();??????????????????????????????????

??? OSTime++;

??? OS_EXIT_CRITICAL();

???

??????????? ptcb = OSTCBList;?????????????????????????????????

??????? while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {?????????

??????????? OS_ENTER_CRITICAL();

??????????? if (ptcb->OSTCBDly != 0) {????????????????????

??????????????? if (--ptcb->OSTCBDly == 0) {??????????????

??????????????????????????????????????????????????????????

??????????????????? if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {

??????????????????????? ptcb->OSTCBStat?? &= ~OS_STAT_PEND_ANY;???????????????

??????????????????????? ptcb->OSTCBPendTO? = TRUE;????????????????????????????

??????????????????? } else {

??????????????????????? ptcb->OSTCBPendTO? = FALSE;

??????????????????? }

??????????????????? if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {?

??????????????????????? OSRdyGrp?????????????? |= ptcb->OSTCBBitY;????????????

??????????????????????? OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

??????????????????? }

??????????????? }

??????????? }

??????????? ptcb = ptcb->OSTCBNext;???????????????????????

??????????? OS_EXIT_CRITICAL();

??????? }

首先在臨界段將OSTime加一,然后遍歷整個(gè)非Free的TCBList,如果OSTCBDly不為0,則,將OSTCBDly減一,如果這時(shí)OSTCBDly為0,而且TCB對應(yīng)的進(jìn)程需要等待任何信號量或Event等,則說明超時(shí)時(shí)間到了,將當(dāng)前TCB的State中OS_STAT_PEND_ANY位去掉,然后將OSTCBPendTo設(shè)置為TRUE,表示這是PEND的超時(shí),否則設(shè)置OSTCBPendTO為FALSE。

如果OSTCBDly減為零,且該進(jìn)程沒有Suspend,則將該進(jìn)程放入Ready TCBList中,使用方法同TaskCreate中的方法。

然后我們來說說OSIntExit這個(gè)函數(shù)。該函數(shù)代碼如下:

void? OSIntExit (void)

{

??? INT8U????? y;

?

??? if (OSRunning == TRUE) {

??????? OS_ENTER_CRITICAL();

??????? if (OSIntNesting > 0) {???????????????????????????

??????????? OSIntNesting--;

??????? }

??????? if (OSIntNesting == 0) {??????????????????????????

??????????? if (OSLockNesting == 0) {?????????????????????

??y???????????? = OSUnMapTbl[OSRdyGrp];?????????

??????????????? OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);

??????????????? if (OSPrioHighRdy != OSPrioCur) {?????????

??????????????????? OSTCBHighRdy? = OSTCBPrioTbl[OSPrioHighRdy];

??????????????????? OSCtxSwCtr++;?????????????????????????

??????????????????? OSIntCtxSw();?????????????????????????

??????????????? }

??????????? }

??????? }

?OS_EXIT_CRITICAL();

??? }

}

首先判斷OSRunning是否為1,也就是OS是否在運(yùn)行,當(dāng)然沒有運(yùn)行就什么都不做。

然后將OSIntNesting減一,這個(gè)是需要在臨界段進(jìn)行的。如果OSIntNesting減為零,并且沒有限制進(jìn)程切換,則找到當(dāng)前最高優(yōu)先級的進(jìn)程(方法同OS_Sched()),然后調(diào)用OSIntCtxSw進(jìn)行進(jìn)程切換。

OSIntCtxSw()是用戶自定義函數(shù),該函數(shù)的主要功能與OSCtxSw類似,只是需要對當(dāng)前的堆棧進(jìn)行稍微的調(diào)整,將OSIntExit和OSIntCtxSw調(diào)用所需要的堆棧去掉,然后做的和OSCtxSw一樣。

在實(shí)際的Porting中發(fā)現(xiàn)要去掉OSIntExit和OSIntCtxSw調(diào)用所占用的堆棧還是比較麻煩的,因此我就現(xiàn)在OSTickISR剛開始的時(shí)候保存好現(xiàn)場之后就將堆棧指針賦給當(dāng)前進(jìn)程TCB的OSStkPtr,這樣,在OSIntCtxSw中就不需要重新對當(dāng)前堆棧的值進(jìn)行保存,只需進(jìn)行切換就可以了

總結(jié)

以上是生活随笔為你收集整理的uC/OS-II源码分析(总体思路 三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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