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

STM32CubeIDE GuiLite图形库移植经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 16:38
一、GuiLite       
# L- H* x, B5 @9 n2 L# w        GuiLite图形库,仅4千行C++代码,0依赖,单一头文件库(GuiLite.h)的跨平台开源GUI库,支持支持的操作系统有iOS/macOS/WatchOS,Android,Linux(ARM/x86-64),Windows(包含VR),RTOS等,甚至无操作系统的单片机上也能流畅运行。" M6 [8 c- N% L

- U: W) V' v/ w& ~二、创建工程
) p8 V4 \: Z* G$ u. w9 T( R3 @6 G+ e( m( E) W0 N
        实现了LCD屏幕点亮功能。# P/ ^( a7 l' X0 z# c8 ^1 C

6 ?4 U6 O# y: y$ F( W) Z        【2】现在CubeIDE工作空间创建一个名为stm32L496VGTx_GUI的文件目录,并将前面工程的stm32L496VGTx_lcm.ioc文件拷贝到该目录下,修改该文件名为stm32L496VGTx_GUI.ioc。1 v$ t6 k8 N" q2 H

' P& Y0 N  N# {$ r6 C7 _        在CubeIDE中,在菜单栏的“新建-> Create a New STM32 Project from an Existing STM32CubeMX Configuration files(.ioc)”,进入创建,基于已有ioc创建一个新工程,如下图所示,特别注意,选择C++支持,因为GuiLite库是C++库。
! T) M0 k/ d7 \' b# i/ r" o# m+ r. Q/ n+ Q" R, }+ h* W4 K0 {  Y
77b7c5fa691448e28c500c6f201140a5.png
* ?! o% i2 c3 _& W, B7 n; b
) v* n; B7 F- Z) u: @& d        【3】完成工程创建后,禁用syscalls.c文件,在工程目录下创建源目录ICore,并移植前面工程的源文件,实现lpuart1串口驱动、按键及LED灯驱动、LCD屏幕驱动,如下图所示;由于前面博文中实现LCD的DMA刷新数据时,使用了SPI回调及全局变量,需要到Core/Src/spi.c文件增加如下内容:
; Z. I. S# j+ `. Z2 g3 Q6 _! c
  1. volatile uint8_t one_frame_done;
    , q- @4 `2 L# x% H# G  k
  2. void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)' O7 {! W/ N2 K* j$ ^# y
  3. {
    $ S  e1 \" _) q- [
  4.         one_frame_done = 1;
    ' C0 @3 w6 j7 m( \2 N
  5. }
复制代码

1 i; C1 b* ?# o& m3 Q) t+ }. Q
1605f3e1bd77401e93684107453c004c.png   [4 {6 C$ o6 `8 _1 Q, Z

7 l. d2 b3 P) y- f$ i- H

