本帖最后由 creep 于 2018-1-13 19:14 编辑
- W, i9 x1 {, l1 L+ h
7 u5 V! s, H# O. ?8 G/ u 推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):
3 A0 {: ?+ C- t- M2 Q, J* w
. W. L& m0 v$ v9 x 开源GUI LittlevGL V5.0版本移植
2 Q) p% ~# Y5 ~) j% p N
Q" f. {3 V* W: f2 V" Q
6 s6 l. i b) M7 TLittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。% v+ s% G$ }9 Q1 Y# c" t ~' ]
8 _0 }. G- x$ |& t y5 Q8 k' j
' W( l0 t: f, p" K1 a+ E
下面是我在STM32F769-DISCO上移植的演示模式的效果图片.5 u8 i* J7 a# N- {
g. s7 p) T" W% ?$ O6 {" ?- Q& B
* W7 b5 o( K8 N/ L; Z5 R. l# D' ?
( X, `; Q1 y' j0 q9 U& |' j* W) r) y, [' t- r, |
主要控件可以通过下面的图片有个基本的了解:6 D% \+ u( B! l$ s4 c2 ?
/ x I# W5 d+ l
( j) ?# d' t' K, K, h& R
$ p% G \5 c c' d; s
1、移植" O$ H. ^! N- k' y" ?. I
" O& F2 G" K8 j, t! Y
LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:
6 f T% K& J" b" }4 Z3 d% ?2 c- Q3 B6 G" a
* m& j1 ?- u# }! d, ]2 ^. W
: I3 P4 ]0 H+ ~% p也就是下面几个函数:
# D+ ~' y: K* }1 o. j) u8 N
1 M1 r! b" L O, H+ S" h; Z9 k1 W! ]/ S" ?! g
- 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
- , ]# h! S, o8 [% y2 A
a)systick的移植直接使用的是HAL库里面提供的- P& [. p# L' S) Y6 ]
5 C% {$ }/ N- L- /**
- C& E4 Z; W! B - * Get the elapsed milliseconds since start up4 S: |$ O; I9 k
- * @return the elapsed milliseconds
" z. v. x5 J0 l! Z1 j - */
: a+ }- q* K6 u, a* k- A2 f7 K - uint32_t systick_get(void)
" z- R! J; d: g' P( k - {% y6 _! I% F. w6 _4 |: l
- return HAL_GetTick();- ^7 U2 h y. a+ Y8 E7 ]% b/ y" c8 A
- }( a, {+ a w7 ?
- /**1 h9 K1 J, U$ n, q8 l+ f
- * Get the elapsed milliseconds science a previous time stamp; G7 h9 p' R. P
- * @param prev_tick a previous time stamp from 'systick_get'
; b# u4 v! R. K5 j0 {) j" [ - * @return the elapsed milliseconds since 'prev_tick'
6 c4 C/ D: V: F( x* ^' u - */9 E6 w6 |1 e E$ k1 T) W: @
- uint32_t systick_elaps(uint32_t prev_tick)
+ G2 R! W9 O) \' E' T" G - {, s0 G% [6 D5 f9 ^+ b
- volatile uint32_t act_time = systick_get();3 w5 \$ M* i6 q. l4 e2 a4 {
- 1 W/ a8 v( ?2 d
- /*If there is no overflow in sys_time
. d* z5 B) ]: x( o) S) q, C7 P: o; ? - simple subtract*/
9 S; ]9 ^: ~( m# J: L# {( P: l0 C0 g# I7 r - if(act_time >= prev_tick) {
+ i/ J: `( b- U0 q# u) ^2 d - prev_tick = act_time - prev_tick;2 V: B: `0 j5 F+ T5 q0 T
- } else {) [0 l* c6 q5 r' u
- prev_tick = UINT32_MAX - prev_tick + 1;3 T' ?' A- v$ i* Y, ~
- prev_tick += act_time;
3 D- ^5 f: O6 n9 u0 t! \& L - }, x2 f2 j5 K1 y+ R% S$ I7 O
- return prev_tick;% P, X. w( y% D
- }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果5 m/ o2 }3 z" v& I- J. B9 r
- /**2 a% ^. W; K6 x+ m; O0 h% W
- * Initialize your input devices here
) R, Y2 A% v0 c* a. t - */
+ `. j# a# q6 r1 k - void indev_init(void)0 [6 r7 t' i# x* x. F5 w
- {4 H7 {! @, X2 I4 ]; b! v; n
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);
; [( ~# Z3 ]* z* u; O4 N1 \ - }
! e6 U8 U4 Y. O M1 b# s/ `: Q6 ~
. g* X0 p3 B+ E- /**& L; Q- H+ z3 Q- u# u
- * Read an input device
$ r8 X3 q5 Z2 Z/ h$ ~" X. Z - * @param indev_id id of the input device to read
* r `9 z/ N0 k. B2 { - * @param x put the x coordinate here% q) p. T* h5 M# E& C: a6 o
- * @param y put the y coordinate here
, q* Z+ U( B D' v# @3 J, P2 g0 \ - * @return true: the device is pressed, false: released
/ B! g' j! E( J& T7 f+ }1 p - */$ s7 H( N# K( g/ S% X
- bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)! [3 d- e7 o5 c2 X+ i+ W
- {3 W! w$ j' U3 x8 l* s
- if(indev_id != 0) {
3 H8 i1 m- [3 _$ j" d - *x = 0;
( ^+ J8 N8 t- L8 z - *y = 0;
9 D2 z# K, |1 u" r - return false;
& [! o4 u' C" m F' e - }' s& o+ A# L+ b* p6 \9 J+ i
- static int16_t last_x = 0;
' X5 z2 Q4 ^5 k - static int16_t last_y = 0;
4 z5 \; Q: _2 Z4 p - bool press;
- e8 o% [" h# O/ j - BSP_TS_GetState(&TS_State);# r4 O/ f" M' C( i1 d
- if(TS_State.touchDetected != 0) {& Z, k1 }, Q+ ~ Y; H
- *x = TS_State.touchX[0];
6 i% k! E) j1 H7 M5 ?9 R5 [4 ]" u - *y = TS_State.touchY[0];3 L O3 F; ?) @8 A
- press = true;# B! V! [ }9 `3 R! O9 b5 S! E
- } else {' w5 E& o' \ @9 ^1 P
- *x = last_x;
* A$ T4 Y$ G n! I3 |+ X6 e& f - *y = last_y;
# _& b- H: _* d7 C: M5 ] - press = false;" U+ ~: T: s3 h. H! M
- }3 U$ b# C3 H p( D+ w
( o4 r/ a8 D1 x- [( i- return press;
; M! J% `# L6 B$ U9 m5 R$ d - }
复制代码 c)LCD的移植分为几个函数,. H8 H# h# c$ H. ^$ w
* O3 Y6 R: y2 A7 e2 q1)一个是用单一色填充矩形区域,这个实际调用的次数较小
/ s2 d1 y4 D/ X( @9 s! I4 H: q' D* f) r) ^3 W* K+ @$ q0 l5 r
- /**
2 y4 K0 F1 V) y# {0 S( x7 ?0 l4 V9 F- r - * Fill a rectangular area with a color1 T9 A: O7 t& f7 o" m
- * @param x1 left coordinate of the rectangle$ m' n3 d, K) b( `7 O1 V) h
- * @param x2 right coordinate of the rectangle# Y! E9 s: M; {! H& Z; r. N. G5 J
- * @param y1 top coordinate of the rectangle0 L, p1 Q2 g" v& C
- * @param y2 bottom coordinate of the rectangle
F6 a2 k7 `9 X+ o - * @param color fill color
$ E |7 |# m/ i6 ~3 ~2 m - */$ f5 U! h3 F( j; Q, D
- void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)& ~! s& }7 T# F
- {
) f% Q# D/ l$ p0 J - /*Return if the area is out the screen*/
+ G. g0 D2 e0 R9 N - if(x2 < 0) return;
$ b2 H" }% r$ d' `" ~* q - 5 j) D8 N+ W' A2 s7 `; q5 O0 _
- if(y2 < 0) return;
1 g, y3 l( K0 g
~, ]- M/ d0 l/ H% R- if(x1 > DISP_HOR_RES - 1) return;% e ]" H/ H5 q# T# i
- - A5 P6 M1 S2 |5 w* E0 t
- if(y1 > DISP_VER_RES - 1) return;
4 [+ f" ^0 j. P) L" V3 C
2 j! S8 P. m$ i: U- /*Truncate the area to the screen*/4 H) L, W9 T0 \/ p1 f8 G3 s
- int32_t act_x1 = x1 < 0 ? 0 : x1;
8 k& Y3 m: c, S) E2 R - int32_t act_y1 = y1 < 0 ? 0 : y1;
. z8 H) r6 O! g! F+ R2 \; Y - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
* n: [2 \! x8 m2 j - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
" Y& _, Q; R' h - . p& e- X: \( }7 p0 J5 ^
- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full))); z. l5 P! O7 R# t! B2 N6 t6 ~9 T2 c
- }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。
1 b, T. m Z2 y7 Q% e& v: f- /**
* y8 D: X4 L/ v& g" j% E) ^ - * Put a color map to a rectangular area/ c$ S( l4 g% o/ n/ _' ?, V2 y
- * @param x1 left coordinate of the rectangle
8 N$ Q3 r7 S$ }! q: y - * @param x2 right coordinate of the rectangle7 g7 e L, f5 S! b* i) J
- * @param y1 top coordinate of the rectangle
: z" Q1 ~3 q7 {: W3 [ - * @param y2 bottom coordinate of the rectangle7 L x8 ?* _2 y& J8 p* D, ]
- * @param color_p pointer to an array of colors, X% Y6 a8 u! A# V. X$ }+ H
- */: u9 u; |: D" {8 `% S8 z
- void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)
' b% p, L, x/ @0 V6 X0 Y! c* l, P% o - {* X6 y4 `; w$ J, U" Y( t# m# |7 _% @
- /*Return if the area is out the screen*/
" c, t3 ]" K7 g! A5 ?3 k J7 ` - if(x2 < 0) return;/ i" y" f! Y- t0 Y
- $ Z, ?2 g' n! U2 Y1 M0 |
- if(y2 < 0) return;& Q9 r( f# h$ S: t! s
- ) V3 Z$ Z3 }8 H) O D/ F
- if(x1 > DISP_HOR_RES - 1) return;9 s4 F$ F: B, B* L( H5 L
) q7 g) a8 B+ `; r% M- if(y1 > DISP_VER_RES - 1) return;- M/ q# x* b/ v. O8 s! L
. @8 d) t1 f" ]; U- /*Truncate the area to the screen*/" k5 @4 }; b7 W, X
- int32_t act_x1 = x1 < 0 ? 0 : x1;
, ]- ^9 L1 W' J. k S9 P1 j - int32_t act_y1 = y1 < 0 ? 0 : y1;3 g* H. r& v. ?5 k
- int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
/ \$ A) P/ d, U6 h9 y - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
3 K! o# Q2 i2 t4 A& O4 y; U) F
4 U; F1 [! S* ]2 H- V. Q4 |9 \
* o) g8 Z, W* }4 I- ?; v- uint32_t y;
) Q, d# g7 r( ? - + V7 L1 c/ }; K F% U
- for(y = act_y1; y <= act_y2; y++) p8 y- E7 r+ u4 w
- {
/ \9 x3 K6 z8 L9 g" } - memcpy(&my_fb[y * DISP_HOR_RES + act_x1],
* u0 \- H4 B- ^* F# T0 Y* [ - color_p,
4 Z! N' f1 Q$ O - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));$ P: s* G0 V. ` K; ^3 n
- color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/# ?$ z) C3 C. _$ E5 g: r! P
- }; `7 T( o' G% @) k* ~1 @: _
- 1 c" p! V" }( j' ~7 a, ~
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存
6 c3 R% g' e; C' }) i- /**
3 s6 S1 S* d# D% i. J - * Copy pixels to destination memory using opacity6 c. o2 E* T/ Z- |& {
- * @param dest a memory address. Copy 'src' here.
2 K, \6 B+ R+ C% H, z+ R - * @param src pointer to pixel map. Copy it to 'dest'.
; s" P. m1 ^5 q) g# `! p. p; [ - * @param length number of pixels in 'src'
5 J$ Q4 V7 q \- t6 e0 |' f0 ~ - * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)( h) {; E3 M5 p8 |
- */
- e3 v# P% H% C9 U: |! I3 v - void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)
+ N, i5 G; B, f. z- f8 U+ K - {
7 N9 I& Q: A( L. q* K, \; n - /*Wait for the previous operation*/4 {% K: Y* ? |& }7 r0 _2 X
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
) W2 r9 F" }1 |
1 K7 k( O, U( Q: l# b% ]- Dma2dHandle.LayerCfg[1].InputAlpha = opa;3 l7 u! h" }7 A8 x
- HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1); j- ~9 y# d2 P( U
- HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);+ b" z% O& i K
- }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:6 a- J* M [, M* w
2 o& }5 r; S; R' q添加到工程中后如下整体如下:
5 t2 z1 Y0 k. q3 p$ p2 W8 k7 I w, B" Z
& I6 c" j3 O& Y- W/ ]8 K; d3 h
p; Z% u J, |7 l. o# A$ `4 k6 n
/ J% f0 E8 R9 B1 U$ |: `9 b* K9 j
: j& S3 w( G% y1 m将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。
( d+ `- A" V1 l4 E' H5 H2 q3 D6 ~/ B+ n5 _3 ?- C
0 M7 P/ C5 G* I
2、运行效果
3 o* W- ~; e& D* ?- V! s! N4 V; r- [5 E' q! C; q+ @+ t9 w# }
LittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可
, E, a8 f+ Q$ r1 Y2 g" A/ Z1 a, F# g# J6 m W0 y0 k& C/ u) u+ v ~# m
" a' k* f# E* E$ a2 F
1 N0 W$ _" x8 ]; ?- V0 L0 ~. a' H O* l8 W
LittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:
# @; c, N& h0 B" F- g7 I" u/ \- B) U
$ o0 y5 B& W* S/ a8 M; P
' d: l0 Q* u/ J+ F2 u( |
1 P' x0 s/ g% Y# w1 V1 n除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。- y3 r1 c8 J5 {9 V/ j! C, q
+ R: N4 _! t/ Z( q# ]' a( X5 n _6 Z& h d
- i: y' Z: u8 {: \% ~
5 I3 w0 p3 B$ U
下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
) D' {" s& ~( z% B+ d0 I
5 X: W* Y! m/ \' ~* ]) A3 B0 D
6 a6 t9 m8 ]! b0 y8 c. U
3、关于LittlevGL5 v6 C8 k- w, V7 J0 `" O7 X+ d# C
3 p; U5 w$ z8 a; ^ LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。
3 @2 ~ z% j1 d目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。/ \2 u- W6 r8 [) G# _
3 O+ P: w" U5 T# R6 {6 M) F
' Z! n4 S. [% x$ `- V* ~
7 d; j8 W1 V5 Y# S" t, r; v; ?
$ d# @" u! z) A' j8 }1 r; n: Y8 o1 M( h
. }/ ]6 p& ^, b
官网和github地址如下:
* f" V/ k. o4 `6 s7 O$ t, y* _0 g( U. T! Z( R% x9 F& y
LittlevGL官网:http://www.gl.littlev.hu/- s$ H( ~2 l) o8 S# x
LittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl
5 p# R' `9 x3 `/ {1 c0 `' F' k( _. y; p2 O0 H/ q1 y5 k
下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。0 [; i, h* H3 I# e# e
How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg
6 ?# U, ^* `* F( {Embedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM, m, t }* [9 z$ a% O
) n1 V4 P1 V2 |/ s1 y 和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。5 p8 w% O7 I; x7 o, E( A
# ]( C M( r# X- F$ ]5 c6 S% m) G& Q( O, |8 @- y
测试代码:: G7 N: T9 U+ x8 |' ` _0 C* ~! {
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。8 l# L* Y0 m$ k* x
http://github.com/littlevgl/proj_pc1 |. G0 Q2 N: ^7 V, D5 M Z& z% {
是的,没有限制,移植吧。
谢谢楼主分享
3 p' h: @9 q% a( i& o! B) @3 ?
如何模拟? 如何在linux中运行?
! f7 k! ]: \ j# a2 Y
' m5 ^$ `' i1 f% d- f
文档很少) t2 o D& z1 \9 i' e& s) `% J
6 B0 d* J. }& R8 J% V9 v( Q
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。