本帖最后由 creep 于 2018-1-13 19:14 编辑 ( o9 b2 O) r: Y' l7 h/ j* u
$ m# g. J1 ?# ?4 ~ 推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):. k$ s# X; C/ b& ?( C
! S8 P- J, W3 Z5 i/ H4 h# t) N7 Q: S% [ 开源GUI LittlevGL V5.0版本移植 9 ?& g: X. z, H, W: D9 v
* l6 V" B7 \& z6 O: B) l' @) {* j- j" M0 _" j6 k0 W7 `
LittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。
7 ^ h! A+ j; D! h1 J( X0 [7 s8 d3 p- c8 Z
# W( m! b A4 q
下面是我在STM32F769-DISCO上移植的演示模式的效果图片.6 K7 X) y4 w& |, y
! u# ~( |7 d4 N% R
% c+ u8 N+ R& s& z- u! g0 C
& ?: {* K# a+ h
5 I5 G5 | K7 i" [" a' }( v: ^
/ a: J q% B' R0 i+ E& x, T6 b
主要控件可以通过下面的图片有个基本的了解:
, H$ t) }+ L. V- {3 q# k) P! j- u/ M- c+ t
5 t* i2 _3 [6 P- {. J
% j: x0 ]$ ~4 e( | O1、移植5 x* d" Y$ O0 |7 |" O1 T$ i
3 A$ B6 E2 X+ X$ ^/ r3 t5 g
LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:
* m3 a( A! ~" b% | ]9 G
( C; G8 c' V ^% {* l; J! u- H
! s9 \; }* J: W8 w
也就是下面几个函数:
$ N# g% Y! m; }: H) ^! a: U2 C% N0 z4 }7 Y& C
e& G- p; z/ [1 U6 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
% q1 w. v1 [ R- \. x a)systick的移植直接使用的是HAL库里面提供的
, U% d+ [6 b. Z" `3 h) p. C
" E S6 E" |+ O4 t9 P* n( V- /**( {0 y0 e- p8 q2 G3 n, @/ H0 T
- * Get the elapsed milliseconds since start up+ F0 @3 E% Z, m m. s/ ]
- * @return the elapsed milliseconds8 F4 ]# _! ^4 x: y( V! M8 @
- */
7 z) C6 P. v' M" b - uint32_t systick_get(void). C; ^; F8 H0 g4 x9 R9 z# U& q
- {. i8 j I) W7 ^% J% d% F
- return HAL_GetTick();
2 k% V, v0 q& r) A - }: h1 O% p9 J! @6 ?0 ~! _0 m
- /**& M% I1 [3 H" g4 Z
- * Get the elapsed milliseconds science a previous time stamp
$ D8 W8 E }$ ?7 j9 J - * @param prev_tick a previous time stamp from 'systick_get'
9 H' i" Z; v0 B+ X' Y( `+ s/ A5 W3 z - * @return the elapsed milliseconds since 'prev_tick'
) \ r! |- o% b' y4 K- c4 G" { - */
/ K7 i/ v/ O# D) E - uint32_t systick_elaps(uint32_t prev_tick)' W" @. }* C: u; O: P
- {, b" P5 H% X3 h0 r
- volatile uint32_t act_time = systick_get();
& P W" Y! o# M4 I/ e) N
7 R: n0 O3 Q* h/ a6 e( S- /*If there is no overflow in sys_time* c% ~4 }2 m- u
- simple subtract*/* p/ |* J4 g% W: \; U! n
- if(act_time >= prev_tick) { Z! u4 }, U0 P% p, p9 z. M
- prev_tick = act_time - prev_tick;% t1 c! W/ i( r3 B
- } else {2 l8 h8 T: j# @, }1 d
- prev_tick = UINT32_MAX - prev_tick + 1;) \. {! O. { a+ e6 c' q( m& y
- prev_tick += act_time;
9 b- F; l7 @# h) k. O! I R - } q d0 I0 ^6 h. Q6 s
- return prev_tick;5 s+ P( P! q9 U* E- I
- }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果% P+ b* b: G3 b6 ?5 M: o; D6 p
- /**' z2 E; s! j' q% b/ ~
- * Initialize your input devices here1 X" q" @ X4 [/ ^! B- b/ m
- */
4 ~. ]/ L- i W7 n7 }& q. t; ^ - void indev_init(void)
/ ? N4 Y+ r! J0 x9 H8 q - {( ^+ m1 y/ c( _7 b" V
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);! `& ?# |! h: M4 D+ u+ `8 ]
- }/ m0 n6 d' z, d: W3 t1 _/ X
- 0 T: D8 b0 |- q. O' a) G; P
- /**- v5 h3 H% y) Y6 b! S9 w# J
- * Read an input device/ S' U3 _7 [4 z) M- L) L1 L
- * @param indev_id id of the input device to read
# d# S2 K! _) I2 b6 s" v4 Z - * @param x put the x coordinate here2 a! n: A2 s1 E Q% K. i# T
- * @param y put the y coordinate here$ D6 b; a. m2 u6 O
- * @return true: the device is pressed, false: released: x( C9 ]- Y# i# |& M5 n/ Q: f
- */4 C& l2 v; N- m% r0 s1 K
- bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)# _1 J) J* ]" w1 Q' S
- {
- U* J* I$ K$ m0 |0 _ - if(indev_id != 0) {( P9 Z8 l+ o1 l. D9 A3 [ `
- *x = 0;
# M/ ~& I! Y9 h; T4 U: `) h3 ^ - *y = 0;
! D) Q3 X) |2 E% u& b* T7 V0 U - return false;# e) m3 e0 q/ |1 O% k7 t% @7 G& H
- }$ c: P; e5 N* E- ^ R
- static int16_t last_x = 0;
U7 O" _$ r; @ - static int16_t last_y = 0;
4 \) x, `$ \% A t - bool press;* m1 H6 h! Y7 \: y3 a4 b
- BSP_TS_GetState(&TS_State);1 |! D3 x. J' |$ d- D* z
- if(TS_State.touchDetected != 0) {" t- e# N% d* W- s0 l' A
- *x = TS_State.touchX[0];/ k. |1 T4 P1 o4 B
- *y = TS_State.touchY[0];/ T1 z% E$ `4 C* R3 M6 j* j
- press = true;
3 ?+ [4 i- j' d% `+ N! t! C: [- v - } else {
- N% p z# D. W$ @- q; w - *x = last_x;
1 y$ {9 ]" T' f) K8 P - *y = last_y;- G; c7 R. V! s# N3 q% r; i
- press = false;
0 J) ~9 f1 v8 X# E Q! v. C* C - }. _! K' T" v+ A
8 O5 l" J0 q8 g% @0 ]2 ?6 j6 y! Z- return press;
# J! x6 Y' K/ b8 f- Q8 Z& F1 g/ N1 b - }
复制代码 c)LCD的移植分为几个函数,
8 X" g, e4 h6 D5 T+ m3 Q
4 w2 P6 A' e( a2 v6 Z1)一个是用单一色填充矩形区域,这个实际调用的次数较小+ p/ {) t' [; R. P5 x" K
' X+ P- m/ `" [ s# F/ L: I* E! `- /**- Y& K+ B+ U% g$ C' ~. i" f
- * Fill a rectangular area with a color
: k" r7 Y8 C, S( Z3 L - * @param x1 left coordinate of the rectangle
/ ]9 Y; ^; U7 j9 h$ e& Q X6 H- D" H - * @param x2 right coordinate of the rectangle
3 z( T! Z8 ?3 ` - * @param y1 top coordinate of the rectangle
) N! h5 [$ W( ^. E" W- z' u - * @param y2 bottom coordinate of the rectangle
- X/ ~& l2 r1 n, a8 z8 k6 h - * @param color fill color0 H3 Y7 u- R: ~3 c
- */
- G7 x9 o' S% I' q# y4 Q - void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)8 y: L9 D! ]/ d- u) u
- {, U- \( F% X5 L, T& _
- /*Return if the area is out the screen*/: }. o9 V3 c. H& w8 Z
- if(x2 < 0) return;
1 `2 H# T1 F! ?- I- R
5 C* }; H6 S/ m& W8 h$ U# r. A- if(y2 < 0) return;
. S: i/ i- \# k3 A2 e* }6 U D
7 {) R K, \( E) N- }. z- if(x1 > DISP_HOR_RES - 1) return;
. J7 z2 L7 l5 N7 J1 y2 _9 d3 |' c5 H - ' E4 @6 {7 V: }% i' }2 t: A7 x- t
- if(y1 > DISP_VER_RES - 1) return;
4 y( ?0 u7 t- i) r
. D' {7 O$ |' a# j4 d5 A- /*Truncate the area to the screen*/6 ~5 S. k- @4 P( q' ~9 H2 H7 O6 j
- int32_t act_x1 = x1 < 0 ? 0 : x1;' F0 e' v# N, O
- int32_t act_y1 = y1 < 0 ? 0 : y1;
/ K! t; V) k: L& j+ ~ - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;# j* n# S- p N4 o0 C
- int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;# R5 k# D/ |6 r1 {) w/ M; E! }+ ~
- ^# |, m5 _& k* c# s- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));
8 q1 j2 X. }% i+ d3 x+ T - }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。& s+ u- I' x, {2 [; I
- /**
$ k# D7 y( `6 `$ d& O - * Put a color map to a rectangular area( T1 L) x: v( C3 s4 p6 f
- * @param x1 left coordinate of the rectangle
( ^& E, U- R' L, v- u4 c: B - * @param x2 right coordinate of the rectangle9 {8 d3 g! V7 m- A% W' E1 ]) ~- {
- * @param y1 top coordinate of the rectangle* |+ |$ |3 l a2 j% S1 w
- * @param y2 bottom coordinate of the rectangle# d2 L3 M( B; v* R4 C
- * @param color_p pointer to an array of colors
( s$ o) ~: y' g- r" Y2 J5 C' Q" P - *// L" U2 A; I: {1 S, F' R
- void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)1 e1 ?9 ^9 N( o |, g
- {
4 n# o6 z5 O3 P! A - /*Return if the area is out the screen*/+ C; O# E5 ?$ ?' e" |) O+ i& A
- if(x2 < 0) return;
4 ~5 p6 [* _! q; w1 a. [
* K4 U' w5 h0 ~. `* q+ {8 B- if(y2 < 0) return;8 \( f9 j0 k I& ]9 A: {$ z
+ w* G5 a6 J* V- if(x1 > DISP_HOR_RES - 1) return;
7 N& r/ ~: _5 z6 \" d) m
1 Y8 ~7 d; E, v! X: c' P- if(y1 > DISP_VER_RES - 1) return;4 q% f! S# b( q! o o1 W9 x: c
. n& _+ m3 ?/ v- /*Truncate the area to the screen*/
, a- b: [; }6 D2 o - int32_t act_x1 = x1 < 0 ? 0 : x1;( ^' q0 U ]3 K( V+ b5 H
- int32_t act_y1 = y1 < 0 ? 0 : y1;
0 P3 `4 P& B, |6 H/ { - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
5 A m, Y2 Q7 d S - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
' f$ p- F1 }" p - % F _2 u- c+ N$ ^
- * r4 Z! N1 k1 f7 v& Y9 ?" O
- uint32_t y;
3 Y( u1 U% N* o) _* `3 { - ' m2 t% F8 R9 C& {2 w; O! i* p1 x) o
- for(y = act_y1; y <= act_y2; y++) c$ Q+ b5 m, N
- {
. @+ o# e7 ?3 w - memcpy(&my_fb[y * DISP_HOR_RES + act_x1],
6 a( X$ t S* F9 X9 J" i - color_p,
1 d( H; ^2 z9 u6 B! h - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));! d0 [- m" Y. d6 H8 }
- color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/
3 b& f. F! X z% D$ [ - }
6 e' x2 p4 ?9 l; \: X5 h, M; S) U
3 X: o3 q% @. d( w5 }& A7 x1 l) F- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存
4 J1 h4 z j. E) Z6 i# c. S- /**
, U, X! ~+ w# {1 e1 M& Y) f - * Copy pixels to destination memory using opacity
3 o' |3 H' q- H6 Z - * @param dest a memory address. Copy 'src' here.
$ |1 A" t6 U+ N8 k1 X' J3 }+ L - * @param src pointer to pixel map. Copy it to 'dest'.
) e. C" |5 a$ c# y3 F - * @param length number of pixels in 'src'
5 v0 i% k, O$ r, {6 y1 c' j - * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover): d2 Q' n# T2 b7 T" m* w
- */2 O. u) q' E9 l$ N$ A8 l* y4 t* _
- void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)2 O' B! I. ^& l+ c: g+ b
- {6 T. m! d$ q$ c8 Z) S1 _
- /*Wait for the previous operation*/
8 j; s- A' p1 T% J - HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
' Y0 _/ {: i9 A- f/ u( `+ Z - 2 z( K: J( R. b
- Dma2dHandle.LayerCfg[1].InputAlpha = opa;
: a/ d2 T" f/ ?/ q - HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
& w- V% P: e0 e0 N7 S. v/ M - HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);
% J1 a2 q7 y' j& k: x - }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:
" j, v! \5 U e7 @! ]" h
+ k& \; S' ~% y0 I' d7 p添加到工程中后如下整体如下:0 U8 `7 {! X) t" U2 A7 X
8 o; [/ ]2 \1 \" J8 A( S7 N% K& m
& O9 c' d8 u- m- E$ h9 j! V
9 D# Z6 `* o0 W/ a' m
8 o9 |2 R H& }% S2 ^将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。 T+ n7 f+ }$ h$ a4 i) b2 v$ X3 U
$ r( {" p8 J$ }/ E9 \( e
! S( m' I* y; I3 N8 d3 ^( v( h2、运行效果
, ?! G" M) b7 ~( N9 v% W' [) P% r$ D5 c$ j0 M0 m
LittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可# D* ?0 `) k* D0 t
; D1 _: H! s9 j; q* [& i# j$ H. q6 z
! w$ W! l p+ g( |, G4 v
! N8 u1 j2 ?' I) `8 a
8 d8 _7 a9 L+ A x. d7 [& HLittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:5 L k! _. A. {; k0 q; d* v/ m
" X/ N) {' M) ^! S4 W6 L7 R l
& \, ]! T, B) G% _
* F5 o" f6 x! C) c- T4 ?+ ] X) N/ Q6 E' A
除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。
3 \8 }5 J6 G' ~9 b/ @2 j1 a! c' a
' f. K" Z3 F9 A4 L$ N* h! w8 G$ ?8 Q
& w9 ?0 i, \! o+ D% C0 z
1 _1 B9 e1 Y; f2 s) w% b' ]7 T
. D. ?; S9 O9 m1 U7 g4 E0 v
下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
5 n( z) b: p3 F9 C; f
7 j. g3 z5 j; z v7 x
1 }8 a$ Y& |- P3 r: A3、关于LittlevGL: I+ ~* {4 e3 k
3 ~. l; i, A# g( V* H$ Y LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。# j) Y+ G, q+ Y+ q" }
目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。
! e6 R: u$ H" I: }: h4 U @
2 C7 o6 O b. F- U+ R
# w6 P$ _2 [. W; \0 E* ^# a2 ?9 }' q# C% @# _0 D
0 U1 d7 J p5 O# P% Y" q% W8 I3 z2 H: U& A
. L$ \5 L8 Q$ M/ X+ `5 r官网和github地址如下:
! }# O" u+ I0 z& f
* s" W3 C$ \7 U. XLittlevGL官网:http://www.gl.littlev.hu/" }) o+ b2 L) E$ g
LittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl
: @- Y1 f. |, [) w) D) `* h$ I
& n3 |5 O% a" L* i o2 C. B下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。
! g6 C2 x4 @: _. ~How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg+ V; ~7 C/ g( \: z, Y/ x: q' y; }
Embedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM) r9 S3 H$ c5 x* E
& H$ ^; g" u, _" t& U9 K9 U' p 和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。
7 ^, T2 H- o3 A+ g- h
7 A! k+ w3 y5 p6 T7 {# X/ @' O7 a
/ y8 W# ]% W$ A% t测试代码:+ E/ y2 y; T/ Y, X
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。
http://github.com/littlevgl/proj_pc
是的,没有限制,移植吧。
谢谢楼主分享
如何模拟? 如何在linux中运行?
0 F5 i3 ^8 x6 T
文档很少
4 [5 }$ \; |2 d# R' T, B/ A
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。