12下一页
返回列表 发新帖我要提问本帖赏金: 100.00元(功能说明)

[MM32生态] 基于MM32的SimpleGUI移植与演示(工业HMI解决方案)

[复制链接]
7821|30
 楼主| xld0932 发表于 2022-2-16 13:32 | 显示全部楼层 |阅读模式
#申请原创#     @21小跑堂

项目背景
在工业领域,带有显示的人机交互界面有不少的解决方案,像组态屏、串口屏、LCD液晶显示屏等等;组态屏、串口屏本身具备了UI的基础操作,完善的上位机制作软件,只需要外部主控MCU加以配合就可以完成人机交互的功能,其成本也比后面的LCD液晶显示屏要高出不少;LCD液晶显示屏本身只是一个显示模组,其操作和显示内容完全由主控MCU来控制,更具有控制上的灵活性,但在显示内容及控制逻辑上面需要设计者更多的投入。
因此在使用LCD液晶显示屏来作为人机交互显示界面时,一套轻量级的成熟且开源的SimpleGUI成为了本文的首选。(本文中提及的LCD液晶显示屏为单色点阵式LCD液晶显示屏,并非彩色TFT制式)。

MM32L3xx系列介绍
MM32L3xx系统MCU使用的是高性能的ARM Cortex-M3作为内核的32位微控制器,最高工作频率可达96MHz,高达128KB的内部FLASH程序存储空间和20KBSRAM,丰富的增强型I/O端口和外设;支持2.0V5.5V的宽供电电压,工作温度范围支持常规型的-40~85℃和扩展型的-40~105℃。

MM32F3270系列介绍
MM32F3270系统MCU使用的是高性能的ARM Cortex-M3作为内核的32位微控制器,最高工作频率可达120MHz,高达512KB的内部FLASH程序存储空间和128KBSRAM,丰富的增强型I/O端口和外设;支持2.0V5.5V的宽供电电压,工作温度范围支持常规型的-40~85℃和扩展型的-40~105℃。

SimpleGUI介绍
SimpleGUI是一个开源项目,它是一个针对单色显示屏设计和开发的GUI接口,支持目前市面上12864240128LCD单色液晶显示屏。SimpleGUI目标就是轻量化,在尽可能减小资源消耗的前提下,提供了点、线、基本几何图形、单色位图、文字等的绘制功能,以及列表、进度条、滚动条、提示框、曲线图等组件的显示功能;另外为了方便脱离硬件平台进行部分GUI开发,SimpleGUI还提供了单色显示屏模拟环境,VirtualSDK,配合SimpleGUI的低耦合性移植接口定义,几乎可以无缝的移植到预期的硬件平台上。

此外SimpleGUI作者为了码农们能够进一步了解和快速上手,为此还录制了部分视频讲解教程,供参考:
内容
地址
01.SimpleGUI概述
https://www.bilibili.com/video/av86593220/
02.基础绘图
https://www.bilibili.com/video/av86890300/
03.文本文字
https://www.bilibili.com/video/av87098997/
04.拓展组件概述
https://www.bilibili.com/video/av87432375/
05.交互引擎HMI
https://www.bilibili.com/video/av87530421/
06.VirtualSDK概述
https://www.bilibili.com/video/av87713369/
07.基于VirtualSDKGUI开发
https://www.bilibili.com/video/BV1qz4y12771/

SimpleGUI码云链接为:https://gitee.com/Polarix/simplegui

原理图设计
MCU我们选用MM32L373PF或者是MM32F3273G6P,这两颗MCU都支持宽电压输入;LCD我们选用的是绘晶科技的HJ240128A液晶屏,工作电压为5V;所以在原理图设计的时候,我们使用一个DC电源输入接口,经过LDOAMS1117-5.0V)将系统工作电压稳定输出在5V,同时带有电压指示灯;另外通过MAX232芯片将MCUUART转换成RS-232,建立与PC的通讯链路,方便程序调试和打印输出日志信息,另外就是可以结合BOOT引脚,通过ISP的方式给MCU下载程序。
90787620c86ff9bcab.png

