你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32CubeIDE GuiLite图形库移植经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 16:38
一、GuiLite       6 N/ B# _3 Q2 G, x) u2 O3 ^4 I
        GuiLite图形库,仅4千行C++代码,0依赖,单一头文件库(GuiLite.h)的跨平台开源GUI库,支持支持的操作系统有iOS/macOS/WatchOS,Android,Linux(ARM/x86-64),Windows(包含VR),RTOS等,甚至无操作系统的单片机上也能流畅运行。( I6 @  T4 F5 a% q% Z. R

2 X# d% w4 q3 x9 W9 }- u) X二、创建工程/ a) y/ R+ @: X7 G; G8 ?

8 ?0 _' C/ w7 f        实现了LCD屏幕点亮功能。# ~2 c7 g' s. b& W2 S- ~  S1 l$ ]

$ T" X; J) m5 Q9 O+ g        【2】现在CubeIDE工作空间创建一个名为stm32L496VGTx_GUI的文件目录,并将前面工程的stm32L496VGTx_lcm.ioc文件拷贝到该目录下,修改该文件名为stm32L496VGTx_GUI.ioc。5 U) e9 h' T% Y- o( ]
; I/ ^$ _2 n8 a4 Z2 B6 n0 |
        在CubeIDE中,在菜单栏的“新建-> Create a New STM32 Project from an Existing STM32CubeMX Configuration files(.ioc)”,进入创建,基于已有ioc创建一个新工程,如下图所示,特别注意,选择C++支持,因为GuiLite库是C++库。; o" K/ {* d' }) Z' U$ a5 O
+ I+ E+ |0 y" {' r9 w
77b7c5fa691448e28c500c6f201140a5.png 1 d5 \8 w9 C' w6 l  b
8 P, X+ v# ^2 [
        【3】完成工程创建后,禁用syscalls.c文件,在工程目录下创建源目录ICore,并移植前面工程的源文件,实现lpuart1串口驱动、按键及LED灯驱动、LCD屏幕驱动,如下图所示;由于前面博文中实现LCD的DMA刷新数据时,使用了SPI回调及全局变量,需要到Core/Src/spi.c文件增加如下内容:
4 D' I9 [* k; {% ]/ S
  1. volatile uint8_t one_frame_done;( \' @+ }7 ]  }  X" |
  2. void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
    ( F* Y+ o2 M$ s
  3. {: D: E  E1 }; e) J( H; V+ ^
  4.         one_frame_done = 1;+ _- f) C" d( \- G; }: K% [
  5. }
复制代码

% T$ C& M! w. [' x
1605f3e1bd77401e93684107453c004c.png
2 `" _: e2 n, x" S6 e9 c2 K8 }1 Z( e& Y+ K% T, p" H

5 r# q1 x* p" E; E9 T三、GuiLite库及Hello3D样例移植
2 g* C( V" G/ C, q0 z9 r9 v        在ICore目录下创建guilite文件夹,将GuiLite库即GuiLite.h文件拷贝到该文件目录,将Hello3D样例的UIcode.cpp源文件拷贝到该文件目录。
2 I- ?; b1 ?, B: `
1 g+ e% m! ~, C
        【1】由于GuiLite.h内的thread_sleep函数调用了延时函数,而样例给出的延时函数过于复杂,本文另外设置了新的延时函数,在ICore目录下新建delay目录,并在该目录下创建了delay.h和delay.c源码。3 {% i5 M9 j' d( B! w$ c0 C- D

6 K' d5 Q9 P  U" V% F        delay.h& ?+ I5 y1 J# f7 Q, U: U
  1. #ifndef DELAY_DELAY_H_8 m! e2 q1 Z5 I- m# h4 G# ]; S( I
  2. #define DELAY_DELAY_H_
    . C! \0 _4 i/ J2 ~
  3. #ifdef __cplusplus& G" e' P* `5 o. n2 v9 i
  4. extern "C" {
    2 T1 |: s! s, p# |# b$ u2 i. X
  5. #endif: ~* z9 y6 o# r7 ]
  6. & Q* |/ E+ p9 b3 ^1 N$ {0 n
  7. #include "stm32l4xx_hal.h" //HAL库文件声明' {  a  e" F3 e9 ]% b6 L; e, ~
  8. void delay_us(uint32_t us); //C文件中的函数声明& I, n7 U3 j) i# ]' g/ O

  9. 5 }  t) ], S# b8 _. ^
  10. #ifdef __cplusplus6 H: t5 D1 i2 [9 N6 U
  11. }7 ~* E& Y4 u1 |( R; }
  12. #endif
    " {/ x! F( N2 C- e
  13. #endif /* DELAY_DELAY_H_ */
