念春時已夏,戀冬雪已融。
總是感嘆時光匆匆,便努力在在平凡中掙扎,在平庸中努力,在平淡中積累。奈何時代飛速發展,時間又被工作佔用,外加生活中的誘惑又太多了,很多想學、想做、想超越的事,都被拋之一旁,漸漸的跟不上時代了,當年對興趣愛好的激情,也下降了好多。
上一篇部落格還是幾年前的,雖然中間進步不少,但是卻少了許多當年寫部落格時的激情飛揚,真是感慨諸多。
按公司要求,以後需要每週交一篇知識分享檔案,索性就繼續寫一下部落格,算是總結,也算是對自己的積累。
由於檔案允許在大框架內自由發揮,所以決定在我的興趣點上找一些還說的過去的東西寫一寫,而不是單純的複製一些網上隨便就能找到的東西。
以後會努力在機械電機、三維重建、影象視覺、深度學習等興趣範圍內做一些比較綜合的整理,而不是僅限於嵌入式的方向。當然,他們的實現都離不開底層,所以肯定是包含嵌入式方向的。
BL808晶片是三核異構的RISC-V CPU,引數如下:
三核異構RISC-V CPUs:
AI NN 通用硬體加速器 —— BLAI-100 用於視訊/音訊檢測/識別
內建 768KB SRAM + 64MB UHS PSRAM
編解碼:
【M1s DOCK】開發板的螢幕是 1.69 寸 240x280 電容觸控式螢幕,所以我們需要在新建介面將Resolution設定為 (280,240) ,Color depth 要設定為 (16 bit swap)模式 。設定好名字和要儲存的地址後就可以點選 CREATE 新建工程了。其實也可以點選上方的 Example 來檢視官方提供的幾個比較豐富的demo範例,跑起來很絢麗。不過由於開發板官方提供的LVGL例程所使用的的版本是8.2的,而SquareLine Studio只能選擇兩個更高的版本,所以下載demo後,程式並不能正常執行。以後有時間再移植成最新的版本再測試吧。
GUI設計介面如圖:
(具體含義和操作可以自行搜尋教學使用,也可以自己摸索)
我們可以點選一個【Button】到介面。
然後點選左上角的【Export】,選擇【Export UI Files】生成程式碼到指定資料夾。
生成成功後,可以看到指定資料夾下有幾個生成的檔案:
將這幾個檔案複製到linux環境中的 M1s_BL808_example/c906_app/lvgl_demo/ 資料夾下(此資料夾下除了原本的 bouffalo.mk 和 main.c,其他的都可以刪掉)。
我用的是VMware虛擬機器器,所以支援win與ubuntu環境的快速複製。如果是別的虛擬機器器環境,自行處理檔案複製問題。
將 ui.h 檔案中的 #include "lvgl/lvgl.h" 改為 #include "lvgl.h",不然會報錯,據說這個是 SquareLine Studio 的BUG。
將 main.c中的 demo測試相關的程式碼替換為ui.h中的ui_init()函數。
編譯通過後,將開發板設定為U盤下載模式(USB插在OTG口,按住兩側按鍵再按RST按鍵),將 M1s_BL808_example/c906_app/build_out/lvgl_demo.bin 檔案拖拽到U盤中即可。
可以看到,所見即所得:
完成基礎範例後,既可以進行更復雜一些的基礎範例了。
首先進行一次頁面切換。
點選做下角的【Screen】圖示即可增加一個顯示介面了。
在介面2上增加一個【Arc】控制元件。
下面,就應該思考該如何做介面切換了。首先,計劃需要實現的功能:點選按鈕進入第二頁面,右劃第二介面回到第一頁面。
實現方法如下:
選中第一頁面的按鈕,可以看到右邊的屬性設定欄,可以對按鈕進行各種屬性設定。
點選最下面的【ADD EVENT】,可以看到,有幾個事件型別選項,我們做如下選擇:
後面可以進行同樣的設定,點選第二頁的螢幕,選中螢幕,右側進行設定
* 【Trigger】選擇 【GESTURE_RIGHT】,即右劃事件
* 【Screen to】選擇【Screen1】,即切換到螢幕1
然後點選【ADD】,新增事件,進入到事件設定介面。
* 【Screen to】選擇【Screen1】,即切換到螢幕1
此時完成預定目標的設定,實現右劃切換回螢幕1,可以點選【執行】三角號按鈕進行模擬測試。
點選【Export】->【Export UI Files】生成程式碼。
複製替換生成的程式碼到linux對應環境下,然後編譯下載,進行實際執行檢視,可以看到實現了既定目標,在裝置上跑起來了,按鈕和滑動也能正常切換。
目前我們已經完成了LVGL的簡單繪製,基本事件繫結等體驗功能,但具體來說,也只是使用SquareLine Studio本身實現的,不需要編寫一行程式碼就能實現(需要移植好的裝置環境),並沒有涉及LVGL之外的互動。所以下面嘗試一下,將LVGL與硬體互動聯絡起來,然後就能舉一反三,實現完整複雜的邏輯功能了。
首先,計劃需要實現的功能:將螢幕2上的【Arc】控制元件於裝置背面的LED的亮度繫結,實現拖拽【Arc】的角度就能控制LED的亮度。
然後,我們來看一下LED的PWM驅動例子。
開啟 M1s_BL808_example/c906_app/pwm_demo 中的main.c,檢視PWM的例子。
可以看到,PWM操作背面的LED燈,只需要幾個特定的函數。
再然後,我們考慮怎麼將LVGL的【Arc】拖動事件與PWM調值聯絡起來。
void Arc_PWMControl(lv_event_t * e)
{
// Your code here
}
裡面沒有任何功能。所以我們需要在本函數中新增回撥函數對應的處理,即獲取改變後的值,然後設定對應脈寬給PWM,實現調節亮度。
使用如下函數即可獲取到【Arc】控制元件的當前值:
int16_t ArcValue = 0;
lv_obj_t* arc = lv_event_get_target(e);//獲取目標控制元件指標
ArcValue = lv_arc_get_value(arc) ;//獲取目標值
然後就可以使用這個值,呼叫 pwm_demo 中的 m1s_xram_pwm_set_duty 函數進行佔空比設定。我們可以在main函數中整合一下PWM操作相關的函數,包括初始化和佔空比調節,進行呼叫。在main.c中增加如下兩個函數:
```
#include "m1s_c906_xram_pwm.h"
#define PWM_PORT (0)
#define PWM_PIN (8)
#define PWM_FREQ 2000 //PWM頻率設定
//PWM驅動LED初始化程式碼
void LED_PWMInit(int freq,int duty){
m1s_xram_pwm_init(PWM_PORT, PWM_PIN, freq, duty);
m1s_xram_pwm_start(PWM_PORT, PWM_PIN);
}
//設定佔空比
void LED_PWMDutySet(int duty){
m1s_xram_pwm_set_duty(PWM_PORT, PWM_PIN, PWM_FREQ, duty);
}
```
將LED_PWMInit()函數放置到main函數中,將LED_PWMDutySet()函數使用extern關鍵字參照到ui_events.c中。
檢視pwm_demo中的m1s_xram_pwm_set_duty()函數,可以看到,佔空比為0-99,我們的【Arc】範圍為0-100,所以需要限制【Arc】的範圍。兩種方法:
/* FreeRTOS */
#include <FreeRTOS.h>
#include <task.h>
/* bl808 c906 std driver */
#include <bl808_glb.h>
#include "demos/lv_demos.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lvgl.h"
#include "ui.h"
#include "m1s_c906_xram_pwm.h"
static void lvgl_task(void *param)
{
while (1) {
lv_task_handler();
vTaskDelay(1);
}
vTaskDelete(NULL);
}
#define PWM_PORT (0)
#define PWM_PIN (8)
#define PWM_FREQ 2000
//PWM驅動LED初始化程式碼
void LED_PWMInit(int freq,int duty){
m1s_xram_pwm_init(PWM_PORT, PWM_PIN, freq, duty);
m1s_xram_pwm_start(PWM_PORT, PWM_PIN);
}
//設定佔空比
void LED_PWMDutySet(int duty){
m1s_xram_pwm_set_duty(PWM_PORT, PWM_PIN, PWM_FREQ, duty);
}
void main()
{
LED_PWMInit(PWM_FREQ,99);//PWM初始化,預設佔空比設為99
lv_init();
lv_port_disp_init();
lv_port_indev_init();//觸控相關
ui_init();
lv_task_handler();
xTaskCreate(lvgl_task, (char *)"lvgl task", 512, NULL, 15, NULL);
}
ui_events.c中程式如下:
#include "ui.h"
extern void LED_PWMDutySet(int duty);
void Arc_PWMControl(lv_event_t * e)
{
// Your code here
int16_t ArcValue = 0;
lv_obj_t* arc = lv_event_get_target(e);//獲取目標控制元件指標
ArcValue = lv_arc_get_value(arc) ;//獲取目標值
if(ArcValue>99)ArcValue=99;
ArcValue = 99-ArcValue;//佔空比對應燈的亮度;由於LED驅動方式的不同,亮度與佔空比不一定是正比
//這樣處理後便將亮度與佔空比換算為正比了
LED_PWMDutySet(ArcValue);
}
將程式編譯,然後將 build_out資料夾下生成的 lvgl_demo.bin 拖拽到模擬U盤中更新程式,可以看到已經實現了既定目標:
(LED在背面,此處不再展示)
以上只是一些簡單的例程,用於實現LVGL的操作體驗和與硬體的互動實現的流程,更多功能便可以很輕鬆的拓展了。其實還有很多優化空間的,比如【Arc】控制元件的左右滑動會激發頁面滑動效果從而回到第一頁面,右下角的引數視窗沒去掉,點選指示圖示是一個USB圖示,SDK的lvgl版本與編輯器的版本不同導致複雜介面卡死等。這些都可以自行深入學習並完善。
關於LVGL深入的學習,還請自行檢視相關教學。而且例程是基於freertos嵌入式作業系統的,在main函數中可以看到,lv_task_handler()控制程式碼是在 lvgl_task 任務中迴圈執行的,所以可以建立其他執行緒執行lvgl之外的功能,而不是僅僅依靠lvgl控制元件的回撥函數實現。後面有時間會再寫一些好玩的東西,比如深入理解一下LVGL的移植,然後實現其他的繪相簿的移植,比如之前寫過的旋轉立方體:
或是基於此演演算法的旋轉時鐘: