似乎软件架构,只有纯上位机软件才有,其实,嵌入式软件也有架构可言,只有好的架构,才能结构清晰,方便开发和让系统稳定的工作。在有嵌入式操作系统的情况下,可以利用多任务和信号量,事件等设计嵌入式软件。但是在没有操作系统的裸机中,更需要有好的架构。例如利用事件和状态机模拟实现多任务,或者利用定时器和消息队列,信号量等模拟实现多任务,有了多任务就能灵活的设计软件架构。
一种简单的信号量实现:
[cpp]
view plain
copy
- void sem_init( volatile U08 *Sem )
- {
- (*Sem)=0;
- }
-
- void sem_post( volatile U08 *Sem )
- {
- if( 0 == (*Sem) )
- (*Sem)++;
- }
-
- U08 sem_wait( volatile U08 *Sem )
- {
- if(0 == *Sem)
- return 1;
-
- (*Sem)--;
-
- return 0;
- }
在一个大的while(1)大循环中,利用信号量实现各个函数(任务)的同步。
[cpp]
view plain
copy
- void Task_SysTime( void )
- {
- static int TaskInitFlg = 0;
- U32 Timer1sCount = 0;
- U32 disstat = 0;
- static int tmrid0 = 0, tmrid1 = 0, tmrid2 = 0, tmrid3 = 0;
-
- if( 0 == TaskInitFlg )
- {
- OSTimeDlyHMSM( 0, 0, 0, 50
-
- tmrid0 = TimerSet(20);
- tmrid1 = TimerSet(1000);
- tmrid2 = TimerSet(500);
- tmrid3 = TimerSet(500);
-
- sem_init( &gSem_EVT_CARDFLG_OK );
-
- APP_DisIdle( 2 );
- APP_DisVoice();
-
- TaskInitFlg = 1;
- }
- else
- {
- HW_IWDG_ReloadCounter();
-
- if( 0 == TimerCheck(tmrid0) )
- {
- tmrid0 = TimerSet(20);
-
- Timer_ScanKeyboard();
- Timer_FindCard();
- TIM20MS_IRQHandler();
- }
- }
- }
-
- void Task_Tick( void )
- {
- Task_SysError();
-
- Task_CardProc();
-
- Task_SysTime();
-
- Task_MenuProc();
-
- Task_MtnLink();
-
- Task_CommProc();
- }
- int main( void )
- {
- Sys_Init();
-
- while( 1 )
- {
- Task_Tick();
-
- if( 0 == sem_wait( &gSem_EVT_QUIT_APP ) )
- break;
- }
- }
以上为借助信号量和定时器实现的一种简单的模拟多任务,其实也算不上是多任务,因为如果一个函数执行时间很长,如何打断它?
以下为借住定时器和任务队列实现的一种模拟多任务:
[cpp]
view plain
copy
- #include
- #include "timTask.h"
- #include "disp.h"
-
-
-
-
-
- typedef struct{
- char flagState;
-
- char flagRun;
-
- char flagType;
-
- ulong cntRun;
- ulong numCircle;
- void (*pTaskFunc)(void);
- }TypeTimTask;
-
- TypeTimTask timTaskTab[TIM_TASK_NUMBER];
-
-
-
-
-
-
-
-
- void TimTaskInit(void)
- {
- int i;
-
- for (i=0; i
- {
- timTaskTab[i].pTaskFunc = 0;
- timTaskTab[i].cntRun = 0;
- timTaskTab[i].numCircle = 0;
- timTaskTab[i].flagRun = 0;
- timTaskTab[i].flagState = 0;
- }
- SPT_register_call_back(TimTaskUpdate);
- SPT_set(TIM_TASK_PERIOD *64 / 1000);
- }
-
-
-
-
-
-
-
-
- short TimTaskAdd(ulong fsttim, ulong cirtim, void (*pTaskFunc)(void), uchar type)
- {
- int i;
- int pos = -1;
-
- for (i=0; i
- {
- if (timTaskTab[i].pTaskFunc == pTaskFunc)
- {
- pos = i;
- break;
- }
- if ((pos == -1) && (timTaskTab[i].flagState == 0))
- {
- pos = i;
- }
- }
-
- if (pos == -1)
- {
- return -1;
- }
-
- timTaskTab[pos].pTaskFunc = pTaskFunc;
- timTaskTab[pos].cntRun = fsttim / TIM_TASK_PERIOD;
- timTaskTab[pos].numCircle = cirtim / TIM_TASK_PERIOD;
- timTaskTab[pos].flagRun = 0;
- timTaskTab[pos].flagType = type;
- timTaskTab[pos].flagState = 1;
-
- return 0;
- }
-
-
-
-
-
-
-
-
- void TimTaskDel(void (*pTaskFunc)(void))
- {
- int i;
-
- for (i=0; i
- {
- if (timTaskTab[i].pTaskFunc == pTaskFunc)
- {
- timTaskTab[i].flagState = 0;
- timTaskTab[i].flagRun = 0;
- return;
- }
- }
- }
-
-
-
-
-
-
-
-
- void TimTaskUpdate(void)
- {
- int i;
-
- SPT_set(TIM_TASK_PERIOD *64 / 1000);
-
- for (i=0; i
- {
- if (timTaskTab[i].flagState != 0)
- {
- if (timTaskTab[i].cntRun != 0)
- {
- timTaskTab[i].cntRun--;
- }
- else
- {
-
- if (timTaskTab[i].flagType != 0)
- (*timTaskTab[i].pTaskFunc)();
- else
- timTaskTab[i].flagRun = 1;
-
- if (timTaskTab[i].numCircle)
- timTaskTab[i].cntRun = timTaskTab[i].numCircle;
- else
- timTaskTab[i].flagState = 0;
- }
- }
- }
- }
-
-
-
-
-
-
-
-
- void TimTaskProc(void)
- {
- int i;
-
- for (i=0; i
- {
- if (timTaskTab[i].flagRun != 0)
- {
- timTaskTab[i].flagRun = 0;
- (*timTaskTab[i].pTaskFunc)();
- }
- }
- }
更为巧妙的是,可以借住函数指针实现一种灵活的菜单和按键实时处理结构。类似于windows下win32的消息驱动机制,
通过中断等方式把实时事件封装成消息。以下为定义界面刷新显示和响应按键处理的结构:
[cpp]
view plain
copy
- #ifndef __PAGE_H_
- #define __PAGE_H_
-
- #include "heads.h"
-
-
-
-
- typedef struct{
- void (* OnPaint)(void);
- void (* OnKey)(short);
- }TypePage;
-
-
-
-
- void WndPageSet(const TypePage *pg, int type = 0);
- TypePage * WndGetPage(void);
- void WndPageEsc(void);
- void WndOnKey(short key);
- void WndOnPaint(void);
- void WndMenuInit(const char *pmn, char mline);
- void WndMenuSelet(int m);
- char WndMenuGetSelet(void);
- long WndGetPaseword(int x, int y, char *psw, int len, long qevent);
[cpp]
view plain
copy
- #include "pageWnd.h"
-
-
-
-
- char flagPaint = 0;
- void (* pOnPaint)(void) = 0;
- void (* pOnKey)(short) = 0;
-
- const char *pMenuStr;
- uchar menuSelect = 0;
- uchar menuLine = 0;
- uchar menuTop;
-
-
- TypePage *pageCurrent;
- TypePage *pageTreeTab[10];
- uchar pageIndex = 0;
-
-
-
-
- void WndDrawMenu(void);
-
-
-
-
-
-
-
-
- void WndPageSet(const TypePage *pg, int type)
- {
- if (pg == &pageMain)
- {
- pageIndex = 0;
- }
- else if (type == 0)
- {
- pageTreeTab[pageIndex++] = pageCurrent;
- }
- pageCurrent = (TypePage *)pg;
- pOnPaint = pg->OnPaint;
- pOnKey = pg->OnKey;
- flagPaint = 1;
- }
-
-
-
-
-
-
-
-
- TypePage * WndGetPage(void)
- {
- return pageCurrent;
- }
-
-
-
-
-
-
-
-
- void WndPageEsc(void)
- {
- TypePage *pg;
-
- if (pageIndex != 0)
- {
- pageIndex--;
- pg = pageTreeTab[pageIndex];
- }
- else
- {
- pg = (TypePage *)&pageMain;
- }
- pageCurrent = pg;
- pOnPaint = pg->OnPaint;
- pOnKey = pg->OnKey;
- flagPaint = 1;
- }
-
-
-
-
-
-
-
-
- void WndOnPaint(void)
- {
- if (flagPaint != 0)
- {
- flagPaint = 0;
- (*pOnPaint)();
- }
- }
-
-
-
-
-
-
-
-
- void WndOnKey(short key)
- {
- if (pOnKey != 0)
- {
- (*pOnKey)(key);
- }
- }
-
-
-
-
-
-
-
-
- void WndMenuInit(const char *pmn, char mline)
- {
- menuSelect = 0;
- pMenuStr = pmn;
- menuLine = mline;
- menuTop = 0;
- WndDrawMenu();
- }
-
-
-
-
-
-
-
-
- void WndMenuSelet(int m)
- {
-
- if (m > 0)
- {
- menuSelect++;
- if (menuSelect == menuLine)
- menuSelect = 0;
-
- if (menuSelect > menuTop + 4)
- {
- if (menuLine < menuTop + 4)
- menuTop = menuLine - 4;
- else
- menuTop = menuSelect - 4;
- }
- }
- else if (m < 0)
- {
- if (menuSelect == 0)
- menuSelect = menuLine - 1;
- else
- menuSelect--;
- }
-
- if (menuSelect < menuTop)
- {
- menuTop = menuSelect;
- }
- else if (menuSelect >= menuTop + 4)
- {
- menuTop = menuSelect - 3;
- }
-
- WndDrawMenu();
- }
-
-
-
-
-
-
-
-
- char WndMenuGetSelet(void)
- {
- return menuSelect + 1;
- }
-
-
-
-
-
-
-
-
- void WndDrawMenu(void)
- {
- int i;
-
- char buf[17];
- const char *pmn = pMenuStr + menuTop * 16;
-
- DispClr();
- for (i=0; i<4; i++)
- {
- if (menuTop + i == menuLine)
- break;
- memcpy(buf, pmn, 16);
- buf[16] = '