MM32L373PFMM32F3273G6P芯片引脚上是PIN TO PIN完全兼容的,MCU可以工作在内部的系统时钟,就可以将外部的时钟晶振省略,这是对时钟要求不高的情况下可以这么设计;系统提供了5个按键,一个是MCU复位按键,另外4个按键功能分别定义为向上、向下、确认、返回;预留了BOOT切换的拨动开关和SWD的程序下载接口;LCD部分使用了PA端口的底8位作为LCD的数据口,其它引脚作为LCD的控制引脚;预留了LCD的背光调节电阻,将LCD的背光电压通过可调电阻,调整到合适的电压,这样可以有效的解决LCD显示鬼影的问题。

另外LCD支持通用的8位并行的8080接口时序控制,MM32L373PF不支持8080接口,但MM32F3273G6P支持8080接口,所以有兴趣的小伙伴,可以修改一下原理图,使用MM32F3273G6P8080接口来控制LCD显示屏。
57055620c871f0b127.png

PCB板设计
PCB板的尺寸和定位孔是按照LCD的尺寸来绘制的,所以PCB会相对大一些,布局和摆放元器件也宽松了很多。
35341620c873a710d0.png

回板焊接与调试
我们直接来看一下焊接好的PCBA和组装好后的整机吧。整体的原理相对简单,只要焊接OK,并且将LCDPCB的尺寸和定位孔对应上,问题就不大了,接下来我们就来调试硬件、移植GUI等软件层面的操作了。
28733620c8751a0e13.png
93733620c8758a308a.png

移植SimpleGUI
SGUI_Config.h文件中,SimpleGUI默认是开启VirtualSDK模式的,所以在移植到我们开发板上的时候,需要将如下这两个宏定义都注释掉:
//#define _SIMPLE_GUI_IN_VIRTUAL_SDK_
//#define _SIMPLE_GUI_ENABLE_DYNAMIC_MEMORY_

