实战贴:开源GUI STemWin在小熊派上的移植(显示很漂亮、很细腻,棒!)

简介: 实战贴:开源GUI STemWin在小熊派上的移植(显示很漂亮、很细腻,棒!)

开篇前来一首歌放松一下,推荐简弘亦的新歌:忽如一面,妥妥的歌唱实力派,可是不知道为啥感觉一直不温不火,我是听了他的不染喜欢上的,好了,进入正题。


现在市面上有很多成熟的GUI,老早前就听说过STemWin了,一直想学习怎么用,但一直又觉得没地方可用,现在手上平台很多(人送外号:最不缺钱且烧钱的玩家640.png),只要有时间,还是要把它搞起来!毕竟多掌握一门技能那肯定有好处的。

640.png

关于GUI的移植,之前也在小熊派上分享过一些别的GUI的教程,文章链接如下:


实战贴:开源GUI LittlevGL在MCU上的移植


MCU SPI屏也能跑这么炫酷的特效?来,移植起来秀一秀


废话不多说,先上效果图:

640.png

640.png

该Demo用GUIBuilder工具画了一个Listview的控件以及三个Text控件以及一个Image控件,最后保存生成代码拷贝到Keil MDK后编译下载到小熊派上运行。

1、STemWin简介

STemWin是SEGGER公司授权给意法半导体(ST)公司,使用ST芯片的用户可免费使用STemWin,关于STemWin的显示效果,有兴趣的可自行百度搜索查看。

1.1 下载并熟悉官网最新版本的STemWin

640.png

640.png

解压后得到以下目录,移植STemWin最主要关心的是Libraies目录下的与STemWin相关的库文件,其它的多数是ST官网的一些Demo例程,暂时用不着,如下图所示:

640.png

简单介绍下以下几个目录:

640.png

2、小熊派移植STemWin

2.1 移植STemWin到小熊派

2.1.1 添加STemWin软件包到带LCD的基础工程

首先需要一个源码工程,这个直接从小熊派源码包拿就行了,不需要重新去写,我们本次移植的是不带操作系统的。

640.png

解压,然后在工程目录下创建两个和STemWin相关的目录:

640.png

将1.1下载的STemWin软件包整个拷贝到STemWin这个目录下。

640.png

2.1.2 添加STemWin相关库及文件到Keil MDK

640.png

以下文件添加模板参考了正点原子的STM32F429 EMWIN开发手册:

640.png

640.png

640.png

这个app.c用来存放GUIBuilder软件生成的代码,最后通过调用STemWin的CreateWindow函数来展示界面。

640.png

640.png

注意:正点原子的STemWin版本可能比较老,当前该版本所有的GUI读点、画点等函数配置只需要在LCDConf_FlexColor_Template.c下就可以完成了,不需要GUIDRV_Template.c这个文件,正点原子的教程和我现在下的最新版本移植还有些区别,仅供参考。

2.1.3 修改STemWin所需要的内存空间

位于GUIConf.c文件:

#define GUI_NUMBYTES  (16*1024)//0x200000 //设置EMWIN内存大小

注意:如果该参数设置太大的话Keil会报空间不够的错误,这里我们根据需求,将其设置为16*1024即可,它分配的其实是一块静态连续的内存空间:

640.png

2.1.4 配置LCD及STemWin相关

位于LCDConf_FlexColor_Template.c文件:

在这个文件中,我们需要包含LCD驱动文件,小熊派已经实现好了,我们直接拿过来用就行了。

#inlcude "lcd.h"

注意lcd.h中并没有写命令和写数据的函数声明,这里我们需要将lcd.c修改一下,然后在lcd.h导出这两个函数,才能给LCDConf_FlexColor_Template.c使用。

640.png

640.png

(1)修改LCD显示分辨率

//更改显示分辨率
#define XSIZE_PHYS  240 // To be adapted to x-screen size
#define YSIZE_PHYS  240 // To be adapted to y-screen size

(2)实现写指令、写数据、写多个数据、读多个数据接口

