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

STM32CubeIDE GuiLite图形库移植经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 16:38
一、GuiLite       - p/ p0 s( C; Q2 d4 d* b$ J, x
        GuiLite图形库,仅4千行C++代码,0依赖,单一头文件库(GuiLite.h)的跨平台开源GUI库,支持支持的操作系统有iOS/macOS/WatchOS,Android,Linux(ARM/x86-64),Windows(包含VR),RTOS等,甚至无操作系统的单片机上也能流畅运行。
; G' Q$ i8 ~# J, c8 f( W# _4 D8 m
2 }& n$ f' c5 {0 `
二、创建工程4 V, _0 t! y( _! V. Q+ Z

6 ?$ Y/ a; B( p# R        实现了LCD屏幕点亮功能。
% U/ W6 h+ w) @+ R/ b7 p. U! p: M4 R5 |$ E- B# \) U
        【2】现在CubeIDE工作空间创建一个名为stm32L496VGTx_GUI的文件目录,并将前面工程的stm32L496VGTx_lcm.ioc文件拷贝到该目录下,修改该文件名为stm32L496VGTx_GUI.ioc。! g/ S4 [  `' ~9 c1 C

1 b! t* Z" T0 Z; F        在CubeIDE中,在菜单栏的“新建-> Create a New STM32 Project from an Existing STM32CubeMX Configuration files(.ioc)”,进入创建,基于已有ioc创建一个新工程,如下图所示,特别注意,选择C++支持,因为GuiLite库是C++库。6 z) l/ F: [8 }/ W  i0 q

, j6 d+ \% v0 i* O8 u) ]' ?
77b7c5fa691448e28c500c6f201140a5.png
$ p' w. z2 p1 H" k: u
+ e9 g8 {' `5 Z6 n        【3】完成工程创建后,禁用syscalls.c文件,在工程目录下创建源目录ICore,并移植前面工程的源文件,实现lpuart1串口驱动、按键及LED灯驱动、LCD屏幕驱动,如下图所示;由于前面博文中实现LCD的DMA刷新数据时,使用了SPI回调及全局变量,需要到Core/Src/spi.c文件增加如下内容:
! f( z9 L% W; T+ J2 ~+ q  P
  1. volatile uint8_t one_frame_done;$ T7 k) N& R3 O; }. {, J0 e; L
  2. void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi). F3 E3 y* e1 _* I  j/ S
  3. {  K* Z- [3 U" u) Q
  4.         one_frame_done = 1;; N, K0 ]) j6 @& A1 r
  5. }