接下来就是初始化SimpleGUI配置参数和实现所需要的LCD接口函数了;在配置SimpleGUI参数时,需要确认LCD的水平像素点和垂直像素点,当前我们使用的240*128显示分辨率的单色LCD液晶显示屏;根据LCD的像素我们需要定义一个显示缓存,缓存的大小为240/*128/8字节;另外还需要实现3个接口函数,分别是LCD在任意坐标画点的功能函数、LCD清除显示屏的功能函数、和LCD刷新显示的功能函数;将这些都配置完成后,就可以调用SimpleGUI的其它功能函数实现简单的图形界面显示了:
LCD代码实现部分:
  1. uint8_t GraphicBuffer[128][30];


  2. /*******************************************************************************
  3. * [url=home.php?mod=space&uid=247401]@brief[/url]       更新显示缓存
  4. * @param      
  5. * @retval      
  6. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  7. *******************************************************************************/
  8. void HJ240128A_DisplayGraphic(void)
  9. {
  10.     /* 设置显示地址 */
  11.     HJ240128A_WriteCommandWithDoubleParam(0x24, 0x00, 0x02);

  12.     /* 进入自动写方式 */
  13.     HJ240128A_WriteCommandWithoutParam(0xB0);

  14.     for(uint16_t i = 0; i < 128; i++)
  15.     {
  16.         for(uint16_t j = 0; j < 30; j++)
  17.         {
  18.             HJ240128A_STA3_CheckBusy();
  19.             HJ240128A_WriteData(GraphicBuffer[i][j]);
  20.         }
  21.     }

  22.     /* 退出自动写方式 */
  23.     HJ240128A_WriteCommandWithoutParam(0xB2);
  24. }


  25. /*******************************************************************************
  26. * @brief       清屏(缓存)
  27. * @param      
  28. * @retval      
  29. * @attention   
  30. *******************************************************************************/
  31. void LCD_ClearScreen(void)
  32. {
  33.     memset(GraphicBuffer, 0, sizeof(GraphicBuffer));
  34. }


  35. /*******************************************************************************
  36. * @brief       画点(缓存)
  37. * @param      
  38. * @retval      
  39. * @attention   
  40. *******************************************************************************/
  41. void LCD_DrawPoint(uint8_t X, uint8_t Y, uint8_t Flag)
  42. {
  43.     uint8_t Buffer[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};

  44.     if((X < 240) && (Y < 128))
  45.     {
  46.         if(Flag)
  47.         {
  48.             GraphicBuffer[Y][X / 8] |=  Buffer[X % 8];
  49.         }
  50.         else
  51.         {
  52.             GraphicBuffer[Y][X / 8] &= ~Buffer[X % 8];
  53.         }
  54.     }
  55. }


  56. /*******************************************************************************
  57. * @brief       读点(缓存)
  58. * @param      
  59. * @retval      
  60. * @attention   
  61. *******************************************************************************/
  62. uint8_t LCD_ReadPoint(uint8_t X, uint8_t Y)
  63. {
  64.     uint8_t Buffer[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};

  65.     return (GraphicBuffer[Y][X / 8] & Buffer[X % 8]);
  66. }


  67. /*******************************************************************************
  68. * @brief       显示ASCII(缓存)
  69. * @param      
  70. * @retval      
  71. * @attention   
  72. *******************************************************************************/
  73. void LCD_DrawASCII(uint8_t X, uint8_t Y, char ch, uint8_t Height)
  74. {
  75.     uint8_t Data = 0;

  76.     for(uint8_t i = 0; i < Height; i++)
  77.     {
  78.         if(Height == 12)
  79.         {
  80.             Data = ASCII_1206[ch - 0x20][i];
  81.         }
  82.         else
  83.         {
  84.             Data = ASCII_1608[ch - 0x20][i];
  85.         }

  86.         for(uint8_t j = 0; j < Height/2; j++)
  87.         {
  88.             if((Data >> j) & 0x01)
  89.             {
  90.                 LCD_DrawPoint(X + j, Y + i, 1);
  91.             }
  92.             else
  93.             {
  94.                 LCD_DrawPoint(X + j, Y + i, 0);
  95.             }
  96.         }
  97.     }
  98. }


  99. /*******************************************************************************
  100. * @brief       更新显示(缓存)
  101. * @param      
  102. * @retval      
  103. * @attention   
  104. *******************************************************************************/
  105. void LCD_Refresh(void)
  106. {
  107.     HJ240128A_DisplayGraphic();
  108. }

SimpleGUI移植接口代码实现部分:
  1. /* Private variables --------------------------------------------------------*/
  2. SGUI_SCR_DEV SimpleGUI_Device;
  3. SGUI_BYTE    SimpleGUI_Buffer[240*128/8];
  4. SGUI_SIZE    SimpleGUI_Lenght = 240 * 16;


  5. /*******************************************************************************
  6. * @brief      
  7. * @param      
  8. * @retval      
  9. * @attention   
  10. *******************************************************************************/
  11. void SGUI_SDK_SetPixel(SGUI_INT iX, SGUI_INT iY, SGUI_UINT iColor)
  12. {
  13.     if(iColor == SGUI_COLOR_FRGCLR)
  14.     {
  15.         LCD_DrawPoint(iX, iY, 1);
  16.     }
  17.     else
  18.     {
  19.         LCD_DrawPoint(iX, iY, 0);
  20.     }
  21. }


  22. /*******************************************************************************
  23. * @brief      
  24. * @param      
  25. * @retval      
  26. * @attention   
  27. *******************************************************************************/
  28. void SGUI_SDK_ClearDisplay(void)
  29. {
  30.     LCD_ClearScreen();
  31. }


  32. /*******************************************************************************
  33. * @brief      
  34. * @param      
  35. * @retval      
  36. * @attention   
  37. *******************************************************************************/
  38. void SGUI_SDK_RefreshDisplay(void)
  39. {
  40.     LCD_Refresh();
  41. }


  42. /*******************************************************************************
  43. * @brief      
  44. * @param      
  45. * @retval      
  46. * @attention   
  47. *******************************************************************************/
  48. void SimpleGUI_Init(void)
  49. {
  50.     SGUI_SystemIF_MemorySet(&SimpleGUI_Device, 0x00, sizeof(SGUI_SCR_DEV));

  51.     SimpleGUI_Device.stSize.iWidth  = 240;
  52.     SimpleGUI_Device.stSize.iHeight = 128;

  53.     SimpleGUI_Device.stBuffer.pBuffer = SimpleGUI_Buffer;
  54.     SimpleGUI_Device.stBuffer.sSize   = SimpleGUI_Lenght;

  55.     SimpleGUI_Device.fnSetPixel   = SGUI_SDK_SetPixel;
  56.     SimpleGUI_Device.fnClear      = SGUI_SDK_ClearDisplay;
  57.     SimpleGUI_Device.fnSyncBuffer = SGUI_SDK_RefreshDisplay;

  58.     SimpleGUI_Device.fnClear();
  59.     SimpleGUI_Device.fnSyncBuffer();
  60. }

