本帖最后由 creep 于 2018-1-13 19:14 编辑
& K$ L! a. b7 P
- d) D! ^. l/ i- ^7 T. |* i 推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):+ l6 u2 p1 e. O
0 @: ^$ F, H+ e$ r5 J: x$ j 开源GUI LittlevGL V5.0版本移植
1 R7 Z" ?- J7 {$ S8 w0 ]; R& x, O, W* o
6 e, h L5 k: n6 N
LittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。6 X6 ?7 [6 s0 [; d; A
" d d& g' R8 Q4 L% {3 x o
1 j5 k# f- d- X. N, F2 y/ O
下面是我在STM32F769-DISCO上移植的演示模式的效果图片.
1 l, l% r X' G7 r( p0 b" Z) B2 b$ W# l/ \7 w& \; P
+ R, H5 g) w$ I, b4 a2 A' o' _( h$ r2 x
: T8 {7 O9 e6 I0 J
$ \( H' n# v8 W
主要控件可以通过下面的图片有个基本的了解:
0 o' i* D; u$ N# s: J) n* ?1 O3 X' n9 @4 ^! ~" L$ m$ N \
1 L# D6 A& s7 K: r4 V: T
1 G& G7 h1 V0 q! f- @1、移植8 f& n( |! r+ v2 i/ K$ ]8 A4 U
3 j. x9 P$ l/ @1 [1 t" B! OLittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:
& ]: P! w6 i* p9 i( k' ^) `( }
" n" S& f' a8 [5 M9 `
X6 u& m9 h2 O. D5 k
也就是下面几个函数:
# P! R$ V1 o: n+ s; d+ ]4 W4 \3 u
& s/ @3 k' \9 N0 p; ~7 Z2 B/ N" W1 I- d( e1 K. E1 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
- . c) b( M' g: V& V/ p# k2 B4 I# H
a)systick的移植直接使用的是HAL库里面提供的8 g& P% {. b& ^
! Z$ V- H4 T0 C7 R9 l+ T0 g' q- /**
% y' r7 Z2 a$ A- ]- _5 {/ d - * Get the elapsed milliseconds since start up
6 a/ Q; V0 u' Y8 Q - * @return the elapsed milliseconds
% S" e1 |# e# X* j, }( } - */! R9 b1 l# n3 c
- uint32_t systick_get(void)
8 p2 d# f+ }/ I' W6 o# y - {( Q. e+ `* t2 |9 H
- return HAL_GetTick();
9 D/ v+ d1 H; p$ T" c9 ? - }
( y: O, }% q. h; x - /**) o. q0 m/ M0 j2 X3 p# j
- * Get the elapsed milliseconds science a previous time stamp
9 d% h. b6 a# p - * @param prev_tick a previous time stamp from 'systick_get'
2 v5 L" X$ q9 h8 r' F. ^0 o - * @return the elapsed milliseconds since 'prev_tick'
. B8 n+ u; k6 o/ f6 _ - */
# P1 d& i& p9 T+ Z - uint32_t systick_elaps(uint32_t prev_tick)$ G! o& J4 @- `8 o/ [, a
- {/ B- H8 X% F( V) r: R2 \4 y9 D
- volatile uint32_t act_time = systick_get();
3 W9 s: r0 A; l! a) Q, @/ M - ; G' E8 B- h' o, R
- /*If there is no overflow in sys_time
8 U( N$ I$ R; Q4 Z+ _- C - simple subtract*/7 H4 t# t7 H0 P9 a2 R
- if(act_time >= prev_tick) {8 O* G# Q$ ~* l; g9 E
- prev_tick = act_time - prev_tick;1 J' O5 h# U- ]% o' u
- } else {
1 ?) h' n- x% `4 u, z& S0 V - prev_tick = UINT32_MAX - prev_tick + 1;
% |% O5 g7 t/ r* B1 Y7 X - prev_tick += act_time;
% e5 r- I( J; ~. s - }
( w6 h) c |, ~ V - return prev_tick;
( t4 A( x* y1 y) |; X; p6 d& q - }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果
5 W' r" T v* K) x' L1 v% w- /**3 ~8 {9 H3 ?, E( w
- * Initialize your input devices here
Q: ^/ Y5 h. E8 g9 u* e6 R! r - */) c7 l+ R, t3 d! @# X% S6 C
- void indev_init(void)
H( e2 Z, ` D - {
; d# @+ T' B0 @% F - BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);
l% O% g6 |# P4 y - }
, y) s6 }. O2 r - 4 K& q" b* [6 n& x! C# Z
- /**
( O% ^2 M R" h9 b - * Read an input device+ a6 ~7 j" h7 m# `0 ]9 j9 C/ n
- * @param indev_id id of the input device to read
- O/ g6 |. H, F- y2 L- N8 C - * @param x put the x coordinate here
; d6 e; f7 Z+ ?% N( ] - * @param y put the y coordinate here6 s6 I# C& E8 t' W, c
- * @return true: the device is pressed, false: released: y9 D, z# n7 Y1 r9 Q
- */4 J/ U) g; l$ N
- bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)
7 @: _1 P+ A; `* m W$ H0 U- D - {
# L& a$ r- V6 b* V- | - if(indev_id != 0) {
) }+ T+ o8 q5 f( K% W7 ?4 R - *x = 0;
$ n! H h' x; e7 h' w/ ^% _% g) W - *y = 0;
( c4 e( R6 }9 c( l8 O" M - return false;$ n1 h. W* v2 Z& U! W
- }3 h5 v- V$ ^9 i$ [
- static int16_t last_x = 0;4 k7 R9 i0 c6 z
- static int16_t last_y = 0;1 a8 x* L0 `5 S8 U
- bool press;( ]& g2 _/ T4 c5 U4 l, [
- BSP_TS_GetState(&TS_State);
; O% D! R% h/ C5 G3 Q - if(TS_State.touchDetected != 0) {
4 v$ z, @. V. J$ S6 G - *x = TS_State.touchX[0];& U8 z! U3 @9 n3 a: X7 a
- *y = TS_State.touchY[0];4 V+ p5 l# }: V+ e
- press = true;( b- i7 `' ?! z8 d* t" J( V0 F
- } else {
6 U: { u, m" ?- n: |4 e5 Q - *x = last_x;
9 E: t) S& T+ b4 ~0 n - *y = last_y; K0 M" ]1 q+ l3 P; [
- press = false;
" l& A# V! v9 i" C5 V - }3 |# ^* \ [8 m+ W- e6 T' o
7 @ q+ F: x! I" q* K6 |( j- return press;
1 n* O7 ?* E' w2 ] - }
复制代码 c)LCD的移植分为几个函数,* m% H, Y& y/ y0 I
% I, t; k( X9 V. _: I1)一个是用单一色填充矩形区域,这个实际调用的次数较小7 [* f3 d6 v0 K- U) s7 k {
. O4 w: Y S1 }" Q7 I% @
- /**2 o, F8 p. E0 |* P8 u, ]) n
- * Fill a rectangular area with a color- N+ W& u, x' Z. t9 m
- * @param x1 left coordinate of the rectangle/ T% X) t. B0 t6 Z8 c
- * @param x2 right coordinate of the rectangle
% ~* e' O* z1 G7 r6 `& X- g - * @param y1 top coordinate of the rectangle8 K; o, L+ D, Y$ F
- * @param y2 bottom coordinate of the rectangle9 `# t5 W2 W5 i( x
- * @param color fill color
! h" L# d# Y0 R! k+ L8 Z# _ - */
* E, F+ t. f. f - void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)
. k# A; i/ z* r2 e+ z. o - {
" i/ ~% h1 f$ U8 D - /*Return if the area is out the screen*/* N: X2 E$ k- \9 D4 v
- if(x2 < 0) return;; c# A' h! e% `1 ?% r$ }
5 t7 F3 C- T" M) L0 c) C$ h- if(y2 < 0) return;
8 k6 h* t- U+ P/ e' E
' v1 o4 j* f4 I2 g0 j# O- if(x1 > DISP_HOR_RES - 1) return;6 u2 q. g, H/ I/ C8 G' {
- % i0 `/ n* k8 S; c: |
- if(y1 > DISP_VER_RES - 1) return;! u2 L$ M" E4 E- q/ l/ d
- 4 t- s$ @1 B; ^! u5 i
- /*Truncate the area to the screen*/. z7 i2 z K9 Z2 n2 A/ S. q5 f
- int32_t act_x1 = x1 < 0 ? 0 : x1;
. ^; S9 V5 w" f - int32_t act_y1 = y1 < 0 ? 0 : y1;
/ H$ d: x7 R" W. ]+ ~2 s - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
. Z% ^0 r, K' j4 o( y - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
' C6 i0 z/ }" b/ X
9 d5 N- ?. n% W1 q( P- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full))); v1 y8 L2 ?# ]3 q
- }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。# E; E$ z1 c! l% B ~+ R: }
- /**: x- l% A! B( o0 U3 B
- * Put a color map to a rectangular area0 a: x1 T( p9 t& l2 j
- * @param x1 left coordinate of the rectangle# y" ]9 w0 M6 ]! v
- * @param x2 right coordinate of the rectangle, Y0 \& k1 x8 C) X0 E
- * @param y1 top coordinate of the rectangle+ D4 R5 E: L" Q
- * @param y2 bottom coordinate of the rectangle
% [0 U1 a! I8 d( K/ f( A) h' |8 b - * @param color_p pointer to an array of colors8 y* ^, u$ G' j `( O
- */6 ~5 o& B" p! ^$ s
- void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)
2 Y0 @/ C$ `8 {! K+ G$ U - {0 j! W/ m4 H) M
- /*Return if the area is out the screen*/) M. s5 X3 r3 S! M' w
- if(x2 < 0) return;7 c: _7 B3 N4 {2 U+ K
9 r: j" Q+ v2 A4 a6 a. v8 {- if(y2 < 0) return;" w! ^! _+ o. v. @1 s8 s
( j# e$ ?) H1 ^- if(x1 > DISP_HOR_RES - 1) return;
3 P! E6 o; ?! f [, S- Y$ d
, S$ f6 E+ K" c( J3 V" L& ^- if(y1 > DISP_VER_RES - 1) return;8 B: h& b J( t- ~3 h1 l9 I
% T k6 ^1 {" q [- /*Truncate the area to the screen*/0 s4 L: O" m6 B
- int32_t act_x1 = x1 < 0 ? 0 : x1;
: P7 g( J. U" y0 @) ~2 L( Y - int32_t act_y1 = y1 < 0 ? 0 : y1;
0 `8 l& J7 W; r N( D5 d% O - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
2 q) ~. ]9 Y- ]% l6 d% E - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;! j3 L6 m) \2 L2 R d1 D
- ( |0 |' d6 y& b! V8 U
- 4 x5 s* |8 h8 b
- uint32_t y;
* Q$ n% I5 X/ }, U3 O) b- q
$ j8 f( W9 C/ x# p+ m% t: P- for(y = act_y1; y <= act_y2; y++)
7 D) @ r/ C+ C9 s- n - {! I9 r3 W; t. N. W
- memcpy(&my_fb[y * DISP_HOR_RES + act_x1],
- f+ |* M# T! z$ n - color_p,
% D" K' H* E! V8 }4 ~! f* c - (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));" N6 h' U5 q* ^
- color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/
- {7 m% d1 n+ n( @, e; T - }
x8 Y* S2 J- X4 G - + J0 b" d6 ?/ U1 ^% q8 J4 Z. j
- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存/ G# N6 k! @1 w4 I' M* D* T
- /**
8 n) ~- V/ P# v. n7 A; F - * Copy pixels to destination memory using opacity: Z) p: }' W; K
- * @param dest a memory address. Copy 'src' here.
# y; @& S; e% v9 S+ N ^1 _ - * @param src pointer to pixel map. Copy it to 'dest'.
+ R% t1 k8 U5 q' F8 I* D - * @param length number of pixels in 'src'. A; }" \. \8 ]6 U4 F
- * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)* [ {) a: A9 i/ D) z/ p
- */' l* |$ C: F I0 {+ V
- void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)/ P6 r; X* Q0 R, U6 B: j
- {7 i- v4 [: z: e( N8 Z3 \
- /*Wait for the previous operation*/, l- R& l' ^) K6 U/ U4 Q
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);0 M- P! c0 G: K) e
$ }+ ~. D1 s: l& t7 W" p& Y- Dma2dHandle.LayerCfg[1].InputAlpha = opa;
- V; v6 m0 ?8 |( x1 M+ ~ - HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);9 }' ]. m) H( M( G& F+ }! R
- HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);
! c. I/ c* g+ W0 b6 R - }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:2 F; {8 V1 M, l! }4 d5 N* K
6 L! H a3 H/ |% V9 s7 v
添加到工程中后如下整体如下:
2 M* q8 w V0 ~. T
7 W2 r1 ^) b) P
% @3 b* Y" W6 X. U# l, R Y/ T( R- K' Z" x$ I! B; l: e$ G
- A4 Y$ E& I* A& [7 b; \! W
+ ^7 n# X; x8 p, m9 C1 o, x6 o* d1 f将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。
/ o/ ~# w; o& j L0 s0 [ s2 {3 c
3 A7 p% a' @+ m) ?
3 _' ~% m* |1 b8 P3 v8 i2 a2、运行效果 ? S& k1 P2 r, d
% X) ~7 x! D: L _* O, RLittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可' {8 _% x+ D) i
) |" c# i' E" k$ S9 b/ c2 n+ T5 {) ]- J
0 W+ a+ j# U7 b: e+ O P1 O
9 K4 a8 X1 F+ I X* j8 U( |' KLittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:
, @# }& M7 L/ L2 v7 b6 O
( J( u# K8 \( Z8 j4 }5 ]) j- e8 R7 x; |! A
' ]1 D4 T. ^4 ?! S9 h! z1 ?! C
3 A5 |2 I' i8 R- g' L# L除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。
5 Q @* ~- A* O
" R8 s% {, z4 q! G2 @- n0 O1 t, ~7 N' X1 ]. V
5 ?0 n4 n7 u$ u8 @6 N& L3 ?( a4 P
% ?1 a! m4 O0 b5 B
下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
1 b$ r3 {) @& w/ b( a$ U
" x" ?- O* t0 S. m L2 u7 D* J6 W1 C1 F% g$ }/ v* {2 I1 \1 m# l( `
3、关于LittlevGL1 z3 ^7 g& M2 b5 H
2 }- g6 G* W ?6 l0 [# W' \* v
LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。$ e9 x4 q, Q9 i
目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。" p! v6 r5 l+ g! U$ C1 {; ^, S4 {
# r/ J1 W+ {" T# O H8 d; F$ {* X) c9 q/ B" W s
$ `. B# ]" u8 Y9 b: n
/ q `* P& X' a9 X6 T- Y7 O0 \
" m3 `( O3 G) d0 p3 m( O9 n6 s- o. V# m3 y& t* T( h' ?5 A
官网和github地址如下:$ S% X, Y U( q( M/ R% v7 [
& Z( d5 n1 h) E" H* l
LittlevGL官网:http://www.gl.littlev.hu/8 C) { z {5 Q8 D7 c2 {
LittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl
! G1 F) h2 l8 F( A
6 ^2 f2 G5 Z9 G7 X下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。' G5 G, r5 }- |% q
How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg
7 L" [4 f$ u- |6 \& ?7 ?Embedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM! H) {. L+ r* g& _2 [# k
4 h+ D! M, E. K 和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。4 ^( u! |8 J" P0 p
7 \! f$ {- I& E( K* K) H! V6 ^3 `0 Q# C3 I
测试代码:- s h9 P5 U$ }
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。; e& @, d/ [* @+ }+ R7 L1 S) E8 f! U
http://github.com/littlevgl/proj_pc2 `$ i0 B4 F" Y' }# w
是的,没有限制,移植吧。
谢谢楼主分享
如何模拟? 如何在linux中运行?
文档很少
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。