www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > > 裸機思維
[導(dǎo)讀]在前面的文章《【喂到嘴邊了的模塊】準(zhǔn)備徒手?jǐn)]GUI?用Arm-2D三分鐘就夠了》中,我們介紹了如何借助 cmsis-pack 快速的在 MDK 中部署 arm-2d。

【說在前面的話】


在前面的文章《【喂到嘴邊了的模塊】準(zhǔn)備徒手?jǐn)]GUI?用Arm-2D三分鐘就夠了》中,我們介紹了如何借助 cmsis-pack 快速的在 MDK 中部署 arm-2d
在過去的一段時間內(nèi),想必很多人都完成了部署,看到了下面的畫面吧?


如果還沒有,推薦先跟著上一篇文章的手把手圖文教程——完成基本的部署吧。本文將在此基礎(chǔ)上繼續(xù)為您介紹如何使用arm-2d來簡化我們手?jǐn)]GUI的過程。

為了避免讓大家產(chǎn)生疑惑,這里我們需要再次明確一下我們所要面對的開發(fā)環(huán)境:
  • 資源相對緊張的MCU,無法負擔(dān)起傳統(tǒng)的嵌入式GUI(比如以體積“小巧”著稱的LVGL):
    • Flash <= 64K,或者
    • 應(yīng)用本身已經(jīng)占用了大量Flash空間,留給GUI的空間非常有限
    • SRAM <= 16K
  • 需要實現(xiàn)的GUI界面較為簡單(這點在隨后會詳細介紹)
  • 幀率要求較低(傳說中的8幀不卡、9幀流暢、10幀電競)


【基于面板的界面設(shè)計】


從用戶的角度來說,如果一個嵌入式產(chǎn)品帶了彩屏,很自然的就會希望它能提供像智能手機(或平板設(shè)備)一樣的操作體驗——但從開發(fā)者的角度來說,用戶的這一期望往往會被錯誤的理解為:用戶希望嵌入式產(chǎn)品上的圖形界面能像手機那樣支持“這樣或那樣”的滑動、滾動效果——如果能做到當(dāng)然最好,但其實這并不是這些“類智能手機界面”設(shè)計的核心。
讓我把話挑明了吧——流暢的滑動只是添料,甚至是可以完全丟棄的——真正核心的是一套與傳統(tǒng)Windows圖形界面設(shè)計完全不同的理念。關(guān)于這套設(shè)計理念,有一套叫做“人本界面”的設(shè)計方法論作為支撐,感興趣的小伙伴可以在豆瓣上搜索同名的圖書。

就本文要討論的內(nèi)容來說,我們可以簡單的關(guān)注以下的一些要點:

  • 智能設(shè)備的界面強調(diào)“簡潔”、并希望“讓用戶的注意力一次只集中在一件簡單的事物上”。
基于這一原則,又派生出了如下的特點:
  • 與Windows不同,智能設(shè)備的界面很少(或者極力避免)窗口重疊
  • 界面的基本單位不是“窗體(Window)”,而是以整個屏幕為基本單位的“面板(Panel)”
  • 每個面板的內(nèi)容都盡可能簡單、通過留白的方式強調(diào)那些需要用戶注意的內(nèi)容;
  • 每個面板的功能都盡可能單一:
    • 一般避免在同一個面板中擠進多個不太相關(guān)的功能
    • 相關(guān)的內(nèi)容,如果能夠放得下,且美觀,則可以有主次的布置在同一個面板中以減少用戶切換面板帶來的不便;
    • 如果相關(guān)的內(nèi)容如果無法在同一個面板中展示,則一定會添加快捷方式方便用戶快速進行面板的切換;
  • 面板間的切換方式以大家熟悉的PPT頁面切換方式類似
    • 對滑動切換來說,要么不做,要做就要“絲滑”(差不多30FPS),否則會給用戶帶來“卡頓”的不適感
    • 完全沒有動畫的切換往往會給用戶“設(shè)備反應(yīng)迅速”的錯覺,對負擔(dān)不起高幀率的嵌入式設(shè)備來說,反而是最好的選擇

仔細回想一下,身邊的智能設(shè)備,是不是都基本滿足上述特點?——其實我們熟悉的手機和平板也是如此。


