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

STM32CubeIDE GuiLite图形库移植经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 16:38
一、GuiLite       
: j+ L# v1 {/ c7 K2 i! p5 A( }        GuiLite图形库,仅4千行C++代码,0依赖,单一头文件库(GuiLite.h)的跨平台开源GUI库,支持支持的操作系统有iOS/macOS/WatchOS,Android,Linux(ARM/x86-64),Windows(包含VR),RTOS等,甚至无操作系统的单片机上也能流畅运行。4 G6 ~! ^; V: N+ {6 J3 t
# Y& S4 S4 [! m& _3 j3 Y* x: C
二、创建工程
- X- r3 @4 _8 j
- F+ \$ k5 t# \        实现了LCD屏幕点亮功能。7 w6 [  q* v6 ]8 r- \; C
8 R/ ~6 r" O" S/ Z" ~) Q
        【2】现在CubeIDE工作空间创建一个名为stm32L496VGTx_GUI的文件目录,并将前面工程的stm32L496VGTx_lcm.ioc文件拷贝到该目录下,修改该文件名为stm32L496VGTx_GUI.ioc。
' O7 |5 ]* K: b+ b$ |. |2 f3 g) K* c6 k$ `
        在CubeIDE中,在菜单栏的“新建-> Create a New STM32 Project from an Existing STM32CubeMX Configuration files(.ioc)”,进入创建,基于已有ioc创建一个新工程,如下图所示,特别注意,选择C++支持,因为GuiLite库是C++库。: k( Z. P* V* e- F
0 e9 W( B3 v) v2 c/ o
77b7c5fa691448e28c500c6f201140a5.png / @* b- O* n" e! x9 d$ f. R/ s
: A9 j/ _* X" H$ g# Y
        【3】完成工程创建后,禁用syscalls.c文件,在工程目录下创建源目录ICore,并移植前面工程的源文件,实现lpuart1串口驱动、按键及LED灯驱动、LCD屏幕驱动,如下图所示;由于前面博文中实现LCD的DMA刷新数据时,使用了SPI回调及全局变量,需要到Core/Src/spi.c文件增加如下内容:
& m3 q0 `; f- y$ |  w$ g- J
  1. volatile uint8_t one_frame_done;% h. h) W0 `: b3 Z  C, w
  2. void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
    ( U+ r( l9 n0 u  g
  3. {$ z: t7 A: }% f
  4.         one_frame_done = 1;
    ) m9 }  Z/ s  D, I  y7 [: B
  5. }
复制代码

0 c% [, ~4 c# O# I. V
1605f3e1bd77401e93684107453c004c.png 6 L7 Y) e9 T* T0 A* Q3 E$ P2 W
3 Z) |% S4 P3 Q+ f4 R

% R. o! @: H& K! I4 f# C9 F: M9 @三、GuiLite库及Hello3D样例移植
5 v( O& a& c) A1 g        在ICore目录下创建guilite文件夹,将GuiLite库即GuiLite.h文件拷贝到该文件目录,将Hello3D样例的UIcode.cpp源文件拷贝到该文件目录。5 l$ F2 M6 Z; ^* a

4 ?6 L* [; C1 j- J6 H, _        【1】由于GuiLite.h内的thread_sleep函数调用了延时函数,而样例给出的延时函数过于复杂,本文另外设置了新的延时函数,在ICore目录下新建delay目录,并在该目录下创建了delay.h和delay.c源码。- _* t& u  U1 ^7 V) A7 M$ Z3 D

