本帖最后由 creep 于 2018-1-13 19:14 编辑
( d, A# f) S5 y4 c. o
: P% a# D6 u& y) y q) m 推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):- t/ O+ c1 U5 |
4 }& z* l3 N: r' z/ R9 r8 b
开源GUI LittlevGL V5.0版本移植 + l0 I* P# R( U4 Z* S4 I' U
" N; n) e" V) Z0 a4 [3 ~+ ^7 l1 ^" x- |" \2 b# Q
LittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。
! d& T" L" y7 o+ s! n5 g/ d
# a" a& {& f- h# W
0 L# ~. v" ]9 Z* e$ P- R& ]. T下面是我在STM32F769-DISCO上移植的演示模式的效果图片.! }8 L G, `: _' V
0 j! o" H0 [6 M4 Z
% U1 _4 J& y* A; K
) _1 [: a2 R3 x5 O# m& W
3 q6 x. F7 z- d5 Y- ^
: U( y4 i, Q3 {4 x @, A
主要控件可以通过下面的图片有个基本的了解:/ N& x+ Y q2 _# Q4 g3 \6 `, O
5 s& l$ d* i7 T9 p5 B8 k* O& v1 b2 `4 w5 e. U% \
7 @( g% ^, H# P% x) I8 r( z
1、移植
7 o$ y/ X( s. q8 ]" F" R; ^+ ?; y8 P7 x0 `' q/ k6 X# n, T8 {( d
LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:4 k' J5 `7 i3 p
S- N- B$ }" ?3 |2 [) y6 t; S3 X+ W
9 Z: A& [9 W5 k% h也就是下面几个函数:
/ g/ P2 _: l3 ^) k% D( k6 k; j; m1 k$ W0 A$ w' _. n) z
& C/ @& H: _- `" X- T
- hal/disp disp_fill(x1, y1, x2, y2, color) to fill area with a color
- hal/disp disp_map(x1, y1, x2, y2, &color_array) copy a color map to an area
- hal/disp disp_color_cpy(dest, src, length, opa) copy pixel, optional for GPU
- hal/indev indev_get(id, &x, &y) get the x and y coordinates from an input device (e.g. touch pad)
- hal/systick systick_get() get a system tick with 1 ms resolution
- hal/systick systick_elapse(prev_time) get the elapsed milliseconds sience prev_time
- 5 Z$ X6 ^: y. t( }# {+ a
a)systick的移植直接使用的是HAL库里面提供的) @4 j$ o' X. v4 ^! _6 I2 N
7 J- |% i9 a' n3 X6 \8 \- /**
. U6 ~2 {) w4 R% ] - * Get the elapsed milliseconds since start up
- ^5 s' b9 o( I$ w - * @return the elapsed milliseconds
1 e' v" B5 l- j7 G3 z; S9 \) G - */
/ K) m' T9 `- t5 x3 T& t/ c - uint32_t systick_get(void)
) _/ h! C. w8 g' U6 J X - {
3 b& F2 _% i6 `% ]) ?* H - return HAL_GetTick();
$ S: W3 G" y/ C) G4 o - }
6 k& P, d) B7 }# E8 ? - /** W6 z* \. _/ V* M
- * Get the elapsed milliseconds science a previous time stamp o$ A/ s2 E7 t6 F6 K: y$ u$ ]+ a
- * @param prev_tick a previous time stamp from 'systick_get'0 i7 r$ r2 D; s
- * @return the elapsed milliseconds since 'prev_tick'
5 ^$ {, @/ t/ B - */" b$ z- R, Q+ b: a: F% f" E, S! N
- uint32_t systick_elaps(uint32_t prev_tick)5 M1 J9 e( h. T0 [8 s
- {
9 i# V2 L$ T: _8 X" O: y6 q/ \ - volatile uint32_t act_time = systick_get();
, C4 O! V% D! m H% i |+ b
% I3 {+ g$ ?# ~" f- /*If there is no overflow in sys_time) d4 t8 x" a8 ?- q5 v1 T4 [0 Q) t
- simple subtract*/' i, A# I+ W' u+ _! n& E
- if(act_time >= prev_tick) {9 C) X, E6 _. b- Y) w5 v& L$ \
- prev_tick = act_time - prev_tick;
0 ?: L B& D L! J3 o - } else {( R( L& e9 X& I+ r, b- L
- prev_tick = UINT32_MAX - prev_tick + 1;
8 ^; M/ m* C) m - prev_tick += act_time;% W9 S% q0 H' x
- }
; w1 n. T. N; T! f4 \1 T8 j - return prev_tick;% S* g# s( [3 ^& O1 O4 Q# g( G2 \
- }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果/ L1 f! W: X( n3 A
- /**
1 R& v! w; J5 V' R e - * Initialize your input devices here
0 {* _. I$ j7 R# V8 g0 `+ J3 M' H - */
( T1 F6 O) u+ @0 n9 {7 S - void indev_init(void)
0 u9 j+ ?) R+ e% v5 Z" a - {8 n7 j$ y; \) c
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);. C, V; p1 U4 U& m" B' U
- }- L; n ~. c$ Z3 f6 u, I
) l, e s2 B' A' p, F- /**3 R1 u, ?; l4 V( H5 L4 f
- * Read an input device
- ~, `* ?# ~+ ^8 M3 r* W - * @param indev_id id of the input device to read
P5 B( E; s0 q, N; M6 K. x! I - * @param x put the x coordinate here
8 G* v7 }% A. a4 l - * @param y put the y coordinate here% I2 y2 ^6 r p
- * @return true: the device is pressed, false: released! g$ \6 h& r/ Z' P+ b0 ^( p
- */4 |1 N' \2 A# @8 k/ c3 Z
- bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)
% {! v0 |4 @7 E: ~3 v' w u - {
% w, T. r9 a) s9 {! t3 U. m, | - if(indev_id != 0) {* Y% W. c3 e% h" Q! T1 g, x: C8 i
- *x = 0;* r4 I+ K# g( D" ]
- *y = 0;
; e$ }, F6 i0 ^9 _+ g# U - return false;/ P; @0 e* Y4 n+ q/ z" Q
- }3 Q* l2 @( M) \9 Z5 c
- static int16_t last_x = 0;
' X9 I* _* U, b7 a5 ~/ {! C( N - static int16_t last_y = 0;4 f% d9 x* [( ^
- bool press;# D& T5 V y& C
- BSP_TS_GetState(&TS_State);
9 M9 t( ^' I4 R& n* h6 {4 g0 H - if(TS_State.touchDetected != 0) {; N1 O4 p* D- z* k, K7 s2 T7 A
- *x = TS_State.touchX[0];- \( p% Z+ K4 n; @
- *y = TS_State.touchY[0];
5 I' T$ z: c- f: ~5 E. K9 k - press = true;
( x5 W E" d7 t& I& W - } else {+ E7 e3 O* @# A8 {
- *x = last_x;* g2 ^% R, L6 t. T
- *y = last_y;
3 I& V/ F7 z2 C0 B2 A - press = false;
! a" F5 V4 A' w - }
9 Y+ V8 b& r! r* r& a& ? - * }' C* m7 U9 v0 o7 s8 p7 ]
- return press;
" a( S; s. M+ U$ I* {) S) O - }
复制代码 c)LCD的移植分为几个函数,
: k/ U: @5 o1 V$ s- [ b0 a# N' m, s/ L+ o1 q/ ^0 f
1)一个是用单一色填充矩形区域,这个实际调用的次数较小; l) f4 m+ h& h& J) x# [
/ I3 ~' e8 R. t7 `, O* {' l" V- /**, F1 b: Q6 [; q4 u
- * Fill a rectangular area with a color
0 l9 L) G, ^) X* {$ d* {! B - * @param x1 left coordinate of the rectangle
8 t* q9 j2 e9 }% }: D8 s - * @param x2 right coordinate of the rectangle. t* Z5 G* p; U
- * @param y1 top coordinate of the rectangle
( g. a# k1 V6 y! U6 m7 m - * @param y2 bottom coordinate of the rectangle
9 M$ K0 s8 @4 v - * @param color fill color
2 e/ U9 t6 a; F - */2 V/ d1 `$ W' {+ I
- void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)
3 {& L! t% A( ]$ X ] - {. H! K3 K( M. n$ ]/ i4 j
- /*Return if the area is out the screen*/
* r6 U) Q% g* A - if(x2 < 0) return;$ l' f p7 o+ m& V0 y* ~2 U2 a
- + h5 _# c, s* B: Q
- if(y2 < 0) return;
+ W1 Z$ m3 P9 e. i. d7 ^ - 9 c- T& H6 e4 L5 h/ }% q; R- S1 e
- if(x1 > DISP_HOR_RES - 1) return;
5 Q% z4 x' M* T2 y4 o5 M8 ^/ o - 6 ?) t* e" R5 E3 `3 @. I
- if(y1 > DISP_VER_RES - 1) return;1 H" ^8 r3 C3 f5 q: i
- ( h& R& c- e9 ]4 Z
- /*Truncate the area to the screen*/
- p) u2 q9 R6 R$ d( T: z/ n - int32_t act_x1 = x1 < 0 ? 0 : x1;
' e/ i" c- M) }' B% {( ] - int32_t act_y1 = y1 < 0 ? 0 : y1;
1 {/ \* W# H4 d9 O - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
" B6 T {% S u" M' |+ I - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;5 n( n- B) p5 d* v6 h1 b
7 l+ c, Y1 u3 O+ ] [# R; Q' i+ L- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));
9 k x6 d9 g# X I9 E4 m3 d - }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。
3 W! x4 m& O5 c! K+ ]- /**
& i; d z5 G; L) R - * Put a color map to a rectangular area
; m, s4 ^" R1 F% W. N - * @param x1 left coordinate of the rectangle% K1 F* ~2 O, ?* ]
- * @param x2 right coordinate of the rectangle
2 @' ^- }% N# x7 a3 A, J6 Z+ c- l; L - * @param y1 top coordinate of the rectangle3 p3 i; {) E6 m2 l- q- S
- * @param y2 bottom coordinate of the rectangle* @. v' k2 d* A& f( p" |, k8 |
- * @param color_p pointer to an array of colors
5 M4 L h a8 s - */
+ S* q; p1 x% {9 h - void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)" f. \9 d& m) j+ X5 A" L5 S
- {
' C7 c: e) m4 h [& u6 t5 q - /*Return if the area is out the screen*// M* ?, r3 O) K5 f a8 s. J) h
- if(x2 < 0) return;
( N/ G* h3 A, ]# } - - i/ w" u O8 T: x# C! A* X
- if(y2 < 0) return;
/ v; K& W" ~" d% S1 c$ {/ i2 k4 s) V# P - 7 E: E. z1 Y9 E. Z4 L K% s9 L0 l. b
- if(x1 > DISP_HOR_RES - 1) return;- w" Q0 T1 c: ^( a# b4 l/ Y8 l' C
! A+ L) H: w$ C6 X/ G+ h- S9 H- if(y1 > DISP_VER_RES - 1) return;
6 @. u9 K5 w1 n* u
4 ]3 Z6 v( h L- /*Truncate the area to the screen*/4 ~. R4 a# H; C |* _
- int32_t act_x1 = x1 < 0 ? 0 : x1;1 E- n/ ]* a0 b, s4 x6 a
- int32_t act_y1 = y1 < 0 ? 0 : y1;
F! |8 t/ G" I7 M0 f# O - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
1 w, o* m2 y8 e1 a - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
5 n' @0 h+ o8 Q. {
% r% V$ ?) S5 h- 6 B+ V8 M5 X i
- uint32_t y;
. m* ]2 V* A4 @$ l% G) i- ]) R" @; Z, g7 R
: N/ `+ y" P& w8 j% S% L+ r# c- for(y = act_y1; y <= act_y2; y++)9 s: A1 c5 K0 X; c
- {
% g( s' @8 j! X - memcpy(&my_fb[y * DISP_HOR_RES + act_x1], P$ i: c' Y; f7 }4 d) `/ ~( d( E8 B
- color_p,
" q; ~9 }+ Y0 ]: ^! { - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));
% j6 F: v' y3 A. O - color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/
- i* P' q% V3 D f# I% L# r - }# D) D' l4 h) W- B3 B
- 4 l7 L4 h6 [" {
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存' l. i6 ^4 a/ Y7 G
- /**
. T8 ~/ e% s" P2 Z8 `8 R8 p: ] - * Copy pixels to destination memory using opacity
; L! |7 z2 x" n3 b; a - * @param dest a memory address. Copy 'src' here., b% G1 k, ]% y6 l0 J/ X
- * @param src pointer to pixel map. Copy it to 'dest'.
/ [6 j' I: |6 ~. n e5 ^ - * @param length number of pixels in 'src'
& J- p/ I# d( J! t/ ~7 r a - * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)
5 o0 a- \9 z# w6 a - */7 [/ L+ v0 j9 C3 K
- void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)
9 x, P0 J/ C* c, N - {
) ]7 l6 R6 c5 X' {+ F3 U - /*Wait for the previous operation*// T7 [# F% I/ J+ p P2 b0 K3 N
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
8 m- G: s0 H' L! x/ V - ; X2 ?9 h* C& } p+ ~
- Dma2dHandle.LayerCfg[1].InputAlpha = opa;7 W" l- I% t) n/ w
- HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
1 g) E4 l; V8 o1 B - HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);
. ^3 Y9 o* W u+ k2 {" ? - }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:. G0 r3 D# B& J s) `. P
- G. r6 y/ `. h" {9 ]/ I! R# d
添加到工程中后如下整体如下:
" e7 \' U( q: Q8 k8 @1 r" B& w4 A$ N+ d$ m4 ~1 V8 x" o
9 M8 G4 ^+ ]( ? z& x# H* z
# Z% V8 X; N: w y
) W$ }& z$ d* H0 Y
; Y1 ^. \5 N# N5 n3 u; L( @8 C4 S; g6 V+ Z将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。
" h2 M4 L* E* ?4 K
1 x5 Y3 p* m/ G! q! f
7 K" v# E3 c# F8 V5 Z) i) \2、运行效果* [" S8 R; w/ K( \+ @ U
+ E f9 b8 f# S ~ b4 s; l0 r& S
LittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可* ?: ]. b8 f) j) B
5 u) P! [ C7 Y- J# C
8 G3 F! }/ B% v& M- K3 b
- i6 O# [( z( t+ u# m
; A* _4 {0 I3 H6 |: qLittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:
/ @$ q- P$ Q! |4 b1 {0 g- L
/ E' }2 Y: V! N+ [! H
9 T; C+ [% M1 u/ `' j1 A7 g
# H, \: p; o* {8 X" ~7 H8 l& c
9 w2 L7 n" s& \除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。5 @: b+ q+ O1 n! k( E
- C0 @ H2 h0 u, d! @, P* l* [' k8 Y% z+ s) y) }
O7 P5 Y1 P% n% f h, Q5 `" M7 |8 h5 K5 O: y3 B' p' M
下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
( y* ^8 x2 |8 m0 ?, I
2 I) @2 D+ j; p0 U8 l6 e' O# V
0 N* B& ?6 c0 B4 a- M
3、关于LittlevGL
: N4 F, V* D, K" L: K' h0 U y& J: I" W" A6 Q0 \
LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。
7 b# n+ i& }! A! M2 P目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。
7 r7 g+ I9 R5 M( g8 T! P
$ u" x- j6 e0 K8 D4 ?/ I0 X- T" Q+ K% H7 l' b
0 ^; z' y* o5 i1 v8 E
! B8 h3 T- p' h! c; g# x5 J. ^; [( M+ w
D; I% [8 e9 ~3 F8 Z, K% Z
# D+ Q, F( L, f& x% z" l1 Z官网和github地址如下:4 ~) E; l8 b1 g& F/ Y
i& @* |7 V: b! X% g
LittlevGL官网:http://www.gl.littlev.hu/
! Q+ l$ ]7 p3 yLittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl
$ `1 ^* n4 ^1 q( Q! \- ^
4 i: L9 J5 H/ U8 ]' y! o7 K# ^下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。
9 V, i0 R/ u. {* k8 SHow to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg
( ?% f* n0 c" dEmbedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM
. e/ d' ]+ s3 T! q( j. I
1 K' Q5 \8 b: b5 I5 Q) q: ] 和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。
/ M+ N9 O# E5 h) z: N! p4 O9 s* p3 d* E/ v& L D
* I' V3 C) [2 d* D S) r测试代码:
! f. M$ o* c1 @$ F% p. s9 |: D
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。
http://github.com/littlevgl/proj_pc4 e3 U0 i% Y" N V+ F
是的,没有限制,移植吧。
谢谢楼主分享
- f9 }7 Y6 G( S% C7 N' x8 l% ^% {; i
如何模拟? 如何在linux中运行?+ }- D5 I$ q- _
4 r: F0 {( N: E0 t. X
+ }) W2 \ T. H0 ^. o
文档很少
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。