注意,官方给的模板默认是一次2个字节的写入,而小熊派LCD是SPI OLED(ST7789),实现的接口是一次只写1个字节的数据,所以我们要将接口改成1个字节的写入,否则显示会有问题。

/********************************************************************
*
*       LcdWriteReg 写寄存器
*
* Function description:
*   Sets display register
*/
static void LcdWriteReg(U8 Data)
{
    // ... TBD by user
    LCD_Write_Cmd(Data);
}
/********************************************************************
*
*       LcdWriteData 写数据
*
* Function description:
*   Writes a value to a display register
*/
static void LcdWriteData(U8 Data)
{
    // ... TBD by user
    LCD_Write_Data(Data);
}
/********************************************************************
*
*       LcdWriteDataMultiple  写多个数据
*
* Function description:
*   Writes multiple values to a display register.
*/
static void LcdWriteDataMultiple(U8 * pData, int NumItems)
{
    while (NumItems--)
    {
        // ... TBD by user
        LCD_Write_Data(*pData++);
    }
}
/********************************************************************
*
*       LcdReadDataMultiple 读多个点
*
* Function description:
*   Reads multiple values from a display register.
*/
static void LcdReadDataMultiple(U8 * pData, int NumItems)
{
    while (NumItems--)
    {
        // ... TBD by user
  //没有读点函数,留空
    }
}

(3)修改LCD_X_Config函数

void LCD_X_Config(void)
{
    GUI_DEVICE * pDevice;
    CONFIG_FLEXCOLOR Config = {0};
    GUI_PORT_API PortAPI = {0};
    // Set display driver and color conversion
    pDevice = GUI_DEVICE_CreateAndLink(GUIDRV_FLEXCOLOR, GUICC_M565, 0, 0);
    // Display driver configuration, required for Lin-driver
    LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
    LCD_SetVSizeEx(0, VXSIZE_PHYS, VYSIZE_PHYS);
    // Orientation
    //Config.Orientation = GUI_SWAP_XY | GUI_MIRROR_Y;
    Config.Orientation = 0 ;
    Config.NumDummyReads = 2;
    GUIDRV_FlexColor_Config(pDevice, &Config);
    // Set controller and operation mode
    PortAPI.pfWrite8_A0  = LcdWriteReg;
    PortAPI.pfWrite8_A1  = LcdWriteData;
    PortAPI.pfWriteM8_A1 = LcdWriteDataMultiple;
    PortAPI.pfReadM8_A1  = LcdReadDataMultiple;
    //ST7789为GUIDRV_FLEXCOLOR_F66709
    GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B8);
}

那么这些参数具体是怎么适配的呢?详情请看STemWin手册参数配置部分的说明,手册讲得相当详细,这里就不再多解释了。

640.png

(4)添加LCD初始化函数

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;
}

(5)添加时基触发

这里我们直接将该变量添加到STM32自带的SysTick回调函数里就可以了,如下所示:


位于:stm32l4xx_it.c

/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
    /* USER CODE BEGIN SysTick_IRQn 0 */
    #include "GUI.h"
    extern volatile GUI_TIMER_TIME OS_TimeMS;
    ++OS_TimeMS ;
    /* USER CODE END SysTick_IRQn 0 */
    HAL_IncTick();
    HAL_SYSTICK_IRQHandler();
    /* USER CODE BEGIN SysTick_IRQn 1 */
    /* USER CODE END SysTick_IRQn 1 */
}

添加完时基以后,需要在主循环中循环调用GUI_Delay()函数,为什么呢?官方文档有相应的描述:

640.png

到这里,STemWin在小熊派上的移植工作就基本结束了,接下来直接编写例程。

3、编写Demo验证

3.1 使用GUIBuilder画界面

这个工具在使用的时候需要注意,在执行该软件前先把配置文件删除。

640.png

为什么呢?我们打开这个配置文件看看就清楚了:

640.png

注意:这个配置文件里填的是Software目录的绝对路径,但这个软件没那么智能,换个地方打开GUIBuilder它还不更新!!!这会导致软件没法用!!!所以用这个工具前记得把它删了,反正重新打开它还会继续生成,这时候的路径才是正确的。


