单片机程序构架

时间:2022-02-24 19:46:54
似乎软件架构,只有纯上位机软件才有,其实,嵌入式软件也有架构可言,只有好的架构,才能结构清晰,方便开发和让系统稳定的工作。在有嵌入式操作系统的情况下,可以利用多任务和信号量,事件等设计嵌入式软件。但是在没有操作系统的裸机中,更需要有好的架构。例如利用事件和状态机模拟实现多任务,或者利用定时器和消息队列,信号量等模拟实现多任务,有了多任务就能灵活的设计软件架构。

一种简单的信号量实现:

  1. void sem_init( volatile U08 *Sem )  
  2. {  
  3.     (*Sem)=0;  
  4. }  
  5.   
  6. void sem_post( volatile U08 *Sem )  
  7. {  
  8.     if( 0 == (*Sem) )  
  9.         (*Sem)++;  
  10. }  
  11.   
  12. U08  sem_wait( volatile U08 *Sem )   
  13. {  
  14.     if(0 == *Sem)  
  15.         return 1;  
  16.   
  17.     (*Sem)--;  
  18.   
  19.     return 0;  


在一个大的while(1)大循环中,利用信号量实现各个函数(任务)的同步。

  1. void Task_SysTime( void )  
  2. {     
  3.     static int TaskInitFlg = 0;  
  4.     U32 Timer1sCount = 0;           //时钟计数器个数   
  5.     U32 disstat = 0;  
  6.     static int tmrid0 = 0, tmrid1 = 0, tmrid2 = 0, tmrid3 = 0;  
  7.   
  8.     if( 0 == TaskInitFlg )  
  9.     {  
  10.         OSTimeDlyHMSM( 0, 0, 0, 50 //主要等待任务删除后才创建卡任务  
  11.           
  12.         tmrid0 = TimerSet(20);  //定时器0(毫秒定时器)用于键盘、寻卡、定时器中断服务程序,20ms  
  13.         tmrid1 = TimerSet(1000);//定时器1(毫秒定时器)用于背显、GPS、定时连接检测、空闲显示  
  14.         tmrid2 = TimerSet(500); //定时器2(毫秒定时器)用于信号显示,500ms  
  15.         tmrid3 = TimerSet(500); //定时器3(毫秒定时器)用于电池显示,500ms  
  16.   
  17.         sem_init( &gSem_EVT_CARDFLG_OK );                   //初始化为没有卡  
  18.           
  19.         APP_DisIdle( 2 );                               //显示一次时间  
  20.         APP_DisVoice();  
  21.           
  22.         TaskInitFlg = 1;                //任务初始化完成  
  23.     }  
  24.     else  
  25.         {  
  26.         HW_IWDG_ReloadCounter();                //清看门狗  
  27.   
  28.         if( 0 == TimerCheck(tmrid0) )  
  29.         {  
  30.             tmrid0 = TimerSet(20);          //定时器0重新定时, 20ms      
  31.   
  32.             Timer_ScanKeyboard();             //20MS键盘扫描   
  33.             Timer_FindCard();           //20MS寻卡处理  
  34.             TIM20MS_IRQHandler();       //20MS定时器中断服务程序  
  35.            }  
  36.       }  
  37. }  
  38.   
  39. void Task_Tick( void )  
  40. {  
  41.     Task_SysError();  
  42.   
  43.     Task_CardProc();  
  44.   
  45.     Task_SysTime();  
  46.   
  47.     Task_MenuProc();  
  48.   
  49.     Task_MtnLink();  
  50.       
  51.     Task_CommProc();  
  52. }  
  53. int main( void )  
  54. {  
  55.     Sys_Init(); //系统初始化  
  56.   
  57.     while( 1 )                                  
  58.     {   
  59.         Task_Tick();    //任务轮询  
  60.   
  61.         if( 0 == sem_wait( &gSem_EVT_QUIT_APP ) )   
  62.            break;     //应用退出  
  63.     }  
  64. }  

以上为借助信号量和定时器实现的一种简单的模拟多任务,其实也算不上是多任务,因为如果一个函数执行时间很长,如何打断它?

以下为借住定时器和任务队列实现的一种模拟多任务:

  1. #include <stdio.h>  
  2. #include "timTask.h"  
  3. #include "disp.h"  
  4.   
  5. /*===================================================== 
  6. =   变量定义 
  7. =====================================================*/  
  8. //任务队列  
  9. typedef struct{  
  10.     char    flagState;  //运行方式  0: 无任务  
  11.                         //          1: 运行   
  12.     char    flagRun;    //完成状态  0: 正在计数  
  13.                         //          1: 计数完成  
  14.     char    flagType;   //处理方式  0: 主任务处理  
  15.                         //          1: 中断处理  
  16.     ulong   cntRun;     //运行计数器  
  17.     ulong   numCircle;  //循环计数器  
  18.     void (*pTaskFunc)(void);    //任务  
  19. }TypeTimTask;  
  20.   
  21. TypeTimTask timTaskTab[TIM_TASK_NUMBER];  
  22.   
  23. /************************************************************************* 
  24. * 函数原型: 
  25. * 功能描述: 
  26. * 入口参数: 
  27. * 出口参数: 
  28. * 返 回 值: 
  29. *************************************************************************/  
  30. void TimTaskInit(void)  
  31. {  
  32.     int i;  
  33.       
  34.     for (i=0; i<TIM_TASK_NUMBER; i++)  
  35.     {  
  36.         timTaskTab[i].pTaskFunc = 0;  
  37.         timTaskTab[i].cntRun = 0;  
  38.         timTaskTab[i].numCircle = 0;  
  39.         timTaskTab[i].flagRun = 0;  
  40.         timTaskTab[i].flagState = 0;  
  41.     }  
  42.     SPT_register_call_back(TimTaskUpdate);  
  43.     SPT_set(TIM_TASK_PERIOD *64 / 1000);  
  44. }  
  45.   
  46. /************************************************************************* 
  47. * 函数原型: 
  48. * 功能描述: 
  49. * 入口参数: 
  50. * 出口参数: 
  51. * 返 回 值: 
  52. *************************************************************************/  
  53. short TimTaskAdd(ulong fsttim, ulong cirtim, void (*pTaskFunc)(void), uchar type)  
  54. {  
  55.     int i;  
  56.     int pos = -1;  
  57.     //查找位置  
  58.     for (i=0; i<TIM_TASK_NUMBER; i++)  
  59.     {  
  60.         if (timTaskTab[i].pTaskFunc == pTaskFunc)  
  61.         {  
  62.             pos = i;  
  63.             break;  
  64.         }  
  65.         if ((pos == -1) && (timTaskTab[i].flagState == 0))  
  66.         {  
  67.             pos = i;  
  68.         }  
  69.     }  
  70.     //任务已满  
  71.     if (pos == -1)  
  72.     {  
  73.         return -1;  
  74.     }  
  75.     //  
  76.     timTaskTab[pos].pTaskFunc = pTaskFunc;  
  77.     timTaskTab[pos].cntRun = fsttim / TIM_TASK_PERIOD;  
  78.     timTaskTab[pos].numCircle = cirtim / TIM_TASK_PERIOD;  
  79.     timTaskTab[pos].flagRun = 0;  
  80.     timTaskTab[pos].flagType = type;  
  81.     timTaskTab[pos].flagState = 1;  
  82.       
  83.     return 0;  
  84. }  
  85.   
  86. /************************************************************************* 
  87. * 函数原型: 
  88. * 功能描述: 
  89. * 入口参数: 
  90. * 出口参数: 
  91. * 返 回 值: 
  92. *************************************************************************/  
  93. void TimTaskDel(void (*pTaskFunc)(void))  
  94. {  
  95.     int i;  
  96.       
  97.     for (i=0; i<TIM_TASK_NUMBER; i++)  
  98.     {  
  99.         if (timTaskTab[i].pTaskFunc == pTaskFunc)  
  100.         {  
  101.             timTaskTab[i].flagState = 0;  
  102.             timTaskTab[i].flagRun = 0;  
  103.             return;  
  104.         }  
  105.     }  
  106. }  
  107.   
  108. /************************************************************************* 
  109. * 函数原型: 
  110. * 功能描述: 
  111. * 入口参数: 
  112. * 出口参数: 
  113. * 返 回 值: 
  114. *************************************************************************/  
  115. void TimTaskUpdate(void)  
  116. {  
  117.     int i;  
  118.       
  119.     SPT_set(TIM_TASK_PERIOD *64 / 1000);  
  120.       
  121.     for (i=0; i<TIM_TASK_NUMBER; i++)  
  122.     {  
  123.         if (timTaskTab[i].flagState != 0)  
  124.         {  
  125.             if (timTaskTab[i].cntRun != 0)  
  126.             {  
  127.                 timTaskTab[i].cntRun--;  
  128.             }  
  129.             else  
  130.             {  
  131.                 //判断处理位置  
  132.                 if (timTaskTab[i].flagType != 0)  
  133.                     (*timTaskTab[i].pTaskFunc)();  
  134.                 else  
  135.                     timTaskTab[i].flagRun = 1;  
  136.                 //判断重载  
  137.                 if (timTaskTab[i].numCircle)  
  138.                     timTaskTab[i].cntRun = timTaskTab[i].numCircle;  
  139.                 else  
  140.                     timTaskTab[i].flagState = 0;  
  141.             }  
  142.         }  
  143.     }  
  144. }  
  145.   
  146. /************************************************************************* 
  147. * 函数原型: 
  148. * 功能描述: 
  149. * 入口参数: 
  150. * 出口参数: 
  151. * 返 回 值: 
  152. *************************************************************************/  
  153. void TimTaskProc(void)  
  154. {  
  155.     int i;  
  156.       
  157.     for (i=0; i<TIM_TASK_NUMBER; i++)  
  158.     {  
  159.         if (timTaskTab[i].flagRun != 0)  
  160.         {  
  161.             timTaskTab[i].flagRun = 0;  
  162.             (*timTaskTab[i].pTaskFunc)();  
  163.         }  
  164.     }  
  165. }  
更为巧妙的是,可以借住函数指针实现一种灵活的菜单和按键实时处理结构。类似于windows下win32的消息驱动机制,
通过中断等方式把实时事件封装成消息。以下为定义界面刷新显示和响应按键处理的结构:
  1. #ifndef __PAGE_H_  
  2. #define __PAGE_H_  
  3.   
  4. #include "heads.h"  
  5.   
  6. /*===================================================== 
  7. =    
  8. =====================================================*/  
  9. typedef struct{  
  10.     void (* OnPaint)(void);  
  11.     void (* OnKey)(short);  
  12. }TypePage;  
  13.   
  14. /*===================================================== 
  15. =    
  16. =====================================================*/  
  17. void WndPageSet(const TypePage *pg, int type = 0);  
  18. TypePage * WndGetPage(void);  
  19. void WndPageEsc(void);  
  20. void WndOnKey(short key);  
  21. void WndOnPaint(void);  
  22. void WndMenuInit(const char *pmn, char mline);  
  23. void WndMenuSelet(int m);  
  24. char WndMenuGetSelet(void);  
  25. long WndGetPaseword(int x, int y, char *psw, int len, long qevent);  

  1. #include "pageWnd.h"  
  2.   
  3. /*===================================================== 
  4. =    
  5. =====================================================*/  
  6. char  flagPaint = 0;  
  7. void (* pOnPaint)(void) = 0;  
  8. void (* pOnKey)(short) = 0;  
  9.   
  10. const char *pMenuStr;  
  11. uchar menuSelect = 0;  
  12. uchar menuLine = 0;  
  13. uchar menuTop;  
  14.   
  15.   
  16. TypePage *pageCurrent;  
  17. TypePage *pageTreeTab[10];  
  18. uchar pageIndex = 0;  
  19.   
  20. /*===================================================== 
  21. =    
  22. =====================================================*/  
  23. void WndDrawMenu(void);  
  24.   
  25. /************************************************************************* 
  26. * 函数原型: 
  27. * 功能描述: 
  28. * 入口参数: 
  29. * 出口参数: 
  30. * 返 回 值: 
  31. *************************************************************************/  
  32. void WndPageSet(const TypePage *pg, int type)  
  33. {  
  34.     if (pg == &pageMain)        //防止出错  
  35.     {  
  36.         pageIndex = 0;  
  37.     }  
  38.     else if (type == 0)  
  39.     {  
  40.         pageTreeTab[pageIndex++] = pageCurrent;  
  41.     }  
  42.     pageCurrent = (TypePage *)pg;  
  43.     pOnPaint = pg->OnPaint;  
  44.     pOnKey = pg->OnKey;  
  45.     flagPaint = 1;  
  46. }  
  47.   
  48. /************************************************************************* 
  49. * 函数原型: 
  50. * 功能描述: 
  51. * 入口参数: 
  52. * 出口参数: 
  53. * 返 回 值: 
  54. *************************************************************************/  
  55. TypePage * WndGetPage(void)  
  56. {  
  57.     return pageCurrent;  
  58. }  
  59.   
  60. /************************************************************************* 
  61. * 函数原型: 
  62. * 功能描述: 
  63. * 入口参数: 
  64. * 出口参数: 
  65. * 返 回 值: 
  66. *************************************************************************/  
  67. void WndPageEsc(void)  
  68. {  
  69.     TypePage *pg;  
  70.       
  71.     if (pageIndex != 0)  
  72.     {  
  73.         pageIndex--;  
  74.         pg = pageTreeTab[pageIndex];  
  75.     }  
  76.     else  
  77.     {  
  78.         pg = (TypePage *)&pageMain;  
  79.     }  
  80.     pageCurrent = pg;  
  81.     pOnPaint = pg->OnPaint;  
  82.     pOnKey = pg->OnKey;  
  83.     flagPaint = 1;  
  84. }  
  85.   
  86. /************************************************************************* 
  87. * 函数原型: 
  88. * 功能描述: 
  89. * 入口参数: 
  90. * 出口参数: 
  91. * 返 回 值: 
  92. *************************************************************************/  
  93. void WndOnPaint(void)  
  94. {  
  95.     if (flagPaint != 0)  
  96.     {  
  97.         flagPaint = 0;  
  98.         (*pOnPaint)();  
  99.     }  
  100. }  
  101.   
  102. /************************************************************************* 
  103. * 函数原型: 
  104. * 功能描述: 
  105. * 入口参数: 
  106. * 出口参数: 
  107. * 返 回 值: 
  108. *************************************************************************/  
  109. void WndOnKey(short key)  
  110. {  
  111.     if (pOnKey != 0)  
  112.     {  
  113.         (*pOnKey)(key);  
  114.     }  
  115. }  
  116.   
  117. /************************************************************************* 
  118. * 函数原型: 
  119. * 功能描述: 
  120. * 入口参数: 
  121. * 出口参数: 
  122. * 返 回 值: 
  123. *************************************************************************/  
  124. void WndMenuInit(const char *pmn, char mline)  
  125. {  
  126.     menuSelect = 0;  
  127.     pMenuStr = pmn;  
  128.     menuLine = mline;  
  129.     menuTop = 0;  
  130.     WndDrawMenu();  
  131. }  
  132.   
  133. /************************************************************************* 
  134. * 函数原型: 
  135. * 功能描述: 
  136. * 入口参数: 
  137. * 出口参数: 
  138. * 返 回 值: 
  139. *************************************************************************/  
  140. void WndMenuSelet(int m)  
  141. {  
  142.     //光标滑动  
  143.     if (m > 0)           //下移  
  144.     {  
  145.         menuSelect++;  
  146.         if (menuSelect == menuLine)  
  147.             menuSelect = 0;  
  148.   
  149.         if (menuSelect > menuTop + 4)  
  150.         {  
  151.             if (menuLine < menuTop + 4)  
  152.                 menuTop = menuLine - 4;  
  153.             else  
  154.                 menuTop = menuSelect - 4;  
  155.         }  
  156.     }  
  157.     else if (m < 0)      //上移  
  158.     {  
  159.         if (menuSelect == 0)  
  160.             menuSelect = menuLine - 1;  
  161.         else  
  162.             menuSelect--;  
  163.     }  
  164.     //图框移动  
  165.     if (menuSelect < menuTop)                //上移  
  166.     {  
  167.         menuTop = menuSelect;  
  168.     }  
  169.     else if (menuSelect >= menuTop + 4)      //下移  
  170.     {  
  171.         menuTop = menuSelect - 3;  
  172.     }  
  173.       
  174.     WndDrawMenu();  
  175. }  
  176.   
  177. /************************************************************************* 
  178. * 函数原型: 
  179. * 功能描述: 
  180. * 入口参数: 
  181. * 出口参数: 
  182. * 返 回 值: 
  183. *************************************************************************/  
  184. char WndMenuGetSelet(void)  
  185. {  
  186.     return menuSelect + 1;  
  187. }  
  188.   
  189. /************************************************************************* 
  190. * 函数原型: 
  191. * 功能描述: 
  192. * 入口参数: 
  193. * 出口参数: 
  194. * 返 回 值: 
  195. *************************************************************************/  
  196. void WndDrawMenu(void)  
  197. {  
  198.     int i;  
  199.   
  200.     char buf[17];  
  201.     const char *pmn = pMenuStr + menuTop * 16;  
  202.   
  203.     DispClr();  
  204.     for (i=0; i<4; i++)  
  205.     {  
  206.         if (menuTop + i == menuLine)  
  207.             break;  
  208.         memcpy(buf, pmn, 16);  
  209.         buf[16] = '\0';  
  210.         if (menuSelect == menuTop + i)  
  211.             DispSetStyle(DISP_POSITION | DISP_REVERSE | DISP_7x9);  
  212.         else  
  213.             DispSetStyle(DISP_POSITION | DISP_NORMAL | DISP_7x9);  
  214.         DispString(0, i * 2, buf);  
  215.         pmn += 16;  
  216.     }  
  217. }  
  218.   
  219. /************************************************************************* 
  220. * 函数原型: 
  221. * 功能描述: 
  222. * 入口参数: 
  223. * 出口参数: 
  224. * 返 回 值: 
  225. *************************************************************************/  
  226. long WndGetPaseword(int x, int y, char *psw, int len, long qevent)  
  227. {  
  228.     int pin = 0;  
  229.     long keyevt;  
  230.     char key;  
  231.     char buf[20];  
  232.       
  233.     memset(buf, '_', len);  
  234.     buf[len] = '\0';  
  235. PSW_INPUT_LOOP:  
  236.     DispString(x, y, buf);  
  237.     keyevt = delay_and_wait_key(0, EXIT_KEY_ALL, 0);  
  238.     if (keyevt == qevent)  
  239.     {  
  240.         psw[0] = '\0';  
  241.         return keyevt;  
  242.     }  
  243.     switch (keyevt)  
  244.     {  
  245.         case EXIT_KEY_0:  
  246.             key = '0';  
  247.             break;  
  248.         case EXIT_KEY_1:  
  249.             key = '1';  
  250.             break;  
  251.         case EXIT_KEY_2:  
  252.             key = '2';  
  253.             break;  
  254.         case EXIT_KEY_3:  
  255.             key = '3';  
  256.             break;  
  257.         case EXIT_KEY_4:  
  258.             key = '4';  
  259.             break;  
  260.         case EXIT_KEY_5:  
  261.             key = '5';  
  262.             break;  
  263.         case EXIT_KEY_6:  
  264.             key = '6';  
  265.             break;  
  266.         case EXIT_KEY_7:  
  267.             key = '7';  
  268.             break;  
  269.         case EXIT_KEY_8:  
  270.             key = '8';  
  271.             break;  
  272.         case EXIT_KEY_9:  
  273.             key = '9';  
  274.             break;  
  275.         case EXIT_KEY_COMM:  
  276.             if (pin != 0)  
  277.             {  
  278.                 buf[--pin] = '_';  
  279.             }  
  280.             goto PSW_INPUT_LOOP;  
  281.             break;  
  282.         case EXIT_KEY_ENTER:  
  283.             psw[pin] = 0;  
  284.             return 0;  
  285.         default:  
  286.             goto PSW_INPUT_LOOP;  
  287.     }  
  288.     if (pin != len)  
  289.     {  
  290.         psw[pin] = key;  
  291.         buf[pin] = '*';  
  292.         pin++;  
  293.     }  
  294.     goto PSW_INPUT_LOOP;  
  295. }  

在软件设计时,如果添加界面和对应的按键处理,很灵活,只需要新添加一个文件就可以了,文件的内容,只需要实现OnPain和对应的OnKey

  1. #include "PageMenu.h"  
  2.   
  3.   
  4. /*===================================================== 
  5. =    
  6. =====================================================*/  
  7. const char mainMenuTab[] = /* 
  8. 1234567890123456*/"\  
  9. 1. 现场采集     \  
  10. 2. 数据上传     \  
  11. 3. 存储状态查询 \  
  12. 4. 时间设置     \  
  13. 5. 对比度设置   \  
  14. 6. 恢复出厂设置 \  
  15. 7. 关于         ";  
  16.   
  17. /*===================================================== 
  18. =    
  19. =====================================================*/  
  20. void PageMenuOnPain(void);  
  21. void WndMenuOnKey(short key);  
  22.   
  23. const TypePage pageMenu = {PageMenuOnPain, WndMenuOnKey};  
  24.   
  25. /************************************************************************* 
  26. * 函数原型: 
  27. * 功能描述: 
  28. * 入口参数: 
  29. * 出口参数: 
  30. * 返 回 值: 
  31. *************************************************************************/  
  32. void PageMenuOnPain(void)  
  33. {  
  34.     WndMenuInit(mainMenuTab, 7);  
  35. }  
  36.   
  37. /************************************************************************* 
  38. * 函数原型: 
  39. * 功能描述: 
  40. * 入口参数: 
  41. * 出口参数: 
  42. * 返 回 值: 
  43. *************************************************************************/  
  44. void WndMenuOnKey(short key)  
  45. {  
  46.     int res;  
  47.       
  48.     switch (key)  
  49.     {  
  50.         case KEY_F1:  
  51.         case KEY_ENTER:  
  52.             res = WndMenuGetSelet();  
  53.             switch (res)  
  54.             {  
  55.                 case 1:  
  56.                     WndPageSet(&pageSimp);  
  57.                     break;  
  58.                 case 2:  
  59.                     WndPageSet(&pagePclink);  
  60.                     break;  
  61.                 case 3:  
  62.                     WndPageSet(&pageInquire);  
  63.                     break;  
  64.                 case 4:  
  65.                     WndPageSet(&pageRtc);  
  66.                     break;  
  67.                 case 5:  
  68.                     WndPageSet(&pageGray);  
  69.                     break;  
  70.                 case 6:  
  71.                     SPageInit();  
  72.                     WndPageSet(&pageMenu, 1);  
  73.                     break;  
  74.                 case 7:  
  75.                     WndPageSet(&pageAbout);  
  76.                     break;  
  77.             }  
  78.             break;  
  79.         case KEY_F2:  
  80.         case KEY_F3:  
  81.             WndPageSet(&pageMain);  
  82.             break;  
  83.         case KEY_1:  
  84.             WndPageSet(&pageSimp);  
  85.             break;  
  86.         case KEY_2:  
  87.             WndPageSet(&pagePclink);  
  88.             break;  
  89.         case KEY_3:  
  90.             WndPageSet(&pageInquire);  
  91.             break;  
  92.         case KEY_4:  
  93.             WndPageSet(&pageRtc);  
  94.             break;  
  95.         case KEY_5:  
  96.             WndPageSet(&pageGray);  
  97.             break;  
  98.         case KEY_6:  
  99.             SPageInit();  
  100.             WndPageSet(&pageMenu, 1);  
  101.             break;  
  102.         case KEY_7:  
  103.             WndPageSet(&pageAbout);  
  104.             break;  
  105.         case KEY_UP:  
  106.             WndMenuSelet(-1);  
  107.             break;  
  108.         case KEY_DOWN:  
  109.             WndMenuSelet(1);  
  110.             break;  
  111.         case KEY_POWER:  
  112.             WndPageSet(&pagePower);  
  113.             break;  
  114.     }  
  115. }  

pageMain,pageAbout,pageRtc,pagePclink等文件,他们的结构很类似。都是实现了OnPaint和OnKey函数。
如:pagePclink.c文件内容:
实现了PagePclinkOnPaint和PagePclinOnKey函数.

CommPclink函数是自己想要实现的功能,可以自己定义。

  1. #include "pagePclink.h"  
  2.   
  3. /*===================================================== 
  4. =    
  5. =====================================================*/  
  6. void PagePclinkOnPaint(void);  
  7. void PagePclinOnKey(short key);  
  8.   
  9. const TypePage pagePclink = {PagePclinkOnPaint, PagePclinOnKey};  
  10.   
  11. /************************************************************************* 
  12. * 函数原型: 
  13. * 功能描述: 
  14. * 入口参数: 
  15. * 出口参数: 
  16. * 返 回 值: 
  17. *************************************************************************/  
  18. void PagePclinkOnPaint(void)  
  19. {  
  20.     DispClr();  
  21.     DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);  
  22.     DispString(0, 0, "    数据上传    ");  
  23.     DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);  
  24.     DispString(0, 6, "[连接]    [返回]");  
  25. }  
  26.   
  27. /************************************************************************* 
  28. * 函数原型: 
  29. * 功能描述: 
  30. * 入口参数: 
  31. * 出口参数: 
  32. * 返 回 值: 
  33. *************************************************************************/  
  34. void PagePclinOnKey(short key)  
  35. {  
  36.     switch (key)  
  37.     {  
  38.         case KEY_F1:  
  39.             CommPclink();  
  40.             break;  
  41.         case KEY_F3:  
  42.             WndPageEsc();  
  43.             break;  
  44.     }  
  45. }  

  1. #ifndef __PAGE_POWER_H_  
  2. #define __PAGE_POWER_H_  
  3.   
  4. #include "pageWnd.h"  
  5.   
  6. /*===================================================== 
  7. =    
  8. =====================================================*/  
  9. extern const TypePage pagePower;  
  10.   
  11. #endif  
  12.   
  13. #include "PagePower.h"  
  14. #include "disp.h"  
  15.   
  16. /*===================================================== 
  17. =    
  18. =====================================================*/  
  19. void PagePowerOnPaint(void);  
  20. void PagePowerOnKey(short key);  
  21.   
  22. const TypePage pagePower = {PagePowerOnPaint, PagePowerOnKey};  
  23.   
  24. /************************************************************************* 
  25. * 函数原型: 
  26. * 功能描述: 
  27. * 入口参数: 
  28. * 出口参数: 
  29. * 返 回 值: 
  30. *************************************************************************/  
  31. void PagePowerOnPaint(void)  
  32. {  
  33.     DispClr();  
  34.     DispSetStyle(DISP_CENTER | DISP_REVERSE | DISP_7x9);  
  35.     DispString(0, 0, "    电源管理    ");  
  36.     DispSetStyle(DISP_POSITION|DISP_NORMAL|DISP_7x9);  
  37.     DispString(0, 2, "  [Enter] 关机  ");  
  38.     DispString(0, 4, "  [F3   ] 返回  ");  
  39. }  
  40.   
  41.   
  42. /************************************************************************* 
  43. * 函数原型: 
  44. * 功能描述: 
  45. * 入口参数: 
  46. * 出口参数: 
  47. * 返 回 值: 
  48. *************************************************************************/  
  49. void PagePowerOnKey(short key)  
  50. {  
  51.     switch (key)  
  52.     {  
  53.         case KEY_ENTER:  
  54.         case KEY_POWER:  
  55.             Halt_EH0218(4);  
  56.             SysInit();  
  57.             break;  
  58.         case KEY_F3:  
  59.             WndPageEsc();  
  60.             break;  
  61.     }  
  62. }  

