【第3版emWin教程】第45章 emWin6.x窗口管理器之定时器使用

2021-10-09 15:03:49 浏览数 (1)

教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

第45章 emWin6.x窗口管理器之定时器使用

本期教程为大家讲解窗口管理器之定时器使用方法,这个定时器使用起来比较简单,而且很实用,以后的项目工程中很多时候要用到,不过使用时有些小问题要特别注意,如果不注意的话,定时器将无法正确启动。

45.1 初学者重要提示

45.2 定时器功能介绍

45.3 桌面窗口上使用定时器实例

45.4 对话框上使用定时器实例

45.5 实验例程说明(RTOS)

45.6 实验例程说明(裸机)

45.7 总结

45.1 初学者重要提示

1、 特别注意定时器使用时的注意事项,在本章45.2小节详细讲解了,要不定时器无法正确启动。然后再结合本章教程给出的实例进行学习。

2、 窗口管理器这块的API函数应该是emWin手册所有章节中函数最多的,定时器的API函数也属于这部分。下图是中文版手册里面API函数位置:

下图是英文版手册里面API函数的位置:

45.2 定时器功能介绍

emWin中有四个定时器相关的API函数供用户调用。

这四个函数都是简单易用,不过使用时有些问题还是要注意下,要不无法正确启动,初学者也是经常在这几个点犯错误,导致配置了定时器,却没有效果。

  • WM_HTIMER WM_CreateTimer(WM_HWIN hWin, int UserId, int Period, int Mode)

此函数用于创建定时器,注意,这个函数创建的定时器是单次的,也是说定时器时间到后定时器就不再工作了,如果还想继续使用,务必要在窗口回调函数的定时器消息WM_TIMER里面调用函数WM_RestartTimer重启此定时器。

第1个参数 hWin填写窗口的句柄,即给那个窗口创建定时器。这个参数比较关键,很多初学者经常在这个参数上犯错误。如果是给对话框创建定时器,且对话框的主体是框架窗口FrameWin或者直接给框架窗口FrameWin创建定时器,此参数必须要使用函数WM_GetClientWindow获得框架窗口的客户区,这一点非常重要。如果对话框的主体是Windows或者直接给Windows窗口创建定时器,无需使用函数WM_GetClientWindow了,直接填句柄就可以了。

第2个参数UserId填写此定时器的ID,设置ID的目的是方便同一个窗口创建了多个定时器的话,可以用来区分是哪个定时器。

第3个参数Period是定时器周期,确切的说是溢出时间更贴切,因为此定时器不是自动重启的,仅执行一次,时间到后会给定时器所在窗口的回调函数发送WM_TIMER消息,如果要重新启动需要在此消息里面调用函数WM_RestartTimer重新启动。

第4个参数暂时保留,未被使用。

  • void WM_DeleteTimer(WM_HTIMER hTimer)

此函数用于定时器删除,参数是定时器句柄(即调用函数WM_CreateTimer的返回值)。

  • int WM_GetTimerId(WM_HTIMER hTimer);

此函数用于获得定时器ID,参数是定时器句柄(即调用函数WM_CreateTimer的返回值)。

  • void WM_RestartTimer(WM_HTIMER hTimer, int Period)

此函数用于重启定时器。

第1个参数是定时器句柄,即调用函数WM_CreateTimer的返回值。

第2个参数是重新配置定时器的溢出时间。

-----------------

讲解完这些,也许初学者还有些模糊,没有关系,且看下面举的几个例子,看完后基本就都理解了。

45.3 桌面窗口上使用定时器实例

这个Demo主要是实现每隔1000ms改变一次桌面窗口的颜色,源代码如下(可以将其直接的复制到开发板或者模拟器上面运行)。

代码语言:javascript复制
#include "DIALOG.h"

/*
*********************************************************************************************************
*                                       变量
*********************************************************************************************************
*/
GUI_COLOR _acColor[3] = {GUI_BLUE,GUI_RED,GUI_YELLOW};  //--------------(1)
static  char ucBackColor;


