單片機通常分為三種工作模式,分別是
1、前后臺順序執行法? ? ? ? ? ? ? ????????? 2、操作系統?????????????????????????3、時間片輪詢法? ? ? ? ? ? ??
1、前后臺順序執行法
????????利用單片機的中斷進行前后臺切換,然后進行任務順序執行,但其實在很多時候都是處于一種浪費資源的使用,因為大部分時候都要去查看事件是否發生,并且其實時性低,由于每個函數或多或少存在毫秒級別的延時,即使是1ms,也會造成其他函數間隔執行時間的不同,雖然可通過定時器中斷的方式,但是前提是中斷執行函數花的時間必須短。當程序邏輯復雜度提升時,會導致后來維護人員的大腦混亂,很難理清楚該程序的運行狀態。
其也就是大輪訓進行執行while里面的函數
2、操作系統
????????嵌入式操作系統EOS(Embedded OperatingSystem)是一種用途廣泛的系統軟件,過去它主要應用于工業控制和國防系統領域,而對于單片機來說,比較常用的有UCOS、FreeRTOS、RT-Thread?Nano和RTX 等多種搶占式操作系統(其他如Linux等操作系統不適用于單片機)
????????操作系統和“時間片輪詢法”,在任務執行方面來說,操作系統對每個任務的耗時沒有過多的要求,需要通過設置每個任務的優先級,在高優先級的任務就緒時,會搶占低優先級的任務;操作系統相對復雜,因此這里沒有詳細介紹了。
3、時間片輪詢法?
? ? ? 時間片輪詢法是介于前后臺順序執行法和操作系統之間的一種程序架構設計方案。任務函數無需時刻執行,存在間隔時間(比如按鍵,一般情況下,都需要軟件防抖,初學者的做法通常是延時10ms左右再去判斷,但10ms極大浪費了CPU的資源,在這段時間內CPU完全可以處理很多其他事情)。
????????該設計方案需要使用一個定時器,一般情況下定時1ms即可(定時時間可隨意定,但中斷過于頻繁效率就低,中斷太長,實時性差),因此需要考慮到每個任務函數的執行時間,建議不能超過1ms(能通過程序優化縮短執行時間則最好優化,如果不能優化的,則必須保證該任務的執行周期必須遠大于任務所執行的耗時時間),同時要求主循環或任務函數中不能存在毫秒級別的延時。
時間片輪詢法的實現(指針方式)
首先定義一個結構體,用于存儲一個任務的所有信息,如下所示:
typedef struct
{uint8_t u8_runflag; /*程序是否運行標志 TASK_OFF_RUN:不運行 TASK_ON_RUN:運行*/uint16_t u16_timer; /*計時器*/uint16_t u16_itvTime; /*運行間隔時間,也就是多久運行一次*/void (*p_TaskHook)(void); /*任務*/
}Task_InfoType;
然后創建一個具有綁定關系的任務數組:
static Task_InfoType Task_Info[TASK_MAX] = {{TASK_OFF_RUN,TASK_200ms,TASK_200ms,logic_task},//邏輯任務{TASK_OFF_RUN,TASK_1000ms,TASK_1000ms,led_task} //LED任務
};
????????從上圖中可以看出,這里創建了兩個任務,一個邏輯任務200ms執行一次,另外一個則是1000ms執行一次的LED任務,根據任務的情況,可以自己添加自己需要的。
? ? ? ? 有了關系之后,那么就需要讓這個小系統跑起來了,下面兩個函數分別是函數標志位修改函數和函數執行函數。其實這個小系統也就是一個計時,到時間,則打開標志位,去執行對應的函數,標志位沒有打開則跳過。
/*任務標志處理函數定時器1ms中斷處理
*/
void Task_Remarks(void)
{for(int i=0;i<TASK_MAX;i++){if(Task_Info[i].u16_timer){Task_Info[i].u16_timer--;if(TASK_TIME_ON == Task_Info[i].u16_timer){//定時器計數到后,打開函數運行標志位Task_Info[i].u16_timer = Task_Info[i].u16_itvTime;Task_Info[i].u8_runflag = TASK_ON_RUN;}}}
}
/*任務函數運行處理放入主函數的循環中
*/
void Task_Process(void)
{for(int i=0;i<TASK_MAX;i++){if(Task_Info[i].u8_runflag == TASK_ON_RUN){Task_Info[i].p_TaskHook();Task_Info[i].u8_runflag = TASK_OFF_RUN;}}
}
弄完這些后,只需要去配置一個1ms定時器,將計時函數放入其中,即可
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *hitm)
{if(hitm->Instance == TIM7){Task_Remarks();}
}
到這里,這個小系統就完成了一大半了,在這里還需要添加一個打印函數,但是如何做到控制這個打印函數,只需要改變宏定義就可以實現關閉所以的打印呢,在實際的項目中,都會使用這種方式來進行系統的調試。
宏定義控制printf-CSDN博客
STM32關于UART的接收方式_stm32中huart1-CSDN博客
關于STM32CubeIDE使用printf串口打印_stm32cubeide printf-CSDN博客
這些都是跟調試有關的一些文章,可以查看。