这样的一种结构,很灵活,在主函数中只需要这样调用:

  1. int main(void)  
  2. {  
  3.     short key;  
  4.     typ_msg_word smw;  
  5.       
  6.     SysInit();  
  7.   
  8.     for ( ; ; )  
  9.     {  
  10.         /* 
  11.           界面刷新 
  12.         */  
  13.         WndOnPaint();  
  14.   
  15.         /* 
  16.           消息处理 
  17.         */  
  18.         smw.s_word = sys_msg(SM_STAY_AWAKE);    //用SM_GOTO_SLEEP串口就不能用  
  19.         //按键处理  
  20.         if (smw.bits.key_available)   
  21.         {  
  22.             LcdOffDelay(LCD_OFF_DELAY);  
  23.               
  24.             key = KEY_read();  
  25.             if (key != -1)  
  26.             {  
  27.                 WndOnKey(key);  
  28.             }  
  29.         }  
  30.         //插入充电电源  
  31.         if (smw.bits.charger_on)  
  32.         {  
  33.             LcdOffDelay(LCD_OFF_DELAY);  
  34.         }  
  35.         //断开充电电源  
  36.         if (smw.bits.charger_off)  
  37.         {  
  38.             LcdOffDelay(LCD_OFF_DELAY);  
  39.             RefreshBattery();  
  40.         }  
  41.         //串口  
  42.         if (smw.bits.comm_data)  
  43.         {  
  44.             CommReceive();  
  45.         }  
  46.         //实时任务  
  47.         if (smw.bits.time_out)  
  48.         {  
  49.             TimTaskProc();  
  50.         }  
  51.     }