本帖最后由 creep 于 2018-1-13 19:14 编辑 ( {, W9 A5 {$ x% r( p
& d1 O3 H6 c% f) R
推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):
) i1 S' s0 E+ f; J& B " I- D5 }" Q- ~# B/ R) }+ h4 H
开源GUI LittlevGL V5.0版本移植
4 x, x1 F& _; P$ k' P0 ^5 E
8 S5 W" M3 f( P
" V$ ?1 W6 x! L: [$ iLittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。
% Z# R! g7 Y3 P: m0 C
" C( `3 C& y$ ]" ]9 j! R/ R T+ z8 x" b9 V6 {
下面是我在STM32F769-DISCO上移植的演示模式的效果图片.
0 F7 d/ V8 r {# F! Z( R1 A% C. v# R6 _; J0 R6 f
/ e/ l: {1 g, M6 {! t
1 a$ S# T6 A! S$ A2 \0 u
; y' {( x5 m+ Z5 t4 u; x
' K. F/ @7 R$ {) {& [
主要控件可以通过下面的图片有个基本的了解:, t! i$ ?+ o9 Z2 t1 p7 M+ X
: c$ O+ F; n4 X
6 E4 j' i. ?& I2 C! W5 ?
2 U5 Y, s# E9 n6 [3 E( X$ ?
1、移植
' q- M4 h+ Q' z& B
' R, r# i/ `" @' }/ wLittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:
5 u( l5 f: S& G. J. K
( B; p# R& y: f+ y0 s% R7 z& K2 x, p2 z3 F1 v. E
也就是下面几个函数:
/ z' S+ K* Z' \0 R2 `0 m. P P
, x' B3 h% V1 p, ?8 _- Q' q7 D/ V
- 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
4 j b/ x* ?: o8 ]: w$ \ a)systick的移植直接使用的是HAL库里面提供的1 t" `5 i& ^ Q* N% ~, ?* I
. E- o5 t5 `# Q) H- /**
; n' |: W7 O3 ]8 v. x - * Get the elapsed milliseconds since start up7 d: i( S8 a* ]1 n
- * @return the elapsed milliseconds0 E9 v4 c, I9 [& H
- */0 G9 Y C9 _+ A0 a+ f5 W
- uint32_t systick_get(void)8 x7 t! j1 v: f+ t3 O4 t
- {
2 @" L$ w% a$ B* U% ^. x l - return HAL_GetTick();8 X$ S5 t( o7 [1 ~1 f+ ~
- }
1 _8 `4 h2 _! Q. S - /**
/ M5 w8 l0 ~5 ^3 L' N0 W8 u - * Get the elapsed milliseconds science a previous time stamp
# g6 |. a1 S! z4 O* S - * @param prev_tick a previous time stamp from 'systick_get'$ @) h/ l6 ~5 N' w8 I" P6 Q. r& s
- * @return the elapsed milliseconds since 'prev_tick'
2 P( H: z+ h! d; U4 P& Y0 z; ^ - */: ?& V5 ~) W4 F5 e
- uint32_t systick_elaps(uint32_t prev_tick)
, Q; O8 X0 j) k- l# n. |% Y" [ - {
/ U9 h! l1 K3 _' |, Z! a% \ - volatile uint32_t act_time = systick_get();, {4 E% n) K" Z4 e2 x
- ) R; n" O1 Y8 t: }9 A
- /*If there is no overflow in sys_time! W' S) s2 T' u1 x- o. Q/ G
- simple subtract*/: w: ?* c3 i! J2 \
- if(act_time >= prev_tick) {! @6 E, a1 B( Y4 y
- prev_tick = act_time - prev_tick;9 b: ]6 z% i3 O/ Q
- } else {: B; P0 S6 W* O' K% e( {3 o$ O
- prev_tick = UINT32_MAX - prev_tick + 1;
H% d# `! C5 ]3 F( C8 M - prev_tick += act_time;7 j; c0 N( X. P5 Q
- }( M- f# x! A9 o8 m7 c: s4 P: b- p
- return prev_tick;& d ?* q# d5 o4 ^- ]0 `1 c3 [
- }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果4 W: C: z5 F7 L
- /**
: t b0 L3 X4 g7 A2 F - * Initialize your input devices here6 u# x8 Z7 G, F
- */
- l }0 @ G Y+ ^% s - void indev_init(void)
( h/ i1 t; P+ M! N2 p3 X8 D - {1 k$ }; S7 Q! W4 R
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);
- U# }5 u5 c! e/ o$ S - }5 W+ }6 K% G d5 r& `% b
- 7 M# ]* g' L7 q4 q# F0 O
- /**
" m, h. N1 J6 I6 ]; B5 g - * Read an input device
1 H8 _; @- N/ H' x - * @param indev_id id of the input device to read' Z% ^) g& G. A" K) O1 i- _# n
- * @param x put the x coordinate here
3 \0 q" r) v3 @( x2 X - * @param y put the y coordinate here8 r/ X- t( {& f" H1 s. c# h3 j
- * @return true: the device is pressed, false: released2 ]7 l; |4 m& t y6 t$ M# M1 v
- */3 \" W1 ?* @" `' @4 b8 O
- bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)% v/ d; {& U }( u/ X4 J6 d
- {
" L0 |5 S4 F* I r5 a3 T3 K7 k5 [ - if(indev_id != 0) {: Q7 R2 J. }/ \% [' m/ r" ~
- *x = 0;
6 {% a+ c9 A2 B @ - *y = 0;# S9 g0 g4 P) Z2 |; m0 t; \
- return false;
" ^; F( K, u3 \( C |* h - }
: R$ J5 c1 X+ `, J/ j$ W& _6 P - static int16_t last_x = 0;
2 m. ^: T% u# e+ P - static int16_t last_y = 0;4 d6 n" U: d- v
- bool press; m I2 A, m4 d# F# p
- BSP_TS_GetState(&TS_State);
! V& `* x8 l/ N5 r, | - if(TS_State.touchDetected != 0) {, r q( A- h- \2 k, S
- *x = TS_State.touchX[0];
) p5 P" T" @" J0 s- F3 v# u - *y = TS_State.touchY[0];; o F7 M. z5 k1 K! M
- press = true;
3 ^, ], }* t) e8 @- s5 L2 w - } else {
. G% e+ v7 Q N; M1 N - *x = last_x;4 z2 s' D! s- _ _7 t, H) p' m
- *y = last_y;
: W) x o* B( E' k - press = false;
1 u5 x% w" ], @6 | - }' p# f+ c/ E; t8 r; H; h
- 7 O5 T0 Y* C5 ^$ U
- return press;
. l4 y/ Q' \' _1 V, ?* w - }
复制代码 c)LCD的移植分为几个函数,
# q" T5 j- T5 T3 S, j& A: @3 E7 w+ K! j
1)一个是用单一色填充矩形区域,这个实际调用的次数较小
; C5 v: f% O2 q* s
. B7 y9 V4 p* v; T6 ]" e: H- /**
* x6 B7 J) O/ ^$ O. N - * Fill a rectangular area with a color# M! O* g. S3 l5 B" f. Z1 H
- * @param x1 left coordinate of the rectangle
6 W1 C4 t. F( y" } - * @param x2 right coordinate of the rectangle
+ t4 l1 s5 R$ H5 Z8 g& a - * @param y1 top coordinate of the rectangle7 [2 s0 v- Q d# J0 ~7 l
- * @param y2 bottom coordinate of the rectangle
. [' b$ y9 y' t n - * @param color fill color
& I1 B1 [( d1 k - */
' c1 D/ h8 n3 s! l - void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)1 r* X1 }5 H3 K2 p1 i! ^4 D
- {
Y: a. S' ~0 b5 b6 |9 z - /*Return if the area is out the screen*/
4 J+ V7 F! e9 ` - if(x2 < 0) return;
! u% }* @, }8 r* u X# M - 8 N# m; Q. p: O2 e/ Z, I. Y% a
- if(y2 < 0) return;
, \6 B6 F5 @ ^2 A e
. L3 m0 u$ F0 [) {* m: n- if(x1 > DISP_HOR_RES - 1) return;6 O# P: C/ x; o, O3 B( [
) G( G# t+ G* n: F% F5 @6 y- if(y1 > DISP_VER_RES - 1) return;
3 e; w" D/ s8 ` - g3 }8 X+ }; ^, d
- /*Truncate the area to the screen*/6 ^7 _- r% F6 [
- int32_t act_x1 = x1 < 0 ? 0 : x1;2 T c" {& r Y; P! a" W0 P8 s p
- int32_t act_y1 = y1 < 0 ? 0 : y1;8 Y0 {$ h- _0 e B
- int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
) Y; F- K- C* Z - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;4 c! j5 i* H/ s* P
- & h# F( X% R% v
- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));
: ]) f- H7 @2 Z0 h- M6 Y& F8 m8 T - }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。' V9 h9 y. \* U/ U1 H
- /**
4 p: `( S. {# b - * Put a color map to a rectangular area
9 ~' A& X3 X! P6 R: W& E2 t - * @param x1 left coordinate of the rectangle- ^# T/ l: P# L E& n+ q
- * @param x2 right coordinate of the rectangle/ k4 e# r4 W5 B3 m, Y
- * @param y1 top coordinate of the rectangle9 W G$ [# J5 E% {5 h
- * @param y2 bottom coordinate of the rectangle9 y( v6 I( T4 v$ H% j9 e( J
- * @param color_p pointer to an array of colors$ \1 N9 R8 s x% L/ K
- */
( s9 q$ N4 \* @1 r - void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)
# H& {: ^1 ?1 e - {
9 ~$ o2 |% e1 E1 i: U0 I3 H, V - /*Return if the area is out the screen*/ b8 I8 H$ O1 F w+ _. B
- if(x2 < 0) return;
. Z" P' o7 F' W$ l - 5 O9 d6 x0 i/ \% K, m
- if(y2 < 0) return;
2 }( S2 y) C% D" z, c; T: G
( m' u( h& h/ Z& g5 E: J/ E- if(x1 > DISP_HOR_RES - 1) return;2 d, o5 j) V# Z. y* s) Y
- / m M; t! v* f4 f6 z: D9 m
- if(y1 > DISP_VER_RES - 1) return;
0 K( J, ^- u5 E- E - 9 T ~7 j2 W9 V- }
- /*Truncate the area to the screen*// A* L. Q, w- S- Y* @6 L# t
- int32_t act_x1 = x1 < 0 ? 0 : x1;' \8 b$ k0 q* F
- int32_t act_y1 = y1 < 0 ? 0 : y1;4 U/ p* V& k6 q9 S8 Y
- int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
9 F2 l' b6 n2 C$ y5 w [5 ]' D - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;! [. T: p9 ~3 O8 d1 X \
- ! S6 H, h) O f" M3 f1 F0 w
9 P8 _5 K% }# B5 g; S' B& u- uint32_t y;! ?. P5 F; V1 J3 ~
: Z9 E1 H5 W6 H- for(y = act_y1; y <= act_y2; y++)( i4 R* m$ A/ ?/ \6 S
- {
' Y! K, f; P) {. B+ U. J) Y, t Q; Y- S - memcpy(&my_fb[y * DISP_HOR_RES + act_x1],8 k: {2 m, u5 e- m1 C
- color_p,
3 e% z/ Z: @# t ]7 N" e+ l! Q) t - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));7 y; o! j7 {2 B8 X' ]0 O
- color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/* z1 ^/ k$ r8 h1 W' @# B" f5 [% |% y! M' r
- }
8 y" V( g* \ y. q W) [ - % k6 G9 G9 P# ^: R
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存: R) s% K# _* m
- /**
( h" u. R5 k' }- j) J; v1 e - * Copy pixels to destination memory using opacity
9 V, W w( v( W# ]9 B" Y* d L - * @param dest a memory address. Copy 'src' here.
# D) H, R7 t9 b - * @param src pointer to pixel map. Copy it to 'dest'., l5 |' _9 g6 \
- * @param length number of pixels in 'src'
, X. l6 f, V- i9 o - * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)
! m8 E" f Q3 |) w - */
$ P; }; z% j0 Y - void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)
, b0 D1 v( J9 ]+ M3 { - {
- E2 Q6 j |% k: j$ i* d - /*Wait for the previous operation*/4 Q" G5 V/ e3 g/ l! X8 q
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
, [6 j- a# x: U2 d& Q - % g) |* I( s0 f; D( u
- Dma2dHandle.LayerCfg[1].InputAlpha = opa;
" c X( {. i" ^3 @ - HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
3 ^9 V: V7 F( P. U# V - HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);- Z( D0 N% N. b6 k
- }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:
. e, G) Y0 f! u* }- U
1 e8 n; O$ q/ T+ Z$ L
添加到工程中后如下整体如下:% ^& |* f4 @3 A* O1 M: B
3 ~1 ]8 b! |& x" `. ?4 U+ Z
9 A" C1 p- o9 V. C: ^1 ?
) s5 Q/ C' H: ?7 F# M F" D
& R9 }8 w- g; u) ?, ~! @) @
^3 D0 K9 }9 R
将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。- p+ D7 A/ K7 U3 {5 r! B0 Q
3 P( h' ]& b# }" h( K5 `4 e. h3 Q2 ^/ @3 T; S4 s* |; d0 v0 F
2、运行效果* P) k. d' B: t( h6 l
' C$ ]! m5 Y9 E+ d5 G# ]
LittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可- G# U0 m6 R9 T8 ]9 }4 O o
6 _$ f) T) Q9 r9 A a$ o; E
! O& E1 m+ }' ]1 T9 k1 m9 z
1 x7 G5 w7 v; r& O- _% e8 F
2 l1 k; N& X& [' ^) ?LittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:
0 y9 \8 l' L: h; B ^7 j5 D$ i+ t; e
: b* K7 _/ Q3 d; G6 W
1 n4 Q) W& T" S+ o4 C
B3 a/ U9 C# ~; l( o除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。
+ D) ?9 m- \6 @3 T4 J
- W* @* d2 I& v5 K
$ M7 \# t% J* w! ^8 k
, [( [- J8 a8 Z$ }
3 [- D0 w- d( O下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
5 B6 q& i8 ]" Z o6 Y
6 h8 {2 S: j7 {7 `) \2 |) t1 M. G) W. t# h9 [3 c* _
3、关于LittlevGL2 P* Q: }* T3 ?- k, e) {5 I
& ~& ]5 J' B6 Q [ LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。$ F' w# W- p. o( I+ j+ d
目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。' y; Y+ {9 o( ]* E" ^ H4 g9 o
" z* n! G) C4 V/ m# `3 `' r( Q/ x. k/ m
1 t! l: ]7 A+ R: b9 c' j& t# n0 {
3 `! u; K g2 a& ?/ m4 U& B+ R) h+ p
9 P }9 w# v/ m& s' G
. l( @9 G, n2 X, a
" Z _$ H$ x9 P+ I官网和github地址如下:2 n$ o' S' {: X0 G
8 j( V5 ~1 p3 h6 |" [( o
LittlevGL官网:http://www.gl.littlev.hu/8 X$ f, b1 v, o; y' L! T$ f
LittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl" U3 w+ \9 p) T7 E4 ?4 B9 `% N/ f% C
/ T3 M9 h# c' B' }下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。$ t- _1 v! g9 u f, A- P: p
How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg+ y$ Z1 t% |6 I; t# g
Embedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM
( ]' n6 {1 H+ R6 D
; Q6 k6 A9 m/ `+ F 和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。1 J- x% I5 B' v
' i* p" _% p: e: c
# @$ F7 r- M* M3 {7 Z/ ~5 k测试代码:, h9 b5 F' c; W x" |6 l
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。
http://github.com/littlevgl/proj_pc
是的,没有限制,移植吧。
谢谢楼主分享
' i' T- N7 ]) [* \" D1 \. W1 l
如何模拟? 如何在linux中运行?2 G1 `3 v1 B, z4 O) v1 a
文档很少) L) k7 `( a% [. P2 F; r
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。