打开软件后,绘制界面如下:

640.png

绘制完毕后Ctrl+S保存,这时候会自动生成代码逻辑,就在当前路径下的WindowDLG.c中。

640.png

640.png

3.2 添加软件生成的代码到工程中

接下来我们打开这个程序,将所有代码复制到app.c中。

640.png

在.h文件中导出CreateWindow函数,该函数就是刚刚画的那个页面的实现流程,详情请分析app.c里的源代码。

640.jpg

3.3 在主函数中添加代码逻辑

包含头文件:

#include "GUI.h"
#include "app.h"

主函数:

int main(void)
{
    /* USER CODE BEGIN 1 */
    /* USER CODE END 1 */
    /* MCU Configuration----------------------------------------------------------*/
    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();
    /* USER CODE BEGIN Init */
    /* USER CODE END Init */
    /* Configure the system clock */
    SystemClock_Config();
    /* USER CODE BEGIN SysInit */
    /* USER CODE END SysInit */
    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_SPI2_Init();
    MX_USART1_UART_Init();
    /* USER CODE BEGIN 2 */
    //打开CRC
    __HAL_RCC_CRC_CLK_ENABLE();
    //初始化STemWin
    GUI_Init();
    //调用CreateWindow
    CreateWindow();
    /* USER CODE END 2 */
    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */
        /* USER CODE BEGIN 3 */
        GUI_Delay(1);
    }
    /* USER CODE END 3 */
}

编译下载后运行结果:

640.png

关于STemWin要学习的东西还有很多,就安富莱和正点原子的学习手册几千页就已经够学习很久了,我也打算以它为主要学习目标,深入学习,后续做出一些好看的样例再继续分享。

4、案例下载

公众号后台回复:STemWin 即可获取本节案例的下载链接。

往期精彩

MCU SPI屏也能跑这么炫酷的特效?来,移植起来秀一秀


代码写得很牛逼但UI界面却搞得很丑?来,杨工带你!


MCU串口命令解析器的实现


实战贴:开源GUI LittlevGL在MCU上的移植

目录
相关文章
|
6月前
|
图形学
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)(上)
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)
222 2
|
6月前
|
图形学
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)(下)
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)(下)
85 0
|
7月前
|
图形学
【Unity 3D】3D游戏跑酷小子实战教学(附源码和步骤 超详细)
【Unity 3D】3D游戏跑酷小子实战教学(附源码和步骤 超详细)
292 0
|
7月前
|
前端开发
前端知识笔记(二十)———简易弹窗制作
前端知识笔记(二十)———简易弹窗制作
71 0
|
C# 图形学
Unity的几个入门小常识
Unity的几个入门小常识
|
存储 Java API
一个精美的主界面窗口功能的设计和实现原来如此简单,万字肝爆
一个精美的主界面窗口功能的设计和实现原来如此简单,万字肝爆
115 0
游戏开发零基础入门教程(5):不要挡住我,我要去上面
这一节我们学习了层级管理,以及通过使用拖拽的方式来调整层级的顺序。 在真实的游戏中可能会包含很多的层级,在调整层级时,不要忘记口诀:谁挡住了我,我就去谁的上面。 试着在游戏中加入更多的层级,拖拽调整层级的顺序,然后观察编辑区中的图片显示效果。
157 0
|
人工智能 移动开发 数据可视化
不会游戏编程还能制作游戏吗?(附无代码游戏制作软件推荐)
在这个时代,你不懂摄影,但是却可以用手机轻松地拍出好看的照片;你不懂图像处理,但是却可以一键让你的照片显示出各种各样的效果;你不懂画画,但是却可以通过语言描述,让 AI 帮助你画出你可能凭借自己永远都无法画出的作品......工具在不断的降低创作的门槛,让越来越多的人能够做一些原本只有少数人才能做到的事。
744 0
|
安全 Android开发
21天打卡Andoid学到的一些小知识-第十九二十二十一天
今天我们学习打卡的内容是:android 10.0 去掉未知来源弹窗 默认授予安装未知来源权限
93 0
下一篇
无影云桌面