SimpleGUI简单图形界面示例代码及效果:
  1. /*******************************************************************************
  2. * @brief      
  3. * @param      
  4. * @retval      
  5. * @attention   
  6. *******************************************************************************/
  7. void SimpleGUI_Demo(void)
  8. {
  9.     SGUI_RECT  stDisplayArea;
  10.     SGUI_POINT stInnerPos;

  11.     SimpleGUI_Device.fnClear();

  12.     stInnerPos.iX = 0;
  13.     stInnerPos.iY = 0;

  14.     stDisplayArea.iX      = 130;
  15.     stDisplayArea.iY      = 0;
  16.     stDisplayArea.iWidth  = SGUI_DEFAULT_FONT_8.iHalfWidth * 12;
  17.     stDisplayArea.iHeight = SGUI_DEFAULT_FONT_8.iHeight;
  18.     SGUI_Text_DrawText(&SimpleGUI_Device, "Hello World!", &SGUI_DEFAULT_FONT_8,  &stDisplayArea, &stInnerPos, SGUI_DRAW_NORMAL);

  19.     stDisplayArea.iX      = 130;
  20.     stDisplayArea.iY      = 16;
  21.     stDisplayArea.iWidth  = SGUI_DEFAULT_FONT_12.iHalfWidth * 12;
  22.     stDisplayArea.iHeight = SGUI_DEFAULT_FONT_12.iHeight;
  23.     SGUI_Text_DrawText(&SimpleGUI_Device, "Hello World!", &SGUI_DEFAULT_FONT_12, &stDisplayArea, &stInnerPos, SGUI_DRAW_REVERSE);

  24.     stDisplayArea.iX      = 130;
  25.     stDisplayArea.iY      = 32;
  26.     stDisplayArea.iWidth  = SGUI_DEFAULT_FONT_16.iHalfWidth * 12;
  27.     stDisplayArea.iHeight = SGUI_DEFAULT_FONT_16.iHeight;
  28.     SGUI_Text_DrawText(&SimpleGUI_Device, "Hello World!", &SGUI_DEFAULT_FONT_16, &stDisplayArea, &stInnerPos, SGUI_DRAW_NORMAL);

  29.     SGUI_Basic_DrawLine(&SimpleGUI_Device, 0, 10, 96, 10, SGUI_COLOR_FRGCLR);
  30.     SGUI_Basic_DrawLine(&SimpleGUI_Device, 0, 10, 15, 25, SGUI_COLOR_FRGCLR);

  31.     SGUI_Basic_DrawRectangle(&SimpleGUI_Device, 20, 35, 20, 20, SGUI_COLOR_FRGCLR, SGUI_COLOR_BKGCLR);

  32.     SGUI_Basic_DrawRoundedRectangle(&SimpleGUI_Device, 15, 80, 40, 30, 5, SGUI_COLOR_FRGCLR, SGUI_COLOR_BKGCLR);

  33.     SGUI_Basic_DrawCircle(&SimpleGUI_Device, 100, 32, 10, SGUI_COLOR_FRGCLR, SGUI_COLOR_FRGCLR);
  34.     SGUI_Basic_DrawCircle(&SimpleGUI_Device, 100, 80, 10, SGUI_COLOR_FRGCLR, SGUI_COLOR_TRANS);

  35.     SimpleGUI_Device.fnSyncBuffer();
  36. }