/*
*********************************************************************************************************
*    函 数 名: _cbBkWindow
*    功能说明: 桌面窗口回调函数        
*    形    参: 无
*    返 回 值: 返回对话框句柄
*********************************************************************************************************
*/
static void _cbBkWindow(WM_MESSAGE * pMsg) 
{
    WM_HWIN hWin = pMsg->hWin;

    switch (pMsg->MsgId) 
    {
        /* 重绘消息 */
        case WM_PAINT:  //--------------(2)
            ucBackColor  ;
            if (ucBackColor == 3)
            {
                ucBackColor = 0;
            }
            GUI_SetBkColor(_acColor[ucBackColor]);
            GUI_Clear();
            break;

        /* 定时器消息 */
        case WM_TIMER: //--------------(3)
            WM_InvalidateWindow(hWin);
            WM_RestartTimer(pMsg->Data.v, 1000);
            break;
            
        default:
            WM_DefaultProc(pMsg);
    }
}

/*
*********************************************************************************************************
*    函 数 名: MainTask
*    功能说明: GUI主函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void MainTask(void) 
{
    WM_HTIMER hTimer;

    /* 初始emWin */
    GUI_Init();

    /* 设置桌面窗口回调函数 */
    WM_SetCallback(WM_HBKWIN, _cbBkWindow); //--------------(4)

    /* 为桌面窗口创建定时器,定时器溢出时间1000ms */
    hTimer = WM_CreateTimer(WM_HBKWIN, 0, 1000, 0); //--------------(5)

    while (1)
    {
        GUI_Delay(10);
    }
}
  1. 定义一个数组,里面有三种颜色,再定义一个变量,用于三种颜色的切换。
  2. 桌面窗口回调函数的重绘消息,每执行一次更新一次背景色。
  3. 定时器消息,这里要特别注意,如果想要定时器周期性执行,而不是只执行一次,必须得调用重启定时器函数WM_RestartTimer()。在这个消息里面将桌面窗口无效,从而会触发窗口管理器去执行WM_PAINT消息,这样就实现了定时修改桌面窗口背景色。
  4. 设置桌面窗口的回调函数。
  5. 创建定时器函数,溢出时间是1000ms。

这个Demo的实际显示效果如下:

45.4 对话框上使用定时器实例

这个Demo的主要功能是在对话框上面实现一个计数功能,每100ms更新一次,下面是源码(可以将其直接的复制到开发板或者模拟器上面运行)

代码语言:javascript复制
#include "DIALOG.h"
#include "stdio.h"



/*
*********************************************************************************************************
*                                        变量
*********************************************************************************************************
*/
static int Count = 0;


/*
*********************************************************************************************************
*                           GUI_WIDGET_CREATE_INFO类型数组
*********************************************************************************************************
*/
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
    { FRAMEWIN_CreateIndirect,  "armfly",   0,               0,  0,  320,240,0,0},
    { TEXT_CreateIndirect,      "0000",     GUI_ID_TEXT0,    30,30,300,48, 0,0}
};


/*
*********************************************************************************************************
*    函 数 名: _cbCallback
*    功能说明: 对话框回调函数        
*    形    参: pMsg  回调参数 
*    返 回 值: 无
*********************************************************************************************************
*/
static void _cbCallback(WM_MESSAGE * pMsg) 
{
    int NCode, Id;
    char buf[10];
    WM_HWIN hWin = pMsg->hWin;

    switch (pMsg->MsgId) 
    {
        case WM_INIT_DIALOG:

            //
            //初始化框架窗口
            //
            FRAMEWIN_SetFont(hWin,&GUI_Font24B_ASCII);
            FRAMEWIN_SetTextAlign(hWin,GUI_TA_VCENTER|GUI_TA_CENTER);
            FRAMEWIN_SetTitleHeight(hWin,30);

            //
            //初始化文本控件
            //
            TEXT_SetFont(WM_GetDialogItem(hWin,GUI_ID_TEXT0), &GUI_FontD36x48);
            break;

        /* 定时器消息 */
        case WM_TIMER:   //--------------(1)
             Count  ;
            sprintf(buf, "d", Count);
            TEXT_SetText(WM_GetDialogItem(hWin,GUI_ID_TEXT0), (const char *)buf);
            WM_RestartTimer(pMsg->Data.v, 100);
              break;
            
        case WM_KEY:
            switch (((WM_KEY_INFO*)(pMsg->Data.p))->Key) 
            {
                case GUI_KEY_ESCAPE:
                    GUI_EndDialog(hWin, 1);
                    break;
                case GUI_KEY_ENTER:
                    GUI_EndDialog(hWin, 0);
                    break;
            }
            break;
            
        case WM_NOTIFY_PARENT:
            Id = WM_GetId(pMsg->hWinSrc); 
            NCode = pMsg->Data.v;        
            switch (Id) 
            {
                case GUI_ID_OK:
                    if(NCode==WM_NOTIFICATION_RELEASED)
                        GUI_EndDialog(hWin, 0);
                    break;
                case GUI_ID_CANCEL:
                    if(NCode==WM_NOTIFICATION_RELEASED)
                        GUI_EndDialog(hWin, 0);
                    break;
            }
            break;
            
        default:
            WM_DefaultProc(pMsg);
    }
}

