物联网智慧教室项目(四):emWin图形界面库

一、emWin移植上

LCD驱动程序

#ifndef __LCD_H__
#define __LCD_H__   
#include "stm32f4xx_hal.h"
void lcd_clear(uint16_t Color);
void lcd_init(void);
void write_data_Prepare(void);
unsigned short lcd_read_gram(unsigned int x,unsigned int y);
void LCD_DrawPoint(uint16_t xsta, uint16_t ysta, uint16_t color);
void LCD_ShowString(uint16_t x0, uint16_t y0, uint8_t *pcStr, uint16_t PenColor, uint16_t BackColor);
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t colour);
#endif

STemWin结构框架

(一)CRC开启

(二)SRAM 写操作要使能

(三)获取STemWin源码文件

STemWin默认在STM32CUBEMX文档下

例如C:\Users\Think\STM32Cube\Repository\STM32Cube_FW_F4_V1.24.1\Middlewares\ST\STemWin

(四)emWin移植到项目工程

  1. 复制STemWin源码到项目工程中
    工程目录:SmartClassRoom\Middlewares\Third_Party\STemWin

  2. 在keil工程中添加相关文件

    1. 新建工作组:Middlewares/STemWin

    2. 添加需要编译的C和库文件

文件名称 文件描述
GUI_X_OS.c OS支持文件,不需要修改
GUIConf.c GUI配置文件,主要用于GUI内存块初始化
GUIDRV_Template.c GUI驱动模块,主要针对LCD操作接口
LCDConf_FlexColor_Template.c GUI显示配置文件,主要用于LCD参数配置,初始化
GUI_X_Touch_Analog.c 需要自己单独定义,用于触摸笔驱动
STemWin_CM4_OS_wc16_ot.a 基于Cortex-M4驱动库,STemWin源码不开放
  1. 修改库文件格式(keil默认不识别.a文件格式,需要我们手动配置)

(五)移植lcd和touch驱动文件

  1. 添加lcd.c和Touch.c到Src目录下

  1. 添加lcd.h和Touch.h到Inc目录下

二、emWin移植下

(一)emWin LCD驱动适配

修改GUIConf.c

#include "GUI.h"

/*********************************************************************
*
*       Defines
*
**********************************************************************
*/
//
// Define the available number of bytes available for the GUI
//
#define GUI_NUMBYTES    (512*1024)		 //定义外部存储器大小
#define GUI_BLOCKSUZE   (0X80)			//定义最小内存库操作大小
#define SRAM_BANK_ADDR  ((U32)0x68000000)	//定义外部存储器首地址

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       GUI_X_Config
*
* Purpose:
*   Called during the initialization process in order to set up the
*   available memory for the GUI.
*/
void GUI_X_Config(void) {
  //
  // 32 bit aligned memory area
  //
	volatile U32* aMemory = (volatile U32*)(SRAM_BANK_ADDR);
  //
  // Assign memory to emWin
  //分配GUI存储器首地址及最小操作内存块大小
  GUI_ALLOC_AssignMemory((void *)aMemory, GUI_NUMBYTES);
  GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSUZE);
  //
  // Set default font
  //
  GUI_SetDefaultFont(GUI_FONT_32_1);
}

修改GUIDRV_Template.c

只需要完成画点和读取点操作即可

/*********************************************************************
*
*       _SetPixelIndex
*
* Purpose:
*   Sets the index of the given pixel. The upper layers
*   calling this routine make sure that the coordinates are in range, so
*   that no check on the parameters needs to be performed.
*/
static void _SetPixelIndex(GUI_DEVICE * pDevice, int x, int y, int PixelIndex) {
    //
    // Convert logical into physical coordinates (Dep. on LCDConf.h)
    //
    #if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)
      int xPhys, yPhys;

      xPhys = LOG2PHYS_X(x, y);
      yPhys = LOG2PHYS_Y(x, y);
    #else
      #define xPhys x
      #define yPhys y
    #endif
    GUI_USE_PARA(pDevice);
    GUI_USE_PARA(x);
    GUI_USE_PARA(y);
    GUI_USE_PARA(PixelIndex);
    {
      //
      // Write into hardware ... Adapt to your system
      //添加lcd画点接口
      LCD_DrawPoint(x,y,PixelIndex);
      // TBD by customer...
      //
    }
    #if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)
      #undef xPhys
      #undef yPhys
    #endif
}
/*********************************************************************
*
*       _GetPixelIndex
*
* Purpose:
*   Returns the index of the given pixel. The upper layers
*   calling this routine make sure that the coordinates are in range, so
*   that no check on the parameters needs to be performed.
*/
static unsigned int _GetPixelIndex(GUI_DEVICE * pDevice, int x, int y) {
  unsigned int PixelIndex;
    //
    // Convert logical into physical coordinates (Dep. on LCDConf.h)
    //
    #if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)
      int xPhys, yPhys;

      xPhys = LOG2PHYS_X(x, y);
      yPhys = LOG2PHYS_Y(x, y);
    #else
      #define xPhys x
      #define yPhys y
    #endif
    GUI_USE_PARA(pDevice);
    GUI_USE_PARA(x);
    GUI_USE_PARA(y);
    {
      //
      // Write into hardware ... Adapt to your system
      //添加lcd读取点接口
      PixelIndex = lcd_read_gram(x,y);
      
      // TBD by customer...
      //
      PixelIndex = 0;
    }
    #if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)
      #undef xPhys
      #undef yPhys
    #endif
  return PixelIndex;
}