5 d$ `$ i. p) n; S' r        delay.h- r& o9 f9 w5 e5 q, _
  1. #ifndef DELAY_DELAY_H_: {# R( q5 C; G; j$ @
  2. #define DELAY_DELAY_H_7 |" Z0 y/ ~" u. y/ J2 F
  3. #ifdef __cplusplus
    / ~+ H# J9 t% ?7 u! S$ l) q: d& Y* [: F
  4. extern "C" {
    - s5 r3 W. V: S" W2 ?
  5. #endif8 g9 Z0 [5 R( h8 K$ C: I8 g& e

  6. / y5 k% H! N" @
  7. #include "stm32l4xx_hal.h" //HAL库文件声明
    ( y8 I5 F0 H; v& v
  8. void delay_us(uint32_t us); //C文件中的函数声明4 q& o: l% Y. E3 j6 ~7 G9 |
  9. ! Q3 Y4 A$ ?) X
  10. #ifdef __cplusplus" H7 s0 |0 F5 Y3 X3 @' N* Z9 w
  11. }
    7 N; B0 v$ U) F* d8 ?. W
  12. #endif4 R+ D1 b6 p* M: a" B% m) O
  13. #endif /* DELAY_DELAY_H_ */
复制代码

. I* o* r+ ^2 z* ]1 x$ x
+ n( l4 j* o9 G8 Y
        delay.c
' c  Q. P' b& @  u1 d! u& v  s
  1. #include "delay.h"# z3 _% H- Z2 q3 l, U+ E

  2. 9 Y; e  i# I6 U
  3. void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数3 [5 m3 {5 R0 i- ^0 _1 T
  4. {: w! v9 B/ R3 \* ~
  5.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数4 U) n$ X" o# S9 m: p" \
  6.     while (delay--); //循环delay次,达到1微秒延时3 f1 _6 z# T- O; \/ n
  7. }
复制代码

! s4 R0 x' E: D) G        由于现在采用的是C++编译语言,因此可以看到 delay.h文件中,和以前不一样的是,增加了extern "C"声明,为了严禁,移植过来的print.h、usart.h、key.h、led.h、oled.h本文都增加了extern "C"声明。
" D7 H( H# I1 a/ S% B' a; w
  1. #ifdef __cplusplus
    : ^: ]) }3 @1 s) C( o. P" ]
  2. extern "C" {0 X) j4 k$ ~4 P" p
  3. #endif5 [  M' F! C$ V! `

  4. / Q, d4 ^  c/ G
  5. //you code2 C1 k& A9 S' G$ ]# i. e

  6. 9 E& f5 A6 j$ m3 M
  7. #ifdef __cplusplus; W& K0 Q3 K+ @: k2 R: |; V0 G
  8. }
复制代码

) {7 `& Y- T/ }: u( |        【2】调整文件GuiLite.h,首先,同样的在文件前面增加了delay.h头文件的引用,以及为了统一,将其宏定义#pragma once进行了替换,结果如下8 z4 _* b9 C) N4 O1 Y
  1. #ifndef GUILITE_H_& W1 x; \* y  K/ k  Z! O
  2. #define GUILITE_H_" _' A, o7 w' B
  3. #include "../delay/delay.h"
复制代码

3 g: Y( z, v( r' A! ?& X5 _9 z' r& ^        在GuiLite.h文件中找到thread_sleep函数,该函数有几处,需要条件编译的地方暂时不用管找到STM32需要的,如下。
4 }- L, l+ b- F/ o
  1. extern "C" void delay_ms(unsigned short nms);
    " N, [6 x1 U( r2 G, n+ e% y: |0 r
  2. void thread_sleep(unsigned int milli_seconds): B; }2 P4 T# O: ~* G7 O
  3. {//MCU alway implemnet driver code in APP.( S; i6 h5 v( `1 d5 m1 _1 j4 w
  4.                 delay_ms(milli_seconds);4 x" A+ L' N$ Y; e' h# y) }3 X
  5. }
复制代码
* `6 Z6 v, _* b0 [
        调整为/ F. Q  V. i2 m4 h7 P. ?$ L
  1. //extern "C" void delay_ms(unsigned short nms);1 M6 H* R* E- |% w
  2. void thread_sleep(unsigned int milli_seconds)
    & R. f# s8 A* u5 g
  3. {//MCU alway implemnet driver code in APP.
    & |! A) b9 l% z: a8 N7 ]6 t
  4.         uint32_t tt = ((uint32_t)milli_seconds)*1000;
    5 |+ b* V7 k/ E
  5.         delay_us(tt);8 q& O/ \! D& g2 o
  6. }
复制代码
' k5 ?# R, ?9 P! U( i; u
        【3】在main.c文件,引用各外设驱动头文件
2 F" f4 w% x' ?. Y
  1. /* USER CODE BEGIN Includes */4 x4 y2 _* d, B
  2. #include "../../ICore/key/key.h"
      z. j8 y" q' h, F
  3. #include "../../ICore/led/led.h"9 w6 l# g6 J: Z- b) A4 y+ b; l6 d
  4. #include "../../ICore/print/print.h"+ {, C8 X: z4 K& j) E, y9 S" {
  5. #include "../../ICore/usart/usart.h"
    3 u3 g' m9 X4 ]# u; J
  6. #include "../../ICore/oled/oled.h"
    / g  w" `% O# U7 W
  7. /* USER CODE END Includes */