基于上述原則,我們甚至可以總結(jié)出一套簡單有效的“嵌入式界面設(shè)計八股”:

  • 用戶界面分成三個部分:狀態(tài)面板導(dǎo)航面板功能面板
  • 狀態(tài)面板又叫待機面板,用于顯示狀態(tài)信息(比如溫度、時間、產(chǎn)品Logo、產(chǎn)品當(dāng)前狀態(tài)等等)。
    • 通常在待機界面上按下任意鍵(或者進行任意觸摸)進入導(dǎo)航面板
    • 一般用戶超過一段時間沒有與界面進行交互后會自動進入狀態(tài)面板,所以狀態(tài)面板有時候又叫待機面板
  • 導(dǎo)航面板:也就是大家常說的菜單。
    • 一般導(dǎo)航面板以圖標(biāo)、列表或者按鈕的形式存在,
    • 一般避免超出屏幕范圍的內(nèi)容,最好做到讓用戶對所有選項“盡收眼底”
    • 導(dǎo)航面板可以通過子面板的形式實現(xiàn)多級菜單,從而簡化開發(fā)
  • 功能面板:實現(xiàn)具體功能的面板,一般由導(dǎo)航面板進入
    • 每個面板的功能都盡可能單一,比如專門設(shè)置溫度、專門設(shè)置時間等等
    • 相關(guān)的導(dǎo)航面板之間可以通過類似左右箭頭(或者底部導(dǎo)航快捷按鈕)的機制進行快捷切換




【什么是場景(scene)】


“場景(scene)”是 arm-2d為“手?jǐn)]GUI”的用戶引入的一個概念,通過配套的“場景播放器(scene player)”,極大的簡化了基于面板的界面開發(fā)。
一般來說,一個簡單的面板用一個場景就可以搞定;而稍微復(fù)雜點的面板則可以通過多個場景(以及基于狀態(tài)機的場景切換)來搞定——總的原則就是,無論多復(fù)雜的面板,都可以拆分成一個個簡單的場景來分而治之。
也許你已經(jīng)注意到了:原本面板本身就已經(jīng)很簡單了,那么所謂“復(fù)雜的面板”根據(jù)狀態(tài)機拆分成多個場景后是不是更加簡單了?——是的,每個場景的功能都是極其單一和簡單的——極大的簡化了每個場景的實現(xiàn)難度。


舉個例子:有個面板的功能是設(shè)置溫度,當(dāng)超過某一特定值后,需要彈出一個窗口提醒用戶當(dāng)前設(shè)置值有某些注意事項。這樣的面板在設(shè)計時就可以拆分成兩個場景:1)一個正常的數(shù)值設(shè)置場景,實現(xiàn)一個類似滑條的功能讓用戶設(shè)置溫度;2)一個專門的場景來提示用戶注意事項——通過這樣的安排,每個場景都可以非常單一。再比如:某個面板的用來設(shè)置多個相關(guān)的選項,并且當(dāng)用戶開啟某個開關(guān)后,會出現(xiàn)一些隱藏選項(或者原本不可設(shè)置的選項變成可選)。此時,就可以根據(jù)這個開關(guān)的狀態(tài),引入兩個場景:一個對應(yīng)開關(guān)關(guān)閉時的面板,一個對應(yīng)開關(guān)開啟時的面板——總之,面板拆的越細致,每個場景的設(shè)計就越簡單。


【場景(scene)的數(shù)據(jù)結(jié)構(gòu)和構(gòu)成】


場景在 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 };};


其數(shù)據(jù)結(jié)構(gòu)并不復(fù)雜。



數(shù)據(jù)結(jié)構(gòu)的主體是這兩個指針:

  • fnScene:指向一個由用戶提供的繪圖函數(shù):

    • 繪制一個場景中所有的內(nèi)容;或者

    • 當(dāng)場景中存在“不會變化且不會被覆蓋的背景”和“少數(shù)”內(nèi)容會發(fā)生變化的前景時,專門用于繪制前景——此時就需要通過ptDirtyRegion來指向描述前景變化區(qū)域的臟矩陣(Dirty Region List)。


  • fnBackground:指向一個由用戶提供的繪圖函數(shù),專門繪制一個場景中那些“只需要繪制一次”且“未來不會被前景覆蓋或者變化”的內(nèi)容,最典型的就是繪制場景中的背景圖片;


需要特別說明的是:

  • fnBackground 只會在繪制每個場景的第一幀時調(diào)用;

  • 隨后的每一幀就只會調(diào)用 fnScene;

  • fnBackground 會繪制整個屏幕;

  • 臟矩陣(ptDirtyRegion)只對 fnScene 有效;

  • 當(dāng)ptDirtyRegion 為 NULL時,fnScene也是繪制整個屏幕。

    • 這意味著,當(dāng) ptDirtyRegionNULL時,fnBackground 繪制的內(nèi)容會 100% 被覆蓋掉——也就是說完全沒用。這意味著:

    • 當(dāng)且僅當(dāng)我們指定了有效的臟矩陣時,fnBackground 才是實際有意義的


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