修改LCDConf_FlexColor_Template.c

  1. 定义显示尺寸 480*272
  2. 定义触摸笔X,Y AD测量值(需要自己测量获得)
  3. 添加触摸笔校准函数
  4. 添加lcd初始化函数
#include "GUI.h"
#include "GUIDRV_FlexColor.h"
#include "lcd.h"

/*********************************************************************
*
*       Layer configuration (to be modified)
*
**********************************************************************
*/

//
// Physical display size
//
#define XSIZE_PHYS  480 //  屏幕X坐标长度
#define YSIZE_PHYS  272 //  屏幕Y坐标长度


#define GUI_TOUCH_AD_Y_TOP 170		// 屏幕X0点坐标AD值
#define GUI_TOUCH_AD_Y_BOTTOM 1900	// 屏幕X480点坐标AD值
#define GUI_TOUCH_AD_X_LEFT 100		// 屏幕Y0点坐标AD值
#define GUI_TOUCH_AD_X_RIGHT 1930	// 屏幕Y272点坐标AD值

/*********************************************************************
*
*       Configuration checking
*
**********************************************************************
*/
#ifndef   VXSIZE_PHYS
  #define VXSIZE_PHYS XSIZE_PHYS
#endif
#ifndef   VYSIZE_PHYS
  #define VYSIZE_PHYS YSIZE_PHYS
#endif
#ifndef   XSIZE_PHYS
  #error Physical X size of display is not defined!
#endif
#ifndef   YSIZE_PHYS
  #error Physical Y size of display is not defined!
#endif
#ifndef   GUICC_565
  #error Color conversion not defined!
#endif
#ifndef   GUIDRV_FLEXCOLOR
  #error No display driver defined!
#endif

/*********************************************************************
*
*       Public functions
*
**********************************************************************
*/
/*********************************************************************
*
*       LCD_X_Config
*
* Function description:
*   Called during the initialization process in order to set up the
*   display driver configuration.
*
*/
void LCD_X_Config(void) {
  //
  // 配置GUI LCD驱动以及颜色显示方式
  //
  GUI_DEVICE_CreateAndLink(&GUIDRV_Template_API, GUICC_M565, 0, 0);
  //
  // 显示尺寸配置
  //
  LCD_SetSizeEx (0, XSIZE_PHYS , YSIZE_PHYS);
  LCD_SetVSizeEx(0, VXSIZE_PHYS, VYSIZE_PHYS);
	
  //触摸笔校准
  GUI_TOUCH_Calibrate(GUI_COORD_X, 0, 480, GUI_TOUCH_AD_X_LEFT , GUI_TOUCH_AD_X_RIGHT);
  GUI_TOUCH_Calibrate(GUI_COORD_Y, 0, 272, GUI_TOUCH_AD_Y_TOP, GUI_TOUCH_AD_Y_BOTTOM);
  //
  // Orientation
  //
  //
  // Set controller and operation mode
  //
}

/*********************************************************************
*
*       LCD_X_DisplayDriver
*
* Function description:
*   This function is called by the display driver for several purposes.
*   To support the according task the routine needs to be adapted to
*   the display controller. Please note that the commands marked with
*   'optional' are not cogently required and should only be adapted if
*   the display controller supports these features.
*
* Parameter:
*   LayerIndex - Index of layer to be configured
*   Cmd        - Please refer to the details in the switch statement below
*   pData      - Pointer to a LCD_X_DATA structure
*
* Return Value:
*   < -1 - Error
*     -1 - Command not handled
*      0 - Ok
*/
int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) {
  int r;
  (void) LayerIndex;
  (void) pData;
  
  switch (Cmd) {
  case LCD_X_INITCONTROLLER: {
    //
    // Called during the initialization process in order to set up the
    // display controller and put it into operation. If the display
    // controller is not initialized by any external routine this needs
    // to be adapted by the customer...
    //
    // ...
		//添加lcd初始化
		lcd_init();
    return 0;
  }
  default:
    r = -1;
  }
  return r;
}

