Author:家有仙妻謝掌柜
Date:2021/2/3
學一個東西一定要學會總結,學單片機也不例外,總結一下用單片機做專案時代碼的架構,寫在這里記錄自己的成長歷程,也分享出去供大家參考!
首先宣告在本程式中和移植相關的針對不同MCU等差異所需要的做出的修改如下:
1.中斷服務函式
Timer1Callback();
2.主函式中
timer_1_enable(32768/10,Timer1Callback);//我這里用的是100ms中斷一次來做實驗
引數32768表示1S,我這里32768/10表示100ms,這個速度已經很慢了,但是為了兼容列印,因為事件中沒有實際的任務,太快列印跟不上,在實際操作中,中斷的時間可以縮短一些,但是不能太短,頻繁的中斷效率也會低的,
3.這里測驗了10個任務同時進行,效果滿足預期,只要每一個任務執行的時間小于該任務設定的時間即可,
//時間片架構測驗
void Task1(void);
void Task2(void);
void Task3(void);
void Task4(void);
void Task5(void);
void Task6(void);
void Task7(void);
void Task8(void);
void Task9(void);
void Task0(void);
/**************************************************************************************
* Name :TaskStruct
* Description :任務結構體
* Details :它包含了一個任務所需要的所有資訊;
* 1:運行狀態標志位:0-不運行;1-運行,
* 2:計數器TimerCountdown--
* 3:計數器數值填充器,預設的初值:TimerInitialValue(任務運行間隔時間)
* 4:任務對應的函式指標
**************************************************************************************/
typedef struct _TaskStruct
{
uint8_t RunningStatus;
uint8_t TimerCountdown;
uint8_t TimerInitialValue;
void (*TaskHook)(void);
}TaskStruct;
/**************************************************************************************
* Name :TaskManage
* Description :任務陣列
* Details :它包含了所有任務所需要的引數;
**************************************************************************************/
//定時器中斷實驗目前是100ms中斷一次
#define InitStatus 0
#define TimerTask1 10
#define TimerTask2 20
#define TimerTask3 30
#define TimerTask4 40
#define TimerTask5 50
#define TimerTask6 60
#define TimerTask7 70
#define TimerTask8 80
#define TimerTask9 90
#define TimerTask0 100
static TaskStruct TaskManage[] =
{
{InitStatus,TimerTask1,TimerTask1,Task1},
{InitStatus,TimerTask2,TimerTask2,Task2},
{InitStatus,TimerTask3,TimerTask3,Task3},
{InitStatus,TimerTask4,TimerTask4,Task4},
{InitStatus,TimerTask5,TimerTask5,Task5},
{InitStatus,TimerTask6,TimerTask6,Task6},
{InitStatus,TimerTask7,TimerTask7,Task7},
{InitStatus,TimerTask8,TimerTask8,Task8},
{InitStatus,TimerTask9,TimerTask9,Task9},
{InitStatus,TimerTask0,TimerTask0,Task0},
/* 這里添加需要的任務,,,, */
};
/**************************************************************************************
* Name :TaskList
* Description :任務串列
* Details :包含所有任務;
* 1:ListTask1
* 2:ListTask2
* ...
* N:ListTasksMax:總的可供分配的定時任務數目
**************************************************************************************/
typedef enum _TaskList
{
ListTask1,
ListTask2,
ListTask3,
ListTask4,
ListTask5,
ListTask6,
ListTask7,
ListTask8,
ListTask9,
ListTask0,
/* 這里添加需要的任務,,,, */
ListTasksMax
}TaskList;
/**************************************************************************************
* FunctionName : TaskMarks()
* Description : 標志位處理函式
* EntryParameter : None
* ReturnValue : None
這個函式是用來更新每個任務的計數器以及它們的運行標志位的,
它是寫在單片機的定時器中斷服務函式中的
**************************************************************************************/
void TaskMarks(void)
{
uint8_t i;
for (i=0;i<ListTasksMax;i++)//逐個任務時間處理
{
if(TaskManage[i].TimerCountdown)//計數器不為0
{
TaskManage[i].TimerCountdown--; //計數器減去一個節拍
if(TaskManage[i].TimerCountdown == 0)//計數器數值減完了
{
TaskManage[i].TimerCountdown = TaskManage[i].TimerInitialValue;//恢復計時器值,重新下一次
TaskManage[i].RunningStatus = 1;//任務可以運行
}
}
}
}
/**************************************************************************************
* FunctionName : TaskMarks()
* Description : 任務處理函式
* EntryParameter : None
* ReturnValue : None
這個函式用來判斷任務是否到了執行時間,它會逐個檢查任務串列中的任務
如果到了就執行,同時清空執行標志位,沒到就不執行
**************************************************************************************/
void TaskProcess(void)
{
uint8_t i;
for (i=0;i<ListTasksMax;i++) // 逐個任務時間處理
{
if (TaskManage[i].RunningStatus) // 時間不為0
{
TaskManage[i].TaskHook(); // 運行任務
TaskManage[i].RunningStatus = 0; // 標志清0
}
}
}
/**************************************************************************************
* FunctionName : Task1()/Task2()/Task3()/Task4()...
* Description : 任務函式
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
void Task1(void)
{
dbg_printf("Task1\r\n");
}
void Task2(void)
{
dbg_printf("Task2\r\n");
}
void Task3(void)
{
dbg_printf("Task3\r\n");
}
void Task4(void)
{
dbg_printf("Task4\r\n");
}
void Task5(void)
{
dbg_printf("Task5\r\n");
}
void Task6(void)
{
dbg_printf("Task6\r\n");
}
void Task7(void)
{
dbg_printf("Task7\r\n");
}
void Task8(void)
{
dbg_printf("Task8\r\n");
}
void Task9(void)
{
dbg_printf("Task9\r\n");
}
void Task0(void)
{
dbg_printf("Task0\r\n");
}
/**************************************************************************************
* FunctionName : Timer1Callback()
* Description : 定時中斷服務函式,回呼函式
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
static void Timer1Callback(void)
{
TaskMarks();
}
/**************************************************************************************
* FunctionName : main()
* Description : 主函式
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
int main(void)
{
All_Initialize();
timer_1_enable(32768/10,Timer1Callback);//我這里用的是100ms中斷一次來做實驗
while(1)
{
TaskProcess();// 任務處理
}
}
總結:
整個程式的執行流程就是:中斷函式不斷重繪著每一個任務的狀態,
任務處理函式根據這些狀態來判斷哪些函式要被執行,如果要執行,就立馬執行,
添加任務就是在任務陣列中添加一個結構體資訊,撰寫一個任務函式,在任務串列中添加一個函式,
基本思想:
舉個例子,有一個函式A,我們給它設定
一個計數器B(程式多久執行一次)
和一個狀態標志位C(用來判斷這個程式是否需要執行)
還有一個計數填充值D,
其中的B會被單片機自帶的定時器中斷服務函式不斷地重繪(遞減重繪),
當B到0的時候C會被置位,同時B會被重新填滿D值,
當主程式運行到A的時候不會直接去運行它,而是先檢查C,
如果C沒有被置位,說明還沒有到A的執行時間,不執行A,
如果C被置位了,就執行A,執行完后將C復位,讓C再等上一段時間才再次被執行,
這個是記錄自己學習的程序!
感謝您的支持!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/256769.html
標籤:其他