复制代码
( b6 S0 S/ [: K" {% P8 s
1605f3e1bd77401e93684107453c004c.png 3 K% _* z' |% I, H* w! p
* w) U# w+ J6 U2 k- C6 C; g" R
' _( b" Z$ D4 i6 A
三、GuiLite库及Hello3D样例移植
, c0 y1 K. ]* c3 a. |0 ~9 N        在ICore目录下创建guilite文件夹,将GuiLite库即GuiLite.h文件拷贝到该文件目录,将Hello3D样例的UIcode.cpp源文件拷贝到该文件目录。+ l  l8 A( f' b
- Y  W2 f: `8 x9 Q& s
        【1】由于GuiLite.h内的thread_sleep函数调用了延时函数,而样例给出的延时函数过于复杂,本文另外设置了新的延时函数,在ICore目录下新建delay目录,并在该目录下创建了delay.h和delay.c源码。- G& Z- ~) T+ E2 P  V' c. x
3 k1 |4 g+ H7 |! c( R
        delay.h
* S5 g$ {' e  R& N" \: r
  1. #ifndef DELAY_DELAY_H_& W# c0 a- w4 Z* W5 V( U
  2. #define DELAY_DELAY_H_% d: @; @( W8 u; ]9 m6 X/ g% W
  3. #ifdef __cplusplus
    . c5 A$ c( o' ?2 H$ u; t
  4. extern "C" {. K+ v$ t5 r6 j( {9 v) Z0 V
  5. #endif. e1 a( ^- A) f

  6. % E0 A" J& n( x1 I7 G
  7. #include "stm32l4xx_hal.h" //HAL库文件声明
    6 x4 t7 R. K: ^+ \
  8. void delay_us(uint32_t us); //C文件中的函数声明
    4 X: M! i" U4 f

  9. ( Y) |& u. A2 u/ r" d
  10. #ifdef __cplusplus
    6 t( @! @* H9 f
  11. }
    5 I! b; s* r, t2 P2 a! I7 V7 |: Z
  12. #endif4 s* w) k& c! D
  13. #endif /* DELAY_DELAY_H_ */
复制代码

' A/ U  s1 q7 Z6 j! z  k

# q9 v& A# k2 q" M3 {3 i; _. y        delay.c
2 s; D3 k! C' A. x5 A" \& b
  1. #include "delay.h"! M1 s4 B6 }) R  V
  2. % J2 t6 R) }  t; l
  3. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
    ! N6 Z0 D4 C& @; v
  4. {
    % _- r# T1 H+ K- R
  5.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数
    ) O  I; M: F! l, B
  6.     while (delay--); //循环delay次,达到1微秒延时- ^: |' \3 P3 z0 f( N# h5 X
  7. }
复制代码
5 [  x) E* ?3 T7 k; t: ]
        由于现在采用的是C++编译语言,因此可以看到 delay.h文件中,和以前不一样的是,增加了extern "C"声明,为了严禁,移植过来的print.h、usart.h、key.h、led.h、oled.h本文都增加了extern "C"声明。
, M  r2 R% W( W+ S
  1. #ifdef __cplusplus
    , o/ v" u/ [" y, q* O# s
  2. extern "C" {
    8 `8 |' U( Q6 O0 j3 i
  3. #endif3 d" i& c  h0 {
  4. 7 w( W8 N: d! z1 A( u
  5. //you code, ^) P  t, x! x6 }' c9 }
  6. * w' ?8 ]6 E8 M; z8 e. |
  7. #ifdef __cplusplus
    - C$ X" p* E/ S- a
  8. }
复制代码
0 N$ Z% F- e- P% e5 c) v- J. e* E
        【2】调整文件GuiLite.h,首先,同样的在文件前面增加了delay.h头文件的引用,以及为了统一,将其宏定义#pragma once进行了替换,结果如下
) k# p+ k, J% F5 O* W7 A4 l$ a
  1. #ifndef GUILITE_H_
    , i9 h8 |9 ?4 r  Q$ z8 J$ Z" T
  2. #define GUILITE_H_7 c' w+ w5 e( [: ^
  3. #include "../delay/delay.h"
复制代码
( p% z9 `2 ]1 @( L3 b2 h* h' `
        在GuiLite.h文件中找到thread_sleep函数,该函数有几处,需要条件编译的地方暂时不用管找到STM32需要的,如下。
1 G$ T/ p+ c5 ?- U
  1. extern "C" void delay_ms(unsigned short nms);, d, e3 o) m- m+ Q. |2 W5 J9 u
  2. void thread_sleep(unsigned int milli_seconds)
    4 w! i+ O0 H. q
  3. {//MCU alway implemnet driver code in APP.
    2 U+ \$ x' ~# o' q
  4.                 delay_ms(milli_seconds);
    # M( m+ n8 h* @7 M0 z( A
  5. }
复制代码
3 H  L, f/ D! i) V6 |; u$ p0 F( H
        调整为
/ K* t9 ?6 G, t, ?# ]
  1. //extern "C" void delay_ms(unsigned short nms);
    & e  R) u& I* f1 \
  2. void thread_sleep(unsigned int milli_seconds)# g) E3 F, L* I) X1 k4 V& ~
  3. {//MCU alway implemnet driver code in APP.
    . i1 p/ p4 R  }  N8 J  n+ \3 }
  4.         uint32_t tt = ((uint32_t)milli_seconds)*1000;" k. a, H+ t& H. d: G; B
  5.         delay_us(tt);% X8 Q! y! [+ d2 k2 U5 n  N
  6. }
复制代码

