硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5161|回复: 1
收起左侧

[emWin教程入门篇] 【STemWin教程】第28章       STemWin多任务设计(

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2015-2-6 16:20:06 | 显示全部楼层 |阅读模式
特别说明:完整STemWin的1-60期教程和配套实例下载地址:链接
第28章      STemWin多任务设计(模拟器)

    本期教程主要是跟大家讲一下STemWin多任务的设计,官方手册对于这部分内容在开头的时候讲的非常好,本期教程主要是把这部分内容给大家做个介绍,并在模拟器上跑一下多任务。
     28. 1  单任务系统(超级循环)
    28. 2 多任务系统:一个任务调用emWin
     28. 3 多任务系统:多个任务调用emWin
     28. 4 官方推荐运行方式
     28. 5 运行多任务(模拟器)
     28. 6 总结
28.1  单任务系统(超级循环)
    STemWin可以配置为不使用RTOS,这时就是整个程序在一个超循环中运行。通常,软件的所有组件都进行周期性调用。因为未使用实时内核,所以软件的实时部分必须使用中断。此类型系统主要用于小型系统,或者实时操作特性无关紧要时。平时大家写裸机程序的时候基本都是下面这种方式:
  1. void main (void)
  2. {
  3.      /* 初始化硬件 */
  4. HARDWARE_Init();
  5. /* 初始化软件组件 */
  6. XXX_Init();
  7. YYY_Init();
  8. /* 超级循环: 规则的调用所以软件组件*/
  9. while (1)
  10. {
  11. /* Exec all compontents of the software */
  12. XXX_Exec();
  13. YYY_Exec();
  14. }
  15. }
复制代码
    加入了STemWin的初始化函数后就是下面这样:
  1. void main (void)
  2. {
  3.      /* 初始化硬件 */
  4. HARDWARE_Init();
  5. /* 初始化软件组件 */
  6. XXX_Init();
  7. YYY_Init();
  8. GUI_Init();  //初始化emWin
  9. /* 超级循环: 规则的调用所以软件组件*/
  10. while (1)
  11. {
  12. /* Exec all compontents of the software */
  13. XXX_Exec();
  14. YYY_Exec();
  15. GUI_Exec(); //调用刷新函数
  16. }
  17. }
复制代码
     关于emWin的使用没有实际的限定。照例,需要在调用GUI_Init()之后才能使用该软件。之后,任何API函数都可使用。如果使用了窗口管理器的回调机制,则必须定期调用emWin更新函数。这通常通过从超循环内调用GUI_Exec()来完成。各种模块化函数,如GUI_Delay()和GUI_ExecDialog()不应在循环中使用,因为它们会阻断其它软件模块。可使用不支持多任务(#define GUI_OS 0)的默认配置;不需要内核接口例程。
l  优点
    因为未使用实时内核 (->较小的ROM大小,仅一个堆栈->用于堆栈的RAM较少),所以不存在使用RTOS中的抢先/同步问题。
l  缺点
     超循环类型程序的大小如果超出某个值,会变得很难维护。实时特性较差,因为一个软件组件无法被任何其它组件中断 (只能通过中断)。这意味着一个软件组件的反应时间取决于系统中所有其它组件的执行时间。
28.2  多任务系统:一个任务调用emWin
     使用了实时内核(RTOS)。用户程序分成不同部分,在不同的任务中执行,这些任务通常具有不同的优先级。通常,实时关键任务 (需要一定的反应时间)将具有最高优先级。一个单任务用于用户界面,它调用emWin函数。此任务在系统中通常具有最低优先级,或至少是最低优先级任务中的一个(一些统计任务或简单的空闲时间处理可能具有更低的优先级)。中断可以但不是必须用于软件的实时部分。
    如果使用了窗口管理器的回调机制,则必须从调用emWin的任务定期调用emWin更新函数(通常为GUI_Exec()、GUI_Delay())。 由 于emWin仅由一个任务调用,所以对于emWin而言,它与在单任务系统中的使用是相同的。可使用不支持多任务(#define GUI_OS 0)的默认配置;不需要内核接口例程。可使用任何实时内核,商用的或专用的。
l  优点
    该系统的实时特性非常优秀。任务的实时特性仅受以较高优先级运行的任务的影响。这意味着对在低优先级任务中运行的程序组件的更改完全不会影响实时特性。如果从低优先级任务执行用户界面,则意味着用户界面的更改不影响实时特性。因此,使用这种系统可轻松将软件的不同组件分配给开发团队的不同成员,成员彼此间可以高度独立地工作。
l  缺点
     用户需要拥有实时内核(RTOS),这需要资金并会耗费ROM和RAM(用于堆栈)。此外,还必须考虑任务的同步,以及如何将信息从一个任务传输到另一个任务。
28.3  多任务系统:多个任务调用emWin
    使用了实时内核(RTOS)。用户程序分成不同部分,在不同任务中执行,这些任务通常具有不同的优先级。通常,实时关键任务 (需要一定的反应时间)将具有最高优先级。多个任务用于用户界面,调用emWin函数。这些任务在系统中通常具有低优先级,所以它们不影响系统的实时特性。中断可以但不是必须用于软件的实时部分。
    如果使用了窗口管理器的回调机制,则必须从调用emWin的一个或多个任务定期调用emWin更新函数 (通常为GUI_Exec()GUI_Delay())。不可使用不支持多任务(#define GUI_OS 0)的默认配置。配置需要启用多任务支持并定义从中调用emWin的任务的最大数目(摘自GUIConf.h):
      #define GUI_OS 1 // Enable multitasking support
      #define GUI_MAX_TASK 5 // Max. number of tasks that may call emWin
    内核接口例程是必需的,并需要与正在使用的内核匹配。可使用任何实时内核,商用的或专用的。
l  优点
    该系统的实时特性非常优秀。任务的实时特性仅受以较高优先级运行的任务的影响。这意味着对在低优先级任务中运行的程序组件的更改完全不会影响实时特性。如果从低优先级任务执行用户界面,则意味着用户界面的更改不影响实时特性。因此,使用这种系统可轻松将软件的不同组件分配给开发团队的不同成员,成员彼此间可以高度独立地工作。
l  缺点
     用户必须拥有实时内核(RTOS),这需要资金并会耗费部分ROM和RAM(用于堆栈)。此外,还必须考虑任务的同步,以及如何将信息从一个任务传输到另一个任务。
28.4  官方推荐运行方式
    上面介绍了三种STemWin的运行方式,下面介绍下官方推荐的运行方式:
l  仅从一个任务调用emWin更新函数(即GUI_Exec()、GUI_Delay()),这有助于保持程序结构清晰。如果在您的系统中有足够的RAM,则指定一个任务(具有最低优先级)来更新emWin。如下面示例所示,此任务将不断调用GUI_Exec(),且不进行任何其它操作。
l  保持实时任务 (它们确定I/O、接口、网络等方面的系统特性)与调用emWin的任务分开,这有助于确保最佳的实时性能。
l  如果可能,仅为用户界面使用一个任务,这有助于保持程序结构简单并简化调试工作。(当然,这不是必须的,而且可能在一些系统中不适合。)
    官方推荐的这几点比较的笼统,后面我会在教程中再跟大家详细讲解。
28.5  运行多任务(模拟器)
    这个例子在模拟器中的位置:
28.1.png

     实际运行效果如下:
28.2.png


下面把相关的代码跟大家解释下:
  1. #ifndef SKIP_TEST
  2. #include <stddef.h>
  3. #include "GUI.h"
  4. #include "FRAMEWIN.h"
  5. #if GUI_OS == 0
  6.   #error Multitasking sample requires task awareness (#define GUI_OS 1)
  7. #endif
  8. /*******************************************************************
  9. *
  10. *       Define how to create a task and start multitasking
  11. *
  12. ********************************************************************
  13. */
  14. #ifndef WIN32
  15.   #include "RTOS.h"    /* Definitions for embOS */
  16.   #define CREATE_TASK(pTCB, pName, pFunc, Priority, pStack)  OS_CREATETASK(pTCB, pName, pFunc, Priority, pStack)
  17.   #define START_MT()  OS_Terminate(0)
  18.   #define Delay(t)    OS_Delay(t)
  19. #else
  20.   #include "SIM.h"     /* Definitions for the Win32 simulation */
  21.   #define CREATE_TASK(pTCB, pName, pFunc, Priority, pStack)   SIM_CreateTask(pName, pFunc)
  22.   #define START_MT()  SIM_Start()
  23.   #define Delay(t)    SIM_Delay(t)
  24. #endif
  25. /*******************************************************************
  26. *
  27. *       Static data
  28. *
  29. ********************************************************************
  30. */
  31. #ifndef WIN32
  32.   //
  33.   // Stacks
  34.   //
  35.   static OS_STACKPTR int Stack_0[600];
  36.   static OS_STACKPTR int Stack_1[600];
  37.   static OS_STACKPTR int Stack_2[600];
  38.   static OS_TASK aTCB[3];               // Task control blocks
  39. #endif
  40. /*******************************************************************
  41. *
  42. *       Static code
  43. *
  44. ********************************************************************
  45. */
  46. /*******************************************************************
  47. *
  48. *       _cbCallbackT0
  49. */
  50. static int XPos;
  51. static const char aText[] = "Moving text...";
  52. static void _cbCallbackT0(WM_MESSAGE * pMsg) {(1)
  53.   switch (pMsg->MsgId) {
  54.   case WM_PAINT:
  55.     //
  56.     // Handle the paint message
  57.     //
  58.     GUI_SetBkColor(GUI_RED);
  59.     GUI_SetColor(GUI_BLACK);
  60.     GUI_SetFont(&GUI_FontComic24B_ASCII);
  61.     GUI_Clear();
  62.     GUI_DispStringAt(aText, XPos, 0);
  63.     break;
  64.   default:
  65.     WM_DefaultProc(pMsg);
  66.   }
  67. }
  68. /*******************************************************************
  69. *
  70. *       _cbCallbackT1
  71. */
  72. static void _cbCallbackT1(WM_MESSAGE * pMsg) {(2)
  73.   WM_HWIN hWin = (FRAMEWIN_Handle)(pMsg->hWin);
  74.   switch (pMsg->MsgId) {
  75.   case WM_PAINT:
  76.     //
  77.     // Handle the paint message
  78.     //
  79.     GUI_SetBkColor(GUI_BLUE);
  80.     GUI_SetColor(GUI_WHITE);
  81.     GUI_SetFont(&GUI_FontComic24B_ASCII);
  82.     GUI_SetTextAlign(GUI_TA_HCENTER | GUI_TA_VCENTER);
  83.     GUI_Clear();
  84.     GUI_DispStringHCenterAt("Moving window...",
  85.                             WM_GetWindowSizeX(hWin) / 2,
  86.                             WM_GetWindowSizeY(hWin) / 2);
  87.     break;
  88.   default:
  89.     WM_DefaultProc(pMsg);
  90.   }
  91. }
  92. /*******************************************************************
  93. *
  94. *       _cbBackgroundWin
  95. */
  96. static void _cbBackgroundWin(WM_MESSAGE* pMsg) {(3)
  97.   switch (pMsg->MsgId) {
  98.   case WM_PAINT:
  99.     //
  100.     // Handle only the paint message
  101.     //
  102.     GUI_SetBkColor(0x00CC00);
  103.     GUI_Clear();
  104.     GUI_SetFont(&GUI_Font24_ASCII);
  105.     GUI_DispStringHCenterAt("emWin - multitasking demo\n", 160, 5);
  106.     GUI_SetFont(&GUI_Font13_1);
  107.     GUI_DispStringAt("Scrolling text and moving windows without flickering", 5, 35);
  108.   default:
  109.     WM_DefaultProc(pMsg);
  110.   }
  111. }
  112. /*******************************************************************
  113. *
  114. *       _Task_0
  115. */
  116. static void _Task_0(void) {(4)
  117.   //
  118.   // Create frame window
  119.   //
  120.   FRAMEWIN_Handle hFrameWin = FRAMEWIN_Create("Task 0",  NULL, WM_CF_SHOW | WM_CF_STAYONTOP,  0, 70, 200, 40);
  121.   //
  122.   // Create child window
  123.   //
  124.   WM_HWIN         hChildWin = WM_CreateWindowAsChild(0, 0, 0, 0, WM_GetClientWindow(hFrameWin),
  125.                                                      WM_CF_SHOW | WM_CF_MEMDEV,  _cbCallbackT0, 0);
  126.   FRAMEWIN_SetActive(hFrameWin, 0);
  127.   //
  128.   // Make sure the right window is active...
  129.   //
  130.   WM_SelectWindow(hChildWin);
  131.   //
  132.   // ...and the right font is selected
  133.   //
  134.   GUI_SetFont(&GUI_FontComic24B_ASCII);
  135.   while(1) {
  136.     GUI_RECT Rect;
  137.     int XLen;
  138.     XLen = GUI_GetStringDistX(aText);       // Get the length of the string
  139.     WM_GetClientRect(&Rect);                // Get the size of the window
  140.     //
  141.     // Show moving text
  142.     //
  143.     for (XPos = 0; XPos < (Rect.x1 - Rect.x0) - XLen; XPos++) {
  144.       WM_InvalidateWindow(hChildWin);
  145.       Delay(50);
  146.     }
  147.     for (; XPos >= 0; XPos--) {
  148.       WM_InvalidateWindow(hChildWin);
  149.       Delay(100);
  150.     }
  151.   }
  152. }
  153. /*******************************************************************
  154. *
  155. *       _Task_1
  156. */
  157. static void _Task_1(void) {(5)
  158.   //
  159.   // Create frame window
  160.   //
  161.   FRAMEWIN_Handle hFrameWin = FRAMEWIN_Create("Task 1", NULL, WM_CF_SHOW | WM_CF_STAYONTOP,
  162.                                               20, 170, 200, 40);
  163.   //
  164.   // Create child window
  165.   //
  166.   WM_HWIN hChildWin = WM_CreateWindowAsChild(0, 0, 0, 0, WM_GetClientWindow(hFrameWin), WM_CF_SHOW | WM_CF_MEMDEV,
  167.                                              _cbCallbackT1, 0);
  168.   FRAMEWIN_SetActive(hFrameWin, 0);
  169.   while(1) {
  170.     int i;
  171.     int nx = 80;
  172.     int ny = 90;
  173.     //
  174.     // Move window continously
  175.     //
  176.     for (i = 0; i < ny; i++) {
  177.       WM_MoveWindow(hFrameWin, 0, -2);
  178.       Delay(50);
  179.     }
  180.     for (i = 0; i < nx; i++) {
  181.       WM_MoveWindow(hFrameWin, 2, 0);
  182.       Delay(50);
  183.     }
  184.     for (i = 0; i < ny; i++) {
  185.       WM_MoveWindow(hFrameWin, 0, 2);
  186.       Delay(50);
  187.     }
  188.     for (i = 0; i < nx; i++) {
  189.       WM_MoveWindow(hFrameWin, -2, 0);
  190.       Delay(50);
  191.     }
  192.   }
  193. }
  194. /*******************************************************************
  195. *
  196. *       _GUI_Task
  197. *
  198. * This task does the background processing.
  199. * The MainTask job is to update invalid windows, but other things such as
  200. * evaluating mouse or touch input may also be done.
  201. */
  202. static void _GUI_Task(void) {(6)
  203.   while(1) {
  204.     GUI_Exec();           // Do the background work ... Update windows etc.)
  205.     GUI_X_ExecIdle();     // Nothing left to do for the moment ... Idle processing
  206.   }
  207. }
  208. /*********************************************************************
  209. *
  210. *       Public code
  211. *
  212. **********************************************************************
  213. */
  214. /*********************************************************************
  215. *
  216. *       MainTask
  217. */
  218. void MainTask(void) {
  219.   //
  220.   // Init GUI
  221.   //
  222.   GUI_Init();
  223.   WM_SetCreateFlags(WM_CF_MEMDEV);              // Use memory devices on all windows to avoid flicker
  224.   WM_SetCallback(WM_HBKWIN, _cbBackgroundWin);  // Set callback for background window
  225.   //
  226.   // Create tasks
  227.   //
  228.   CREATE_TASK(&aTCB[0], "Task_0",   _Task_0,   80, Stack_0);(7)
  229.   CREATE_TASK(&aTCB[1], "Task_1",   _Task_1,   60, Stack_1);
  230.   CREATE_TASK(&aTCB[2], "GUI_TASK", _GUI_Task,  1, Stack_2);
  231.   //
  232.   // Start multitasking
  233.   //
  234.   START_MT();
  235. }
  236. #endif
复制代码
跟大家讲这个DEMO,主要是想让大家对emWin的多任务框架有个了解,对于初学者可以不必了解主要是实现了什么功能。但必须得知道这个多任务实现的框架。
1.     任务0所创建窗口的回调函数。
2.     任务1所创建窗口的回调函数。
3.     桌面窗口的回调函数。
4.     任务0所跑的具体函数
5.     任务1所跑的具体函数。
6.     这个任务专门用emWin的刷新。
7.     创建三个任务。
28.6  总结
    本期教程就跟大家讲这么多,大家要认真的学习一下本期教程开头对emWin多种运行方式的介绍。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

1

主题

5

回帖

1

积分

新手上路

积分
1
发表于 2015-8-4 18:40:37 | 显示全部楼层
您好我有个多任务的问题想请教您一下:
我用emWin和ucos2做了一个项目,使用多任务调用emWin,其中一个任务emwin_task()调用GUI_Exec()函数进行刷新,这个任务只负责刷新,不处理其他业务,后来发现出现死机问题,调试发现是程序卡在了GUI_Exec()这个函数里面无法返回,后来通过调试窗口发现程序在WM_Exec(),GUI_ALLOC_LockH(),GUI_ALLOC_UnlockH(),GUI_ALLOC_h2p()这几个函数之间乱跳,但他们是emwin的库函数,无法看见源码,但上网查看相关资料后发现这几个函数应该是与内存管理相关的函数,所以就怀疑死机是由于内存或多任务调用emwin时的资源保护相关,于是就把分配给emwin的内存增加,同时通过ucos的信号量实现GUI_X_LOCK()和GUI_X_UNLOCK()函数,可是问题仍然没有解决,希望大家给予帮助,谢谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-15 08:24 , Processed in 0.287276 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表