TMOS實現(xiàn)長延時,并且不影響藍牙功能

問題:

? ? 在使用CH58X開發(fā)BLE功能時,遇到一個問題,就是如果使用了稍微長一點的延時或者處理耗時的操作時。BLE會斷開連接。


原因:

? ? CH58X的藍牙功能是基于TMOS輪詢的方式去處理各個事件的。因為是單線程,所以如果在代碼里使用了延時就會導致藍牙的事件沒能得到及時處理,就會導致斷開連接。


解決思路:

? ? 在一個低優(yōu)先級中斷中去執(zhí)行TMOS的輪詢。這樣主函數(shù)就能無限延時或者處理各種耗時操作。相當于雙線程運行。為了保證其它中斷不受影響,這個執(zhí)行TMOS輪詢的中斷必須是最低優(yōu)先級的,并且能被所有中斷搶斷。


接下來我們使用RTC中斷來驗證我們的思路:

? ? 使用官方BLE_USB的Demo來實現(xiàn),具體步驟如下:

? ? 首先,把HAL_SLEEP宏打開

? ? 然后main函數(shù)需要改成:

int?main(void)
{
????...
????PFIC_DisableIRQ(RTC_IRQn);?????????????//先關(guān)閉RTC中斷
????CH58X_BLEInit();
????HAL_Init();
????GAPRole_PeripheralInit();
????Peripheral_Init();
????app_usb_init();
????PFIC_EnableIRQ(RTC_IRQn);?????????????//所有初始化工作完成后,打開RTC中斷
????RTC_SetTignTime(RTC_GetCycle32k()?+?10);????//設(shè)置RTC在10個時鐘周期后觸發(fā)中斷
????Main_Circulation();
}

? ?

主循環(huán)需要把TMOS_SystemProcess();注釋掉,然后改成一個周期打印的功能來測試

void?Main_Circulation()
{
????while(1)
????{
????????//TMOS_SystemProcess();
????????PRINT("123\n");
????????DelayMs(1000);
????}
}

?

在SLEEP.c文件的HAL_SleepInit函數(shù)中需要增加設(shè)置RTC中斷優(yōu)先級成最低優(yōu)先級

void?HAL_SleepInit(void)
{
#if(defined(HAL_SLEEP))?&&?(HAL_SLEEP?==?TRUE)
????sys_safe_access_enable();
????R8_SLP_WAKE_CTRL?|=?RB_SLP_RTC_WAKE;?
????sys_safe_access_enable();
????R8_RTC_MODE_CTRL?|=?RB_RTC_TRIG_EN;?
????sys_safe_access_disable();??????????????
????PFIC_SetPriority(RTC_IRQn,?0xFF);????//將RTC中斷優(yōu)先級設(shè)置到最低,用于跑TMOS事務(wù)輪詢
#endif
}

然后把CH58X_LowPower函數(shù)中的休眠相關(guān)的函數(shù)注釋掉,并且在設(shè)置RTC觸發(fā)時間后把RTC中斷標志位清除

uint32_t?CH58X_LowPower(uint32_t?time)
{
#if(defined(HAL_SLEEP))?&&?(HAL_SLEEP?==?TRUE)
????uint32_t?time_sleep,?time_curr,?irq_status;
????SYS_DisableAllIrq(&irq_status);
????time_curr?=?RTC_GetCycle32k();
????//?檢測睡眠時間
????if?(time?<?time_curr)?{
????????time_sleep?=?time?+?(RTC_TIMER_MAX_VALUE?-?time_curr);
????}?else?{
????????time_sleep?=?time?-?time_curr;
????}
????if?((time_sleep??(RTC_TIMER_MAX_VALUE?-?TMOS_TIME_VALID)))?{
????????SYS_RecoverIrq(irq_status);
????????return?2;
????}
????RTC_SetTignTime(time);
????SYS_RecoverIrq(irq_status);
????R8_RTC_FLAG_CTRL?=?(RB_RTC_TMR_CLR?|?RB_RTC_TRIG_CLR);??//清除中斷標志位,等待下一次RTC觸發(fā)
#endif
????return?0;
}