在這個場景中:

  • 作為背景的狗頭實際上不會發(fā)生變化,因此我們只需在 fnBackground 所指向的繪圖函數(shù)中繪制即可;

  • 動態(tài)進度條由于其內(nèi)容一直在變化,因此需要在 fnScene所指向的繪圖函數(shù)中“配合臟矩陣”進行重復(fù)繪制。


為了方便應(yīng)用開發(fā),arm_2d_scene_t 提供了一系列事件處理程序接口(回調(diào)函數(shù)),它們與背景、場景的繪制關(guān)系如下:


可以看到,這里的事件處理順序并不復(fù)雜,大家可以根據(jù)實際的應(yīng)用需求各取所需。

【場景播放器(scene player)的本質(zhì)是什么】
場景播放器的本質(zhì)是一個針對場景(scene)的隊列(FIFO):


  • 用戶可以預(yù)先生成多個場景,并通過函數(shù)arm_2d_scene_player_append_scenes壓入隊列中;
  • 隊列的頭部就是當(dāng)前生效的場景;
  • 用戶可以在任意時刻通過函數(shù)arm_2d_scene_player_switch_to_next_scene來安全的觸發(fā)場景切換,
    • 所謂的場景切換就是丟棄隊列當(dāng)前的頭部場景——換成下一個;
  • 場景切換后,被丟棄的場景會調(diào)用 fnDepose ,用戶可以利用這個函數(shù)為對應(yīng)場景“擦屁股”
    • 比如,假設(shè)一個場景(arm_2d_scene_t)對象本身就是動態(tài)分配的(從 malloc中分配),那么就可以通過 fnDepose 方法來將內(nèi)存釋放掉(比如調(diào)用 free函數(shù))。
  • 場景播放器提供了 arm_2d_scene_player_flush_fifo 方法,它會清空整個隊列。
    • 被清空出去的場景都會被依次調(diào)用 fnDepose,因此不用擔(dān)心內(nèi)存泄露的問題。
  • 場景切換是支持特效的,比如:淡入淡出、滑動和擦除等等


【用場景開發(fā)也太簡單了8!】


前面洋洋灑灑的做了這么多理論鋪墊,也許會讓你對 scene 的使用產(chǎn)生了“非常復(fù)雜”的錯覺或者擔(dān)憂,但實際情況卻相反:借助cmsis-packRTE的幫助,創(chuàng)建 scene 幾乎只要點幾下鼠標(biāo)就可以搞定,而且立即就可以使用。
假設(shè)你已經(jīng)根據(jù)《【喂到嘴邊了的模塊】準(zhǔn)備徒手?jǐn)]GUI?用Arm-2D三分鐘就夠了》的描述,完成了 arm-2d 的部署,并且成功的加入了一個 Display Adapter,此時我們應(yīng)該能看到這樣的效果:


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


如果你的界面中找不到 Scene,說明你的 arm-2d cmsis-pack 版本較老,可以關(guān)注公眾號【裸機思維】后,發(fā)送關(guān)鍵字 arm-2d 后獲取最新版本的網(wǎng)盤鏈接。

Scene的右邊,我們可以通過“增加數(shù)值”的方式向工程中添加指定數(shù)量的場景。單擊確定后,對應(yīng)數(shù)量的場景模板會加入到工程管理器中:


這里的 arm_2d_scene_0.harm_2d_scene_0.c 分別對應(yīng)我們新加入的場景的頭文件和源代碼。


打開 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 后,我們調(diào)用場景的初始化函數(shù)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(); }  }

調(diào)用函數(shù) 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(); }  }


為了方便觀察效果,不妨設(shè)置一個場景切換效果:


#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);  /* 設(shè)置切換特效為 淡入淡出(白色) */ arm_2d_scene_player_set_switching_mode(  &DISP0_ADAPTER, ARM_2D_SCENE_SWITCH_MODE_FADE_WHITE); /* 設(shè)置切換持續(xù)時間為 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(); }  }  

編譯后運行,可以看到類似如下的效果:



可以看到,場景播放器從默認的“轉(zhuǎn)圈圈”界面以“漸明漸暗”的形式切換到了我們的新場景 scene0 中。



細心的小伙伴可能很快就注意到了一個奇怪的地方:為啥很快 scene0 又消失在白屏中了呢?要解答這一疑問不妨打開
本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