本帖最后由 creep 于 2018-1-13 19:14 编辑
( e1 E9 a. ^+ m1 a- ?8 ^. b+ y p) L$ O, |* I
推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):/ \* Y4 P+ w# r. {8 ?" w
/ d0 P+ f- D% T
开源GUI LittlevGL V5.0版本移植
, K& d1 w5 E* n8 j6 \1 [# f6 @3 j p! ~* `
% n2 W$ k" a) P! i: q
LittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。
u" A' N! C; ]& x7 ?2 K7 U" g5 x/ [2 B2 A3 }8 q( O
7 Z3 B) r7 V1 l& P( }下面是我在STM32F769-DISCO上移植的演示模式的效果图片.8 F7 K4 i; r- L5 t. z
8 m B0 D; `' u- F6 z( E3 [ Y9 f" i4 [' p/ l# m- Q
- @( Y$ s |* N) b
1 Y7 `! u6 T' _0 k. w8 Q
6 r( ^6 |1 D' n& [主要控件可以通过下面的图片有个基本的了解:
4 i! t# z1 P; C3 `, N' O) Y& L: ^5 O5 ~5 J. G# `! M0 `
9 g0 j* D2 x+ l/ c! m
8 Z2 Y+ z4 l1 ?1、移植, z# l/ H' L- W3 p
, R" d' I- j4 z! |
LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:
& X0 W) V' X0 g( Q* N& s3 ?! w
& B) t, T' A8 E; m0 D w! @
& P" b' o' k0 B- t6 d也就是下面几个函数:* |2 V* H. J: d& ^0 J& M
" R& q6 d1 p& i
: E8 D# a7 _* u
- 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
G1 S1 L$ [) P( r$ x* i( c( r a)systick的移植直接使用的是HAL库里面提供的3 {: A2 C" q( O( p! a
8 \$ O+ \. O: }2 k; l2 V
- /**
+ X5 j0 O+ t! w' I' i/ R8 i% ] - * Get the elapsed milliseconds since start up
`7 K; J# r a' G& H' k$ u# j - * @return the elapsed milliseconds; h( t ]' x; K, D+ r0 Y* d% p
- */) z _6 e; O5 w6 [3 C6 M9 G I( Y
- uint32_t systick_get(void), X& G: G( d- B" E$ x- }+ g
- {' s; o9 m# M9 }- ?" z) {
- return HAL_GetTick();
0 e" z, B: ~' U& }; t4 i7 ~7 B - }
7 I! [8 ~/ R A5 ]1 c - /**
: |/ d# J+ V8 H - * Get the elapsed milliseconds science a previous time stamp
- k7 M1 }( Y$ P- J$ N7 E - * @param prev_tick a previous time stamp from 'systick_get'% Q- x4 O; |4 }: p: n
- * @return the elapsed milliseconds since 'prev_tick'
( H8 |5 g+ p8 N F0 W; X! E/ w& N! U - */
. `' ]3 n% w2 ^; o - uint32_t systick_elaps(uint32_t prev_tick)) e9 ]6 }; n; j
- {
8 L' {8 G( ~4 }5 i/ Z p, m: L9 y - volatile uint32_t act_time = systick_get();8 u% E2 L# H. ^$ K; S
K8 ] ~0 ?* B' q$ e* X* j$ O- /*If there is no overflow in sys_time6 X( o4 o& w7 s
- simple subtract*/, ^# ^# t' e! N- V
- if(act_time >= prev_tick) {
+ P7 p2 X; C- D$ K3 o - prev_tick = act_time - prev_tick;1 [' @" g( P( |& R0 \- }* w9 k
- } else {
% K' L* m8 K- o) Y - prev_tick = UINT32_MAX - prev_tick + 1;( @ h1 y6 g: O B# v
- prev_tick += act_time;; {7 g$ A5 ~* t; E9 k
- }
: S; i8 m8 I9 ~7 s) c - return prev_tick;1 Q1 R. ~) S2 F2 | h
- }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果
; Y4 g1 ] n5 H& @ z1 l, x- /**
1 t! |( M: P" f" }+ m1 I - * Initialize your input devices here5 b/ T \( w5 n
- */
$ [/ n" Q8 q g6 B! P7 } - void indev_init(void)
5 H1 J8 s: o3 \, D0 g$ T) s3 e - {- x2 e- e7 M4 j( |
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);8 o! ?/ j/ r% l! E& {
- }! W3 d0 i5 F# x% v( G
- ! n2 B- w9 @6 o$ M
- /**
9 Z, _# f. _4 E1 u - * Read an input device$ e# F0 r- C1 u
- * @param indev_id id of the input device to read
2 S& _5 N# d! ~. y! G! C - * @param x put the x coordinate here
3 l8 L' z! O9 ~' Q - * @param y put the y coordinate here
9 g: L# H# ^$ y. q' P: ]% H/ I4 f - * @return true: the device is pressed, false: released# h+ e1 c0 D" s& \2 G6 G5 ^
- */
, X1 _, Z! J4 ]1 U- z; X7 U - bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)
- S& b8 W; s8 e; x. G* O1 O: C" Z - {
. i& P% `7 `6 k - if(indev_id != 0) {
# D# i* B, u7 X - *x = 0;' r7 i1 Q' B* `" P5 B. `
- *y = 0;
8 r" S- F p8 D( Y$ {( J - return false;7 v$ Y& R* Q; P* h
- } n& R9 I) h9 S( o" g. ?; A. A
- static int16_t last_x = 0;' H$ x9 Z. A! E3 `% m! L. f
- static int16_t last_y = 0;5 n2 s% V. N+ D8 E$ e) q3 R: ?
- bool press;
0 Q, H' ?" t2 c - BSP_TS_GetState(&TS_State);
4 ~- A2 W# { A4 Q% I/ a1 ^" t2 X - if(TS_State.touchDetected != 0) {2 Y+ U/ \# b$ l: i6 P: ?: X
- *x = TS_State.touchX[0];* x5 E; C, J3 Y* ^3 c' x
- *y = TS_State.touchY[0];3 U6 b3 I0 f* W* {+ u& L* P; S
- press = true;& B5 d$ e9 Q/ d* T$ v
- } else {" v' ?4 S- l+ C- w
- *x = last_x;
# @6 C. w- Q: t* C8 S( u - *y = last_y;
3 W) t) L2 b+ v0 U: |! b- @ - press = false;2 l" C, N/ ]% l9 l0 a8 A
- }+ N$ b2 |0 O z/ u
- 6 D; Z' \; f( V5 e' V2 ^0 E
- return press;% Q6 e, \! ]2 `' ?- w1 Y. x C
- }
复制代码 c)LCD的移植分为几个函数,
% m2 k; W/ W3 O7 o' T+ l% W4 S
/ |6 j# P; ?$ ]2 H" L1)一个是用单一色填充矩形区域,这个实际调用的次数较小. T% _3 g8 p2 c1 c- R0 s
6 E) d" f3 j8 Q/ N& ?- /**
& P w8 U: P/ n - * Fill a rectangular area with a color" `0 ~: x. x8 C- J8 r$ h2 f; @: U8 @
- * @param x1 left coordinate of the rectangle0 K5 U* R* Y% f- _% J6 `
- * @param x2 right coordinate of the rectangle
. L6 u2 j0 B0 M8 Z. w& T - * @param y1 top coordinate of the rectangle
$ v9 }! b6 e$ a" a7 q2 S - * @param y2 bottom coordinate of the rectangle
7 x3 B" L' {: m T+ |- M. ] - * @param color fill color
( N- I2 y6 N0 W5 T8 W - */
1 M3 U5 ~6 I1 w$ H- c - void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)
- Z$ H J. @; n8 S - {" E: ?3 w* h# X$ ~# X9 K
- /*Return if the area is out the screen*/ @& _* G/ Q0 Y
- if(x2 < 0) return;5 m3 S* s5 Y+ f8 A0 O4 H- N8 H2 ^
7 @; ]; d+ K @# S- if(y2 < 0) return;
' o% M9 V; E( y
) J5 n6 T; ~) T6 d% Y- if(x1 > DISP_HOR_RES - 1) return;
( v3 Q5 Y! d) s+ S/ s: Z Y; l0 P - ; P& t& X+ h4 y$ T% m) `6 n
- if(y1 > DISP_VER_RES - 1) return;
( i) k1 V! m# U7 o' s - ! _# D. C4 u; o1 K
- /*Truncate the area to the screen*/
$ p9 Z% x: L0 Z# R - int32_t act_x1 = x1 < 0 ? 0 : x1;! X9 [# y3 g6 L3 u f1 T% F7 M
- int32_t act_y1 = y1 < 0 ? 0 : y1;
- O/ P" m& s. e$ R& ?6 s - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
K% i% X% f* L X2 E, j - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;8 F! n2 E7 B7 ?* u+ o
3 I) i' [% O( k& Q& Z8 B8 u& f- W. D" k( C- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));- J) e1 M3 L9 e" l9 V8 y
- }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。
4 E; |" H+ D& ?" I- /**
9 {& [; f5 Z! K% Z) M0 { - * Put a color map to a rectangular area
" j% f; a6 y$ t2 C1 a9 J - * @param x1 left coordinate of the rectangle
- f' K: A8 \' y1 X: }) { - * @param x2 right coordinate of the rectangle
" m- b8 f4 D: `$ r8 V - * @param y1 top coordinate of the rectangle: x8 d6 b' a. g
- * @param y2 bottom coordinate of the rectangle/ @$ F( B& q- [4 Z
- * @param color_p pointer to an array of colors
* G: w% g1 ~7 a6 G ?# } - */0 q8 @/ I9 x! g7 {- c
- void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)
( }$ x4 m3 ]( W4 k& H6 s5 Z - {
5 D D/ [1 r9 R5 e( x% f$ Y - /*Return if the area is out the screen*/
& v6 s& i- |# o - if(x2 < 0) return;7 _; w: ]* T& y& x& @$ a$ D9 D
- " l% t* w. t: T! Y9 i
- if(y2 < 0) return;
2 [: g7 ~7 d6 q3 y+ w5 u3 ^/ n8 M
P7 Y4 `8 L8 d1 S- if(x1 > DISP_HOR_RES - 1) return;$ k: i, e. C9 H1 ]6 K
- 8 H- |) P; H! o( X( n4 w
- if(y1 > DISP_VER_RES - 1) return;
( \1 f) _, U5 w" L2 x% G
# n! Q; c: b w- /*Truncate the area to the screen*/
: O1 D5 }6 @4 B2 ]. m1 J+ Z8 y - int32_t act_x1 = x1 < 0 ? 0 : x1;" L" z% k: E: \4 M3 o
- int32_t act_y1 = y1 < 0 ? 0 : y1;
, g& L1 U' i" ~ - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;( |8 T3 x6 ^; E+ N
- int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
" ?& b2 R3 O) _1 v - 4 _% I- n* i4 E: u
; v! r$ {9 p$ t0 {; _( _. {1 a6 J5 A- uint32_t y;
2 U6 \6 N# i* Q+ Y, h. s3 P
) G* b, e* z) I( N0 a- for(y = act_y1; y <= act_y2; y++)% e/ V* T) P6 b8 G8 X- v8 x
- {
7 q' F) c1 l* S: u+ S( H! @& Q* H - memcpy(&my_fb[y * DISP_HOR_RES + act_x1],: A/ D. P( @& {
- color_p,
, J( p4 `6 R+ u - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));
0 \' e" V* z+ ] P' w - color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/; P7 _. K+ x9 Q9 s( |1 ]
- }0 ~+ C) G$ E0 z8 K! Q" P, a% I0 y
- , C' F/ a o& x+ T1 i% G* s
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存( i& o: @) M" b- l
- /**6 U" h2 {( c I4 |5 ]
- * Copy pixels to destination memory using opacity
# b" b. ~: M4 Q% h% M7 g - * @param dest a memory address. Copy 'src' here.
Z8 O6 l/ O5 ^, s6 U - * @param src pointer to pixel map. Copy it to 'dest'.7 D; ]' T) e) [2 _4 N
- * @param length number of pixels in 'src'
! D8 C! F5 y& M. s/ D. @ - * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)) j+ l- i a, A* _, \* N/ L
- */
1 J( q8 v& _* U3 ~ - void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)
. D- u$ l9 S3 N" B/ a" m! O# J - {8 |% ? _3 }+ h6 n- @4 U: z" b
- /*Wait for the previous operation*/ I' k0 e7 Q- R
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
. V; O# b. b/ b
4 M# n0 @2 F1 i# t5 n- Dma2dHandle.LayerCfg[1].InputAlpha = opa;& S o$ R/ s) m8 o0 ~
- HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);" P1 h/ R; ~, B2 p
- HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);3 G$ m/ f. ` p
- }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:" a8 f. A! e% v( i3 m4 i7 X
) n$ U0 N4 R! H5 \3 G0 j
添加到工程中后如下整体如下:# a1 c# o, |2 V
8 T7 s2 e* L% x1 O
6 R& w) \0 }4 _. h* v% u1 T7 d9 ]; q) E" p, {& q
" z7 }9 [ ? c0 E1 h0 g0 P& r& ?
- ?; V4 R% ]: C$ m* ` m8 `将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。
2 O9 ~: l/ ]5 s$ ]
" H. T2 |" ]* \; E1 ~1 ?5 z8 S; n
2、运行效果+ r b9 v9 `4 d3 z! m# z! W f
/ l/ [3 T: |, ]% d }
LittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可) l# N' Z" A8 ?' }/ r2 e/ h
: N! Q5 b. r) i
4 X, f6 E- v8 W3 `- H
+ _8 ~3 W8 N! P% `- K
4 W }/ X1 G" K) }! K8 @/ b: d
LittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:4 \8 _$ Z* z9 h1 q0 H% a0 i
: M& G% h( q1 {3 L2 s2 L6 x {* k2 Y( ?7 h3 U O3 \
~: L3 V5 n! _% S1 U
3 b: A$ j( E% o7 A/ a2 q" j除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。7 u' M, \3 S8 w4 F. F9 I
8 ^* O1 S( a' B0 F$ H% e1 j2 ]7 b) w5 ?) V
2 P1 j6 [# l' C. C" M
. H' W) L* C! c6 |' P! ?下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
, y# T# g' ]6 e. P% {2 J. O
6 k9 @# B" `/ K" G
5 T8 X, j6 v0 X1 Q5 D3、关于LittlevGL
& E+ c( [# j, x. Y K& u
* U" q( f& ^5 {5 u' O" Z) O' d/ E' _ LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。
/ C9 F" [( r: g: H" k" q目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。
/ F, B" g7 \& i# e
3 E% ~% {. \" ~
6 Q' j( H u5 M. a
0 n) W) e9 ]3 F' q, j- S5 u- a
" }" Q& `$ Y4 r& w% {/ k) Y- S! B9 h- |& H( C1 g0 p
% g, g) M7 U8 R- r官网和github地址如下:
3 r/ I3 U9 w9 s! F/ v' O. G" E4 C% w; s {! \, c
LittlevGL官网:http://www.gl.littlev.hu/
- T& t/ h- V4 S1 TLittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl
0 J9 P7 o" x: G$ z; t, @/ z6 G; |9 [* k6 Y, d$ U; [6 A' @
下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。) X9 V X O2 }
How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg/ ]; u- m$ k5 D" X. |
Embedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM6 i3 @- F( a: N1 Q5 Q" H
0 {3 t# @8 d. R/ T
和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。
* U- u& A1 g4 b2 ]
) C$ }4 f) r' _( z! R
; t7 P6 ]4 Z0 X/ ^测试代码:: c" s) l9 E$ x, O. _
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。
http://github.com/littlevgl/proj_pc4 i: X2 q/ X) Z
是的,没有限制,移植吧。
谢谢楼主分享
* \* L2 S. C1 F: \
如何模拟? 如何在linux中运行?
文档很少: M1 p* R4 L' y5 N' q w
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。