/*
*********************************************************************************************************
*    函 数 名: MainTask
*    功能说明: GUI主函数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void MainTask(void) 
{
    WM_HWIN hDlg;
    WM_HTIMER hTimer;
    

    /* 初始emWin */
    GUI_Init();
    
    /* 窗口使能使用内存设备,防止闪烁 */
    WM_SetCreateFlags(WM_CF_MEMDEV);  

   /* 创建一个对话框 */
    hDlg = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), &_cbCallback, 0, 0, 0);

    /* 给对话框hDlg创建定时器,溢出时间是100ms */
    hTimer = WM_CreateTimer(WM_GetClientWindow(hDlg), 0, 100, 0); //--------------(2)

    while (1)
    {
        GUI_Delay(10);
    }
}
  1. 定时器消息,在定时器消息中实现文件控件计数值的更新,每次计数值加1。
  2. 给对话框创建一个定时器,特别注意,这里需要获取对话框中客户区窗口的句柄才可以使用。

这个例子的实际显示效果如下:

45.5 实验例程说明(RTOS)

配套例子:

V7-558_emWin6.x实验_窗口管理器之定时器使用(RTOS)

实验目的:

  1. 本实验主要学习窗口管理器之定时器使用方法。
  2. emWin功能的实现在MainTask.c文件里面。

实验内容:

1、K1按键按下,串口或者RTT打印任务执行情况(串口波特率115200,数据位8,奇偶校验位无,停止位1)。

2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。

(2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。

3、默认上电是通过串口打印信息,如果使用RTT打印信息:

MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可

#define Enable_RTTViewer 1

4、各个任务实现的功能如下:

App Task Start 任务 :启动任务,这里用作BSP驱动包处理。

App Task MspPro任务 :消息处理,这里用作LED闪烁。

App Task UserIF 任务 :按键消息处理。

App Task COM 任务 :暂未使用。

App Task GUI 任务 :GUI任务。

μCOS-III任务调试信息(按K1按键,串口打印):

RTT 打印信息方式:

程序设计:

任务栈大小分配:

μCOS-III任务栈大小在app_cfg.h文件中配置:

#define APP_CFG_TASK_START_STK_SIZE 512u

#define APP_CFG_TASK_MsgPro_STK_SIZE 2048u

#define APP_CFG_TASK_COM_STK_SIZE 512u

#define APP_CFG_TASK_USER_IF_STK_SIZE 512u

#define APP_CFG_TASK_GUI_STK_SIZE 2048u

任务栈大小的单位是4字节,那么每个任务的栈大小如下:

App Task Start 任务 :2048字节。

App Task MspPro任务 :8192字节。

App Task UserIF 任务 :2048字节。

App Task COM 任务 :2048字节。

App Task GUI 任务 :8192字节。

系统栈大小分配:

μCOS-III的系统栈大小在os_cfg_app.h文件中配置:

#define OS_CFG_ISR_STK_SIZE 512u

系统栈大小的单位是4字节,那么这里就是配置系统栈大小为2KB

emWin动态内存配置:

GUIConf.c文件中的配置如下:

代码语言:javascript复制
#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:

#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。

#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。

默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。

emWin界面显示效果:

800*480分辨率界面效果。

45.6 实验例程说明(裸机)

配套例子:

V7-557_emWin6.x实验_窗口管理器之定时器使用(裸机)

实验目的:

  1. 本实验主要学习窗口管理器之定时器使用方法。
  2. emWin功能的实现在MainTask.c文件里面。

emWin界面显示效果:

800*480分辨率界面效果。

emWin动态内存配置:

GUIConf.c文件中的配置如下:

代码语言:javascript复制
#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:

#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。

#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。

默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。

45.7 总结

本章节就为大家讲解这么多,窗口定时器简单实用,望初学者务必掌握,以后用到的地方还是很多的。

0 人点赞