這麼簡單做夢能笑醒,四部教你單片機實現真正的多線程的最優解
可以參考我的開源項目:基於循環時間的跨平台多任務管理系統(可用於MCS51,STM32等單片機)
1.簡介
1.1系統簡介
基於循環時間的跨平台任務管理系統(可用於MCS51,STM32等單片機)
///插播一條:我自己在今年年初錄製了一套還比較系統的入門單片機教程,想要的同學找我拿就行了免費的,私信我就可以哦~點我頭像黑色字體加我也能領取哦。最近比較閒,帶做畢設///
1.2文件目錄說明
·TaskManager_c:c語言實現的任務管理系統
·TaskManager_cpp:c++實現的任務管理系統
·Demo:提供多種示例,涵蓋電腦模擬器(MSVC),STM32,8081等多種運行環境
2.用法(C語言版)
2.1 API用法
系統配置(TaskManager_config.h):
·MAX_TASK_NUM:最大任務數量,默認為10個,根據自己的需要修改
·SYS_CYCLE_TIME:系統的循環時間(單位為ms),默認為1,表示1ms
【注】在MSVC下,SYS_CYCLE_TIME只能為1,系統循環時間為1s
·編譯器:目前支持的編譯器為ARM_KILL (AC5和AV6均可)和WIN_MSVC
API接口(TaskManager_c):
·TaskMsg:【結構體】任務信息,結構體成員為任務函數,開始時間,周期時間,運行次數,PID
任務函數:只能是無參數,無返回值的函數,不能是阻塞函數
開始時間:任務開始運行的時間,START_NOW表示立即開始運行
周期時間:任務每周期時間運行一次
運行次數:任務需要運行的次數,RUN_FOREVER表示無窮次
PID:任務編號號,初始化的時候傳入PID_INIT
·void TM_init():系統初始化
·uint32_t TM_add_task(TaskMsg* new_task_msg):添加任務
·void TM_kill_by_PID(uint32_t PID):通過任務序號刪除任務
·void TM_kill_by_taskmsg(TaskMsg* task_msg):通過任務信息刪除任務
·void TM_run(void):運行系統
示例代碼1:
#include "taskmanager.h"
#include "TaskManager_config.h"
#include "stdio.h"
//任務1
void task1(void)
{
printf("task1!\n");
}
//任務2
void task2(void)
{
printf("task2!\n");
}
void main(void)
{
TM_init();
//任務1立即啟動,每2ms中運行一次,無休無止的運行
TaskMsg tasks_msg1 = { task1,START_NOW,2,RUN_FOREVER,0 };
TM_add_task(&tasks_msg1);
//任務2在1ms之後啟動,每4ms運行一次,運行5次自動結束
TaskMsg tasks_msg2 = { task2,1,4,5,0 };
TM_add_task(&tasks_msg2);
while (1)
{
//任務管理器啟動
TM_run();
}
}
示例代碼2[Demo/MSVC/c_language]
#include "../TaskManager/taskmanager.h"
#include "../TaskManager/TaskManager_config.h"
#include "stdio.h"
void task0(void)
{
static i = 1;
printf_s("\n%d:", i);
i++;
}
void task1(void)
{
printf_s("task1!");
}
void task2(void)
{
printf_s("task2!");
}
void main(void)
{
TM_init(1);
TaskMsg tasks_msg0 = { task0,START_NOW,1,RUN_FOREVER,0 };
int PID0 = TM_add_task(&tasks_msg0);
TaskMsg tasks_msg1 = { task1,START_NOW,2,RUN_FOREVER,0 };
int PID1 = TM_add_task(&tasks_msg1);
TaskMsg tasks_msg2 = { task2,START_NOW,4,RUN_FOREVER,0 };
int PID2 = TM_add_task(&tasks_msg2);
while (1)
{
TM_run();
if (get_systime() > 10)
tasks_msg1.period = 1;
if (get_systime() > 20)
TM_kill_by_PID(PID1);
if (get_systime() > 30)
TM_kill_by_taskmsg(&tasks_msg2);
if (get_systime() > 40)
return;
}
}
運行結果:
1:task1!task2!
2:
3:task1!
4:
5:task1!task2!
6:
7:task1!
8:
9:task1!task2!
10:
11:task1!
12:
13:task1!task2!
14:task1!
15:task1!
16:task1!
17:task1!task2!
18:task1!
19:task1!
20:task1!
21:task2!
22:
23:
24:
25:task2!
26:
27:
28:
29:task2!
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
C:\Users\Harry\Desktop\TaskManager\Demo\MSVC\c_language\Debug\c_language.exe (進程 41888)已退出,返回代碼為: 0。
若要在調試停止時自動關閉控制台,請啟用「工具」->「選項」->「調試」->「調試停止時自動關閉控制台」。
按任意鍵關閉此窗口...
2.2移植方法
將TaskManager_c添加到程序目錄下,引用taskmanager.h,TaskManager_config.h和systime.h並配置時鐘即可。
以移植STM32F107為例,說明如下:
Step1:添加項目文件
·添加c文件到項目目錄
·添加頭文件路徑
Step2:更改系統頭文件
進入TaskManager_config.h,查看如下代碼
//跨平台移植,處理編譯器
#ifdef ARM_KILL // kill編譯器
#include "stm32f10x_conf.h"
#endif
將stm32f10x_conf.h換成系統相關的文件(標準庫)
如果使用HAL庫,請根據以下內容自行修改
·引入uint32_t,uint8_t等數據類型定義
·系統時鐘初始化,根據情況,更改TM_init()函數內SysTick_Config(SYS_CYCLE_TIME * 72000000 / 1000);,完成系統初始化
Step3:更改滴答計時器的初始化
在stm32f10x_it.c中,覆蓋原有的SysTick_Handler中斷服務函數
#include "systime.h"
void SysTick_Handler(void)
{
update_systime();
}
3.系統原理【有機會重寫】
·任務狀態:系統在一個循環時間SYS_CYCLE_TIME內,根據時間判斷任務是否處於就緒狀態
判斷依據:每個任務都有一個【下次開始時間】的屬性,判斷該值是否等於系統現在的時間
for (uint32_t PID=0; PID
{
if (task_list[PID]->start_time == systime)
{
; //執行相應任務
}
}
·任務執行:系統在一個循環時間SYS_CYCLE_TIME內,執行完所有就緒任務,並更新所有任務下次執行的時間
所以,循環時間不能太小,否則系統溢出造成未知錯誤
·其他:在一個循環時間內,如果所有任務執行完,還有額外的時間,系統空轉。
4.碎碎念
4.1 TODO
歡迎大家一起完成!
·提供STM32標準庫版本
·提供 HAL庫版本
·完成c++版本程序
·支持帶形參的任務
·為更多平台提供移植 demo
4.2 開源地址:
GitHub - sunshineharry/TaskManager: A cross-platform(STM32, MCS51, WIN, et al.) multitasking management system based on cycle time.基於循環時間的跨平台多任務管理系統(可用於MCS51,STM32等單片機)