本帖最后由 creep 于 2018-1-13 19:14 编辑
9 y+ h5 b4 [% a
- V C. E% N- g* O- o; |0 x+ J4 d 推荐阅读最新的Littlevgl移植(更新时间:2018-1-13):
8 r8 W/ g( Z x [0 ~( t" j, s5 Q/ Q; f+ e
开源GUI LittlevGL V5.0版本移植 & c0 k3 g+ g K
: ^3 ^3 t* m& e6 ` Q
: a: |( r/ L3 }- LLittlevGL 是一个开源免费的GUI,支持触摸屏操作,移植简单方便,开发者一直在不断完善更新。LittlevGL 自带了丰富的控件:窗口、按键、标签、list、图表等,还可以自定义控件;支持很多特效:透明、阴影、自动显示隐藏滚动条、界面切换动画、图标打开关闭动画、平滑的拖拽控件、分层显示、反锯齿等等。9 o2 ?: D0 k6 k6 v) w
& x( u' q& N7 T$ O) w6 {
# |- g( T6 Z) r下面是我在STM32F769-DISCO上移植的演示模式的效果图片.9 T- Z. _( E# Q* T3 w( n) D
& X; F+ T+ z/ X# }) g6 d
8 P, s- d' a2 V- I; L9 |% F- g! V8 @& L- s# h7 ^
4 g# P+ S7 Y' t, @- N
, H; R$ ~( G( J" B* X c主要控件可以通过下面的图片有个基本的了解:+ Q5 j7 W* {# S3 i" J
3 b8 C7 f, A3 G7 L4 ^; I" R0 z( c( T1 J# Q* a" F l6 ~) `5 s. H
+ J2 R0 D! x* ]. }
1、移植
* n Y$ D; w5 K' }3 [$ k* d' K9 x/ D$ U% Y+ \- w6 j* D9 |' D) P) u
LittlevGL 的移植非常简单,用户只需要提供systick、触摸屏、LCD显示接口即可。源码里面有3个文件用于分别添加这3个接口,具体如下:1 R: { D& \& t% Y
4 z# X; z6 C* f
* X6 y& W; g: Q [) n也就是下面几个函数:/ ]; n, d2 D. h- W/ ]3 F
$ d ?) q( B# n n9 p
/ b1 p5 O8 ?+ h$ 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
- . p; J, y, R" u5 C& R1 n
a)systick的移植直接使用的是HAL库里面提供的; u& D' B3 A2 C! w: `3 L
' y3 ~% M- P1 d, V5 ~4 Q2 Q x- /**
1 N5 g" d$ b1 B% D7 R* e - * Get the elapsed milliseconds since start up
1 p/ Q1 _; A% H- x) q$ |; g ^ - * @return the elapsed milliseconds3 Z7 K) G: `* l$ ~! T
- */
; o- j$ T+ z& E: d: p) I - uint32_t systick_get(void)
& Z$ \0 ^' |% w% v$ h0 f - {! x4 U2 t4 M4 V; C3 ?* R
- return HAL_GetTick();
) K/ q* `9 k( z2 \ - }( @% N: E; T1 [- {
- /**
$ k) l- N" y. @! K6 G - * Get the elapsed milliseconds science a previous time stamp5 h8 ~- H: s+ r
- * @param prev_tick a previous time stamp from 'systick_get'
! S F2 A& C* e - * @return the elapsed milliseconds since 'prev_tick' s- q! t1 Y$ n% ]+ D
- */3 @; f6 b" E) Z9 k/ }. Q) i
- uint32_t systick_elaps(uint32_t prev_tick)
4 g e+ h6 N: Z& A - {
5 x3 _/ v0 P. a1 z - volatile uint32_t act_time = systick_get();
& L2 v4 {4 [ {- Y% {0 @+ @6 D
4 Y: l* s" i& y! k" r, ~- a# g% p- /*If there is no overflow in sys_time
, ^* E) M% i7 \2 s/ q/ F - simple subtract*/
# k& e' \* J: J# k3 e3 A" j - if(act_time >= prev_tick) {1 Q7 D' s7 f$ W; ]! x1 X' m
- prev_tick = act_time - prev_tick;0 O* S5 s$ p/ k2 V- V0 `
- } else {8 B' ~) ~- `* Y9 m) p, J9 x3 t1 ^
- prev_tick = UINT32_MAX - prev_tick + 1;
2 i$ n& ^, V/ T, O+ w* s! _ - prev_tick += act_time;
v/ G3 Q! \9 L: ? - }4 m. n: n* ]: N9 I; T6 v: Y+ f- Y
- return prev_tick;
5 y7 N; a" c$ ?- Y; \5 s - }
复制代码 b)提供触摸屏的函数,用于初始化触摸屏和返回触摸屏扫描结果
. A( G+ B6 H, p' }* q5 e8 B7 B# C- /**
/ p2 {9 m9 f" g0 }" b. D% ] - * Initialize your input devices here
1 c9 l' J( a* I* ^$ x- U3 y( ? - */
: E; i! }# i; [ - void indev_init(void)
, e* f1 f9 N9 H$ q' l0 b- v - { v" E3 y* d: u2 x: P C
- BSP_TS_Init(DISP_HOR_RES, DISP_VER_RES);
: x8 L8 E, x) ^- i- g - }5 F0 i7 _$ g6 Z& f
7 j( _" K) c# y- /**
) J& Q' m. @6 G# @0 ] - * Read an input device: K! ^6 E: n: q) y6 f; I$ P# L
- * @param indev_id id of the input device to read
2 N- E, U3 Y2 e/ y5 v - * @param x put the x coordinate here
+ o8 A' P+ E: A& `. f* ^ - * @param y put the y coordinate here
" y5 @8 ?; n% r( Y& a+ I - * @return true: the device is pressed, false: released- t, D7 y5 h. a1 y) L/ k0 R
- */9 y7 b3 f& D, i2 K, U9 Q) q8 }
- bool indev_get(uint8_t indev_id, int16_t * x, int16_t * y)
4 O5 Y3 I( i, D$ y) y3 T+ r - {, [, x0 Y8 e c: ]! z
- if(indev_id != 0) {7 ^! P/ R7 p% a0 K3 q$ k8 ?
- *x = 0;: O! t' d1 {% O4 I
- *y = 0;4 Y6 P* n) `4 b' [
- return false;* r/ E6 d7 t( U' S+ K9 l; w' Z
- }
) z8 k( L+ f/ A/ H. U* k* C7 M, n - static int16_t last_x = 0;
' D- ~4 ]& h% K7 g: Y+ l - static int16_t last_y = 0;
) ?# c5 d$ _4 {/ T; \ - bool press;! _; Z) ^) c1 x6 w1 F5 x6 Z8 y8 g
- BSP_TS_GetState(&TS_State);
" Y0 Z3 z+ y1 `4 J3 [/ n, h - if(TS_State.touchDetected != 0) {
4 j" D; B5 [+ x - *x = TS_State.touchX[0];+ ^9 @, V4 S& b; f7 b2 l% q
- *y = TS_State.touchY[0];9 S5 m1 I/ Z; K5 @) F# e* z
- press = true;
$ Q; \2 ]7 G8 T4 z( ~ - } else {' s- j+ {/ ^/ w. P' ?1 i
- *x = last_x;
( y2 {5 L8 m; P& d" A: M - *y = last_y;) S0 z. _0 s1 [) e
- press = false;" D( }6 t) t( g" m; P
- }' j, k3 a P; b% @" R
- % c7 w6 @; E5 q
- return press;5 S& I6 }0 p, M. A; h: g* n4 N
- }
复制代码 c)LCD的移植分为几个函数, D% `8 }9 f; F8 ?- K! ?
8 I4 ^' { h3 ~. [5 D. o1)一个是用单一色填充矩形区域,这个实际调用的次数较小
: E0 _0 k1 F; V$ x! j
& y, b) r2 O* Y5 G) f' T' s- /**
& ^9 {5 T" o& e$ Q - * Fill a rectangular area with a color& P2 E8 `7 v- P5 S& R% e1 b# W
- * @param x1 left coordinate of the rectangle
; j4 H, I6 v+ h% |9 ^. ^: ^/ g/ x - * @param x2 right coordinate of the rectangle
! E6 G. y- }# A7 |# I - * @param y1 top coordinate of the rectangle: n2 W; e7 l" G
- * @param y2 bottom coordinate of the rectangle
; k* M( C5 w% _0 Y0 @0 Y X @ - * @param color fill color5 ]$ |6 c' o. N" N% g9 N! P
- */
# G0 @( n- v: `; i3 C' d - void disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, color_t color)( r; j9 v& G# P0 O
- {. P, ~; f" W/ o% z \$ {7 Q
- /*Return if the area is out the screen*/& Z3 m+ l4 @0 {% h" n* v
- if(x2 < 0) return;! f. p/ |0 P- [) j( f8 l9 w
& V$ k2 }+ ]) c7 F1 o7 `- if(y2 < 0) return;
f* t: s3 v% e/ V - 5 @$ n+ x U. e4 q9 t% h, D
- if(x1 > DISP_HOR_RES - 1) return;. w; |3 J: x! `* _( }- G
- 0 L0 ~$ I) B7 |6 s6 E
- if(y1 > DISP_VER_RES - 1) return;
. A4 c: Z. o+ s2 s$ `
L* G& q! S6 g+ i% \- /*Truncate the area to the screen*/
4 V' b( n$ r- a6 H( g - int32_t act_x1 = x1 < 0 ? 0 : x1;
. n$ Z4 v( n ^ t/ l9 i( ` - int32_t act_y1 = y1 < 0 ? 0 : y1;
9 A7 s% L3 L& Q7 `+ H - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
% D( u. M. y. o: L8 o% f - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
2 T2 D$ J/ D6 @' l5 i8 A1 O
. }4 F! H- |. i# A2 a- LCD_FillRectPart(act_x1, act_y1, act_x2 - act_x1 + 1, act_y2 - act_y1 + 1, ((color.full)));2 j( j c- Q1 L& o; P5 f0 Z
- }
复制代码 2)这个是用一个颜色map填充一个矩形区域,这个主要用显示时局部刷新使用,是LCD显示调用的底层接口,使用非常频繁,如果需要优先显示速度,可以从这个函数入手,使用块内存复制或者DMA2D来实现。
6 h& O4 L: K+ I" y* h7 b- /**
3 g8 `4 f1 @1 A - * Put a color map to a rectangular area! ^/ w* C2 l" j+ \, A2 O
- * @param x1 left coordinate of the rectangle `. d. r- c1 [2 w/ m' @; e- o9 n
- * @param x2 right coordinate of the rectangle! V' P* c3 g& I4 J \5 ] [
- * @param y1 top coordinate of the rectangle
/ \$ f2 r# m6 A0 o; ~% ]5 E$ X& b - * @param y2 bottom coordinate of the rectangle
`7 r! |3 g ?& F - * @param color_p pointer to an array of colors
* y. |4 C/ \* x5 R' |& h - */4 D1 x1 n: f8 S" } U, ^2 o' R
- void disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const color_t * color_p)$ [( C, \2 B0 w* f. o
- {
) `/ i' i. K1 P3 ?( D - /*Return if the area is out the screen*/3 m2 Q' M8 c9 F& F; P- T3 B: J
- if(x2 < 0) return;
& H1 a f- P. H: K* }$ y0 E
" Z7 i$ [( I$ r- if(y2 < 0) return;
& w0 P! z% _* m% Q/ w, i# _7 `
! C$ f+ i5 |, v0 t9 \' d4 @! s" g- if(x1 > DISP_HOR_RES - 1) return;
1 {8 \- Q3 y3 T2 z
" |# a; N4 Y" L- if(y1 > DISP_VER_RES - 1) return; A e6 I, _# a9 I$ T
- . T6 e! Y. O8 ]$ ^* \ b
- /*Truncate the area to the screen*/4 M' V( D" u$ {. u
- int32_t act_x1 = x1 < 0 ? 0 : x1;
: ~! A# j o3 O* q$ U' E - int32_t act_y1 = y1 < 0 ? 0 : y1;
: H9 @0 e" A$ Y$ V( M+ r7 b9 b2 a2 C - int32_t act_x2 = x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : x2;
: m, Z. i/ Z! P, y+ T - int32_t act_y2 = y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : y2;
0 h2 W" g; _ Y) Y8 C4 O - - p ^4 u3 ~& @ R
. X+ [1 h# H! h% |0 [- uint32_t y;" E I1 }3 _* V8 O8 E6 q
5 L8 A" r% S$ e7 s- for(y = act_y1; y <= act_y2; y++)/ U4 D6 N7 g6 K8 A0 w
- {0 j# p, t3 f' [
- memcpy(&my_fb[y * DISP_HOR_RES + act_x1],+ z0 P% ]: b/ u& h8 a
- color_p,7 Z5 j0 v. B7 \
- (act_x2 - act_x1 + 1) * sizeof(my_fb[0]));
' H8 b# q6 w1 Y - color_p += x2 - x1 + 1; /*Skip the parts out of the screen*/
( J' Q7 v7 p; K2 p4 F - }/ q7 b3 k+ U# p& l' e9 ?8 n
6 `$ F: Y% A* @' k5 j0 y4 Y$ H" p- }
复制代码 3)硬件加速可选项打开后可以使用下面的函数复制加速填充复制内存
* e, s# W/ l6 G$ n! a- /**3 `. F# Y% f1 d- B
- * Copy pixels to destination memory using opacity0 r9 Y; b2 W/ g$ }: h: a, Y
- * @param dest a memory address. Copy 'src' here.
4 b7 k# E" `, O: B' H - * @param src pointer to pixel map. Copy it to 'dest'.1 k. y5 w- W, I
- * @param length number of pixels in 'src'. A. r) Q* ~- F" S
- * @param opa opacity (0, OPA_TRANSP: transparent ... 255, OPA_COVER, fully cover)5 Z! D0 ?+ _1 D" Y; A* Q
- */0 P# n& o1 ^- t
- void disp_color_cpy(color_t * dest, const color_t * src, uint32_t length, opa_t opa)4 O+ L4 ~4 F& }8 ^5 C: m& ]
- {
3 S+ S# Q3 |# t" Z6 d8 b- V5 e. I; A - /*Wait for the previous operation*/2 O. ^! l: f# f! A$ G
- HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
% K, { u# Z1 _) x5 J1 `& l* b - % Q: X7 M+ q/ L+ ^: G9 r2 u
- Dma2dHandle.LayerCfg[1].InputAlpha = opa;
/ \, U* M& l* L5 r- t4 [ - HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
% C8 P+ C! I3 F( B( N3 Z2 d! { - HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);9 {$ A2 U1 w' ]3 d
- }
复制代码 移植了上面接口之后基本问题就不大了,littlevgl 目前的代码结构有点乱,分为core、hal、misc 几个部分,我是分别建立一个文件夹然后把相应的文件全部添加到里面了,官网也没有详细的移植说明文档。所有的源码如下:' F( I& c2 W7 `% ~
9 o _- n, ]" p" r
添加到工程中后如下整体如下:8 B5 N3 u& ~* b8 t
/ w7 ~; B3 l2 r6 [7 n, g3 ]- b. u7 \0 n. n" ]
: x# m$ U8 m2 M" B5 f
* i7 V) e' ^2 X! |( L' I) C' L6 ?! Y V
将所有的文件添加到工程中后用keil编译可能会有一些错误和警告出现,但都很好解决。
. ?/ i) J( D6 N& U2 F% z2 S2 t" {' T
_) o% r9 R6 P- O/ }6 L2 `0 ^/ Q1 I( G; y" J
2、运行效果. |! h' n0 q5 O
) r2 g$ }( x7 z9 @+ j- N7 sLittlevGL内置一个类似桌面系统的演示例子,通过打开相应的宏定义即可3 n, h( S1 w' O+ l/ R1 N, x' r
4 j q; d9 \: S
& r. G' r9 \: W; ^1 _% J
$ w! e i+ D/ k8 d/ |# E
. Z9 m2 D# S. bLittlevGL有个桌面上模拟的工程,下面是论坛网友 @QianFan 在linux下运行官方例子的运行效果:0 {8 D, y5 |0 T
; W# _4 C2 w' R: s9 {, r v5 V& a
y, l" Z- g1 K$ t. O
* ^( v0 {6 e/ A& Y; L) k5 s
1 k! H) Q- S3 B1 p& X除此之外官网还有一个在STM32F429-DISOC上移植的例子,在youtube上可以观看,因为转换为了gif可能看起来不是很流畅,实际演示效果很不错。
; e5 b$ l5 C0 I! w6 L) y% @, {. r$ ~7 z5 m
1 y/ @& f% U8 e; f) p
( \8 I4 a+ F3 L& n
- ~; C' m5 ? k下面是我在STM32F769-DISOC上面的移植,和linux下模拟运行的差不多。因为769-disco的分辨率很高,移植后我没有使用优化,所以可以看到画面切换有些闪烁。
, T5 k2 B/ m( y$ j" n2 o/ |
6 |# Q$ R8 Z' z/ G
( r# g. T) z6 s/ {5 S4 h3、关于LittlevGL4 m4 b; o+ d4 X
! @7 ^6 S# G( G! z# L, A& C LittlevGL里面有个简单的时间片调度系统,刷新显示和触摸处理等任务会周期的被调用处理。LCD刷新采用了局部缓存刷新,这样能避免闪烁出现。LittlevGL目前只有一个开发者在业余时间维护更新,但是开发者热情很高,可以在github上看到更新很频繁,我测试的使用的V4.2版本,开发者正在开发4.3版本并加入了不少新的功能,有建议可以在github和作者讨论互动。( `3 I" m- j9 ]# G- k: A4 d0 E
目前代码结构看上去有点乱,有人在也提到了这个问题,计划好像是在5.0版本引入新的代码组织结构,感兴趣的可以去github提意见,开发者很乐意沟通讨论。官网也有不少控件的使用介绍和例子参考。
5 ^( C/ O p7 t+ {
& y- a; O4 `: j2 w K) T2 n1 b& o0 s0 A+ f1 f2 ?3 h" C
4 b0 ]3 e2 M; B1 T
' T5 I" M* K, K1 T( }$ ?* {
" _1 L+ V6 k( K) ~5 y$ j
4 h1 w: h- O/ ]5 R" k0 \9 B. U& B官网和github地址如下:/ q0 v4 m; Q o. a1 n, F
4 i3 j3 Y0 T' x; [3 zLittlevGL官网:http://www.gl.littlev.hu/
0 T; b' O# }- s' U4 bLittlevGLgithub :http://github.com/littlevgl 和 http://github.com/littlevgl/lvgl
" y1 [8 ~' @1 S- u- ?% L3 t- k8 e ]$ v
下面2个视频是在PC Simulator (Linux)和F4-DICO上的移植演示可能需要科学的方式才能打开。
0 B0 b# }1 g, ` v: \How to Run Littlev Graphics Library in PC Simulator (Linux):http://youtu.be/ZzLdct2ymvg! \% O& e" v5 T" r8 J, f- B
Embedded GUI on STM32 Discovery with Littlev Free Graphics Library:http://youtu.be/DcJdK137WKM8 v0 e# ~* _. p9 R$ n. U
# O- F( D, q% N- {; n5 e& g. j* V 和众多开源的RTOS不一样,目前GUI开源的不是很多,虽然很多商用的GUI也很炫酷,但是我们没法知道具体效果的实现细节,也没法学习到这种能力,LittlevGL目前实现的一些特性和控件我认为是开源的GUI里面水平非常高的了。但是目前LittlevGL资料不是很多,只能通过阅读源码去学习和研究。# W$ ~4 f: f* J4 P9 h$ O
/ F9 L: W, z8 B ~ E
2 [1 A7 K0 ]' y( r测试代码:
* k7 G) R, W: }" P' j# A5 X
LittlevGL-STM32F769-DISCO.rar
(4.72 MB, 下载次数: 867)
|
看到一个别人分享的开源中文教程。
http://github.com/littlevgl/proj_pc6 O0 c) H) h: t
是的,没有限制,移植吧。
谢谢楼主分享
0 p( J* \' A( d0 }6 f
8 c# i0 t! V& L
如何模拟? 如何在linux中运行?
文档很少- I. q( y3 _" u
# A! e5 s* i4 e; E
文档是很少,只能通过看代码学习了,如果感兴趣的话可以一起讨论。