一种简单的信号量实现:
- 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)大循环中,利用信号量实现各个函数(任务)的同步。
- 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); //定时器0(毫秒定时器)用于键盘、寻卡、定时器中断服务程序,20ms
- tmrid1 = TimerSet(1000);//定时器1(毫秒定时器)用于背显、GPS、定时连接检测、空闲显示
- tmrid2 = TimerSet(500); //定时器2(毫秒定时器)用于信号显示,500ms
- tmrid3 = TimerSet(500); //定时器3(毫秒定时器)用于电池显示,500ms
- sem_init( &gSem_EVT_CARDFLG_OK ); //初始化为没有卡
- APP_DisIdle( 2 ); //显示一次时间
- APP_DisVoice();
- TaskInitFlg = 1; //任务初始化完成
- }
- else
- {
- HW_IWDG_ReloadCounter(); //清看门狗
- if( 0 == TimerCheck(tmrid0) )
- {
- tmrid0 = TimerSet(20); //定时器0重新定时, 20ms
- Timer_ScanKeyboard(); //20MS键盘扫描
- Timer_FindCard(); //20MS寻卡处理
- TIM20MS_IRQHandler(); //20MS定时器中断服务程序
- }
- }
- }
- 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; //应用退出
- }
- }
以上为借助信号量和定时器实现的一种简单的模拟多任务,其实也算不上是多任务,因为如果一个函数执行时间很长,如何打断它?
以下为借住定时器和任务队列实现的一种模拟多任务:
- #include <stdio.h>
- #include "timTask.h"
- #include "disp.h"
- /*=====================================================
- = 变量定义
- =====================================================*/
- //任务队列
- typedef struct{
- char flagState; //运行方式 0: 无任务
- // 1: 运行
- char flagRun; //完成状态 0: 正在计数
- // 1: 计数完成
- char flagType; //处理方式 0: 主任务处理
- // 1: 中断处理
- ulong cntRun; //运行计数器
- ulong numCircle; //循环计数器
- void (*pTaskFunc)(void); //任务
- }TypeTimTask;
- TypeTimTask timTaskTab[TIM_TASK_NUMBER];
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- void TimTaskInit(void)
- {
- int i;
- for (i=0; i<TIM_TASK_NUMBER; 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<TIM_TASK_NUMBER; 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<TIM_TASK_NUMBER; 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<TIM_TASK_NUMBER; 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<TIM_TASK_NUMBER; i++)
- {
- if (timTaskTab[i].flagRun != 0)
- {
- timTaskTab[i].flagRun = 0;
- (*timTaskTab[i].pTaskFunc)();
- }
- }
- }
通过中断等方式把实时事件封装成消息。以下为定义界面刷新显示和响应按键处理的结构:
- #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);
- #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] = '\0';
- if (menuSelect == menuTop + i)
- DispSetStyle(DISP_POSITION | DISP_REVERSE | DISP_7x9);
- else
- DispSetStyle(DISP_POSITION | DISP_NORMAL | DISP_7x9);
- DispString(0, i * 2, buf);
- pmn += 16;
- }
- }
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- long WndGetPaseword(int x, int y, char *psw, int len, long qevent)
- {
- int pin = 0;
- long keyevt;
- char key;
- char buf[20];
- memset(buf, '_', len);
- buf[len] = '\0';
- PSW_INPUT_LOOP:
- DispString(x, y, buf);
- keyevt = delay_and_wait_key(0, EXIT_KEY_ALL, 0);
- if (keyevt == qevent)
- {
- psw[0] = '\0';
- return keyevt;
- }
- switch (keyevt)
- {
- case EXIT_KEY_0:
- key = '0';
- break;
- case EXIT_KEY_1:
- key = '1';
- break;
- case EXIT_KEY_2:
- key = '2';
- break;
- case EXIT_KEY_3:
- key = '3';
- break;
- case EXIT_KEY_4:
- key = '4';
- break;
- case EXIT_KEY_5:
- key = '5';
- break;
- case EXIT_KEY_6:
- key = '6';
- break;
- case EXIT_KEY_7:
- key = '7';
- break;
- case EXIT_KEY_8:
- key = '8';
- break;
- case EXIT_KEY_9:
- key = '9';
- break;
- case EXIT_KEY_COMM:
- if (pin != 0)
- {
- buf[--pin] = '_';
- }
- goto PSW_INPUT_LOOP;
- break;
- case EXIT_KEY_ENTER:
- psw[pin] = 0;
- return 0;
- default:
- goto PSW_INPUT_LOOP;
- }
- if (pin != len)
- {
- psw[pin] = key;
- buf[pin] = '*';
- pin++;
- }
- goto PSW_INPUT_LOOP;
- }
在软件设计时,如果添加界面和对应的按键处理,很灵活,只需要新添加一个文件就可以了,文件的内容,只需要实现OnPain和对应的OnKey
- #include "PageMenu.h"
- /*=====================================================
- =
- =====================================================*/
- const char mainMenuTab[] = /*
- 1234567890123456*/"\
- 1. 现场采集 \
- 2. 数据上传 \
- 3. 存储状态查询 \
- 4. 时间设置 \
- 5. 对比度设置 \
- 6. 恢复出厂设置 \
- 7. 关于 ";
- /*=====================================================
- =
- =====================================================*/
- void PageMenuOnPain(void);
- void WndMenuOnKey(short key);
- const TypePage pageMenu = {PageMenuOnPain, WndMenuOnKey};
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- void PageMenuOnPain(void)
- {
- WndMenuInit(mainMenuTab, 7);
- }
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- void WndMenuOnKey(short key)
- {
- int res;
- switch (key)
- {
- case KEY_F1:
- case KEY_ENTER:
- res = WndMenuGetSelet();
- switch (res)
- {
- case 1:
- WndPageSet(&pageSimp);
- break;
- case 2:
- WndPageSet(&pagePclink);
- break;
- case 3:
- WndPageSet(&pageInquire);
- break;
- case 4:
- WndPageSet(&pageRtc);
- break;
- case 5:
- WndPageSet(&pageGray);
- break;
- case 6:
- SPageInit();
- WndPageSet(&pageMenu, 1);
- break;
- case 7:
- WndPageSet(&pageAbout);
- break;
- }
- break;
- case KEY_F2:
- case KEY_F3:
- WndPageSet(&pageMain);
- break;
- case KEY_1:
- WndPageSet(&pageSimp);
- break;
- case KEY_2:
- WndPageSet(&pagePclink);
- break;
- case KEY_3:
- WndPageSet(&pageInquire);
- break;
- case KEY_4:
- WndPageSet(&pageRtc);
- break;
- case KEY_5:
- WndPageSet(&pageGray);
- break;
- case KEY_6:
- SPageInit();
- WndPageSet(&pageMenu, 1);
- break;
- case KEY_7:
- WndPageSet(&pageAbout);
- break;
- case KEY_UP:
- WndMenuSelet(-1);
- break;
- case KEY_DOWN:
- WndMenuSelet(1);
- break;
- case KEY_POWER:
- WndPageSet(&pagePower);
- break;
- }
- }
pageMain,pageAbout,pageRtc,pagePclink等文件,他们的结构很类似。都是实现了OnPaint和OnKey函数。
如:pagePclink.c文件内容:
实现了PagePclinkOnPaint和PagePclinOnKey函数.
CommPclink函数是自己想要实现的功能,可以自己定义。
- #include "pagePclink.h"
- /*=====================================================
- =
- =====================================================*/
- void PagePclinkOnPaint(void);
- void PagePclinOnKey(short key);
- const TypePage pagePclink = {PagePclinkOnPaint, PagePclinOnKey};
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- void PagePclinkOnPaint(void)
- {
- DispClr();
- DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);
- DispString(0, 0, " 数据上传 ");
- DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);
- DispString(0, 6, "[连接] [返回]");
- }
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- void PagePclinOnKey(short key)
- {
- switch (key)
- {
- case KEY_F1:
- CommPclink();
- break;
- case KEY_F3:
- WndPageEsc();
- break;
- }
- }
- #ifndef __PAGE_POWER_H_
- #define __PAGE_POWER_H_
- #include "pageWnd.h"
- /*=====================================================
- =
- =====================================================*/
- extern const TypePage pagePower;
- #endif
- #include "PagePower.h"
- #include "disp.h"
- /*=====================================================
- =
- =====================================================*/
- void PagePowerOnPaint(void);
- void PagePowerOnKey(short key);
- const TypePage pagePower = {PagePowerOnPaint, PagePowerOnKey};
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- void PagePowerOnPaint(void)
- {
- DispClr();
- DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);
- DispString(0, 0, " 电源管理 ");
- DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);
- DispString(0, 2, " [Enter] 关机 ");
- DispString(0, 4, " [F3 ] 返回 ");
- }
- /*************************************************************************
- * 函数原型:
- * 功能描述:
- * 入口参数:
- * 出口参数:
- * 返 回 值:
- *************************************************************************/
- void PagePowerOnKey(short key)
- {
- switch (key)
- {
- case KEY_ENTER:
- case KEY_POWER:
- Halt_EH0218(4);
- SysInit();
- break;
- case KEY_F3:
- WndPageEsc();
- break;
- }
- }
这样的一种结构,很灵活,在主函数中只需要这样调用:
- int main(void)
- {
- short key;
- typ_msg_word smw;
- SysInit();
- for ( ; ; )
- {
- /*
- 界面刷新
- */
- WndOnPaint();
- /*
- 消息处理
- */
- smw.s_word = sys_msg(SM_STAY_AWAKE); //用SM_GOTO_SLEEP串口就不能用
- //按键处理
- if (smw.bits.key_available)
- {
- LcdOffDelay(LCD_OFF_DELAY);
- key = KEY_read();
- if (key != -1)
- {
- WndOnKey(key);
- }
- }
- //插入充电电源
- if (smw.bits.charger_on)
- {
- LcdOffDelay(LCD_OFF_DELAY);
- }
- //断开充电电源
- if (smw.bits.charger_off)
- {
- LcdOffDelay(LCD_OFF_DELAY);
- RefreshBattery();
- }
- //串口
- if (smw.bits.comm_data)
- {
- CommReceive();
- }
- //实时任务
- if (smw.bits.time_out)
- {
- TimTaskProc();
- }
- }
- }