出於個人興趣決定在原Forairaaaaa/Chappie-II的基礎上進行個性化修改和部分特殊功能的實現,本文主要包括:
- 開發環境配置
- 系統邏輯簡讀
- 設定頁面menu實現
注:僅為隨筆,不建議做任何技術參考
1. 環境配置
1.1 WSL+VScode+PIO
因為習慣了將開發環境整合在wsl中,然後用vscode連線後使用,所以本次依然是WSL+VScode這一套。由於原工程就是PIO工程,曾經也用過vscode上的PIO外掛,所以不多做贅述。
PIO安裝與使用可參考在vscode 中用PlatformIO開發-CSDN部落格。
其中需要注意的是程式的燒錄等操作依賴USB連線,而wsl並不會像宿主機一樣輕鬆識別使用USB裝置,所以需要使用USB/IP 開源專案 usbipd-win來實現開發板與開發環境的連線,方法可以參考連線 USB 裝置 | Microsoft Learn。
但因為程式燒錄時有上電操作,所以連線會斷開,需要手動使用usbipd attach --wsl --busid <busid>
來連線一下。如果嫌麻煩可以寫個指令碼。
1.2 檔案樹和依賴庫
1.2.1 檔案樹
Chappie-II/Firmware
├── default_16MB.csv
├── lib
│ ├── arduinoFFT
│ ├── ESP32-BLE-Gamepad
│ ├── FastLED
│ ├── LovyanGFX
│ ├── lv_conf.h
│ ├── lvgl
│ ├── NimBLE-Arduino
│ └── README
├── platformio.ini
├── src
├── ChappieBsp
├── ChappieUI
└── main.cpp
1.2.2 下載依賴
git submodule init
git submodule update
cd lib
git clone https://github.com/lovyan03/LovyanGFX.git
git clone -b v8.3.5 https://github.com/lvgl/lvgl.git
git clone https://github.com/FastLED/FastLED.git
git clone https://github.com/lemmingDev/ESP32-BLE-Gamepad.git
git clone https://github.com/h2zero/NimBLE-Arduino.git
git clone --branch 1.6.2 https://github.com/kosme/arduinoFFT.git
注意,使用高於1.6.2版本的arduinoFFT會出現報錯。
2. 系統邏輯簡讀
2.1 系統啟動
#include "Arduino.h"
#include "ChappieUI/ChappieUI.h"
CHAPPIEUI ChappieUI;
/**
* @brief 系統初始化並啟動App_Launcher
*/
void setup()
{
ChappieUI.begin();
}
/**
* @brief 重新整理App_Launcher以獲得實時資訊
*/
void loop()
{
ChappieUI.update();
delay(5);
}
系統功能以APP為單位體現,包括此處的App_Launcher本身也是App。輪詢App和系統狀態實現App的啟動和退出。
此處App_Launcher的功能包括:
void App_Launcher::onCreate()
:App_Launcher的建立void App_Launcher::onDestroy()
:App_Launcher的退出,以載入lvgl主螢幕並銷燬Launcher screen實現void App_Launcher::updateDeviceStatus()
:響應按鍵A、B一個電源鍵一個home鍵void App_Launcher::updateAppManage()
:App狀態管理,包括onCreate、isRunning、onDestroy三種狀態。可以看到App被退出也就是onDestroy狀態,會預設建立App_Launcher,實現退出返回主頁的效果。且在App預設框架中要求返回Appname,與AppRegister中已註冊的App對應,實現查詢和訪問。
2.2 App_Settings簡讀
App_Settings是系統中的”設定“app,可以看到其透過WIFI實現時間的同步
static void xTaskOne(void *xTask1)
{
while (1)
{
uint8_t i = 0;
WiFi.mode(WIFI_AP_STA);
WiFi.begin();
while (WiFi.status() != WL_CONNECTED)
{ //這裡是阻塞程式,直到連線成功
vTaskDelay(100);
i++;
if(i == 100)
{
//vTaskDelete(NULL);
break;//等待10秒,若未連線,則退出聯網
}
}
i = 0;
if(WiFi.status() != WL_CONNECTED)
{
WiFi.beginSmartConfig();
}
if(WiFi.status() != WL_CONNECTED)
{
while (!WiFi.smartConfigDone())
{
delay(500);
i++;
if(i == 200)
{
WiFi.disconnect();
vTaskDelete(NULL);//等待25秒,若仍未配網,則登出執行緒
}
}
i = 0;
vTaskDelay(100);
while (WiFi.status() != WL_CONNECTED)
{
vTaskDelay(100);
i++;
if(i == 100)
{
WiFi.disconnect();
vTaskDelete(NULL);
}
}
}
http.begin("http://quan.suning.com/getSysTime.do"); //HTTP begin
int httpCode = http.GET();
if (httpCode > 0)
{
// httpCode will be negative on error
if (httpCode == HTTP_CODE_OK) // 收到正確的內容
{
String resBuff = http.getString();
char *pEnd;
char charArray[100];
char str [30];
resBuff.toCharArray(charArray, 61);
for(i=0;i<=15;i++){str[i]=charArray[i+46];}
int nums[6];
extract_ints(str, nums, 6);
rtc_date.year = nums[0];
rtc_date.month = nums[1];
rtc_date.date = nums[2];
rtc_time.hours = nums[3];
rtc_time.minutes = nums[4];
rtc_time.seconds = nums[5]+1;//補償資料處理的時間
uint16_t y = nums[0];
uint8_t m = nums[1];
uint8_t d = nums[2];
if(m<3)
{
m+=12;
y-=1;
}
rtc_date.weekDay=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;
device->Rtc.setDate(&rtc_date);
device->Rtc.setTime(&rtc_time);
}
}
http.end();
WiFi.disconnect();
vTaskDelete(NULL);
}
}
WIFI的連線使用了官方的smartconfig方法,還沒進行測試。剩下的功能則是畫了一個圓弧ui,不知道作何用處的。
3. menu實現
基礎例程和呼叫lvgl庫的版本進行初始修改(函式功能和名稱發生了改變)
具體的顯示效果等下次有時間和回撥函式一起完成,嘗試把原有的Wifi同步時間的功能顯示在menu中。
/**
* @brief 設定介面的多級選單
* @author K0maru3
*/
void App_Settings_menu(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
/*Create a sub page*/
lv_obj_t * sub_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
/*Create a main page*/
lv_obj_t * main_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
}