2 E$ s+ x* m/ H+ C2 Q2 b        【3】在main.c文件,引用各外设驱动头文件
, v9 _* e' _( P
  1. /* USER CODE BEGIN Includes */1 K4 I( {$ m/ U4 M/ \' [
  2. #include "../../ICore/key/key.h"  r4 ^" R. q: L  m* [2 H3 F% s
  3. #include "../../ICore/led/led.h"
    ( k5 M5 V3 H. E  |* [$ t
  4. #include "../../ICore/print/print.h"9 E9 j) h' B0 E
  5. #include "../../ICore/usart/usart.h"
    - @6 s& i6 t4 C- I* l# H
  6. #include "../../ICore/oled/oled.h"
    * a* ^! }; l) d: y4 U+ }
  7. /* USER CODE END Includes */
复制代码

5 d0 L" Z% t6 s0 c" C1 Z$ `) c        在main.c文件中参考Hello3D样例的main.c源文件(Hello3D/BuildSTM32F103-Keil/USER/main.c · idea4good/GuiLiteSamples - Gitee.com)进行声明GuiLite库调用前置声明如下,主要就是需要改写调用本文LCD屏幕支持依据坐标值及颜色值,进行点绘制功能函数。
* S% ~) b& d1 ^( Z; ^" W, R
  1. /* USER CODE BEGIN 0 */) @4 O8 j% G( ^, D
  2. //Transfer GuiLite 32 bits color to your LCD color# h- T3 v) F2 b! b3 b' |8 C; o- N
  3. #define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8))  _0 U# O5 E. ]; X
  4. //Encapsulate your LCD driver:. l2 ^! v  j+ \7 t' b2 y7 h
  5. void gfx_draw_pixel(int x, int y, unsigned int rgb)+ `+ I0 ~( S; H2 ^$ v0 k7 R
  6. {# y. W5 n! [/ \* }# z8 l, J8 ]0 c; S
  7.     //LCD_Fast_DrawPoint(x, y, GL_RGB_32_to_16(rgb));//注释参考样例的* `! U1 @+ }" a% Y
  8.         OLED_WritePixel(x, y, GL_RGB_32_to_16(rgb));//新增本工程支持绘制点函数调用(oled.h)
    9 ]+ f( f0 K) g
  9. }+ r* o, k% R0 g; c; E7 L2 X
  10. //Implement it, if you have more fast solution than drawing pixels one by one.
    ) |% C* X7 G7 x0 E6 T
  11. //void gfx_fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb){}
    , Z/ q, V# U# n) w
  12. 1 N8 W) H7 E1 m# v9 R8 a! `
  13. //UI entry
    . X/ f( x: l5 g6 `
  14. struct DISPLAY_DRIVER& m9 y9 C. x  x5 p0 ?
  15. {3 G" o" T$ \# m' [/ ^: H
  16.         void (*draw_pixel)(int x, int y, unsigned int rgb);
    % Q7 y& ?" R4 e& r% K
  17.         void (*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb);
    7 e0 d9 K/ M: y) R4 |; g/ M
  18. } my_driver;1 G' F1 X5 W& }- V' S
  19. extern void startHello3D(void* phy_fb, int width, int height, int color_bytes, struct DISPLAY_DRIVER* driver);
    ) c, u& U2 ~7 [; ~$ c, `' C
  20. /* USER CODE END 0 */
复制代码
  }$ m5 _0 A% d& `
* r2 D" S& L; X6 }1 |
        在Hello3D样例的main主函数中,先初始化延时函数、在配置中断和LCD屏幕初始化,然后进行3D效果绘制渲染输出。

9 T  E! \; g, l; D7 Z1 k
  1. delay_init();
    1 n* K! G( T1 z/ B3 i
  2.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);$ K8 v& @& p1 P4 d
  3.         LCD_Init();
    $ u* y/ Q. J' n
  4. 3 l; A5 y# _. r9 z* {, {* z+ _
  5.         //Link your LCD driver & start UI:) w1 t! z# I2 E+ E. X
  6.         my_driver.draw_pixel = gfx_draw_pixel;3 U  a; b) @8 ^8 y2 i) C
  7.         my_driver.fill_rect = NULL;//gfx_fill_rect;
    # s& F, Q& P7 p
  8.         startHello3D(NULL, 240, 320, 2, &my_driver);' \% G" I5 S' h0 K" m7 S
  9.         while(1);
复制代码

: M3 s, V  P  ~" l( V5 U  v        在本博文移植中,在main函数内进行外设初始设置,例如lpuart1中断接收开启、lcd初始化,主要是LCD初始化。
7 Z8 R6 ^* l8 A: {8 [5 u
  1.   /* USER CODE BEGIN 2 */
    7 j' B9 A% O- z8 d; N8 z9 e8 O
  2.   ResetPrintInit(&hlpuart1);# b" h/ \/ m! k$ Y0 z
  3.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断5 ?0 P- d+ E8 H* B* O" f
  4.   HLPUSART_RX_STA = 0;
    8 E8 B8 D4 ^2 h/ w! I( P1 l
  5.   //1 W6 n- S% e- d3 a1 L
  6.   OLED_init();
    8 s+ j. o, S$ G' V0 `  Q$ ^+ [; Q
  7.   //设置OLED蓝色背景显示3 a2 ~3 ~7 y. t
  8.   BSP_LCD_Clear_DMA(LCD_DISP_BLUE);
    ) J0 t! x9 Y# z5 A& P
  9.   printf("OLED_Clear_DMA\r\n");  b9 R1 h, P9 m
  10.   /* USER CODE END 2 */