46150620c883c2b652.png

移植SimpleGUI Demo演示例程
SimpleGUI主要由GUIHMI两部分组成的,GUI部分主要功能为屏幕显示的控制,例如基础几何图形的绘制、文字的绘制、以及基础基础几何图形和文字的各种组件的绘制,而HMI部分则是负责屏幕画面的组织和与用户交互的处理,主要目的是将画面显示与业务/功能处理分割开来方便项目的维护。在官方提供的SimpleGUI源码包里DemoProcGUIHMIVirtualSDK这两个文件夹;其中DemoProc提供了SimpleGUI支持的组件的示例程序和演示,结合HMI引擎,达到一个GUI小项目系统的功能。

可能刚一开始接触到DemoProc.C以及HMI_Engine.c会有点蒙;具体的可以参考官方提供的《02-移植演示程序.md》去熟悉,也可以参考本文中最后给的附件代码来理解;附件中给出的代码是基于MM32F3270系列MCU移植的SimpleGUI Demo演示程序,当然也是基于上述的开发板硬件平台上的适配程序。

运行效果显示
0216_2.gif
0216_3.gif
0216_1.gif
0216_4.gif
0216_5.gif

附件:
HJ240128A: 240128A模块说明书.pdf (935.82 KB, 下载次数: 35)
原理图: Schematic_MM32L373PF_LCD240128_2022-02-16.pdf (148.99 KB, 下载次数: 38)
SimpleGUI移植例程: SimpleGUI.zip (9.78 MB, 下载次数: 104)
SimpleGUI DemoProc演示例程: SimpleGUI_DemoProc.part1.rar (5 MB, 下载次数: 118) SimpleGUI_DemoProc.part2.rar (4.65 MB, 下载次数: 149)
SimpleGUI官方程序: simplegui-Develope.zip (9.25 MB, 下载次数: 59)


打赏榜单

21小跑堂 打赏了 100.00 元 2022-02-17
理由:恭喜通过原创奖审核!请多多加油哦!

yangxiaor520 发表于 2022-2-16 20:37 来自手机 | 显示全部楼层
牛X,学习了。
guijial511 发表于 2022-2-17 08:40 来自手机 | 显示全部楼层
这个不错
WoodData 发表于 2022-2-17 09:22 | 显示全部楼层
效果不错啊
 楼主| xld0932 发表于 2022-2-17 12:22 | 显示全部楼层
htmlme 发表于 2022-2-20 15:04 | 显示全部楼层
SimpleGUI怎么样   
minzisc 发表于 2022-2-20 15:19 | 显示全部楼层
工业HMI?      
primojones 发表于 2022-2-21 11:43 | 显示全部楼层
GUI移植真是难呢   
macpherson 发表于 2022-2-21 11:52 | 显示全部楼层
SimpleGUI移植示例
jtracy3 发表于 2022-2-21 12:02 | 显示全部楼层
运行的效果怎么样  
belindagraham 发表于 2022-2-21 12:12 | 显示全部楼层
这个工业上用的吗  

评论

可以用在工业上  发表于 2022-2-21 12:37
coslight 发表于 2022-2-23 19:48 | 显示全部楼层
不错的使用,这个值得留意
LED2013 发表于 2022-2-28 22:27 | 显示全部楼层
这个学习起来还是够力
wiba 发表于 2022-3-1 14:09 | 显示全部楼层
移植过程顺利吗
kxsi 发表于 2022-3-1 14:16 | 显示全部楼层
应用领域应该很广泛
coshi 发表于 2022-3-1 14:30 | 显示全部楼层
感觉还是比较流畅的
drer 发表于 2022-3-1 14:38 | 显示全部楼层
这个是什么接口的屏幕啊
qcliu 发表于 2022-3-1 14:58 | 显示全部楼层
原理图很见功底啊
foxsbig 发表于 2022-3-4 17:23 | 显示全部楼层
赞~~~非常好的说
zjsx8192 发表于 2022-8-15 10:16 | 显示全部楼层
lcd部分不错
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 在线客服 返回列表 返回顶部