本帖最后由 creep 于 2018-1-13 19:14 编辑
1 c) `8 q! i* T! R% e1 d2 n/ s' g7 j+ l$ K) q
推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):" w. L* b. P* N; ~
* W* ~; W: x$ W1 F$ J7 b 开源GUI LittlevGL V5.0版本移植
$ U* T( M% e \3 k8 b% A' L- G" A6 {3 l1 `& U% s
3 |4 R+ u- u% T% m! J5 ?. Z2 y* V/ \LittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。" r- M: ^# k: I8 }# M
4 s2 k8 ~+ L d5 w9 R* Q
& j+ \# M2 u2 P9 F
下面是我在STM32F769-DISCO上移植的演示模式的效果图片.
9 Y8 H5 U3 ~/ N/ s# I2 _% b; ]
% B$ d; z) i2 r, o9 j$ a* G7 d' Z& Y( V2 Y8 `1 y: H
/ d' u. h) d+ K7 H
) o& i. ^! _9 D7 j m- M {; U/ ~
m: J6 G. M* T1 x. {
主要控件可以通过下面的图片有个基本的了解:$ T: K* U9 H# _6 q! s
7 q# y2 f% w0 _, E+ E
7 r# {' B0 {9 ~% Y0 v! o* V
, b% D$ u2 F" [" m# a/ N3 ]- P2 K1、移植
8 P+ C1 h4 d7 z, j: E- x6 `/ Y: y, M- B, c; o4 n5 f* V
LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:
& [8 N7 Y4 e$ e) Z
& l& z) M7 n. R2 v1 e9 o" O$ B0 z0 {: u4 S
也就是下面几个函数:( x1 x) C/ y7 P/ l, c1 p( h3 f' m
& n2 }2 i+ d# U$ P {* K! a7 V6 n
& N( {/ k. d, 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
9 w3 ~) g* E% O u a)systick的移植直接使用的是HAL库里面提供的
" W. C6 j# u; a4 N/ b; R/ Z' D1 S8 T" A' t/ F% ]! M, Y( j! x8 a$ v
- /**# i3 F7 R; R5 R5 A- ]
- * Get the elapsed milliseconds since start up% B3 |8 ~8 [0 H
- * @return the elapsed milliseconds
5 t# y) b6 {' \5 Q - */6 ^' C; @! @! [3 {" Q
- uint32_t systick_get(void): c5 |' G8 V) i+ K8 j( Q- I! g! a4 f
- {6 c5 ?) V* H9 s( D3 B4 |
- return HAL_GetTick();0 c6 m/ E) R- ?1 c
- }) c$ _# {9 ^7 k) c2 A
- /**
% L' P9 e& ~8 V9 M( a/ c - * Get the elapsed milliseconds science a previous time stamp
. P+ H0 C' L6 f2 U - * @param prev_tick a previous time stamp from 'systick_get'. j& Z6 ~ d9 Y2 F9 x5 C6 u0 y7 p; v
- * @return the elapsed milliseconds since 'prev_tick'
, z- o% g+ }6 S% X# {3 G - */
6 D$ ?; B G: n b u$ ] - uint32_t systick_elaps(uint32_t prev_tick)
# t( h/ S0 R$ O |! L - {
/ h% M& M# @9 T" W% x2 t" h - volatile uint32_t act_time = systick_get();: ? s$ d$ ^: y
- . F% ^6 C0 a, ^3 l# O+ G
- /*If there is no overflow in sys_time& z6 n8 p N6 |4 N0 @# E
- simple subtract*/2 E8 Q' }4 Y$ p! Y
- if(act_time >= prev_tick) {% [) T, w7 Y# [1 l
- prev_tick = act_time - prev_tick;
r! B& P7 G$ f1 E' [ - } else {
: N, ]- T) @1 R! L9 n/ b l - prev_tick = UINT32_MAX - prev_tick + 1;9 a) E% j+ u0 y
- prev_tick += act_time;7 L9 ^2 M: T5 a) I
- }
2 J& G2 A, S0 K* E - return prev_tick;) q1 F; j3 w8 D6 D: c
- }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果6 Z) M! W$ O/ b
- /**
2 z- U* o: `3 [( C' E - * Initialize your input devices here4 n0 o3 V. E9 }, y5 V1 Q0 [6 T; t
- */+ @0 |1 f& s5 X) w2 C
- void indev_init(void)
6 v% P) m% m& i) V9 } - {3 |$ m* L0 p3 c, a2 \* z" u; H
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);
; S+ b( U* A+ T8 P: Z/ f5 c' |7 R - }
7 |2 _1 T7 G- x& P5 U5 O8 c - 7 {0 \3 z4 P4 ~5 ~
- /**
4 C* H% l! @" p; q+ s% Q - * Read an input device
9 Z, L& ]& U5 q3 a6 ^ - * @param indev_id id of the input device to read+ D6 p: i, \( A$ ?7 v' v }( {4 X- S
- * @param x put the x coordinate here
: S# Y5 R I! ~5 M3 x$ `$ k - * @param y put the y coordinate here. Z2 \0 N2 W- F& E' i
- * @return true: the device is pressed, false: released- w7 F- Q0 E0 K' Q
- */
7 S7 \* G' l& H0 k - bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)
4 I* W6 W7 i3 p& t9 F, y - {# `" p- b% j, v- W: @/ ?6 _
- if(indev_id != 0) {2 k3 C9 j1 f6 _% f, t1 c# L
- *x = 0;
( v; f3 G2 Z+ g# ]3 a) x7 [+ g2 L - *y = 0;4 e0 N, P/ ?- |* F& H S- ]1 M
- return false;
$ q# T3 N- V6 W2 _ - }
' Z8 ]5 u5 {! S2 m! d' ^2 \; r - static int16_t last_x = 0;
1 Q) N; K; P* e6 X - static int16_t last_y = 0;
( I& a( W q- b* b' ^7 Q% w' d - bool press;
) m' |# y! v& }9 k( H - BSP_TS_GetState(&TS_State);8 k1 q, X1 x) Q9 o% M. M
- if(TS_State.touchDetected != 0) {
$ _" G/ C4 N+ g - *x = TS_State.touchX[0];; }, _ A1 \9 ~
- *y = TS_State.touchY[0];, ?( ?1 B2 ] E k! R! n+ [* n+ }0 @
- press = true;( S2 Q& @5 e% a9 {
- } else {
/ k/ C& n. I0 Q8 F+ C - *x = last_x;& O9 K. m* H' p. G ^7 P+ e
- *y = last_y;, B/ M& G# c$ b
- press = false;) a/ s( z, W7 j5 ?
- }" g, o5 p- }4 W) y# ]/ Q/ m ]
, A$ y6 T: [: T) q7 R6 X- return press;% |6 a1 N; g- \2 S/ I2 s* H
- }
复制代码 c)LCD的移植分为几个函数,
) d. V# w8 Q4 M+ ]. Z$ v& w+ H& W3 t# Q2 d* ^: p8 \; t
1)一个是用单一色填充矩形区域,这个实际调用的次数较小1 v0 ?% C0 _2 [7 Q
* t$ f+ [) D* P
- /**
* E# i. S1 L" g8 W& C( B - * Fill a rectangular area with a color
+ P+ r0 k0 @* Q# g2 x; o - * @param x1 left coordinate of the rectangle7 `1 b/ Q! A& Y+ P
- * @param x2 right coordinate of the rectangle2 D. p& I- U: s9 d. j L v. A6 u
- * @param y1 top coordinate of the rectangle! z' F% s! V( t8 ]% b: v
- * @param y2 bottom coordinate of the rectangle+ T! x ]8 s# b6 ^
- * @param color fill color
3 }" j+ ?* g: Y4 ]: q - */: B% ]+ c! j P& q# v3 B8 l& \4 `
- void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)& d( b: d& ]1 J7 C5 J
- {. d5 F: q! v5 b1 ?* _$ n: g
- /*Return if the area is out the screen*/
2 `! N: S+ L# L& O0 U - if(x2 < 0) return;
: w! i6 s3 w {& |+ | - 0 G" _) T9 p( K7 V$ x- K, m- k
- if(y2 < 0) return;
8 _, c6 C0 ?, i8 r2 y
) D2 v' v% S g4 Q+ h- if(x1 > DISP_HOR_RES - 1) return;$ e. q9 ^) e" E3 k
7 j: t: w7 \8 c! v. P* Y! u- if(y1 > DISP_VER_RES - 1) return;% u, i) ^! r4 Q' h& C
' J5 ^' R7 G+ x( N! g6 c+ a5 f, k- /*Truncate the area to the screen*/
# m3 S q- @0 {: X5 q - int32_t act_x1 = x1 < 0 ? 0 : x1;
7 ] R" g$ \+ k5 n - int32_t act_y1 = y1 < 0 ? 0 : y1;3 x5 D3 t4 |1 P8 t% ] r9 P
- int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
0 d2 n! n g, h/ A: \ - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
" p; w* y" G$ R4 e& m8 k - * v# u5 T! R T A
- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));
) b0 R) y( i* ^- {; P. I - }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。
& c7 r. g. o7 F- /**8 u8 d2 V) j1 [' f% d9 D5 y" T
- * Put a color map to a rectangular area
# j; X4 x5 j& L1 P$ p - * @param x1 left coordinate of the rectangle7 A; {4 J/ s8 g2 }3 p2 D
- * @param x2 right coordinate of the rectangle2 X/ p# H0 \' ~, ?4 Q) V
- * @param y1 top coordinate of the rectangle
5 a' E U3 [9 G - * @param y2 bottom coordinate of the rectangle
7 R4 H; F& R1 N& a6 ?/ X% F - * @param color_p pointer to an array of colors
5 U. t+ G+ ]& \ - */
' M, ?) O7 h9 T: V( L3 C - void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)' g) \# H( c' N1 K- U/ [5 \
- {$ Z7 B4 d8 h+ [
- /*Return if the area is out the screen*/
" \+ x2 v# r: _# h* Y( L - if(x2 < 0) return;
& ~5 s: U, H/ Y4 |; \2 {9 a2 C - 5 t3 o3 O0 c' l: x. w* a4 _
- if(y2 < 0) return;+ t- D5 M1 ]6 Q' x7 _; O. W5 ]
- ; y0 z- k3 P; Q7 B
- if(x1 > DISP_HOR_RES - 1) return;
/ }3 |# D h/ y+ E. ], K
3 e5 v9 ]/ {# U1 I0 z1 D" n- if(y1 > DISP_VER_RES - 1) return;
$ j9 z; f2 |* G) G - : P: y5 k" C, K! g6 ^( B
- /*Truncate the area to the screen*/
1 I, ~3 \; `/ X' ?% W - int32_t act_x1 = x1 < 0 ? 0 : x1;
7 _1 S" o6 O, k' o; w - int32_t act_y1 = y1 < 0 ? 0 : y1;
: N8 l6 r0 D8 d+ r( h - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;& F/ O- z( H, H! G& l# |
- int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;+ L, z. I* \1 X& W* A$ ~! M9 ]
- 5 ^- T e* K2 O- Q
- 3 P# c. ^! K" Y
- uint32_t y;0 I! z) c2 k. M. j% `2 W# {# ^9 D4 @
- 4 v1 t# w5 h3 s
- for(y = act_y1; y <= act_y2; y++)4 B( d2 [) @& G
- {
6 i6 q" p7 `$ O0 Z$ A8 B - memcpy(&my_fb[y * DISP_HOR_RES + act_x1],' P) w. `( u0 A2 M% o# J x
- color_p,
2 Q+ ^7 f2 ?. a- n0 H4 G - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));
3 M* ]# a4 d% [1 }3 \ - color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/
. ], m) s2 b, B - }8 K! s2 F9 s- l9 N$ S
- + \& k% T4 x; C4 J
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存& C% v) m+ ?3 y/ R
- /**6 c. ?2 ?* A- G/ h+ [6 x ]0 _ ~
- * Copy pixels to destination memory using opacity/ o8 }, r# O# Z" t
- * @param dest a memory address. Copy 'src' here.) o# \& W" z- L: i
- * @param src pointer to pixel map. Copy it to 'dest'.! }4 a' m" B, s( o& I5 Y
- * @param length number of pixels in 'src'
" D: n7 m x# q. ` N - * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)
4 u% r1 k, R2 M3 K" Z8 e, k - */8 O% `5 B8 O. S
- void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)
& J: ^4 p/ q% d$ Y - { c5 p' L3 C+ f4 N
- /*Wait for the previous operation*/3 @' i) w% o3 g/ Z. r" n3 H
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);5 }3 a9 M* m) P: @
, L. ?, M9 _' N9 e- Dma2dHandle.LayerCfg[1].InputAlpha = opa;
& i1 ]9 r4 p0 D8 {9 Y# V3 M/ T - HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
; b4 L2 ? W- d& @+ G$ m - HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);$ h: C3 U4 T8 a# d7 n! O
- }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:
! Q* ~ X- M. r- B0 x' {, J
5 l; F2 O0 G: Y! j添加到工程中后如下整体如下:! P7 n& W. h* j! W
& l ~1 E/ k, |. X2 e
( E9 I1 S; w. ?! V* L
2 C2 F, k0 ^3 @# a: V( y4 H
/ {; @5 i$ N8 u( k2 u
5 m5 ~+ r* J0 K' y$ u
将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。1 r. ^2 f" C6 Y- c$ X1 C: l
" S0 b, e7 K W* j% W/ V L6 k, a# N& R0 c! \! U7 F
2、运行效果2 j, U K! J; i; A$ [5 j
2 L/ r4 Q7 f- d% l: R
LittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可 F! R# z' |" H3 W8 D4 q) D3 {
q# a/ G$ u$ T( E/ n
" S! Y$ t, j2 I1 S
0 x; ?# B# h* T8 E' ]8 ^# X% U7 ]+ w; J+ P! ]; m
LittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:
9 F9 l) w y# p) P5 G3 e& F4 r( L( Z8 v+ \, R* h* M
5 e4 Q/ L; J8 f0 L
+ X1 d8 U, u# D* T
% \; r9 \1 g% ?
除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。
: Z$ q4 `: P: [" R3 Z6 h& l) k
8 E+ [3 P2 \7 f& B2 w
% A, I! S. B. C2 i
7 u. q9 `% r/ ~! P9 @
+ I5 p# b2 O# s" R8 @! }2 C( _下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。3 r' Y% q3 K; M) O% H9 Q8 L* V2 Y
( H G9 s' h/ a/ L& z
: f, p5 n3 m# S' J* }4 C
3、关于LittlevGL
4 F9 w9 m- C8 L% k" n# }8 F- M5 n3 y1 _
LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。
_7 _* ^0 A" u6 p, [+ E3 X目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。; X# A# h% Q i4 v) L. e
% L4 q" [$ D4 {: `! J/ a5 Y/ N$ k% ]$ _+ _5 p6 K6 l$ Y, i( M
: L8 x; j, H( w( m
- v, I8 f5 g3 ~/ h" X- K, V
) V" v4 c: t* Y5 e: \/ R5 k: M7 K' M+ y1 n, W6 I6 F
官网和github地址如下:
7 y, k ~% a! | [" D8 _( o/ U- j8 d n* k4 E# }3 D
LittlevGL官网:http://www.gl.littlev.hu/
" k' S! v+ N; e5 W: [4 D5 W! s8 OLittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl7 p# T' A8 a' b) p. E. L
" X! k" ?0 ]4 W9 H
下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。) R& ^6 A, Z' ^1 X' ~0 I
How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg
, x- q' I$ |. T) ~ JEmbedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM6 t+ n- L$ F4 w6 Q
* m6 c: j3 V4 O( i9 C! L
和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。 T1 ~% O9 Y7 f# h% J
1 C% e2 k5 c7 [9 U F7 g+ C
- U# A# C/ A# b7 [1 h* j测试代码:
8 X% ~: j+ N' e$ \+ J
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。) N( o4 r; ?; X2 h9 t
http://github.com/littlevgl/proj_pc9 E v5 a- T) Z( f5 G% s
是的,没有限制,移植吧。
谢谢楼主分享
* L) ?3 `. x1 O5 ^9 i) T4 [9 B
0 o" H/ ]. n: i
如何模拟? 如何在linux中运行?8 j; n8 ]5 v7 j9 i$ O: h: j
/ N5 n+ }5 I/ A, t; X, X3 o, `
文档很少
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。