复制代码
$ O- G+ @$ Z$ y) I
        然后在main函数主循环中,通过按键KEY2按键进入3D效果绘制渲染输出,读者可以屏蔽串口接收功能、按键KEY0、KEY1的亮屏功能,直接进入KEY2下的3D效果绘制渲染功能是OK的。注意startHello3D调用需要根据自身屏幕宽、高设值,本文开发板支持240*240像素显示。0 [5 m2 _* C7 z5 C, w
  1.   /* USER CODE BEGIN WHILE */
    % P  Z/ i  w5 @0 T: P" s. p' e/ D  w
  2.   while (1)9 N7 X+ w% e7 K5 f" x5 \! Y2 Y4 l: ]
  3.   {
    - \- q; b8 ?% T2 b+ L* @
  4.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始) S1 E: n: w) u$ S8 c: O5 J
  5.                   //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
    , }# ~& E* o0 K$ E
  6.                   OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
    & h; R+ \  v* s6 O2 q! c( g/ P- y% b
  7.                   HLPUSART_RX_STA=0;//接收错误,重新开始" E0 q- h2 ^: l
  8.                   HAL_Delay(100);//等待
    ; b1 g, ^7 U. q9 P, i
  9.           }
    8 H# M4 J3 j6 H& m+ h6 {+ S
  10.           if(KEY_0())
      w# @0 D% t; x% P
  11.           {  k; ~' S8 W$ ^( j% k% j- U  E
  12.                   BSP_LCD_login(24,108);8 i; h5 V( C" W' k
  13.           }
    / t: R* C, d& {& s. _
  14.           if(KEY_1()): e6 p, S0 s% ]5 l( q$ S
  15.             {6 H  \/ @  K. f
  16.                   BSP_LCD_img_DMA();# ~8 U3 w5 q2 k" }9 C% P
  17.             }
    + ^) e* b$ A( [5 N
  18.           if(KEY_2())0 W$ x7 n9 E7 A2 w' y3 q$ a: J
  19.             {1 v% j2 K& H9 R% I/ J5 I: a
  20.                   my_driver.draw_pixel = gfx_draw_pixel;
    3 z" y  m# |% c" E# m* ]" ]
  21.                   my_driver.fill_rect = NULL;//gfx_fill_rect;1 p4 J- \0 b6 z$ n$ n
  22.                   startHello3D(NULL, 240, 240, 2, &my_driver);' r8 t  U! A3 _
  23.             }! ^3 A6 i% W) b  ?
  24.     /* USER CODE END WHILE */
复制代码

! p* ^6 k7 @' ~- n4 G四、编译及测试* |( _( I4 H8 F/ H( T. n9 [
        完成代码移植及改写后,进行运行配置设置,点击编辑及运行按钮,将程序下载到开发板上。6 }/ w$ M" u9 Z0 r4 K* t. H& E

  _9 N/ C0 D8 F0 h
2f01fdf679234e349c31a2a72f836efa.png . F  \5 g) O( C

4 D6 x1 Q4 @1 h. u8 c+ E2 d         按键KEY2进入GuiLite库的3D绘制效果,按键KEY2按下时,屏幕会较慢地进行背景色(黑色)逐点绘制,因此较慢。最终处理的是一个3D立方体缓慢旋转刷新显示的动态画面,效果如下图(手指是拍摄时屏幕镜面映射效果,哈哈)。
  u/ }3 f! ?1 [, b; }. Y
" d% ]2 x9 U( J/ W8 F
722f590bf3e54cb2bc457cca2ee1d67e.png
- c: e, V7 n2 O% _3 y9 Z# S6 F& K% S8 ~; b8 L% A9 z# s* S
366b7d4b58f54925bde9496b94657fa6.png + ]  l: P$ i9 c" r/ c) d  t/ ~
————————————————+ Q; @" Y0 G: E# ~1 \" I
版权声明:py_free-物联智能. k, [7 ^* }6 G$ O8 r5 A/ P
如有侵权请联系删除
: e; X" w4 i% ~0 Y
收藏 评论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 手机版