复制代码

  a) y8 e' b1 Y5 c6 P; \, ?0 G

8 K" N, a! i% [0 q, {2 t        delay.c

$ E3 u5 r7 x+ e  b, a
  1. #include "delay.h"
    ' b0 d+ w' G' ?" S- _
  2. 5 i  q+ [2 i* C$ B0 W* d
  3. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
    6 Q2 ?$ y1 P8 k: ?5 A
  4. {$ x9 A; z/ W) v9 X3 R1 K/ G0 V' O
  5.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数6 Q0 x+ W; }1 Z# n# S/ ~( |. E
  6.     while (delay--); //循环delay次,达到1微秒延时
    6 h5 g( ^6 ^4 K
  7. }
复制代码
/ i! n; i) }% [# @9 ?
        由于现在采用的是C++编译语言,因此可以看到 delay.h文件中,和以前不一样的是,增加了extern "C"声明,为了严禁,移植过来的print.h、usart.h、key.h、led.h、oled.h本文都增加了extern "C"声明。
6 D9 Q( A% r; S5 A9 b! q
  1. #ifdef __cplusplus5 w" D7 I% z7 ?% }/ Q9 }9 C8 T
  2. extern "C" {
    9 j% g( E/ u5 Z" V
  3. #endif
    # Z4 Y) D: t- C5 E2 I

  4. - P% s  c1 o: @3 M9 w6 g% D
  5. //you code- L8 J1 e1 i+ J0 i& @$ w1 {6 q
  6. : M7 E$ v7 T$ [+ D2 r/ o, h& ~& ~
  7. #ifdef __cplusplus
    , z7 V* j2 \; t/ P! Z; ?, w9 S
  8. }
复制代码
) }6 W4 h( u# R5 H$ W1 G- b' u
        【2】调整文件GuiLite.h,首先,同样的在文件前面增加了delay.h头文件的引用,以及为了统一,将其宏定义#pragma once进行了替换,结果如下) X6 t5 U6 P  J# S" z+ K
  1. #ifndef GUILITE_H_. o' e6 ]7 \* ?3 @
  2. #define GUILITE_H_
      I, Z3 W3 J) Z
  3. #include "../delay/delay.h"
复制代码
; \+ D0 L  q8 u7 s
        在GuiLite.h文件中找到thread_sleep函数,该函数有几处,需要条件编译的地方暂时不用管找到STM32需要的,如下。- F/ j7 e+ g! Z7 l; r9 L
  1. extern "C" void delay_ms(unsigned short nms);
    " }9 Q( E* v: p7 r
  2. void thread_sleep(unsigned int milli_seconds)
    ' G( ^) r- `& T
  3. {//MCU alway implemnet driver code in APP.
    . T: ]6 U; X' b3 R) i! }
  4.                 delay_ms(milli_seconds);
    ; R9 R6 o$ F& q% m
  5. }
复制代码
7 Q" r$ k, u5 g. F0 Q/ }/ `
        调整为0 R5 O( t) u# Z/ m5 T7 I
  1. //extern "C" void delay_ms(unsigned short nms);
    & ~: h  v8 y& V: b( v
  2. void thread_sleep(unsigned int milli_seconds)
    ( Q. n7 \9 ^$ d
  3. {//MCU alway implemnet driver code in APP.
    ; b9 f4 h0 Y  x7 o: }/ |; r
  4.         uint32_t tt = ((uint32_t)milli_seconds)*1000;% z1 O$ Y, s3 s
  5.         delay_us(tt);  q' h& m* f& |
  6. }
复制代码

  g1 I' d7 L/ S3 t  \( ^        【3】在main.c文件,引用各外设驱动头文件
5 o8 u% r3 a: ~2 {2 W5 j- k5 O
  1. /* USER CODE BEGIN Includes */$ U# a+ ^& p: B: q" m1 d  M
  2. #include "../../ICore/key/key.h"/ R: m& y4 \9 k0 |
  3. #include "../../ICore/led/led.h"9 g* `" E: R3 ]1 Q" H! E# Q8 X
  4. #include "../../ICore/print/print.h"( W+ A* U% u/ I5 }" A* H. m
  5. #include "../../ICore/usart/usart.h"
    - b; N0 y% t! f  ~. F1 [
  6. #include "../../ICore/oled/oled.h"
    + A' `; H$ A  F9 x" w3 b
  7. /* USER CODE END Includes */
复制代码

  R1 j! H5 d$ |        在main.c文件中参考Hello3D样例的main.c源文件(Hello3D/BuildSTM32F103-Keil/USER/main.c · idea4good/GuiLiteSamples - Gitee.com)进行声明GuiLite库调用前置声明如下,主要就是需要改写调用本文LCD屏幕支持依据坐标值及颜色值,进行点绘制功能函数。
: j/ N- g% ?& M: K1 l8 q- o
  1. /* USER CODE BEGIN 0 */% {# d# _0 T/ N9 P1 s6 T
  2. //Transfer GuiLite 32 bits color to your LCD color
    7 H' w: V1 `& @) N, B& r3 b
  3. #define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8))
    $ z, V. X$ G$ Y2 C$ [5 _- l/ F
  4. //Encapsulate your LCD driver:) c! Z8 n$ u8 y" B* d
  5. void gfx_draw_pixel(int x, int y, unsigned int rgb)
    , h$ `' O4 p7 n0 x: v
  6. {
    # i  M% O! I4 \* `# P: h1 R
  7.     //LCD_Fast_DrawPoint(x, y, GL_RGB_32_to_16(rgb));//注释参考样例的! `4 a' P6 H! b- `/ B
  8.         OLED_WritePixel(x, y, GL_RGB_32_to_16(rgb));//新增本工程支持绘制点函数调用(oled.h)2 I4 f: @9 T: E& R# @  U  m* j
  9. }; l' f# G# {) ~; G9 d
  10. //Implement it, if you have more fast solution than drawing pixels one by one.
    0 }6 e" m+ }- X; T% F
  11. //void gfx_fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb){}
    9 y% s, g4 U* P- ^. s! F. U6 u

  12. 4 J- O9 n" E$ I$ @; D. G4 B
  13. //UI entry$ E6 d8 B0 [. J
  14. struct DISPLAY_DRIVER/ L* ^. o! p$ l# T7 X* n
  15. {0 T2 v; n4 e2 x! o5 D
  16.         void (*draw_pixel)(int x, int y, unsigned int rgb);
    ( h$ q& [9 Z; T
  17.         void (*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb);6 u8 v. Y% Z+ \
  18. } my_driver;
    , w& V* h: h1 N% n
  19. extern void startHello3D(void* phy_fb, int width, int height, int color_bytes, struct DISPLAY_DRIVER* driver);
    - C# f1 V  \- s5 g8 U0 @0 ]
  20. /* USER CODE END 0 */
复制代码

/ h0 Q. Z0 O" f8 Y5 D
$ n/ P, `( l) i( q. Y
        在Hello3D样例的main主函数中,先初始化延时函数、在配置中断和LCD屏幕初始化,然后进行3D效果绘制渲染输出。

$ j0 y* q6 ?0 h# f+ k0 }& {
  1. delay_init();3 o" w, g, o6 b1 w! `, U
  2.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    ( _( C6 W7 y$ {9 @9 Y
  3.         LCD_Init();
    1 i3 v% D- u+ }, m

  4. ) b5 _9 k/ T8 c5 O) W- s
  5.         //Link your LCD driver & start UI:
    3 `# i$ X! U# q; u
  6.         my_driver.draw_pixel = gfx_draw_pixel;
    5 T+ Y0 }; U; n  \8 s! f
  7.         my_driver.fill_rect = NULL;//gfx_fill_rect;
      `5 \1 i/ ?# {) G
  8.         startHello3D(NULL, 240, 320, 2, &my_driver);
    : n7 w! i5 ?1 M6 g
  9.         while(1);
复制代码
4 U0 c# e. q* f+ V  B7 ^  d
        在本博文移植中,在main函数内进行外设初始设置,例如lpuart1中断接收开启、lcd初始化,主要是LCD初始化。
8 o! z5 r7 w( l2 h8 q
  1.   /* USER CODE BEGIN 2 */# D7 C7 d) i* y4 w+ f8 q- [. ?9 Y
  2.   ResetPrintInit(&hlpuart1);
    # v4 ~$ n& l$ b5 s
  3.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
    5 {1 w7 g0 s/ y4 h  G! ?# q
  4.   HLPUSART_RX_STA = 0;
    ( z, S7 M1 A% |; H+ j( ]
  5.   //. V* y9 _7 l8 ?
  6.   OLED_init();
    . B1 T- q  L8 u$ b: {
  7.   //设置OLED蓝色背景显示
    + L# V3 p* I/ c2 c8 h, j7 L
  8.   BSP_LCD_Clear_DMA(LCD_DISP_BLUE);( P1 z1 y5 Q0 O# J3 V8 N
  9.   printf("OLED_Clear_DMA\r\n");
    $ B# ]: N- L. c* ~- y" n/ W
  10.   /* USER CODE END 2 */
复制代码
5 O6 e. Z. k! r
        然后在main函数主循环中,通过按键KEY2按键进入3D效果绘制渲染输出,读者可以屏蔽串口接收功能、按键KEY0、KEY1的亮屏功能,直接进入KEY2下的3D效果绘制渲染功能是OK的。注意startHello3D调用需要根据自身屏幕宽、高设值,本文开发板支持240*240像素显示。
% Y( Z5 M- P6 V3 Y: ]9 l
  1.   /* USER CODE BEGIN WHILE */
    ' k& o7 Z  y) A" h1 p( o
  2.   while (1)
    # R' [: V% X. H7 d  F
  3.   {4 S4 \# m1 i) i% b7 r
  4.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
    . b, _" F! Y6 `
  5.                   //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);; i2 |+ O0 s% ?2 `6 J% n1 o7 {
  6.                   OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
    2 [# L# b9 X) l: H+ }, ?( [
  7.                   HLPUSART_RX_STA=0;//接收错误,重新开始# u2 k9 k! q; B. D) r
  8.                   HAL_Delay(100);//等待
      y8 F# b; k* m
  9.           }
    ) g$ ~# A6 |0 Z  |0 c
  10.           if(KEY_0())
    ) K, v8 r6 g0 t" x  S0 |/ x
  11.           {# U; U, H9 p9 k9 L" |$ x
  12.                   BSP_LCD_login(24,108);
    7 m$ g- }" n: T8 S9 S6 x  }" e. Y4 Q
  13.           }( i; r: h1 X: O+ D1 r
  14.           if(KEY_1())6 M7 B( I) e- k+ v: {7 J2 g
  15.             {# O6 V; }7 z) `: E2 c. o/ o7 F
  16.                   BSP_LCD_img_DMA();# A- P# f! P, i8 ^% g
  17.             }
    : U9 E/ F( h4 V5 |* J
  18.           if(KEY_2())
    ( j/ _" z  B4 F1 A
  19.             {/ I7 w* R: F* t1 y
  20.                   my_driver.draw_pixel = gfx_draw_pixel;3 o+ ?: V# X+ d
  21.                   my_driver.fill_rect = NULL;//gfx_fill_rect;
    + h& F$ U4 N7 {3 P* Z" Y
  22.                   startHello3D(NULL, 240, 240, 2, &my_driver);; ~: M# ?+ |, m5 i9 L- {1 e. f
  23.             }
    , j% {0 ]0 b, d' y& @6 ~# x6 ^
  24.     /* USER CODE END WHILE */
复制代码

: e, x+ F8 C9 u& R四、编译及测试' V% t0 }3 u  L7 K4 a6 ~$ u
        完成代码移植及改写后,进行运行配置设置,点击编辑及运行按钮,将程序下载到开发板上。
, Y; g8 [' {, i+ _% C$ j! [! Q, w. x! W9 A' j
2f01fdf679234e349c31a2a72f836efa.png 9 z3 R1 ?6 ?1 Y9 [% i
: s5 Y! Y: T! y7 X
         按键KEY2进入GuiLite库的3D绘制效果,按键KEY2按下时,屏幕会较慢地进行背景色(黑色)逐点绘制,因此较慢。最终处理的是一个3D立方体缓慢旋转刷新显示的动态画面,效果如下图(手指是拍摄时屏幕镜面映射效果,哈哈)。$ d: @, e; i" I" [3 E
. v  T9 ^; n  D. Y& k3 t/ S
722f590bf3e54cb2bc457cca2ee1d67e.png
  E' n  z4 h9 E' |. @7 Y2 E
3 M; Y; z% H0 E# u
366b7d4b58f54925bde9496b94657fa6.png
. D) J* {3 Y# ?" W————————————————* X' D# b- U! q, }$ K
版权声明:py_free-物联智能# g1 b. a( O' Y7 w2 H# {! p
如有侵权请联系删除( V7 Q$ s3 _, O- N6 e
收藏 评论4 发布时间:2023-4-6 16:38

举报

4个回答
shenxiaolin_mai 回答时间:2023-8-10 10:14:10
不知道c++库可以用在keil上么?还是非常开心的。
shenxiaolin_mai 回答时间:2023-8-10 10:14:39
感谢分享,更详细一点就好了
lospring 回答时间:2023-8-10 10:15:03

内容很详细,谢谢分享

STMWoodData 回答时间:2023-8-10 10:21:30

这个GUI效果真不错,有空可以尝试移植一下看看。

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版