單片機的ROM與RAM存貯空間有限,一般沒有多線程可用,給復雜的單片機項目帶來困擾。
經過多年的單片機項目實踐,借鑒windows消息機制的思想,編寫了單片機多任務事件驅動C代碼,應用于單片機項目,無論復雜的項目,還是簡單的項目,都可以達到優化代碼架構的目的。
經過幾輪的精簡、優化,現在分享給大家。
代碼分為3個模塊:任務列表、事件列表、定時器列表。
任務列表創建一個全局列表管理任務,通過調用taskCreat()創建事件處理任務,創建成功返回任務ID,任務列表、事件列表與定時器列表通過任務ID關聯。
事件列表創建一個全局循環列表管理事件,調用taskEventIssue()生成一個事件,放到事件循環列表,taskEventLoop()函數放到主線程循環調用,當事件循環列表中有事件時,根據任務ID分發到具體的事件處理任務。
定時器列表創建一個全局列表管理定時器,taskTimer()建立一個定時器,放到定時器列表執行,當定時時間到,會生成一個定時器事件,放到事件列表,分發到具體的事件處理任務。
//common.h #ifndef __COMMON_H #define __COMMON_H #include "stdio.h" #include#include typedef short int16_t; typedef int int32_t; typedef long long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef unsigned char bool; #define false 0 #define true 1 #endif // __COMMON_H
//task.h #ifndef _THREAD_H #define _THREAD_H #define TASK_MAX 20 // 最多任務數量 #define TASK_EVENT_MAX 100 // 任務隊列長度 #define TASK_TIMER_MAX 100 // 定時器最大數量 typedef void (*CBTaskEvent)(int taskID,uint32_t eventID); typedef struct _TASK_EVENT { int taskID; uint32_t eventID; } TASK_EVENT; int taskCreat(CBTaskEvent task); void taskLoop(); void taskEventIssue(int taskID,uint32_t eventID); void taskEventLoop(); //定時、休眠 typedef struct _TASK_TIMER { bool isValid; int taskID; uint32_t eventID; uint32_t timeMs; uint32_t start; } TASK_TIMER; void taskTicksInc(); void taskTimer(int taskID,uint32_t eventID,uint32_t time_ms); void taskTimerLoop(); #endif // _THREAD_H
//task.c
#include "common.h"
#include "task.h"
CBTaskEvent g_taskList[TASK_MAX]={0};
int taskFindEmpty()
{
static int index = -1;
for(int i=0; i
",taskID);
return taskID;
}
void taskDestroy(int taskID)
{
printf("Destroy task<%d>
",taskID);
g_taskList[taskID] = NULL;
}
void taskLoop()
{
taskEventLoop();
taskTimerLoop();
}
TASK_EVENT g_taskEventList[TASK_EVENT_MAX];
int g_TKEventWrite=0;
int g_TKEventRead=0;
int tkEventGetSize()
{
return (g_TKEventWrite + TASK_EVENT_MAX - g_TKEventRead)% TASK_EVENT_MAX;
}
void taskEventIssue(int taskID,uint32_t eventID)
{
int writePos;
if(taskID >= TASK_EVENT_MAX || taskID < 0)
{
printf("taskEventIssue() error:taskID
");
return;
}
writePos = (g_TKEventWrite + 1)% TASK_EVENT_MAX;
if(writePos == g_TKEventRead)
{
printf("taskEventIssue() error:task<%d> event list is full!
",taskID);
return;
}
g_taskEventList[g_TKEventWrite].taskID=taskID;
g_taskEventList[g_TKEventWrite].eventID=eventID;
g_TKEventWrite=writePos;
//printf("add event:%x
",eventID);
}
void taskEventLoop()
{
TASK_EVENT event;
CBTaskEvent task;
int size;
size=tkEventGetSize();
while(size-- >0)
{
event=g_taskEventList[g_TKEventRead];
g_TKEventRead = (g_TKEventRead + 1)% TASK_EVENT_MAX;
task = g_taskList[event.taskID];
if(!task)
{
printf("taskEventLoop() error:task is NULL
");
continue;
}
task(event.taskID,event.eventID);
}
}
// 定時、休眠
uint32_t g_taskTicks=0;
uint32_t getTaskTicks()
{
return g_taskTicks;
}
void taskTicksInc() // 1ms時間基準
{
g_taskTicks++;
}
uint32_t taskTickDiff(uint32_t now,uint32_t last)
{
uint64_t diff;
diff = now + 0x100000000 - last;
return (diff & 0xffffffff);
}
TASK_TIMER g_taskTimerList[TASK_TIMER_MAX]={0};
int taskTimerFindEmpty()
{
for(int i=0; i %ums
",taskID,eventID,time_ms);
}
void taskTimerLoop()
{
static uint32_t start=0;
if(taskTickDiff(getTaskTicks(),start)<3)
{
return;
}
start=getTaskTicks();
for(int i=0; i=g_taskTimerList[i].timeMs)
{
taskEventIssue(g_taskTimerList[i].taskID,g_taskTimerList[i].eventID);
g_taskTimerList[i].isValid=false;
}
}
}
}
//test_task.h #ifndef _TEST_THREAD_H #define _TEST_THREAD_H void testInit(); void testLoop(); #endif //
//test_task.c
#include "common.h"
#include "task.h"
#define CTRL_EVENT1 0x01
#define CTRL_EVENT2 0x02
#define CTRL_EVENT3 0x04
void eventProcess(int taskID,uint32_t event)
{
switch(event)
{
case CTRL_EVENT1:
printf("task[%d] CTRL_EVENT1
",taskID);
//taskEventIssue(taskID,CTRL_EVENT2);
taskTimer(taskID,CTRL_EVENT2,1000);
break;
case CTRL_EVENT2:
printf("task[%d] CTRL_EVENT2
",taskID);
//taskEventIssue(taskID,CTRL_EVENT3);
taskTimer(taskID,CTRL_EVENT3,2000);
break;
case CTRL_EVENT3:
printf("task[%d] CTRL_EVENT3
",taskID);
taskTimer(taskID,CTRL_EVENT1,4000);
break;
default:
break;
}
}
void testLoop()
{
taskLoop();
}
void testInit()
{
int taskID1,taskID2;
printf("testInit()
");
taskID1 = taskCreat((CBTaskEvent)&eventProcess);
taskTimer(taskID1,CTRL_EVENT1,5000);
taskID2 = taskCreat((CBTaskEvent)&eventProcess);
taskEventIssue(taskID2,CTRL_EVENT2);
taskDestroy(taskID1);
taskDestroy(taskID2);
//taskEventIssue(taskID1,CTRL_EVENT1);
taskID1 = taskCreat((CBTaskEvent)&eventProcess);
taskEventIssue(taskID1,CTRL_EVENT1);
}
審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
單片機
+關注
關注
6076文章
45495瀏覽量
670317 -
ROM
+關注
關注
4文章
579瀏覽量
89068 -
WINDOWS
+關注
關注
4文章
3702瀏覽量
94026 -
定時器
+關注
關注
23文章
3368瀏覽量
123606 -
源碼
+關注
關注
8文章
685瀏覽量
31319
原文標題:一份單片機多任務事件驅動C源碼
文章出處:【微信號:c-stm32,微信公眾號:STM32嵌入式開發】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
熱點推薦
單片機小型操作系統多任務并行的原理
如果在單片機的中斷中修改了堆棧中的PC指針值,那么是不是中斷就返不回來原來的程序地址?如果還是這個地址是我故意設定的值那么他是不是執行完這個中斷就跳到我的設定的這個地址上去了?如果這個地址又是另外一個任務
發表于 10-18 10:59
51單片機多任務機制的實現策略研究
從操作系統實現多任務機制的原理入手,分析了51單片機實現多任務機制的基本條件,論述了5l單片機實現多任務控制的二種方案。
發表于 09-19 17:26
?159次下載
單片機系統多任務實現方法
考慮到成本等因素,大多數單片機系統的開發還是基于處理器直接編寫,但開發者經常面臨同時處理多個任務的要求,提出了一種單片機多任務程序設計的方法
發表于 11-21 16:47
?751次下載
MSP430單片機實時多任務操作系統c源代碼
: 資料-【C】嵌入系統-【C0】嵌入式綜合-【2】單片機編程-【參考程序】-MSP430單片機的實時多任務操作系統
發表于 09-18 10:18
?91次下載
如何使用51單片機進行多任務機制及應用
傳統的單片機程序一般采用單任務機制,單任務系統具有簡單直觀、易于控制的優點。然而由于程序只能按順序依次執行,缺乏靈活性,只能使用中斷函數實時地處理一
發表于 04-15 18:24
?8次下載
如何使用51單片機實現多任務機制的策略詳細資料說明
51單片機在微型智能控制系統中應用很廣,隨著人們對控制系統的要求不斷提高,51單片機的功能局限越發明顯。特別是51系列單片機不具有實時多任務支持功能,大大限制其在控制系統中的進
發表于 07-17 17:38
?6次下載
使用單片機實現道路交通燈多任務控制系統的課件說明
RTX-51是運行于8051單片機環境中的實時多任務操作系統(RTOS),其常用于處理復雜的多任務控制系統。8051單片機支持典型的RTX-51 Tiny和RTX-51 Full實時
發表于 04-16 17:31
?7次下載
基于M16C62單片機構成的實時多任務系統
、多任務系統的設計合應用成為單片機應用的新的發展趨勢。 μC/OS-Ⅱ是一個源碼公開的實時嵌入式操作系統,它的特點在于公開的源代碼,很強的移
一份單片機多任務事件驅動C源碼
評論