当前位置:首页 > 公众号精选 > 裸机思维
[导读]在前面的文章《【喂到嘴边了的模块】准备徒手撸GUI?用Arm-2D三分钟就够了》中,我们介绍了如何借助 cmsis-pack 快速的在 MDK 中部署 arm-2d。

【说在前面的话】


在前面的文章《【喂到嘴边了的模块】准备徒手撸GUI?用Arm-2D三分钟就够了》中,我们介绍了如何借助 cmsis-pack 快速的在 MDK 中部署 arm-2d
在过去的一段时间内,想必很多人都完成了部署,看到了下面的画面吧?


如果还没有,推荐先跟着上一篇文章的手把手图文教程——完成基本的部署吧。本文将在此基础上继续为您介绍如何使用arm-2d来简化我们手撸GUI的过程。

为了避免让大家产生疑惑,这里我们需要再次明确一下我们所要面对的开发环境:
  • 资源相对紧张的MCU,无法负担起传统的嵌入式GUI(比如以体积“小巧”著称的LVGL):
    • Flash <= 64K,或者
    • 应用本身已经占用了大量Flash空间,留给GUI的空间非常有限
    • SRAM <= 16K
  • 需要实现的GUI界面较为简单(这点在随后会详细介绍)
  • 帧率要求较低(传说中的8帧不卡、9帧流畅、10帧电竞)


【基于面板的界面设计】


从用户的角度来说,如果一个嵌入式产品带了彩屏,很自然的就会希望它能提供像智能手机(或平板设备)一样的操作体验——但从开发者的角度来说,用户的这一期望往往会被错误的理解为:用户希望嵌入式产品上的图形界面能像手机那样支持“这样或那样”的滑动、滚动效果——如果能做到当然最好,但其实这并不是这些“类智能手机界面”设计的核心。
让我把话挑明了吧——流畅的滑动只是添料,甚至是可以完全丢弃的——真正核心的是一套与传统Windows图形界面设计完全不同的理念。关于这套设计理念,有一套叫做“人本界面”的设计方法论作为支撑,感兴趣的小伙伴可以在豆瓣上搜索同名的图书。

就本文要讨论的内容来说,我们可以简单的关注以下的一些要点:

  • 智能设备的界面强调“简洁”、并希望“让用户的注意力一次只集中在一件简单的事物上”。
基于这一原则,又派生出了如下的特点:
  • 与Windows不同,智能设备的界面很少(或者极力避免)窗口重叠
  • 界面的基本单位不是“窗体(Window)”,而是以整个屏幕为基本单位的“面板(Panel)”
  • 每个面板的内容都尽可能简单、通过留白的方式强调那些需要用户注意的内容;
  • 每个面板的功能都尽可能单一:
    • 一般避免在同一个面板中挤进多个不太相关的功能
    • 相关的内容,如果能够放得下,且美观,则可以有主次的布置在同一个面板中以减少用户切换面板带来的不便;
    • 如果相关的内容如果无法在同一个面板中展示,则一定会添加快捷方式方便用户快速进行面板的切换;
  • 面板间的切换方式以大家熟悉的PPT页面切换方式类似
    • 对滑动切换来说,要么不做,要做就要“丝滑”(差不多30FPS),否则会给用户带来“卡顿”的不适感
    • 完全没有动画的切换往往会给用户“设备反应迅速”的错觉,对负担不起高帧率的嵌入式设备来说,反而是最好的选择

仔细回想一下,身边的智能设备,是不是都基本满足上述特点?——其实我们熟悉的手机和平板也是如此。


基于上述原则,我们甚至可以总结出一套简单有效的“嵌入式界面设计八股”:

  • 用户界面分成三个部分:状态面板导航面板功能面板
  • 状态面板又叫待机面板,用于显示状态信息(比如温度、时间、产品Logo、产品当前状态等等)。
    • 通常在待机界面上按下任意键(或者进行任意触摸)进入导航面板
    • 一般用户超过一段时间没有与界面进行交互后会自动进入状态面板,所以状态面板有时候又叫待机面板
  • 导航面板:也就是大家常说的菜单
    • 一般导航面板以图标、列表或者按钮的形式存在,
    • 一般避免超出屏幕范围的内容,最好做到让用户对所有选项“尽收眼底”
    • 导航面板可以通过子面板的形式实现多级菜单,从而简化开发
  • 功能面板:实现具体功能的面板,一般由导航面板进入
    • 每个面板的功能都尽可能单一,比如专门设置温度、专门设置时间等等
    • 相关的导航面板之间可以通过类似左右箭头(或者底部导航快捷按钮)的机制进行快捷切换




【什么是场景(scene)】