! {( J: [* ^2 H' s三、GuiLite库及Hello3D样例移植
9 ^' u9 D' Y" m' @, s2 a        在ICore目录下创建guilite文件夹,将GuiLite库即GuiLite.h文件拷贝到该文件目录,将Hello3D样例的UIcode.cpp源文件拷贝到该文件目录。
8 }/ ~' [/ o  f" f" t1 R
# N: G- R/ p4 z
        【1】由于GuiLite.h内的thread_sleep函数调用了延时函数,而样例给出的延时函数过于复杂,本文另外设置了新的延时函数,在ICore目录下新建delay目录,并在该目录下创建了delay.h和delay.c源码。( m: P) }! a( _
# `+ Q* \7 N  o/ K! s
        delay.h( d, X9 n8 ~7 P- d6 J# w
  1. #ifndef DELAY_DELAY_H_3 T* F1 K& v8 F$ @  h1 W- {
  2. #define DELAY_DELAY_H_
    ' T! g* x6 s1 B. z' n% k) D" [
  3. #ifdef __cplusplus& X( [  h  \- S. H3 S, b& m
  4. extern "C" {1 Z- Z) H5 X4 [3 b3 n9 a; F
  5. #endif
    ' B4 H. h. p2 X- ]/ T4 g
  6. ; J( d  M/ Z; L: i
  7. #include "stm32l4xx_hal.h" //HAL库文件声明7 G) P$ g+ g$ G- f1 c! s
  8. void delay_us(uint32_t us); //C文件中的函数声明
    * D) A8 I" i% f8 P( F0 U* D* n
  9. - I! f3 _  B* R- h- f% l5 ^6 Q
  10. #ifdef __cplusplus
    ! `4 V% W2 W3 P" G' {5 l
  11. }
    5 W( t4 {$ ~. y$ n% j
  12. #endif
    4 x' s1 K' Q1 x  f3 C! `" n8 D  S) Y
  13. #endif /* DELAY_DELAY_H_ */
复制代码
& V/ Y8 E  r* s8 r0 w: ~

. x5 m' v2 Y! E$ x4 B: Q/ r4 H& p        delay.c

' w2 U( ^; ]# G; L* z
  1. #include "delay.h"8 p) r: j6 ?5 x: R/ u) J/ h. N& Q
  2. 6 ~# B  e4 c7 ?1 @
  3. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
    " k  B1 ~9 {5 z, o# V* }
  4. {! r* m4 Z* H8 x' m+ D; ]  u# M
  5.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数& u: c' U0 r) u( v% X, E$ H
  6.     while (delay--); //循环delay次,达到1微秒延时' a, `/ }( M2 F7 e2 x3 D( R
  7. }
复制代码

% \% m+ @5 e" n( w9 c        由于现在采用的是C++编译语言,因此可以看到 delay.h文件中,和以前不一样的是,增加了extern "C"声明,为了严禁,移植过来的print.h、usart.h、key.h、led.h、oled.h本文都增加了extern "C"声明。. c( ?3 J" t! D+ c- ]* t! X$ i
  1. #ifdef __cplusplus2 d% B+ b+ L; A0 W8 z( j4 g! A
  2. extern "C" {
    . N! L. o* s4 X, {
  3. #endif
    7 d- H: T- E  y4 D' D
  4. % G3 r9 H) j( k
  5. //you code
    7 Y  p( ?) s  o; b

  6. * s' W! P9 K. c# D) L" B( o$ z; a
  7. #ifdef __cplusplus- N% I$ m* k& O3 k" @0 T, w# X* u
  8. }
复制代码

( M: a7 C* g, J6 |6 u8 ^        【2】调整文件GuiLite.h,首先,同样的在文件前面增加了delay.h头文件的引用,以及为了统一,将其宏定义#pragma once进行了替换,结果如下' n) g. \. Q+ ?, }; O
  1. #ifndef GUILITE_H_0 f5 e0 l7 u, n
  2. #define GUILITE_H_9 I1 v# N/ ]% A. r
  3. #include "../delay/delay.h"
复制代码
/ O. i# R% }2 M7 z
        在GuiLite.h文件中找到thread_sleep函数,该函数有几处,需要条件编译的地方暂时不用管找到STM32需要的,如下。
: y8 S" E$ h# m
  1. extern "C" void delay_ms(unsigned short nms);
    ; C4 C9 e7 {  W% w( s
  2. void thread_sleep(unsigned int milli_seconds)8 p: Y7 q  V5 }- V6 l6 F; I
  3. {//MCU alway implemnet driver code in APP.6 `" x- R: D- O  v6 Q
  4.                 delay_ms(milli_seconds);7 m' w  }( g% R9 O
  5. }
复制代码
5 Z1 I6 N8 J  m6 u
        调整为
0 E% P  O" H0 {+ H7 Z+ a% P5 \
  1. //extern "C" void delay_ms(unsigned short nms);6 J- \, W7 N7 k7 C. C
  2. void thread_sleep(unsigned int milli_seconds)
    9 `3 f, N) t- Y$ z2 `2 G; |9 K
  3. {//MCU alway implemnet driver code in APP.* B8 p8 k( \) F- ^/ H
  4.         uint32_t tt = ((uint32_t)milli_seconds)*1000;
    4 `; ?( T* g: _. j- o
  5.         delay_us(tt);6 A3 W; r; S! E; u4 I0 d. T/ V
  6. }
复制代码
( L4 \# \& T; D
        【3】在main.c文件,引用各外设驱动头文件% Z- x; Y- |3 h. [
  1. /* USER CODE BEGIN Includes */
    9 [; Z+ D+ ?! J& ^$ ~
  2. #include "../../ICore/key/key.h"6 d0 k) K0 Q6 e6 ^6 G
  3. #include "../../ICore/led/led.h"6 d) y5 v& l5 I: M# o
  4. #include "../../ICore/print/print.h"6 g! b  C# j. O" y8 X% q
  5. #include "../../ICore/usart/usart.h"
    0 S* ]( m) ^3 Z, X7 w
  6. #include "../../ICore/oled/oled.h"/ A8 Y( z9 _% g. M" ^! Q
  7. /* USER CODE END Includes */
复制代码
& z. M# D8 i. f( m
        在main.c文件中参考Hello3D样例的main.c源文件(Hello3D/BuildSTM32F103-Keil/USER/main.c · idea4good/GuiLiteSamples - Gitee.com)进行声明GuiLite库调用前置声明如下,主要就是需要改写调用本文LCD屏幕支持依据坐标值及颜色值,进行点绘制功能函数。2 H9 |, N" r- ^: `' x/ j
  1. /* USER CODE BEGIN 0 */. C. \+ F3 k" C9 K6 j5 J
  2. //Transfer GuiLite 32 bits color to your LCD color/ q, V" `' {# ~- `- k, m
  3. #define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8))# _( e3 X: H5 n4 {% U6 B/ p0 n
  4. //Encapsulate your LCD driver:* W; y% z+ l6 @; _  F6 o
  5. void gfx_draw_pixel(int x, int y, unsigned int rgb)
    / u. K5 C: ?" c1 Z3 G
  6. {# O, b5 Z" q: g& v+ ^
  7.     //LCD_Fast_DrawPoint(x, y, GL_RGB_32_to_16(rgb));//注释参考样例的
    " k- F$ z) ]5 p3 i" O
  8.         OLED_WritePixel(x, y, GL_RGB_32_to_16(rgb));//新增本工程支持绘制点函数调用(oled.h)& v$ t: @, k3 d2 o* R/ f
  9. }
    # P7 [8 M6 Q* m" l
  10. //Implement it, if you have more fast solution than drawing pixels one by one.2 D6 }& g7 B% K9 j) F
  11. //void gfx_fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb){}% A* C5 w0 ?/ j/ ?* e

  12. . L$ Z9 w9 g0 c" I* U. _
  13. //UI entry/ j* C* @7 K) i: l
  14. struct DISPLAY_DRIVER
    5 ~" E6 Z3 X# U% g
  15. {
    . [; \" _  s' e, P2 n
  16.         void (*draw_pixel)(int x, int y, unsigned int rgb);  W/ K$ `1 E1 s7 n! Q: u
  17.         void (*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb);* d& ~2 G$ e3 b, ~% J# t& L
  18. } my_driver;
    3 W, u+ ]( c6 q; G* c
  19. extern void startHello3D(void* phy_fb, int width, int height, int color_bytes, struct DISPLAY_DRIVER* driver);; e: l* c# U6 F
  20. /* USER CODE END 0 */
复制代码

% d5 l( A9 C; p" m/ f4 f( n/ q! D
0 M. y4 U3 G: i# g& O7 Q
        在Hello3D样例的main主函数中,先初始化延时函数、在配置中断和LCD屏幕初始化,然后进行3D效果绘制渲染输出。

4 a) ^* J' A1 n0 e' m: A+ ^2 D' s
  1. delay_init();5 j; C2 G( n2 ]0 y
  2.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);4 E' N; r) f) o: U. P8 ~
  3.         LCD_Init();! X8 f: G* C! j7 X7 J% i
  4. ; A" j" b+ [! ~9 Z  r2 S+ d
  5.         //Link your LCD driver & start UI:( }( u7 n! _  P0 m2 K
  6.         my_driver.draw_pixel = gfx_draw_pixel;2 b( D" l5 R% i
  7.         my_driver.fill_rect = NULL;//gfx_fill_rect;; o; j( k. e; Y0 ?+ @% a& j
  8.         startHello3D(NULL, 240, 320, 2, &my_driver);
    9 y' N+ C$ U3 x) I$ ^& f
  9.         while(1);
复制代码

# ?3 a" r2 Y5 ~" ~5 }- X7 g        在本博文移植中,在main函数内进行外设初始设置,例如lpuart1中断接收开启、lcd初始化,主要是LCD初始化。
! D, G5 E( L/ s* j: C
  1.   /* USER CODE BEGIN 2 */
    4 C7 d$ q' Z- N" t. p! p( T% j
  2.   ResetPrintInit(&hlpuart1);1 ]+ C- c9 U) m' g
  3.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
    * Z1 E( @% D; t9 ?$ S
  4.   HLPUSART_RX_STA = 0;
    & L5 M4 H& A, y8 H% a! L1 c
  5.   //# W  j8 V! @$ d$ G
  6.   OLED_init();9 c( o' T' p: A1 V
  7.   //设置OLED蓝色背景显示
    . W: B+ m6 \9 I- ?/ b1 @
  8.   BSP_LCD_Clear_DMA(LCD_DISP_BLUE);' G9 P) d& G; f& R; y- A
  9.   printf("OLED_Clear_DMA\r\n");; }  _1 V$ l: o9 Y9 Q% q
  10.   /* USER CODE END 2 */
复制代码

6 W# q" j6 O, b& y        然后在main函数主循环中,通过按键KEY2按键进入3D效果绘制渲染输出,读者可以屏蔽串口接收功能、按键KEY0、KEY1的亮屏功能,直接进入KEY2下的3D效果绘制渲染功能是OK的。注意startHello3D调用需要根据自身屏幕宽、高设值,本文开发板支持240*240像素显示。5 t3 ^3 Q* A& X1 N
  1.   /* USER CODE BEGIN WHILE */
    3 r( |# P0 p% s, t) s  ]
  2.   while (1)2 v7 G' Q9 ]! I
  3.   {( L# g! `4 C( H
  4.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始. A2 s0 _/ D# D5 s* K/ o- R
  5.                   //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);% t6 C- s* @  ?% H% A
  6.                   OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);' t) A# B) d/ g6 ?% Z# d
  7.                   HLPUSART_RX_STA=0;//接收错误,重新开始3 I& E" ?9 E/ a+ K, v
  8.                   HAL_Delay(100);//等待
    , \: v' _. y& ^3 _
  9.           }
    5 C- ^$ R' Y4 C( k0 P* H2 i
  10.           if(KEY_0())/ E0 u" X2 F3 i# U1 h0 o
  11.           {3 h4 l8 \9 I* L$ I3 t2 s/ C
  12.                   BSP_LCD_login(24,108);- N4 X; c  C5 g; e5 U
  13.           }
    + G# ]) X7 e4 k- j
  14.           if(KEY_1())% l! ]* z- y% |0 j2 B+ h- w' D: f" C
  15.             {) L8 x+ R5 f- a; N6 n8 O5 ^0 D+ n
  16.                   BSP_LCD_img_DMA();1 I& L. _. Z  a/ ?. o
  17.             }+ ]5 [& e) N6 ~5 ^- _2 q7 c
  18.           if(KEY_2())
    6 x4 [; s* e4 I0 o, \1 A# L
  19.             {2 v$ A& p' X$ Z6 j
  20.                   my_driver.draw_pixel = gfx_draw_pixel;& A. x4 v1 Q# M+ p( m2 [/ u# W" U
  21.                   my_driver.fill_rect = NULL;//gfx_fill_rect;+ L, B5 L3 Y% T6 L2 C
  22.                   startHello3D(NULL, 240, 240, 2, &my_driver);
    ( g& O4 {( |/ H* T! K
  23.             }
    # D9 f+ K; `1 o  X! M. [
  24.     /* USER CODE END WHILE */
复制代码
, _9 H6 f+ @2 M# h. G2 B
四、编译及测试& k  _( S4 x; e/ W
        完成代码移植及改写后,进行运行配置设置,点击编辑及运行按钮,将程序下载到开发板上。3 b: x' \  }! N

' S# F4 {' J+ E3 d3 H) f
2f01fdf679234e349c31a2a72f836efa.png # b9 g2 X% n+ F! {& x7 B

- f7 K+ C8 w5 e; I) Q5 K+ O& G! I         按键KEY2进入GuiLite库的3D绘制效果,按键KEY2按下时,屏幕会较慢地进行背景色(黑色)逐点绘制,因此较慢。最终处理的是一个3D立方体缓慢旋转刷新显示的动态画面,效果如下图(手指是拍摄时屏幕镜面映射效果,哈哈)。
- a* o9 W, |( h3 Q+ j# ]% P! w+ T( c5 k  E/ n3 C: K. V
722f590bf3e54cb2bc457cca2ee1d67e.png
. e7 w' O6 L' X0 u  a! i5 z
9 Q# x' ~' K: r, I! U$ I
366b7d4b58f54925bde9496b94657fa6.png
- c# a8 {$ l1 c+ T) z4 R————————————————
* ?0 k/ u: R4 ]  A8 a0 h# U版权声明:py_free-物联智能
7 L& S5 F9 K) {, v  ^# n如有侵权请联系删除
2 @" W0 s1 o: J2 K7 b& U
收藏 评论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 手机版