1、emWin和ucGUI的关系
记得刚上大学的时候接触到单片机领域的一个图形界面叫ucGUI,也是跑在STM32上的,后来过了没多久网上查资料发现大家都是用的emWIn了,了解了一下它们之间的关系,其实是同一个东西。emWIn是在ucGUI的基础上发展起来的,两者同属一家公司(SEEGER)开发,没错就是咱买的JLINK调试器的那家公司,以前旧版本的ucGUI是开源的,后来emWin发展到5.0版本后进行了很大的更新,特别是底层驱动方面。但是emWIn5.xx版本向下完全的兼容低版本,也包括ucGUI5.xx以下的版本。emWIn5.xx以后的版本只有库没有源码,所以想要了解底层实现的话可以看早起的版本。
2、emWIn和STemWIn的关系
SEEGER公司授权给ST、NXP、Energy Micro等公司的处理器可以免费使用emWin。跑在ST处理器上的emWin我们称之为STemWin,STemWIn对ST的控制器做了专门的优化。出于一定的保护措施,STemWin的库是不能在其他芯片厂商的处理器上跑的,因为在STemWin初始化前要使能CRC校验。如果没有使能,STemWIn则启动不起来,KEIL MDK安装目录也带有emWIn的软件包,需要注册RL-ARM才可以使用。
1、emWin模拟器
按照正常的思路,我们应该是在KEIL上写好了代码,然后再对工程进行编译,将程序下载到开发板上查看现象,但是对于嵌入式来说这样的调试方式还是太慢了,如果能在PC上直接仿真运行就可以省去下载代码和开发板上调试的时间了,而且仿真的编译速度也比KEIL更加的快。
目前emWIn已经更新到V6.10版本了,大家可以在官网(SEEGER官网)下载到不同版本的emWIn模拟器以及相关的手册资料,下载之前需要注册一个账号,因为外网原因下载速度可能比较慢。本文最后的资料链接里也附有这个文件。下面我用的是V5.32版本的来展示。目录结构如下:
我电脑上装的是VS2013直接双击sln文件就可以打开工程了,如果提示升级什么组件的话直接点确定。
然后直接点调试运行就可以看到运行的官方demo了。
2、emWin + uCosIII模拟器
这是我在网上找到的资料,看到有人把uCosIII和emWin模拟器移植到了一起,个人感觉挺好的,因为我们有时候可能把嵌入式操作系统和图形界面一起用上,而且emWin也是支持操作系统的。这个资源会在本文最后面给出。VS编译的时候可能会报错:错误 206 error LNK1281: 无法生成 SAFESEH 映像。 解决方法是:选中项目,右键菜单->属性->链接器->命令行,在“附加选项”框中 输入 /SAFESEH:NO ,然后点击应用。
有了PC端的模拟器其实还不够方便,因为这只是在运行阶段给我们提供了方便,而在代码的编写阶段能不能够一样给我们提供方便呢?就像QT、C#等等界面开发软件一样,支持用户拖拽控件生成代码的功能。GUIBuilder就是要完成这个功能。这个工具在KEIL的安装目录下就有,具体路径见下图。
双击GUIBuilder.exe看到编辑界面。
随便拖几个控件上去练练手:
完成后选择左上角的File->Save可以看到在当前目录下生成了一个.c文件FramewinDLG.c:
里面的代码如下:
/*********************************************************************
* *
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
* *
**********************************************************************
* *
* C-file generated by: *
* *
* GUI_Builder for emWin version 5.24 *
* Compiled Jan 27 2014, 11:28:24 *
* (c) 2013 Segger Microcontroller GmbH & Co. KG *
* *
**********************************************************************
* *
* Internet: www.segger.com Support: [email protected] *
* *
**********************************************************************
*/
// USER START (Optionally insert additional includes)
// USER END
#include "DIALOG.h"
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
#define ID_FRAMEWIN_0 (GUI_ID_USER + 0x00)
#define ID_BUTTON_0 (GUI_ID_USER + 0x02)
#define ID_CHECKBOX_0 (GUI_ID_USER + 0x03)
#define ID_DROPDOWN_0 (GUI_ID_USER + 0x04)
// USER START (Optionally insert additional defines)
// USER END
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
// USER START (Optionally insert additional static data)
// USER END
/*********************************************************************
*
* _aDialogCreate
*/
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
{ FRAMEWIN_CreateIndirect, "Framewin", ID_FRAMEWIN_0, 0, 0, 320, 240, 0, 0x64, 0 },
{ BUTTON_CreateIndirect, "Button", ID_BUTTON_0, 96, 24, 80, 20, 0, 0x0, 0 },
{ CHECKBOX_CreateIndirect, "Checkbox", ID_CHECKBOX_0, 97, 53, 80, 20, 0, 0x0, 0 },
{ DROPDOWN_CreateIndirect, "Dropdown", ID_DROPDOWN_0, 104, 90, 80, 19, 0, 0x0, 0 },
// USER START (Optionally insert additional widgets)
// USER END
};
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
// USER START (Optionally insert additional static code)
// USER END
/*********************************************************************
*
* _cbDialog
*/
static void _cbDialog(WM_MESSAGE * pMsg) {
WM_HWIN hItem;
int NCode;
int Id;
// USER START (Optionally insert additional variables)
// USER END
switch (pMsg->MsgId) {
case WM_INIT_DIALOG:
//
// Initialization of 'Framewin'
//
hItem = pMsg->hWin;
FRAMEWIN_SetFont(hItem, GUI_FONT_32B_ASCII);
FRAMEWIN_SetText(hItem, "HelloWorld");
FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER);
//
// Initialization of 'Checkbox'
//
hItem = WM_GetDialogItem(pMsg->hWin, ID_CHECKBOX_0);
CHECKBOX_SetText(hItem, "Check");
// USER START (Optionally insert additional code for further widget initialization)
// USER END
break;
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc);
NCode = pMsg->Data.v;
switch(Id) {
case ID_BUTTON_0: // Notifications sent by 'Button'
switch(NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
case ID_CHECKBOX_0: // Notifications sent by 'Checkbox'
switch(NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_VALUE_CHANGED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
case ID_DROPDOWN_0: // Notifications sent by 'Dropdown'
switch(NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_SEL_CHANGED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
// USER START (Optionally insert additional code for further Ids)
// USER END
}
break;
// USER START (Optionally insert additional message handling)
// USER END
default:
WM_DefaultProc(pMsg);
break;
}
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* CreateFramewin
*/
WM_HWIN CreateFramewin(void);
WM_HWIN CreateFramewin(void) {
WM_HWIN hWin;
hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0);
return hWin;
}
// USER START (Optionally insert additional public code)
// USER END
/*************************** End of file ****************************/
代码里面写好了生成界面的代码,只需要在运行时调用最后的CreateFramewin函数就可以生成界面了。接下来我们看看模拟器的代码,是在GUIDEMO_Start.c这个文件里调用GUI_Init()和生成界面的函数的,想要运行我们刚刚的界面就需要在这个函数里调用CreateFramewin函数而不去调用官方的demo界面。GUIDEMO_Start.c内容如下:
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2015 SEGGER Microcontroller GmbH & Co. KG *
* *
* Internet: www.segger.com Support: [email protected] *
* *
**********************************************************************
** emWin V5.32 - Graphical user interface for embedded applications **
emWin is protected by international copyright laws. Knowledge of the
source code may not be used to write a similar product. This file may
only be used in accordance with a license and should not be re-
distributed in any way. We appreciate your understanding and fairness.
----------------------------------------------------------------------
File : GUIDEMO_Start.c
Purpose : GUIDEMO initialization
----------------------------------------------------------------------
*/
#include "GUIDEMO.h"
/*********************************************************************
*
* MainTask
*/
void MainTask(void) {
#if GUI_WINSUPPORT
WM_SetCreateFlags(WM_CF_MEMDEV);
#endif
GUI_Init();
#if GUI_WINSUPPORT
WM_MULTIBUF_Enable(1);
#endif
GUIDEMO_Main();
}
/*************************** End of file ****************************/
我们把除了MainTask函数以上的部分全部删除,替换为FramewinDLG.c文件里的内容,再对MainTask函数进行适当修改,如下:
/*********************************************************************
* *
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
* *
**********************************************************************
* *
* C-file generated by: *
* *
* GUI_Builder for emWin version 5.24 *
* Compiled Jan 27 2014, 11:28:24 *
* (c) 2013 Segger Microcontroller GmbH & Co. KG *
* *
**********************************************************************
* *
* Internet: www.segger.com Support: [email protected] *
* *
**********************************************************************
*/
// USER START (Optionally insert additional includes)
// USER END
#include "DIALOG.h"
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
#define ID_FRAMEWIN_0 (GUI_ID_USER + 0x00)
#define ID_BUTTON_0 (GUI_ID_USER + 0x02)
#define ID_CHECKBOX_0 (GUI_ID_USER + 0x03)
#define ID_DROPDOWN_0 (GUI_ID_USER + 0x04)
// USER START (Optionally insert additional defines)
// USER END
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
// USER START (Optionally insert additional static data)
// USER END
/*********************************************************************
*
* _aDialogCreate
*/
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
{ FRAMEWIN_CreateIndirect, "Framewin", ID_FRAMEWIN_0, 0, 0, 320, 240, 0, 0x64, 0 },
{ BUTTON_CreateIndirect, "Button", ID_BUTTON_0, 96, 24, 80, 20, 0, 0x0, 0 },
{ CHECKBOX_CreateIndirect, "Checkbox", ID_CHECKBOX_0, 97, 53, 80, 20, 0, 0x0, 0 },
{ DROPDOWN_CreateIndirect, "Dropdown", ID_DROPDOWN_0, 104, 90, 80, 19, 0, 0x0, 0 },
// USER START (Optionally insert additional widgets)
// USER END
};
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
// USER START (Optionally insert additional static code)
// USER END
/*********************************************************************
*
* _cbDialog
*/
static void _cbDialog(WM_MESSAGE * pMsg) {
WM_HWIN hItem;
int NCode;
int Id;
// USER START (Optionally insert additional variables)
// USER END
switch (pMsg->MsgId) {
case WM_INIT_DIALOG:
//
// Initialization of 'Framewin'
//
hItem = pMsg->hWin;
FRAMEWIN_SetFont(hItem, GUI_FONT_32B_ASCII);
FRAMEWIN_SetText(hItem, "HelloWorld");
FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER);
//
// Initialization of 'Checkbox'
//
hItem = WM_GetDialogItem(pMsg->hWin, ID_CHECKBOX_0);
CHECKBOX_SetText(hItem, "Check");
// USER START (Optionally insert additional code for further widget initialization)
// USER END
break;
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc);
NCode = pMsg->Data.v;
switch (Id) {
case ID_BUTTON_0: // Notifications sent by 'Button'
switch (NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
case ID_CHECKBOX_0: // Notifications sent by 'Checkbox'
switch (NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_VALUE_CHANGED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
case ID_DROPDOWN_0: // Notifications sent by 'Dropdown'
switch (NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
case WM_NOTIFICATION_SEL_CHANGED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
// USER START (Optionally insert additional code for further Ids)
// USER END
}
break;
// USER START (Optionally insert additional message handling)
// USER END
default:
WM_DefaultProc(pMsg);
break;
}
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* CreateFramewin
*/
WM_HWIN CreateFramewin(void);
WM_HWIN CreateFramewin(void) {
WM_HWIN hWin;
hWin = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0);
return hWin;
}
// USER START (Optionally insert additional public code)
// USER END
/*************************** End of file ****************************/
/*********************************************************************
*
* MainTask
*/
void MainTask(void) {
#if GUI_WINSUPPORT
WM_SetCreateFlags(WM_CF_MEMDEV);
#endif
GUI_Init();
#if GUI_WINSUPPORT
WM_MULTIBUF_Enable(1);
#endif
//GUIDEMO_Main();
CreateFramewin();
while (1)
{
GUI_Delay(10);
}
}
/*************************** End of file ****************************/
修改后运行就可以得到如下的结果了,是我们在GUIBuilder中设计的界面。
emWIn查看器和GUIBuilder都是在同一个目录下的,叫emWinView.exe,运行界面如下图所示:
无论我们emWin模拟器是先运行还是后运行,emWin查看器都可以捕捉到模拟器的运行画面。查看器上面有很多的功能可以使用,有助于调试,在多层显示的时候比较有用。
链接:https://pan.baidu.com/s/1L6EZrFFqEyOFIoCrkOVpaQ 提取码:zi6r