“场景(scene)”是 arm-2d为“手撸GUI”的用户引入的一个概念,通过配套的“场景播放器(scene player)”,极大的简化了基于面板的界面开发。
一般来说,一个简单的面板用一个场景就可以搞定;而稍微复杂点的面板则可以通过多个场景(以及基于状态机的场景切换)来搞定——总的原则就是,无论多复杂的面板,都可以拆分成一个个简单的场景来分而治之
也许你已经注意到了:原本面板本身就已经很简单了,那么所谓“复杂的面板”根据状态机拆分成多个场景后是不是更加简单了?——是的,每个场景的功能都是极其单一和简单的——极大的简化了每个场景的实现难度


举个例子:有个面板的功能是设置温度,当超过某一特定值后,需要弹出一个窗口提醒用户当前设置值有某些注意事项。这样的面板在设计时就可以拆分成两个场景:1)一个正常的数值设置场景,实现一个类似滑条的功能让用户设置温度;2)一个专门的场景来提示用户注意事项——通过这样的安排,每个场景都可以非常单一。再比如:某个面板的用来设置多个相关的选项,并且当用户开启某个开关后,会出现一些隐藏选项(或者原本不可设置的选项变成可选)。此时,就可以根据这个开关的状态,引入两个场景:一个对应开关关闭时的面板,一个对应开关开启时的面板——总之,面板拆的越细致,每个场景的设计就越简单


【场景(scene)的数据结构和构成】


