教程不断更新中: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);
}
}
- 定义一个数组,里面有三种颜色,再定义一个变量,用于三种颜色的切换。
- 桌面窗口回调函数的重绘消息,每执行一次更新一次背景色。
- 定时器消息,这里要特别注意,如果想要定时器周期性执行,而不是只执行一次,必须得调用重启定时器函数WM_RestartTimer()。在这个消息里面将桌面窗口无效,从而会触发窗口管理器去执行WM_PAINT消息,这样就实现了定时修改桌面窗口背景色。
- 设置桌面窗口的回调函数。
- 创建定时器函数,溢出时间是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。
- 给对话框创建一个定时器,特别注意,这里需要获取对话框中客户区窗口的句柄才可以使用。
这个例子的实际显示效果如下:
45.5 实验例程说明(RTOS)
配套例子:
V7-558_emWin6.x实验_窗口管理器之定时器使用(RTOS)
实验目的:
- 本实验主要学习窗口管理器之定时器使用方法。
- 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实验_窗口管理器之定时器使用(裸机)
实验目的:
- 本实验主要学习窗口管理器之定时器使用方法。
- 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 总结
本章节就为大家讲解这么多,窗口定时器简单实用,望初学者务必掌握,以后用到的地方还是很多的。