本帖最后由 creep 于 2018-1-13 19:14 编辑
$ H+ s+ ]: X5 w( F( `" J( K; r0 o: A* U2 L/ N) K' Y9 f. e6 V
推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):
7 Q3 ?# P4 u' C
/ `' u: c7 z. i+ h' r7 H: O; n 开源GUI LittlevGL V5.0版本移植
2 |; N$ C; @1 j! A1 i- t& a0 ]* h
4 m9 x* g9 q+ jLittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。
Y) Y3 d! d( o P" X4 T. k: J. A; p5 D1 z" G
! w1 |$ N3 ]% f8 T- e Y
下面是我在STM32F769-DISCO上移植的演示模式的效果图片.
. l' h, s3 ? }, }# _4 H9 f) ~
x2 j9 e9 A( E }" v4 M% o; I" W8 L) Y3 @
' ]' T+ {$ W! f" m! ?
8 a0 ?9 J2 q% \1 W" M
' A1 t$ O% S. |3 F: _3 `
主要控件可以通过下面的图片有个基本的了解:/ U5 T% _2 a7 }0 e% W
; D# E" |, Y; }3 L. w3 Q+ m5 e( T# Q# Z
; P& f! `( ^! f- Q. ], [4 j1、移植
+ T# [0 m1 |1 D$ z G# J
+ z4 H9 t' m2 y- `& \LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:6 y3 d# {: u% R% z9 J9 m, w: ~, [! l
, T$ z; `* @5 B
, S% O) m" Y6 n8 n; C$ e$ ]也就是下面几个函数:0 P' ^4 Y# q: x9 h7 j
5 r2 f, b. x0 p6 U- Y: \; q8 ^/ l8 B+ S
- 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
) d$ u0 Z4 C( C0 P6 R a)systick的移植直接使用的是HAL库里面提供的- f ]* D: q' {
! o; S! W/ X, ]! V: \- /**$ r( [! _& z1 K' J: Z
- * Get the elapsed milliseconds since start up$ E: Z1 X! }- J7 L) U& I a
- * @return the elapsed milliseconds
$ ]4 J/ f( |5 Y* o) R6 j5 H - */, l2 E2 I8 M2 Z4 n
- uint32_t systick_get(void) K( d' P; C8 Y& d( u K. s
- {+ Y. e# ^( e( ~9 s3 x
- return HAL_GetTick();
2 D7 l2 x1 i4 y+ B, s - }. I: ~$ P t: i; P5 [- V, p7 L5 q
- /**
1 |! c+ X( |& a; n - * Get the elapsed milliseconds science a previous time stamp, g9 C# d8 r# }; J+ U
- * @param prev_tick a previous time stamp from 'systick_get'
* j o3 X: s8 @ i - * @return the elapsed milliseconds since 'prev_tick'6 G/ I5 D7 w7 |/ i; K$ N) @6 E
- */$ n$ V5 f: f( g" N& H! |8 w( D
- uint32_t systick_elaps(uint32_t prev_tick)
5 g" x# Z; c7 U1 b' \8 h - {7 ?, F' ^- v: q- t" z; Y
- volatile uint32_t act_time = systick_get();
. K4 u5 |- q: a7 [
8 _/ j$ u( ~: s! m7 E- /*If there is no overflow in sys_time
- @& Y2 ~9 H% U - simple subtract*/; C7 }5 r8 v4 |# u# ]" R% |' r
- if(act_time >= prev_tick) {& E* O) ~# @, U) X4 p7 x' O
- prev_tick = act_time - prev_tick;- z0 x `6 p- f+ Y* H
- } else {
5 Z& d# }$ p. y9 Z8 n7 Q, l" [7 i - prev_tick = UINT32_MAX - prev_tick + 1;
! b0 ?, v3 S3 @$ C% j - prev_tick += act_time;
1 b$ G$ N. D; e7 @ - }( i, o `. A- q; X$ q7 l. |. m$ C- h0 R
- return prev_tick;
5 x( Z1 l' J/ S# A+ r! C- @ - }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果
7 {4 C' ~% h" `- D7 d Q6 s4 }- /**: p3 z, w! u" I3 n9 D8 i
- * Initialize your input devices here
% ]0 F! G5 Z# K7 K$ ]1 b- U0 u+ Y - */
( N) ?* I9 T4 k" i - void indev_init(void)
3 p: X/ [" P& }3 F - {7 b9 U9 a: Y1 \# t. X( ]
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);
8 z, r A. \6 Q6 X9 g - }
& v" L; ?# G% u$ T7 l7 W) J( e6 E4 P - 9 r, Q) ~, E8 o6 I
- /**
( t: [; Y' t6 x! I - * Read an input device+ }( }2 D+ d m' k% w: p
- * @param indev_id id of the input device to read
5 k# W9 b" g0 G6 D* K. O - * @param x put the x coordinate here5 |0 ?# G, J* ^! r: r$ ~
- * @param y put the y coordinate here0 X+ Z" ^+ o3 ^+ d5 l' G
- * @return true: the device is pressed, false: released
& I4 v6 Z" {' b$ r- P4 V/ ]- m- X - */
3 x4 u; }8 y5 x0 R - bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)
. q1 p; t7 O1 \1 y+ T - {
; D/ H: t9 ], R% z* i7 d0 d - if(indev_id != 0) {9 Y& W1 K# c6 ^) @' u" @9 d. [6 @. _
- *x = 0;
: a4 @( w/ h% Q$ H; d6 x$ @9 }( C - *y = 0;5 X& I; o6 s& s, C( ?6 _
- return false;
* ~- G' S8 E$ R: i8 f' M - }& u6 R7 Y5 n3 n: p
- static int16_t last_x = 0;
% U/ q7 ^, W% E - static int16_t last_y = 0;
3 n1 s$ t, C. W: m3 ]" p - bool press;
1 f7 n5 j8 d8 d5 o' U - BSP_TS_GetState(&TS_State);
( Z3 f% \$ e- R8 X - if(TS_State.touchDetected != 0) {
6 H: p% I* C- N" `, E - *x = TS_State.touchX[0];2 `0 I9 C5 w6 k
- *y = TS_State.touchY[0];
& T1 |9 p6 m5 ^2 B$ b1 y - press = true; E& L. X% v+ r4 j" l7 t
- } else {
1 ~: d5 F) s; j2 S/ S - *x = last_x;
1 v# X4 R$ ]1 j* { - *y = last_y;- n1 c" r k6 \- v
- press = false;
( y* p8 r% v7 c( e - }# ^6 q4 C7 A3 U4 A0 o* B2 [9 I
7 |7 V9 J2 a9 I8 z q6 h7 z- return press;
) |: v; h* f) ^& S. t - }
复制代码 c)LCD的移植分为几个函数,
4 {/ l$ l2 o3 V4 }) o5 E/ l+ O8 K' O/ U$ L- N
1)一个是用单一色填充矩形区域,这个实际调用的次数较小/ [, Q; n1 I* {* n: F
, T7 r. N% B0 B+ Q
- /**" T. F4 R' X0 H$ g! d
- * Fill a rectangular area with a color: \' ~; @8 M; z3 D* g2 O
- * @param x1 left coordinate of the rectangle7 p- j$ g) W5 R4 a; S
- * @param x2 right coordinate of the rectangle
4 B+ ~5 @& Y- U- `& r - * @param y1 top coordinate of the rectangle
/ v% }# s' C9 N" T- { - * @param y2 bottom coordinate of the rectangle, v' E1 B( A+ |/ J$ w
- * @param color fill color' Q3 T- A1 R, H* t) l
- */
1 g% Z) I2 B: a, A+ N/ \+ L - void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)
$ L' I9 T ^) j& A3 P( \( p# r - {
4 [) S$ i8 u, _6 ]' q - /*Return if the area is out the screen*/
/ j, K: [' y0 B& V - if(x2 < 0) return;
, j5 u- m# o1 U5 K* a! ?7 P, R! v# q - % N2 O$ l7 Y6 j8 G' c) E
- if(y2 < 0) return;
# J, v2 W8 Y. P' \2 ]9 O1 E9 d - 6 O/ ?( v; d4 R' G0 N" K2 J2 l5 b
- if(x1 > DISP_HOR_RES - 1) return;7 @5 J; I1 o, ^2 D' g, _% U, s: O1 o
' U) x2 e8 a5 A1 k6 X- [- E- if(y1 > DISP_VER_RES - 1) return;
0 i5 B) @ u6 }* e* C" F: Z - 0 [. Z! D/ a5 [
- /*Truncate the area to the screen*/1 M9 t: q* G8 C- l W% H0 q+ H
- int32_t act_x1 = x1 < 0 ? 0 : x1;: {6 @+ V- F9 e5 N; G
- int32_t act_y1 = y1 < 0 ? 0 : y1;0 ?7 H" f1 Q0 d8 \, t2 |8 C8 y
- int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
; ]3 \8 r l+ G, A - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
. ]" t. \' N& \6 n5 L- c - ) @# A F: t; i* q+ k) a" K
- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));( ^ l( O: I v2 M
- }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。
[+ I+ h: e! H3 a; `1 a* d- /**& N) j0 C% p2 \* O) ~* v
- * Put a color map to a rectangular area
. }8 ^# z, M/ J" M2 Y - * @param x1 left coordinate of the rectangle
3 Q% V# o$ G5 e+ o4 }9 F& P - * @param x2 right coordinate of the rectangle3 ]0 N/ ?* ^" G
- * @param y1 top coordinate of the rectangle% s |- R. x: M9 }( f
- * @param y2 bottom coordinate of the rectangle2 O% \/ c1 P% O; ]! N
- * @param color_p pointer to an array of colors, K) t* u) i( b! T# V9 c6 B
- */: v* J+ f& m" j# U$ d, V/ s9 j
- void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)
$ u0 i. l! J! s* t- @ - {) f9 h- d* k7 `3 G/ j. G& T
- /*Return if the area is out the screen*/
" O" `0 ~; Z6 e; F' d - if(x2 < 0) return;
6 J' ?$ s* Z, }4 i7 y) A
9 N. n+ q' T: h4 F7 _# z- if(y2 < 0) return;$ k$ X' [( f: a
- 5 m: t# e1 h& K( T5 g' B: H% L
- if(x1 > DISP_HOR_RES - 1) return;
4 M% e6 K3 t6 ~' H3 u% I1 p
$ e% `0 c6 i J8 @ e9 V6 W- y- if(y1 > DISP_VER_RES - 1) return;
! Q' ~; t" {2 P% k0 I3 R% N8 X* B
& J1 T! O% k: `1 X! x- /*Truncate the area to the screen*/
4 j# [8 Q+ C+ o8 Y, g& v9 k - int32_t act_x1 = x1 < 0 ? 0 : x1;
2 _; S& d$ o- i% V. O - int32_t act_y1 = y1 < 0 ? 0 : y1;4 y/ c! ^6 h# H* j3 A
- int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;9 b6 S' B/ l9 h9 _0 H; x- p @
- int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;1 B! H8 S! P5 W1 X. `. z
- ! N& }! U; m; [0 p. n4 d9 @2 m
- " Y1 |9 p c3 Z# e! i3 r
- uint32_t y;! E% X' \8 a6 f* U$ o- Y% l" Z
- ( p: ^% C; z- @( @! q. @5 C
- for(y = act_y1; y <= act_y2; y++)& X! _) f3 o5 H3 d
- { A! P9 ~ w; H& b' v
- memcpy(&my_fb[y * DISP_HOR_RES + act_x1],
1 X( r+ E% }: U! X5 j1 P5 M+ j+ A - color_p,
' \' F9 e, w6 ]8 } - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));
7 ]! j4 N/ L+ k) c! q7 H7 v - color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/
/ w+ {8 D& A7 }0 L - }
; I3 q8 K8 D- u/ N7 [4 s - ; d% j) f% V) \2 |; K. B5 o
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存
3 c4 |3 F) t6 L! A4 y" U" w3 p- /**: ~" {4 k# ^0 K+ h, n& H1 R' W
- * Copy pixels to destination memory using opacity+ ^, |6 d% _. ~& ~
- * @param dest a memory address. Copy 'src' here.
, D% W4 J' J p0 ~) |7 [# I - * @param src pointer to pixel map. Copy it to 'dest'.6 Q% g- Y- U* t: z- k- i, t, x
- * @param length number of pixels in 'src'9 Q9 k1 T4 J4 t4 K; q
- * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)7 M/ Y! h6 _* }
- */* @ K4 o' e# ]/ i; f; G9 F$ Z8 h
- void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)
9 l8 I: B( R4 G - {" `( ^& N; n3 ~6 ]
- /*Wait for the previous operation*/
8 w( l+ ?8 h. w! `1 f - HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
. N7 Y, d4 N& Z
2 @5 @1 r* r4 T5 x; t7 r2 `- Dma2dHandle.LayerCfg[1].InputAlpha = opa;
8 V. I! {. w# W- L: d - HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);! o* S4 J7 c; T4 {8 H
- HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);
0 u( h% @# i& L4 B: |9 P' H0 s - }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:/ T( s, H2 ]0 i- c# X! W
! H3 M; |/ x+ _% F. N, K) o
添加到工程中后如下整体如下:/ l3 i1 W7 \8 y
9 M' n" R8 |0 a& I' M
* S2 }# G0 }& S! |0 R
- Y- [+ A' y8 s# l& O6 j( k0 w! Q
. d: C' ]9 E. V" ?/ n& K
/ W4 l, Q3 E$ z将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。$ z, M4 j" ^- Y2 y/ o0 ?
* Z3 b' b- p `* o7 g) K$ W
0 w" q3 \. r) Y! ?6 v2、运行效果/ Q9 K/ U+ N2 P& a1 C+ N T" R% Z
2 w: ]8 s0 ?; j( w& n2 [9 t
LittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可
) L, {, X* Z9 I- V% \3 w" n2 [4 D8 l: v+ |
' g2 N9 U# f, }+ q$ K Z
: u% r' O- _2 n
+ V% l% A- c! j0 Z/ Y3 V fLittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:0 i* p+ [$ H( K: T) n
3 W, T4 J7 d8 T3 ]. _ }$ _3 K* g- m- T* G6 Q ^
1 i* q# e! b- M4 g
1 u( j9 w/ i! J; `" @. ?( ^
除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。
% Z* i5 W; M! h6 g& T. F0 J9 j# W( x" R' \) w( s; V
0 K# c5 {% x- `: w" C3 B/ ~; f% h
& b8 k; S+ k! |! o
5 q7 o5 M' f3 r6 c2 o下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
& [/ o$ |% T) d. g/ d8 i
5 J. ?& p1 B6 [. y9 }, h0 H L- A X# V& ^3 d
3、关于LittlevGL+ }4 U0 n- o y/ R0 ]5 t2 b
8 `* f% c! m% G: x$ e7 k
LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。
- g9 a. f8 Y5 t1 w. v目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。- k) O& K% `( p# o( s9 S* w. y
: q0 ~* w1 P3 P( M( T( x
% b. ]0 }* t: x/ K+ _; e' y/ y Q# Q/ d$ P
4 M9 e$ L2 \; q) z6 p
, G/ [( I1 r' v" O" D+ A& J' a$ p5 t2 G, c5 m
官网和github地址如下:8 n5 G9 f8 S' Q
! o: W" o( i: M6 J/ W2 m$ { ?LittlevGL官网:http://www.gl.littlev.hu/
$ J# W/ T' ^5 D# l1 p/ d. D% oLittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl
$ p4 o8 N% @- X5 e6 t
5 k8 m4 {$ [% q下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。
; F) v' {4 i' n( g' I" f/ \How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg
3 K# R2 p) @3 a! w+ D2 kEmbedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM0 N2 a* s$ H' @0 t q* Z( l7 H3 r U
/ `; y4 V/ P: H( A1 A
和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。
0 G) u( A8 o1 q; E% Z1 Y- [# N3 X3 T* Z. I1 X. k7 S
3 L) g0 Y. ~3 d测试代码:
) F }9 N) z* d! M6 e
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。$ x* k* ~9 _3 i; o
http://github.com/littlevgl/proj_pc+ T. a5 e. Y+ r: \" U
是的,没有限制,移植吧。
谢谢楼主分享
如何模拟? 如何在linux中运行?( E. A# n, l7 t, g5 E
) y" u% x' a+ I) \& Y/ t
- H: @0 {7 x, n; b
文档很少
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。