场景在 arm-2d 中以类 arm_2d_scene_t 来描述:
/*! * \brief a class for describing scenes which are the combination of a *        background and a foreground with a dirty-region-list support *  */typedef struct arm_2d_scene_t arm_2d_scene_t;struct arm_2d_scene_t { arm_2d_scene_t *ptNext; //!< next scene arm_2d_scene_player_t *ptPlayer; //!< points to the host scene player arm_2d_region_list_item_t *ptDirtyRegion; //!< dirty region list for the foreground  arm_2d_helper_draw_handler_t *fnBackground; //!< the function pointer for the background  arm_2d_helper_draw_handler_t *fnScene; //!< the function pointer for the foreground void (*fnOnBGStart)(arm_2d_scene_t *ptThis); //!< on-start-drawing-background event handler void (*fnOnBGComplete)(arm_2d_scene_t *ptThis); //!< on-complete-drawing-background event handler void (*fnOnFrameStart)(arm_2d_scene_t *ptThis); //!< on-frame-start event handler void (*fnOnFrameCPL)(arm_2d_scene_t *ptThis); //!< on-frame-complete event handler  /*! * \note We use fnDepose to free the resources */ void (*fnDepose)(arm_2d_scene_t *ptThis); //!< on-scene-depose event handler struct { uint8_t bOnSwitchingIgnoreBG    : 1; //!< ignore background during switching period uint8_t bOnSwitchingIgnoreScene : 1; //!< ignore forground during switching period };};


其数据结构并不复杂。



数据结构的主体是这两个指针:

  • fnScene:指向一个由用户提供的绘图函数:

    • 绘制一个场景中所有的内容;或者

    • 当场景中存在“不会变化且不会被覆盖的背景”和“少数”内容会发生变化的前景时,专门用于绘制前景——此时就需要通过ptDirtyRegion来指向描述前景变化区域的脏矩阵(Dirty Region List)。


  • fnBackground:指向一个由用户提供的绘图函数,专门绘制一个场景中那些“只需要绘制一次”且“未来不会被前景覆盖或者变化”的内容,最典型的就是绘制场景中的背景图片;


需要特别说明的是:

  • fnBackground 只会在绘制每个场景的第一帧时调用;

  • 随后的每一帧就只会调用 fnScene

  • fnBackground 会绘制整个屏幕;

  • 脏矩阵(ptDirtyRegion)只对 fnScene 有效;

  • 当ptDirtyRegion 为 NULL时,fnScene也是绘制整个屏幕

    • 这意味着,当 ptDirtyRegionNULL时,fnBackground 绘制的内容会 100% 被覆盖掉——也就是说完全没用。这意味着:

    • 当且仅当我们指定了有效的脏矩阵时,fnBackground 才是实际有意义的


如果你对“背景”和“前景”的分工感到似懂非懂,不妨看下面这个例子:



在这个场景中:

  • 作为背景的狗头实际上不会发生变化,因此我们只需在 fnBackground 所指向的绘图函数中绘制即可;

  • 动态进度条由于其内容一直在变化,因此需要在 fnScene所指向的绘图函数中“配合脏矩阵”进行重复绘制。


为了方便应用开发,arm_2d_scene_t 提供了一系列事件处理程序接口(回调函数),它们与背景、场景的绘制关系如下:


可以看到,这里的事件处理顺序并不复杂,大家可以根据实际的应用需求各取所需。

【场景播放器(scene player)的本质是什么】
场景播放器的本质是一个针对场景(scene)的队列(FIFO):


  • 用户可以预先生成多个场景,并通过函数arm_2d_scene_player_append_scenes压入队列中;
  • 队列的头部就是当前生效的场景;
  • 用户可以在任意时刻通过函数arm_2d_scene_player_switch_to_next_scene来安全的触发场景切换,
    • 所谓的场景切换就是丢弃队列当前的头部场景——换成下一个;
  • 场景切换后,被丢弃的场景会调用 fnDepose ,用户可以利用这个函数为对应场景“擦屁股”
    • 比如,假设一个场景(arm_2d_scene_t)对象本身就是动态分配的(从 malloc中分配),那么就可以通过 fnDepose 方法来将内存释放掉(比如调用 free函数)。
  • 场景播放器提供了 arm_2d_scene_player_flush_fifo 方法,它会清空整个队列。
    • 被清空出去的场景都会被依次调用 fnDepose,因此不用担心内存泄露的问题。
  • 场景切换是支持特效的,比如:淡入淡出、滑动和擦除等等


【用场景开发也太简单了8!】


前面洋洋洒洒的做了这么多理论铺垫,也许会让你对 scene 的使用产生了“非常复杂”的错觉或者担忧,但实际情况却相反:借助cmsis-packRTE的帮助,创建 scene 几乎只要点几下鼠标就可以搞定,而且立即就可以使用。
假设你已经根据《【喂到嘴边了的模块】准备徒手撸GUI?用Arm-2D三分钟就够了》的描述,完成了 arm-2d 的部署,并且成功的加入了一个 Display Adapter,此时我们应该能看到这样的效果:


此时,打开 RTE,展开Acceleration后在Arm-2D Helper中找到 Scene


如果你的界面中找不到 Scene,说明你的 arm-2d cmsis-pack 版本较老,可以关注公众号【裸机思维】后,发送关键字 arm-2d 后获取最新版本的网盘链接。

Scene的右边,我们可以通过“增加数值”的方式向工程中添加指定数量的场景。单击确定后,对应数量的场景模板会加入到工程管理器中:


这里的 arm_2d_scene_0.harm_2d_scene_0.c 分别对应我们新加入的场景的头文件和源代码。


打开 main.c,加入对场景的头文件引用:
#include "arm_2d_scene_0.h"

其实,所谓的 Display Adapter 就是场景播放器(arm_2d_scene_player_t):

ARM_NOINITexternarm_2d_scene_player_t DISP0_ADAPTER;

在初始化完 Display Adapter 后,我们调用场景的初始化函数arm_2d_scene0_init()——将它们加入指定的场景播放器队列中:

#include "arm_2d_scene_0.h"...int main (void) { arm_irq_safe { arm_2d_init(); }   disp_adapter0_init();  arm_2d_scene0_init(&DISP0_ADAPTER);  while(1) { disp_adapter0_task(); }  }

调用函数 arm_2d_scene_player_switch_to_next_scene() 来切换到我们新加入的场景中:

#include "arm_2d_scene_0.h"...int main (void) { arm_irq_safe { arm_2d_init(); }   disp_adapter0_init();  arm_2d_scene0_init(&DISP0_ADAPTER); arm_2d_scene_player_switch_to_next_scene(&DISP0_ADAPTER);  while(1) { disp_adapter0_task(); }  }


为了方便观察效果,不妨设置一个场景切换效果:


#include "arm_2d_scene_0.h"...int main (void) { arm_irq_safe { arm_2d_init(); }   disp_adapter0_init();  /* 初始化场景 scene0,并将其加入到场景播放器 DISP0_ADAPTER 中 */ arm_2d_scene0_init(&DISP0_ADAPTER);  /* 设置切换特效为 淡入淡出(白色) */ arm_2d_scene_player_set_switching_mode(  &DISP0_ADAPTER, ARM_2D_SCENE_SWITCH_MODE_FADE_WHITE); /* 设置切换持续时间为 3000ms */ arm_2d_scene_player_set_switching_period( &DISP0_ADAPTER,  3000);  /* 申请切换到新加入的场景中 */ arm_2d_scene_player_switch_to_next_scene(&DISP0_ADAPTER);  while(1) { disp_adapter0_task(); }  }  

编译后运行,可以看到类似如下的效果:



可以看到,场景播放器从默认的“转圈圈”界面以“渐明渐暗”的形式切换到了我们的新场景 scene0 中。



细心的小伙伴可能很快就注意到了一个奇怪的地方:为啥很快 scene0 又消失在白屏中了呢?要解答这一疑问不妨打开
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