复制代码
, x' M" X3 y; ?  y6 {) L& z
        在main.c文件中参考Hello3D样例的main.c源文件(Hello3D/BuildSTM32F103-Keil/USER/main.c · idea4good/GuiLiteSamples - Gitee.com)进行声明GuiLite库调用前置声明如下,主要就是需要改写调用本文LCD屏幕支持依据坐标值及颜色值,进行点绘制功能函数。2 V( P4 w0 b: a; J7 S
  1. /* USER CODE BEGIN 0 */$ L, ^5 o9 h0 v- Q
  2. //Transfer GuiLite 32 bits color to your LCD color
    1 e4 @7 ?3 y7 l" @. J* r" c
  3. #define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8)). v  {. l' S2 G' M+ K
  4. //Encapsulate your LCD driver:
    0 J, A9 F/ H5 s3 Y
  5. void gfx_draw_pixel(int x, int y, unsigned int rgb)/ E% g2 z8 Z9 X1 o) W- D
  6. {( d$ o$ j( T, I9 _+ M3 C  M
  7.     //LCD_Fast_DrawPoint(x, y, GL_RGB_32_to_16(rgb));//注释参考样例的; o/ }% h" U, ~1 V
  8.         OLED_WritePixel(x, y, GL_RGB_32_to_16(rgb));//新增本工程支持绘制点函数调用(oled.h)
    % j5 q- ~' l# q% q
  9. }5 P+ k2 c+ q$ b1 N3 `3 s+ \0 l
  10. //Implement it, if you have more fast solution than drawing pixels one by one.
    4 z6 f2 c# E4 y. T3 O% X3 |2 r: |
  11. //void gfx_fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb){}
    8 T% j* g0 l7 x/ A

  12. , _. t" O- z' A
  13. //UI entry6 U! o5 S4 C! G  t: c. h
  14. struct DISPLAY_DRIVER1 m; V7 r1 k4 R2 x* h8 ]
  15. {
    5 x; O2 ?  ~3 R6 J
  16.         void (*draw_pixel)(int x, int y, unsigned int rgb);
    8 M( S4 @* ~8 _5 C8 c0 Y" y
  17.         void (*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb);0 d/ p) h  A  M% v
  18. } my_driver;8 j0 E/ G/ v. m/ f$ [% W
  19. extern void startHello3D(void* phy_fb, int width, int height, int color_bytes, struct DISPLAY_DRIVER* driver);0 U# c# w) N! B  m, e8 i
  20. /* USER CODE END 0 */
复制代码

" P4 l% Y2 x1 a: Q7 S

2 m/ g9 S  |% ^  C: b) A( g        在Hello3D样例的main主函数中,先初始化延时函数、在配置中断和LCD屏幕初始化,然后进行3D效果绘制渲染输出。

4 _; m2 C2 ^8 _3 A$ k! t* L
  1. delay_init();( L+ r  p! a" ~' q0 R5 b( S
  2.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    / C% N7 i$ O- k6 x9 l3 A1 c' O' F: D
  3.         LCD_Init();8 @8 t8 i" `% m+ m
  4. / N% A# }4 M$ f* q, W% Y! C
  5.         //Link your LCD driver & start UI:+ ]5 c6 W, i8 G2 H+ s
  6.         my_driver.draw_pixel = gfx_draw_pixel;
    ) A5 i: T' u  C9 |
  7.         my_driver.fill_rect = NULL;//gfx_fill_rect;- r% O, r7 o4 c& N
  8.         startHello3D(NULL, 240, 320, 2, &my_driver);6 z" N: @9 e( B# ?/ \% |* W; J
  9.         while(1);
复制代码

+ J8 @1 {' d, n- F# I        在本博文移植中,在main函数内进行外设初始设置,例如lpuart1中断接收开启、lcd初始化,主要是LCD初始化。
1 R2 ~( r- f9 t2 Y0 ]4 f
  1.   /* USER CODE BEGIN 2 */+ ?5 w3 h" }+ [' h
  2.   ResetPrintInit(&hlpuart1);
    6 B/ U8 I$ l3 [: Z# @
  3.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
    2 U) s$ e/ @% Z* y% d- j+ s. H3 v/ z
  4.   HLPUSART_RX_STA = 0;0 m2 R5 k+ I6 Q! D% U% G1 B
  5.   //
    5 I4 G+ q) p: ~: h0 J7 R2 `
  6.   OLED_init();
    " b3 R+ u8 O3 }3 }
  7.   //设置OLED蓝色背景显示
    ) |- _9 o$ \; K6 u, d, [
  8.   BSP_LCD_Clear_DMA(LCD_DISP_BLUE);& n. [( O) o1 g6 v
  9.   printf("OLED_Clear_DMA\r\n");
    4 C0 p( L! R# W% X6 |
  10.   /* USER CODE END 2 */
复制代码

5 M( s; V/ U3 v! r9 g/ [        然后在main函数主循环中,通过按键KEY2按键进入3D效果绘制渲染输出,读者可以屏蔽串口接收功能、按键KEY0、KEY1的亮屏功能,直接进入KEY2下的3D效果绘制渲染功能是OK的。注意startHello3D调用需要根据自身屏幕宽、高设值,本文开发板支持240*240像素显示。+ H, L/ s! j9 u- i" a
  1.   /* USER CODE BEGIN WHILE */) Y& m8 E2 R/ A! |
  2.   while (1)4 ~- I7 W. k8 e5 F, B- _2 P
  3.   {/ |4 y8 P8 O; p8 t1 g. \% `0 ^  l. h' C
  4.           if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始/ H/ z( v2 r  \' Y$ H1 x: W
  5.                   //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);+ N& a4 j- Y* t; U) v* F/ Z, @/ d
  6.                   OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
    * A6 f1 j- L. U, a' z& Z9 {' `# |
  7.                   HLPUSART_RX_STA=0;//接收错误,重新开始
    0 S( F$ G+ ~; H- N' L4 M- z% r
  8.                   HAL_Delay(100);//等待6 ^$ \% k6 g3 Z. P# a" |
  9.           }
    ! @. m9 l$ ]2 r) t5 J2 o5 x) m
  10.           if(KEY_0())
    # u( g. B* F/ I* i1 q
  11.           {
    : {9 g. j% _4 y, s7 r
  12.                   BSP_LCD_login(24,108);, m& b2 [8 _- _- @2 A% x* h5 J9 @
  13.           }
    ! l& ]/ `6 S8 z0 l% H
  14.           if(KEY_1())( Y% C# C6 w4 W, ]. X$ z
  15.             {# l$ f; @! |" m
  16.                   BSP_LCD_img_DMA();
    9 k( D% b, `4 n' H# a
  17.             }' K, o" I6 ?- }0 M7 g1 q' [
  18.           if(KEY_2())
      Z' m/ d- I, S2 q# [/ k- ]3 `) p
  19.             {
    ) `5 C- h" S- k; }6 C" ~8 i
  20.                   my_driver.draw_pixel = gfx_draw_pixel;& H4 v) H, T& b2 q! W
  21.                   my_driver.fill_rect = NULL;//gfx_fill_rect;  U5 C: O" {. e$ i% y
  22.                   startHello3D(NULL, 240, 240, 2, &my_driver);
    " y3 s  I& }4 p3 `1 V5 u
  23.             }( }: q& M* `1 @' e, @% T/ K. M* H
  24.     /* USER CODE END WHILE */
复制代码

/ w* G' v3 U( {, Z) s2 P# i四、编译及测试
" \) E6 P* [  P        完成代码移植及改写后,进行运行配置设置,点击编辑及运行按钮,将程序下载到开发板上。
2 B: I7 |$ K0 `% f
/ K5 e% s! Z# y1 a- ^% S( f
2f01fdf679234e349c31a2a72f836efa.png
' |' t+ m1 w; ]7 b1 W
7 G8 b  ~2 P# n         按键KEY2进入GuiLite库的3D绘制效果,按键KEY2按下时,屏幕会较慢地进行背景色(黑色)逐点绘制,因此较慢。最终处理的是一个3D立方体缓慢旋转刷新显示的动态画面,效果如下图(手指是拍摄时屏幕镜面映射效果,哈哈)。
8 t* u: {6 e; U0 O' }7 _2 R: l( t% N3 {+ G* K+ K9 ]# j# M& M
722f590bf3e54cb2bc457cca2ee1d67e.png 4 ?) \/ l% [; p4 M5 L  B$ ?$ A
# ~/ @5 J. v* w4 Y
366b7d4b58f54925bde9496b94657fa6.png - X& G8 D( W3 o8 u, @$ v
————————————————1 t& x8 d) H  x
版权声明:py_free-物联智能3 e- o' \7 W4 R7 N2 w/ j3 Z
如有侵权请联系删除: M  x6 W5 z1 b
收藏 评论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 手机版