添加GUI_X_Touch_Analog.c

#include "GUI.h"
#include "Touch.h"


void GUI_TOUCH_X_ActivateX(void) 
{

}

void GUI_TOUCH_X_ActivateY(void)
{

}

//获取X坐标AD值
int  GUI_TOUCH_X_MeasureX(void) 
{
	return XPT_Read_XY(CMD_RDX);
}

//获取Y坐标AD值
int  GUI_TOUCH_X_MeasureY(void) 
{	
	return XPT_Read_XY(CMD_RDY);
}

(二)emWin测试程序编写

测试程序编写

/* USER CODE BEGIN Header_Touch_Task */
/**
  * @brief  Function implementing the TouchTask thread.
  * @param  argument: Not used 
  * @retval None
  */
/* USER CODE END Header_Touch_Task */
void Touch_Task(void const * argument)
{

	GUI_PID_STATE State;    
                 
//  /* init code for FATFS */
//  MX_FATFS_Init();

//  /* init code for LWIP */
//  MX_LWIP_Init();


  GUI_Init();
  GUI_SetBkColor(GUI_BLUE);
  GUI_SetFont(GUI_FONT_32_1);
  GUI_SetColor(GUI_YELLOW);
  GUI_Clear();	
  /* Infinite loop */
  for(;;)
  {			
  		//执行触摸笔检测
		GUI_TOUCH_Exec();	
        //获取触摸笔状态值
		GUI_TOUCH_GetState(&State);
		//是否按下
		if(State.Pressed){
			//打印触摸笔坐标信息
			GUI_DispStringAt("X:",0,0);
			GUI_DispDecAt(State.x,32,0,4);
			GUI_DispStringAt("Y:",0,24);
			GUI_DispDecAt(State.y,32,24,4);			
		}
		osDelay(10);
	}
  /* USER CODE END Touch_Task */
}

测试结果

当触摸笔按下时,显示X(0-480)和Y(0-272)坐标信息

三、emWin开发环境搭建

开发环境压缩包请自提:链接:https://pan.baidu.com/s/12lO9r7CG43mPEpcIbQ3fug?pwd=6pqm

提取码:6pqm

开发环境介绍

CodeBlocks

GUIBuilder

Simulation(模拟器)

emwin Simulation (模拟器)

仿真模拟器是在window开发环境下的C工程,可以通过VC6或者codeblockd IDE环境下进行开发仿真

  1. 下载地址
    https://www.segger.com/downloads/emwin/

根据自己使用的STemwin库,进行下载,我们采用V5.44版本

  1. 添加工程到codeblockd
    1. 打开外部工程
    2. 选择.cbp文件

  1. 添加工程到codeblockd
    1. 点击编译运行按钮
    2. 生成模拟器

GUIBuilder 制作界面

Created with Raphaël 2.3.0

放置窗口

放置按钮

放置文本

生成代码

界面添加到模拟器

修改模拟器原始工程

  1. 把无用的代码移除工程

  1. 添加WindowDLG.c到工程中
    1. 首先复制WindowDLG.c到SeggerEval_WIN32_MSVC_MinGW_GUI_V544\Application目录下

    2. 添加WindowDLG.c到工程中

    3. 选择Application工程目录,新建mainTask.c

    4. 在mainTask.c添加代码

#include "dialog.h"//包含window对话框 头文件
void MainTask(void)

{

    GUI_Init();                     //初始化emWin
    CreateWindow();                 //创建窗体,父窗体是桌面背景
    while(1) {GUI_Delay(20);}       //调用GUI_Delay函数延时20MS(最终目的是调用GUI_Exec()函数)

}

四、emWin运行原理分析

emWin使用说明书(第三点中压缩包包含)

emWin初始化

执行模型

单任务使用注意事项

我们在操作系统下使用emwin,必须要创建一个任务,用来调用emWin函数,并且官方说,此任务的优先级配置为最低
    
 emWin函数指的是什么???

时间调度


指针输入设备

五、emWin应用编程方法

GUIBuilder

对话框

资源表

资源:我们这个对话框内部的小工具(小窗口)------- window 按钮 文本 图片

窗口管理器

窗口消息

窗口对象

作者:下面我就简单说两句

物联沃分享整理
物联沃-IOTWORD物联网 » 物联网智慧教室项目(四):emWin图形界面库

发表回复