本帖最后由 creep 于 2018-1-13 19:14 编辑 8 e8 H- [$ A: h% f/ B7 O
- B+ a4 T% F6 E8 h/ \) P* h
推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):
, {; N" x, f3 d# m+ A 2 @5 J9 P1 ^8 v5 W k' g8 O/ L7 Z
开源GUI LittlevGL V5.0版本移植 ) O* e. A+ m5 e+ r! g
! z; J2 ^( m6 }! R+ e
4 Y( K: ^9 w% N& qLittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。
6 C( i3 q& A9 G3 s. k2 W* k
& P2 r, ~3 }/ m3 d7 T* F D! t# s5 o) r% B `2 _- l: v, a: W
下面是我在STM32F769-DISCO上移植的演示模式的效果图片.
: E9 X/ K( g1 F+ t; Z% \7 r' _# J- P: t6 a2 H! q, Y
& J- C- l R' \. b' I/ N3 o, j5 k: v- [% G. I
2 _3 T& g# j9 }' \- }
% B9 T. d; I7 _3 F3 x6 u& j* q主要控件可以通过下面的图片有个基本的了解:1 k/ N/ Q: C* u6 l; y( v( }# _; \
* y. o# ]7 b( d' F' X& o$ V( r( ~4 z6 s
$ V. `/ S- Q5 S* X
1、移植
' m/ K0 ?. r, p) g% J$ x: v' \9 |
LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:% ]: t1 S( p7 |" Q0 w) g
0 y8 F" `1 B1 C1 C: z" |8 u; X
' g: D- G6 |/ n) K/ S4 ]
也就是下面几个函数:
1 r* I: O7 m5 F2 y
5 S& \$ _* U5 _* k8 T8 d8 v/ ~
5 G3 G- S( D5 g; |- f" 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
- % a+ F5 m" c4 g$ ?: \3 @
a)systick的移植直接使用的是HAL库里面提供的
1 i9 }4 @) E0 e4 L$ X: {1 |) \" D
g3 x5 H1 ?' N7 N( {$ F+ s* S- /**
# |5 j* R+ {5 K. L, k6 x3 Y - * Get the elapsed milliseconds since start up
' J3 _3 O9 k1 z( N - * @return the elapsed milliseconds
& k: p Y- H5 d" G! | - */
1 k. N! g3 e3 u7 } - uint32_t systick_get(void)3 Q- u9 a4 _6 p1 D
- {" L1 ^* E$ P% s
- return HAL_GetTick();( {0 \" y- }% I/ F/ `: V
- }* h+ ~3 ^5 t0 P% ~' L
- /**% H& s1 E& p, C! c$ Q: f
- * Get the elapsed milliseconds science a previous time stamp
+ m4 G, p6 j4 ` - * @param prev_tick a previous time stamp from 'systick_get'
! ]% b* \% |6 d% N, D( g- G! y - * @return the elapsed milliseconds since 'prev_tick'
% E* e6 [* T$ t% ` S. @ - */
6 G7 C* K1 o; w1 [* J" y& L - uint32_t systick_elaps(uint32_t prev_tick)
q$ S/ t, _# x, V- } - {
: Y, }; Y7 y7 t* K7 x+ S6 c - volatile uint32_t act_time = systick_get();
2 w3 g, j$ K5 s5 P: Z( B: I1 y - , G7 M0 S; g9 E2 z4 H3 ]' Z S7 D
- /*If there is no overflow in sys_time1 ^7 \0 Z' f: B6 W0 a$ C
- simple subtract*/
# ~# W5 n, T6 ^# j4 ? - if(act_time >= prev_tick) {
1 q* x" d; i/ |; ^& V( c - prev_tick = act_time - prev_tick;
. H5 d" P# Q) H2 h) y - } else {" k: {0 ~% o1 Y6 `% G8 @5 e
- prev_tick = UINT32_MAX - prev_tick + 1;3 D7 V+ A/ ]- z# c
- prev_tick += act_time;4 l! Z4 Y3 I1 `) V" L: C
- }
1 r2 z/ D: {) O' u2 c5 d - return prev_tick;3 h% D3 H: d, Z# a
- }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果
4 S4 s1 [! L, q4 @; q6 K6 N- /**
4 q5 x8 U$ D* F8 C2 E i/ a - * Initialize your input devices here0 K- m7 C3 M; N; o7 E+ M& B
- */
B* i. X7 `# i - void indev_init(void) W: S% S0 }+ k! ?
- {
4 H; z) F: N# }' {3 k, }* a - BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);5 N; p/ }1 o9 e
- }
0 [7 K; w2 T. V0 y' s8 z( p - - ]" M2 T9 w6 D0 W( @5 [5 r
- /**
1 h4 [3 L( Y) U1 Q - * Read an input device% ]! X! L9 R* R+ o$ [( y S
- * @param indev_id id of the input device to read% x' U k- Y0 w' K# ^6 D
- * @param x put the x coordinate here2 [. G' W2 N8 ]) u" c
- * @param y put the y coordinate here+ Z& J7 L5 c/ ~% t2 R/ Y- _
- * @return true: the device is pressed, false: released7 f* O; n; l. F* T$ V
- */" f% V! ?. Y1 Q- N0 n4 h
- bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)" X/ s9 L* i; J9 g
- {4 {: b( B0 Z0 ?
- if(indev_id != 0) {7 v* X0 Y9 c3 N& n& |
- *x = 0;
. S4 U" J3 D- _; n- ~ - *y = 0;0 G' a- o/ c: X7 N8 r
- return false;9 x% v# E: r h+ }7 i% e
- }0 O# e& b' n+ c/ H+ E. h/ a. [
- static int16_t last_x = 0;
# t/ y" p. R( t, h/ s - static int16_t last_y = 0;
0 |6 g$ _" p1 L - bool press;
7 l5 z, z+ K. u% l5 b/ x - BSP_TS_GetState(&TS_State);' i& S, c6 t; V' g
- if(TS_State.touchDetected != 0) {
5 m9 ?/ L2 g0 ]: [. K - *x = TS_State.touchX[0];
7 K! m+ X8 ~4 E3 m: ?! X" Z) W L - *y = TS_State.touchY[0];
/ N) o/ @% Z1 k; t1 ] - press = true;
. u7 _1 K7 y: p: \' Y' L - } else {- D/ m- v3 k+ J
- *x = last_x;, G, P6 ~. n4 O$ _% G
- *y = last_y;+ v: ?; N* z* D& j
- press = false;5 ^# {: f, y3 \9 s) D
- }
# P# I" n5 A3 k! A& T9 { - - i6 \5 [# K* ?, i5 Y
- return press;
6 P6 v9 ^3 M* `. m/ ` - }
复制代码 c)LCD的移植分为几个函数,
% Z4 M4 Z! j, W1 |9 i
8 a- F1 F M) y* c9 i1)一个是用单一色填充矩形区域,这个实际调用的次数较小
8 R6 i! y# @% X7 ^1 l) P+ w$ v: Q9 f, Y
- /**8 `3 O, I% W I. c" }/ x* U: U
- * Fill a rectangular area with a color) B: ^; j: o$ R9 [6 M! A: E
- * @param x1 left coordinate of the rectangle' a; T: c$ o$ y$ i( @& \; D, g
- * @param x2 right coordinate of the rectangle
4 ]/ A/ Z. l7 }3 F+ p' Z1 O; J - * @param y1 top coordinate of the rectangle, ?$ w% w. w3 l/ _' @% S# Z3 c
- * @param y2 bottom coordinate of the rectangle' L: \. D8 n6 C4 ]( S* O/ o: J
- * @param color fill color
/ i6 l4 V$ A9 {0 G' }0 t - */
1 a* `4 q' E( Y3 v$ o - void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)
$ K: R, S) m0 [: _ - {$ n4 {! D# c- s
- /*Return if the area is out the screen*/
4 e3 L3 K' G/ X - if(x2 < 0) return;
z5 d# b K( O* W( [$ C
/ O; f" K5 s! x9 e4 M- if(y2 < 0) return;# s4 P Y; D: ]# x
- ( S) x* u& J2 U5 \" ]
- if(x1 > DISP_HOR_RES - 1) return;. s8 ]/ W9 x. K. R7 j( z+ m) z& Q& q
- 6 O% o7 c8 p, k m; ]' o6 o/ [
- if(y1 > DISP_VER_RES - 1) return;
" e) C, B, R7 }3 o7 v8 ?
, b' Z5 d; Y6 H- /*Truncate the area to the screen*/) R# ^& n+ ~9 V2 _( W* X% t
- int32_t act_x1 = x1 < 0 ? 0 : x1;
3 O& [! z" B5 q2 |6 ^* h( L - int32_t act_y1 = y1 < 0 ? 0 : y1;
) P" r2 h6 R7 H( o8 m9 W - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;. Y7 |/ S2 |2 S* \3 A, H
- int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
& Z( R1 e }% Y7 @ - 7 ^( I/ ^5 w4 Z2 I6 c
- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));: H3 y5 q. D: x* W% f& B" \4 E- P
- }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。
6 ^# J- B2 V8 ~2 ^# B% J* Y- /**/ L, c! c5 J# v& L
- * Put a color map to a rectangular area, ` G+ j% L1 y- h
- * @param x1 left coordinate of the rectangle
& g' Z o7 w, j4 f. ^( u - * @param x2 right coordinate of the rectangle8 V3 G- u& T) q6 t$ W o$ [
- * @param y1 top coordinate of the rectangle
7 M+ |$ e9 u; U$ H# N) @, Z3 o - * @param y2 bottom coordinate of the rectangle( Q' Z$ o% {) N
- * @param color_p pointer to an array of colors
; D: ` l3 U: H0 F: o, z0 E4 e5 ?$ \ - */2 i7 Y' {, p/ r* w5 f
- void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)$ E9 L! d' k+ k9 v" @0 |7 R$ s
- {# Z- f: P" l, _/ |5 q! G
- /*Return if the area is out the screen*/# @; ^6 b; \; v6 q
- if(x2 < 0) return;
6 s, ^4 E, _* N, {! \
; h3 w5 H& a4 `1 f: {- if(y2 < 0) return;' C( {& o, d) \) s/ u; ~- v4 l
- ; c. Q6 M1 u7 V d' K: _6 X( l
- if(x1 > DISP_HOR_RES - 1) return;
: b2 j m3 c6 |6 C
0 d& ?& G* ]4 i% x/ a% d( A- if(y1 > DISP_VER_RES - 1) return;, T ^* f' h: w3 a( v* Q+ I
- - p6 N/ o; }0 x4 V! a
- /*Truncate the area to the screen*/
b9 n7 r3 a+ Y" A6 L - int32_t act_x1 = x1 < 0 ? 0 : x1;7 Y: [* t0 Y* q B y
- int32_t act_y1 = y1 < 0 ? 0 : y1;
! m0 ]$ N2 m; x( J1 ? - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
- k$ L6 ]5 v% q3 w - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
' @" m; B; r& e+ b3 M
3 U3 x2 ?' P% y( u$ w% o' |. a! r
* D5 y- [& a8 A- w5 }! Y- uint32_t y;8 D+ _, {. [+ \7 Q
4 @- n4 \/ F. q9 t- for(y = act_y1; y <= act_y2; y++)
9 `6 \( h: {/ B+ M4 C% @# J - {
* V% [/ h( Q7 W2 @; k! E - memcpy(&my_fb[y * DISP_HOR_RES + act_x1],
8 E! A: x" M" U - color_p,
3 I$ {: @' Q1 v3 b+ v; G - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));
$ F7 g2 O9 |' e - color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/) m! d: H" a6 ?# d0 b B
- }+ J0 j$ { i0 O& z$ s
- , d1 P1 I8 a* g& d( k* V
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存
8 g2 M1 y1 ~! D5 @6 a {1 U8 B- /**+ b* H; f- C2 ?1 w" W7 ~
- * Copy pixels to destination memory using opacity
3 I1 u5 r s/ a4 i9 @7 s+ B) w - * @param dest a memory address. Copy 'src' here.; z A1 ?) |7 X/ [, z
- * @param src pointer to pixel map. Copy it to 'dest'.# s" Q# E2 q% C" F
- * @param length number of pixels in 'src'
+ R( b& q0 X5 `, G - * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)
7 \* e% X4 c7 {' f9 ~9 z, [1 [ - */% T' T1 h, G! J. h
- void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)! A6 p+ G- p0 T! @0 T
- {
/ k' Q3 s: Z, p# F; W8 G - /*Wait for the previous operation*/. K8 d, |1 d. F+ q* Y- _( ~
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);/ m$ ? j9 A% t! y
# ^" j, M$ U- ~) T/ C: Y' s- Dma2dHandle.LayerCfg[1].InputAlpha = opa;
( m/ e# ]7 l* p/ P8 G; i - HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
) x$ M5 s; p. z) y$ k - HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);+ W2 |2 F$ B0 c0 K7 e
- }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:
8 j" v8 t5 S" a1 T. C8 W5 X+ {# h
2 H. R. f# E- N: ~% h添加到工程中后如下整体如下:# w) N, H6 p( g h& b+ q8 s
" {$ P* ~7 `5 m1 D7 o- t3 u
K' z3 I' Q2 N4 L* N2 X% M9 r* Z' O* z- B
* ~- m7 W' K; I$ Y! P% l
0 g& C6 i% l" j* k# c+ h" I将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。* j# k3 y5 z* C& b- A
4 K( t# j& ]- D/ U
9 h. A6 b( a7 A3 g$ K2、运行效果2 {7 X; c; b1 e7 ?1 b+ f
, Q& ]$ z# a. f3 u5 SLittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可
; ]6 y9 l8 A5 O* Q# I4 b3 M" |- U9 h5 }9 ?/ g# m
$ _7 m* _, l( k) h# S& x! U/ b1 w
$ K9 M2 {7 |$ A$ Q7 p! \. s5 i/ b# R3 v2 \, J, u6 N
LittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:
; d. r' R! E8 S6 A6 A q' X) W/ m# c$ w/ Q( t. c
/ `$ J4 y+ }' G+ m% O1 d
3 D8 ?; u& _ Y# ^ Z
$ o( l- t1 X6 @ {& ?除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。
- J! G8 q/ q9 y- k/ G- A7 |5 b! ?3 o7 y& V* f; L
( K1 P7 ^% C6 p' @/ B
1 [( F- b+ `- B8 s# z, U! E" A2 L) F( K$ |
下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。) s9 a+ }) G& Q: D/ B
) F* j6 s5 @* v+ `/ ~5 _, r. @, r, p- Z* N3 \1 ]
3、关于LittlevGL$ x( l C2 T7 F
! F, _: w8 h/ \$ ] A9 H6 e LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。
7 t8 ^" R# [& O. Z( z( n6 H目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。
' f! |' |! q+ \) m4 Y& A- u" h* U j$ b+ O" C
( J: f1 A$ s/ v( y4 |
9 I \1 _. q( x. @
9 [# c b/ x% G" \8 \
, O, e+ S7 `* x4 F1 _0 w6 y; _
; U4 Z1 O1 N' M/ B7 \; ]+ M* ]5 j官网和github地址如下:
( ~: l% i# C( _: k0 S7 k
# K2 ]9 H0 ]4 t* r1 p" c8 rLittlevGL官网:http://www.gl.littlev.hu/6 J. X! V3 v8 { L& K
LittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl5 o& w6 v5 ~: Y
* w) E2 G. ^! l* Q下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。
9 v8 g! `* S2 s5 LHow to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg* e1 i) b! {2 l1 q0 x$ A( ^* Z, o
Embedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM* {5 }( E f i7 H/ L3 `$ G- h
/ f: m) X/ L* n! R5 ?& o3 h
和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。$ s6 H" [) }9 d' W' Q) ~/ I
K9 l: o; t4 j4 u3 e0 H- p/ ^
; A2 j7 E. [0 |+ v& W! }& ?测试代码:
; B' X8 P! L2 }- @, L( W
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。
http://github.com/littlevgl/proj_pc
是的,没有限制,移植吧。
谢谢楼主分享
$ M3 @' b4 w& F+ s; O
1 W9 C4 X# x2 o7 w+ G
如何模拟? 如何在linux中运行?
文档很少
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。