在RTC.c文件中需要修改RTC_IRQHandler函數(shù)為:

void?RTC_IRQHandler(void)?{
????RTCTigFlag?=?1;
????TMOS_SystemProcess();????//RTC中斷中進行TMOS事務(wù)輪詢,并且不清除中斷標志位。
?????????????????????????????//等TMOS調(diào)用CH58X_LowPower時才清除標志,不然一直進中斷。
}


到此代碼修改完畢,編譯、燒錄、測試。在主循環(huán)中延時1秒鐘也不會影響藍牙的連接、數(shù)據(jù)收發(fā)。并且USB功能正常。


附上工程代碼

icon_rar.gifCH58X.rar


注意事項:

1、PRINT在主循環(huán)和RTC中斷中都會調(diào)用到,因為PRINT不是可重入函數(shù),有可能會導致錯誤。


收藏


中斷跑大任務(wù)總感覺不可靠,會不會莫名其妙什么棧溢出


認為理想的程序還是不要有阻塞式的延時,大任務(wù)可以拆分為多個小任務(wù)。

我做的藍牙案子也沒碰到因執(zhí)行阻塞導致的藍牙連接斷開。


主要是項目用到一個外設(shè)的庫很耗時,導致藍牙直接斷開了,改外設(shè)的庫又太麻煩


嗯,TMOS是個支持搶占的RTOS就好了。


這樣持續(xù)在中斷里調(diào)用還是有問題的吧,你現(xiàn)在只有兩個任務(wù),是不是再多幾個任務(wù)就亂了套了,這個RTC中斷周期可是625us,程序持續(xù)進中斷了,啥也別干了


TMOS依靠RTC提供時鐘信號,整個任務(wù)執(zhí)行時間過長,貌似會導致TMOS亂套。


TMOS并不是基于RTC中斷,而是基于RTC的計數(shù)的,在RTC中斷里執(zhí)行任務(wù)時RTC計數(shù)并不會停止,所以不會影響TMOS。

然后RTC中斷如果在不設(shè)置觸發(fā)時間的情況下是24小時計數(shù)溢出的時候才進一次中斷的,并不是625us進一次中斷。

目前的邏輯是只有事件觸發(fā)的時候才會進RTC中斷執(zhí)行TMOS輪詢,并不會一直進RTC中斷。



嗯,9樓是對的。有定時事件TMOS會設(shè)置RTC定時事件,用以喚醒芯片。


之前做過實驗在主循環(huán)中調(diào)用延時函數(shù)不能超過625us,否則會影響TMOS_SystemProcess()導致藍牙中斷,這意味著在移動到RTC中斷后,其他高優(yōu)先級中斷處理時間也不能超過625us



是的,目前改過的這套代碼也是只能在主循環(huán)中執(zhí)行延時或者耗時的操作。其它中斷里面或者TMOS的任務(wù)還是一樣不能延時或者處理耗時任務(wù),不然會影響藍牙的功能。


請教:這種方法雖然可以長延時,但是否就無法進入休眠狀態(tài)?


這樣的邏輯寫程序,只能說瘋了…

如果是剛?cè)腴T,建議先把基礎(chǔ)打牢不要走歪路,接著學學單片機OS原理編程,按OS的思維去寫多任務(wù)程序,以后的路會好走太多太多了。


請教:這種方法雖然可以長延時,但是否就無法進入休眠狀態(tài)?
回復(fù):不影響進入休眠,在主函數(shù)里把
DelayMs改成對應(yīng)的休眠函數(shù)即可


回復(fù)14#:TMOS固然好用,但是還是有局限性,很多沒法拆分的耗時操作沒辦法處理。比如我現(xiàn)在用到的ST的NFC庫,讀卡時就是要這么耗時,你不可能去改ST的NFC庫。而像諾迪克的藍牙SDK就能實現(xiàn)無限的延時也不會影響到藍牙工作,其實實現(xiàn)的思路也是一樣的


只有登錄才能回復(fù),可以選擇微信賬號登錄

国产91精品新入口,国产成人综合网在线播放,九热这里只有精品,本道在线观看,美女视频a美女视频,韩国美女激情视频,日本美女pvp视频