赞
踩
~最近在优化平衡车的UI界面~
寻寻觅觅间,偶然在B站上看到一个很优雅的UI框架WouoUI,底层的oled驱动操作使用的是U8G2方式,于是花了点时间把它移植了过来(丙正正),跑在小平衡车(小黑)上效果真的很哇塞,以一路foc电机+一个按钮作为输入;
~以下是UI的视频效果:
~以下是移植的源码,希望对想移植的后来者有所帮助:
- /************************************* 屏幕驱动 *************************************/
- //分辨率128*64,可以使用硬件IIC接口
- #include "flex_ui.h"
- #include "u8g2_ssd1306.h"
-
- #include <driver/gpio.h>
- #include <driver/spi_master.h>
- #include <esp_log.h>
- #include <freertos/FreeRTOS.h>
- #include <freertos/task.h>
- #include "nvs_flash.h"
- #include "nvs.h"
-
- #include "sbus.h"
- #include "param.h"
- #include "ms5611.h"
- #include "tle5012b.h"
- #include "drv_adc.h"
- #include "drv_motor.h"
- #include "stabilizer.h"
- #include <stdio.h>
- #include <string.h>
- #include <u8g2.h>
-
- #include "wiring.h"
- #include "lv_math.h"
-
- static const char *TAG = "flex_ui";
-
- /************************************* 定义页面 *************************************/
-
- //总目录,缩进表示页面层级
- enum
- {
- M_WINDOW,
- M_SLEEP,
- M_MAIN,
- M_EDITOR,
- M_KNOB,
- M_KRF,
- M_KPF,
- M_VOLT,
- M_SETTING,
- M_ABOUT,
- };
-
- //状态,初始化标签
- enum
- {
- S_FADE, //转场动画
- S_WINDOW, //弹窗初始化
- S_LAYER_IN, //层级初始化
- S_LAYER_OUT, //层级初始化
- S_NONE, //直接选择页面
- };
-
- //菜单结构体
- typedef struct MENU
- {
- char *m_select;
- } M_SELECT;
-
- /************************************* 定义内容 *************************************/
-
- /************************************* 文字内容 *************************************/
-
- M_SELECT main_menu[]
- {
- {"Sleep"},
- {"Editor"},
- {"Volt"},
- {"Setting"},
- };
-
- M_SELECT editor_menu[]
- {
- {"[ Editor ]"},
- {"- Function 0"},
- {"- Function 1"},
- {"- Function 2"},
- {"- Function 3"},
- {"- Function 4"},
- {"- Function 5"},
- {"- Function 6"},
- {"- Function 7"},
- {"- Function 8"},
- {"- Function 9"},
- {"- Knob"},
- };
-
- M_SELECT knob_menu[]
- {
- {"[ Knob ]"},
- {"# Rotate Func"},
- {"$ Press Func"},
- };
-
- M_SELECT krf_menu[]
- {
- {"[ Rotate Function ]"},
- {"--------------------------"},
- {"= Disable"},
- {"--------------------------"},
- {"= Volume"},
- {"= Brightness"},
- {"--------------------------"},
- };
-
- M_SELECT kpf_menu[]
- {
- {"[ Press Function ]"},
- {"--------------------------"},
- {"= Disable"},
- {"--------------------------"},
- {"= A"},
- {"= B"},
- {"= C"},
- {"= D"},
- {"= E"},
- {"= F"},
- {"= G"},
- {"= H"},
- {"= I"},
- {"= J"},
- {"= K"},
- {"= L"},
- {"= M"},
- {"= N"},
- {"= O"},
- {"= P"},
- {"= Q"},
- {"= R"},
- {"= S"},
- {"= T"},
- {"= U"},
- {"= V"},
- {"= W"},
- {"= X"},
- {"= Y"},
- {"= Z"},
- {"--------------------------"},
- {"= 0"},
- {"= 1"},
- {"= 2"},
- {"= 3"},
- {"= 4"},
- {"= 5"},
- {"= 6"},
- {"= 7"},
- {"= 8"},
- {"= 9"},
- {"--------------------------"},
- {"= Esc"},
- {"= F1"},
- {"= F2"},
- {"= F3"},
- {"= F4"},
- {"= F5"},
- {"= F6"},
- {"= F7"},
- {"= F8"},
- {"= F9"},
- {"= F10"},
- {"= F11"},
- {"= F12"},
- {"--------------------------"},
- {"= Left Ctrl"},
- {"= Left Shift"},
- {"= Left Alt"},
- {"= Left Win"},
- {"= Right Ctrl"},
- {"= Right Shift"},
- {"= Right Alt"},
- {"= Right Win"},
- {"--------------------------"},
- {"= Caps Lock"},
- {"= Backspace"},
- {"= Return"},
- {"= Insert"},
- {"= Delete"},
- {"= Tab"},
- {"--------------------------"},
- {"= Home"},
- {"= End"},
- {"= Page Up"},
- {"= Page Down"},
- {"--------------------------"},
- {"= Up Arrow"},
- {"= Down Arrow"},
- {"= Left Arrow"},
- {"= Right Arrow"},
- {"--------------------------"},
- };
-
- M_SELECT volt_menu[]
- {
- {"A0"},
- {"A1"},
- {"A2"},
- {"A3"},
- {"A4"},
- {"A5"},
- {"A6"},
- {"A7"},
- {"B0"},
- {"B1"},
- };
-
- M_SELECT setting_menu[]
- {
- {"[ Setting ]"},
- {"~ Disp Bri"},
- {"~ Tile Ani"},
- {"~ List Ani"},
- {"~ Win Ani"},
- {"~ Spot Ani"},
- {"~ Tag Ani"},
- {"~ Fade Ani"},
- {"~ Btn SPT"},
- {"~ Btn LPT"},
- {"+ T Ufd Fm Scr"},
- {"+ L Ufd Fm Scr"},
- {"+ T Loop Mode"},
- {"+ L Loop Mode"},
- {"+ Win Bokeh Bg"},
- {"+ Knob Rot Dir"},
- {"+ Dark Mode"},
- {"- [ About ]"},
- };
-
- M_SELECT about_menu[]
- {
- {"[ FlexUI ]"},
- {"- Version: v1.0"},
- {"- Board: ESP32 PICO"},
- {"- Ram: 340k"},
- {"- Flash: 4MB"},
- {"- Freq: 240Mhz"},
- {"- Creator: Leon"},
- {"- Billi UID: 20230705"},
- };
-
- /************************************* 图片内容 *************************************/
-
- const uint8_t main_icon_pic[][120]
- {
- {
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xF1,0x3F,
- 0xFF,0xFF,0xC3,0x3F,0xFF,0xFF,0x87,0x3F,0xFF,0xFF,0x07,0x3F,0xFF,0xFF,0x0F,0x3E,
- 0xFF,0xFF,0x0F,0x3E,0xFF,0xFF,0x0F,0x3C,0xFF,0xFF,0x0F,0x3C,0xFF,0xFF,0x0F,0x38,
- 0xFF,0xFF,0x0F,0x38,0xFF,0xFF,0x0F,0x38,0xFF,0xFF,0x07,0x38,0xFF,0xFF,0x07,0x38,
- 0xFF,0xFF,0x03,0x38,0xF7,0xFF,0x01,0x38,0xE7,0xFF,0x00,0x3C,0x87,0x3F,0x00,0x3C,
- 0x0F,0x00,0x00,0x3E,0x0F,0x00,0x00,0x3E,0x1F,0x00,0x00,0x3F,0x3F,0x00,0x80,0x3F,
- 0x7F,0x00,0xC0,0x3F,0xFF,0x01,0xF0,0x3F,0xFF,0x07,0xFC,0x3F,0xFF,0xFF,0xFF,0x3F,
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F
- },
- {
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFF,0xF9,0xE7,0x3F,
- 0xFF,0xF9,0xE7,0x3F,0xFF,0xF9,0xE7,0x3F,0xFF,0xF0,0xE7,0x3F,0x7F,0xE0,0xE7,0x3F,
- 0x7F,0xE0,0xC3,0x3F,0x7F,0xE0,0xC3,0x3F,0x7F,0xE0,0xC3,0x3F,0x7F,0xE0,0xE7,0x3F,
- 0xFF,0xF0,0xE7,0x3F,0xFF,0xF9,0xE7,0x3F,0xFF,0xF9,0xE7,0x3F,0xFF,0xF9,0xE7,0x3F,
- 0xFF,0xF9,0xE7,0x3F,0xFF,0xF9,0xC3,0x3F,0xFF,0xF9,0x81,0x3F,0xFF,0xF0,0x81,0x3F,
- 0xFF,0xF0,0x81,0x3F,0xFF,0xF0,0x81,0x3F,0xFF,0xF9,0x81,0x3F,0xFF,0xF9,0xC3,0x3F,
- 0xFF,0xF9,0xE7,0x3F,0xFF,0xF9,0xE7,0x3F,0xFF,0xF9,0xE7,0x3F,0xFF,0xFF,0xFF,0x3F,
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F
- },
- {
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xEF,0xFF,0xFF,0x3F,0xC7,0xFF,0xFF,0x3F,
- 0xC7,0xF3,0xFF,0x3F,0x83,0xC0,0xFF,0x3F,0xEF,0xCC,0xFF,0x3F,0x6F,0x9E,0xFF,0x3F,
- 0x6F,0x9E,0xFF,0x3F,0x2F,0x3F,0xFF,0x3F,0x2F,0x3F,0xFF,0x3F,0x8F,0x7F,0xFE,0x3F,
- 0x8F,0x7F,0xFE,0x39,0x8F,0x7F,0xFE,0x39,0xCF,0xFF,0xFC,0x3C,0xCF,0xFF,0xFC,0x3C,
- 0xEF,0xFF,0xFC,0x3C,0xEF,0xFF,0x79,0x3E,0xEF,0xFF,0x79,0x3E,0xEF,0xFF,0x33,0x3F,
- 0xEF,0xFF,0x33,0x3F,0xEF,0xFF,0x87,0x3F,0xEF,0xFF,0xCF,0x3F,0xEF,0xFF,0x7F,0x3E,
- 0xEF,0xFF,0x7F,0x38,0x0F,0x00,0x00,0x30,0xFF,0xFF,0x7F,0x38,0xFF,0xFF,0x7F,0x3E,
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,
- },
- {
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,
- 0xFF,0x1F,0xFE,0x3F,0xFF,0x1F,0xFE,0x3F,0xFF,0x0C,0xCC,0x3F,0x7F,0x00,0x80,0x3F,
- 0x3F,0x00,0x00,0x3F,0x3F,0xE0,0x01,0x3F,0x7F,0xF8,0x87,0x3F,0x7F,0xFC,0x8F,0x3F,
- 0x3F,0xFC,0x0F,0x3F,0x0F,0x3E,0x1F,0x3C,0x0F,0x1E,0x1E,0x3C,0x0F,0x1E,0x1E,0x3C,
- 0x0F,0x3E,0x1F,0x3C,0x3F,0xFC,0x0F,0x3F,0x7F,0xFC,0x8F,0x3F,0x7F,0xF8,0x87,0x3F,
- 0x3F,0xE0,0x01,0x3F,0x3F,0x00,0x00,0x3F,0x7F,0x00,0x80,0x3F,0xFF,0x0C,0xCC,0x3F,
- 0xFF,0x1F,0xFE,0x3F,0xFF,0x1F,0xFE,0x3F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F,
- 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0x3F
- },
- };
-
- /************************************* 页面变量 *************************************/
-
- //OLED变量
- #define DISP_H 64 //屏幕高度
- #define DISP_W 128 //屏幕宽度
- uint8_t *buf_ptr; //指向屏幕缓冲的指针
- uint16_t buf_len; //缓冲长度
-
- //UI变量
- #define UI_DEPTH 20 //最深层级数
- #define UI_MNUMB 100 //菜单数量
- #define UI_PARAM 16 //参数数量
- enum
- {
- DISP_BRI, //屏幕亮度
- TILE_ANI, //磁贴动画速度
- LIST_ANI, //列表动画速度
- WIN_ANI, //弹窗动画速度
- SPOT_ANI, //聚光动画速度
- TAG_ANI, //标签动画速度
- FADE_ANI, //消失动画速度
- BTN_SPT, //按键短按时长
- BTN_LPT, //按键长按时长
- TILE_UFD, //磁贴图标从头展开开关
- LIST_UFD, //菜单列表从头展开开关
- TILE_LOOP, //磁贴图标循环模式开关
- LIST_LOOP, //菜单列表循环模式开关
- WIN_BOK, //弹窗背景虚化开关
- KNOB_DIR, //旋钮方向切换开关
- DARK_MODE, //黑暗模式开关
- };
- struct
- {
- bool init;
- uint8_t num[UI_MNUMB];
- uint8_t select[UI_DEPTH];
- uint8_t layer;
- uint8_t index = M_MAIN;
- uint8_t state = S_LAYER_IN;
- bool sleep = true;
- uint8_t fade = 1;
- uint8_t param[UI_PARAM];
- } ui;
-
- //磁贴变量
- //所有磁贴页面都使用同一套参数
- #define TILE_B_FONT u8g2_font_helvB18_tr //磁贴大标题字体
- #define TILE_B_TITLE_H 18 //磁贴大标题字体高度
- #define TILE_ICON_H 30 //磁贴图标高度
- #define TILE_ICON_W 30 //磁贴图标宽度
- #define TILE_ICON_S 36 //磁贴图标间距
- #define TILE_INDI_H 27 //磁贴大标题指示器高度
- #define TILE_INDI_W 7 //磁贴大标题指示器宽度
- #define TILE_INDI_S 36 //磁贴大标题指示器上边距
- struct
- {
- float title_y_calc = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H * 2;
- float title_y_trg_calc = TILE_INDI_S + (TILE_INDI_H - TILE_B_TITLE_H) / 2 + TILE_B_TITLE_H;
- int16_t temp;
- bool select_flag;
- float icon_x;
- float icon_x_trg;
- float icon_y;
- float icon_y_trg;
- float indi_x;
- float indi_x_trg;
- float title_y;
- float title_y_trg;
- } tile;
-
- //列表变量
- //默认参数
-
- #define LIST_FONT u8g2_font_HelvetiPixel_tr //列表字体
- #define LIST_TEXT_H 8 //列表每行文字字体的高度
- #define LIST_LINE_H 16 //列表单行高度
- #define LIST_TEXT_S 4 //列表每行文字的上边距,左边距和右边距,下边距由它和字体高度和行高度决定
- #define LIST_BAR_W 5 //列表进度条宽度,需要是奇数,因为正中间有1像素宽度的线
- #define LIST_BOX_R 0.5 //列表选择框圆角
-
- /*
- //超窄行高度测试
- #define LIST_FONT u8g2_font_4x6_tr //列表字体
- #define LIST_TEXT_H 5 //列表每行文字字体的高度
- #define LIST_LINE_H 7 //列表单行高度
- #define LIST_TEXT_S 1 //列表每行文字的上边距,左边距和右边距,下边距由它和字体高度和行高度决定
- #define LIST_BAR_W 7 //列表进度条宽度,需要是奇数,因为正中间有1像素宽度的线
- #define LIST_BOX_R 0.5 //列表选择框圆角
- */
- struct
- {
- uint8_t line_n = DISP_H / LIST_LINE_H;
- int16_t temp;
- bool loop;
- float y;
- float y_trg;
- float box_x;
- float box_x_trg;
- float box_y;
- float box_y_trg[UI_DEPTH];
- float bar_y;
- float bar_y_trg;
- } list;
-
- //曲线相关
- #define WAVE_SAMPLE 20 //采集倍数
- #define WAVE_W 94 //波形宽度
- #define WAVE_L 24 //波形左边距
- #define WAVE_U 0 //波形上边距
- #define WAVE_MAX 27 //最大值
- #define WAVE_MIN 4 //最小值
- #define WAVE_BOX_H 32 //波形边框高度
- #define WAVE_BOX_W 94 //波形边框宽度
- #define WAVE_BOX_L_S 24 //波形边框左边距
- //列表和文字背景框相关
- #define VOLT_FONT u8g2_font_helvB18_tr //电压数字字体
- #define VOLT_TEXT_BG_L_S 24 //文字背景框左边距
- #define VOLT_TEXT_BG_W 94 //文字背景框宽度
- #define VOLT_TEXT_BG_H 29 //文字背景框高度
- struct
- {
- int ch0_adc[WAVE_SAMPLE * WAVE_W];
- int ch0_wave[WAVE_W];
- int val;
- float text_bg_r;
- float text_bg_r_trg;
- } volt;
-
-
- //选择框变量
-
- //默认参数
- #define CHECK_BOX_L_S 95 //选择框在每行的左边距
- #define CHECK_BOX_U_S 2 //选择框在每行的上边距
- #define CHECK_BOX_F_W 12 //选择框外框宽度
- #define CHECK_BOX_F_H 12 //选择框外框高度
- #define CHECK_BOX_D_S 2 //选择框里面的点距离外框的边距
-
- /*
- //超窄行高度测试
- #define CHECK_BOX_L_S 99 //选择框在每行的左边距
- #define CHECK_BOX_U_S 0 //选择框在每行的上边距
- #define CHECK_BOX_F_W 5 //选择框外框宽度
- #define CHECK_BOX_F_H 5 //选择框外框高度
- #define CHECK_BOX_D_S 1 //选择框里面的点距离外框的边距
- */
- struct
- {
- uint8_t *v;
- uint8_t *m;
- uint8_t *s;
- uint8_t *s_p;
- } check_box;
-
- //弹窗变量
- #define WIN_FONT u8g2_font_HelvetiPixel_tr //弹窗字体
- #define WIN_H 32 //弹窗高度
- #define WIN_W 102 //弹窗宽度
- #define WIN_BAR_W 92 //弹窗进度条宽度
- #define WIN_BAR_H 7 //弹窗进度条高度
- #define WIN_Y - WIN_H - 2 //弹窗竖直方向出场起始位置
- #define WIN_Y_TRG - WIN_H - 2 //弹窗竖直方向退场终止位置
- struct
- {
- //uint8_t
- uint8_t *value;
- uint8_t max;
- uint8_t min;
- uint8_t step;
-
- MENU *bg;
- uint8_t index;
- char title[20];
- uint8_t select;
- uint8_t l = (DISP_W - WIN_W) / 2;
- uint8_t u = (DISP_H - WIN_H) / 2;
- float bar;
- float bar_trg;
- float y;
- float y_trg;
- } win;
-
- //聚光灯变量
- struct
- {
- float l;
- float l_trg;
- float r;
- float r_trg;
- float u;
- float u_trg;
- float d;
- float d_trg;
- } spot;
-
- /********************************** 自定义功能变量 **********************************/
-
- //旋钮功能变量
- #define KNOB_PARAM 4
- #define KNOB_DISABLE 0
- #define KNOB_ROT_VOL 1
- #define KNOB_ROT_BRI 2
- enum
- {
- KNOB_ROT, //睡眠下旋转旋钮的功能,0 禁用,1 音量,2 亮度
- KNOB_COD, //睡眠下短按旋钮输入的字符码,0 禁用
- KNOB_ROT_P, //旋转旋钮功能在单选框中选择的位置
- KNOB_COD_P, //字符码在单选框中选择的位置
- };
- struct
- {
- uint8_t param[KNOB_PARAM] = { KNOB_DISABLE, KNOB_DISABLE, 2, 2 }; //禁用在列表的第2个选项,第0个是标题,第1个是分界线
- } knob;
-
- /************************************* 断电保存 *************************************/
-
- //#include <EEPROM.h>
-
- //EEPROM变量
- #define EEPROM_CHECK 11
- struct
- {
- bool init;
- bool change;
- int address;
- uint8_t check;
- uint8_t check_param[EEPROM_CHECK] = { 'a', 'b', 'c', 'd', 'e', 'f','g', 'h', 'i', 'j', 'k' };
- } eeprom;
-
- //EEPROM写数据,回到睡眠时执行一遍
- void eeprom_write_all_data()
- {
- #if 0
- eeprom.address = 0;
- for (uint8_t i = 0; i < EEPROM_CHECK; ++i) EEPROM.write(eeprom.address + i, eeprom.check_param[i]); eeprom.address += EEPROM_CHECK;
- for (uint8_t i = 0; i < UI_PARAM; ++i) EEPROM.write(eeprom.address + i, ui.param[i]); eeprom.address += UI_PARAM;
- for (uint8_t i = 0; i < KNOB_PARAM; ++i) EEPROM.write(eeprom.address + i, knob.param[i]); eeprom.address += KNOB_PARAM;
- #else
- nvs_handle handle;
- int32_t err;
-
- // Open
- err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle);
- if (err != ESP_OK) goto err;
-
- err = nvs_set_blob(handle, "ui_param_ck", eeprom.check_param, EEPROM_CHECK);
- if (err != ESP_OK) goto err;
-
- err = nvs_set_blob(handle, "ui_param", ui.param, UI_PARAM);
- if (err != ESP_OK) goto err;
-
- err = nvs_set_blob(handle, "knob_param", knob.param, KNOB_PARAM);
- if (err != ESP_OK) goto err;
-
-
- ESP_LOGI(TAG, "param write all finish!");
-
- err = nvs_commit(handle);
- if (err != ESP_OK) goto err;
-
- err:
- // Close
- nvs_close(handle);
- #endif
- }
-
- //EEPROM读数据,开机初始化时执行一遍
- void eeprom_read_all_data()
- {
- #if 0
- eeprom.address = EEPROM_CHECK;
- for (uint8_t i = 0; i < UI_PARAM; ++i) ui.param[i] = EEPROM.read(eeprom.address + i); eeprom.address += UI_PARAM;
- for (uint8_t i = 0; i < KNOB_PARAM; ++i) knob.param[i] = EEPROM.read(eeprom.address + i); eeprom.address += KNOB_PARAM;
- #else
- nvs_handle handle;
- size_t length;
- int32_t err;
-
- // Open
- err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle);
- if (err != ESP_OK) goto err;
-
- err = nvs_get_blob(handle, "ui_param", NULL, &length);
- err = nvs_get_blob(handle, "ui_param", ui.param, &length);
- if (err != ESP_OK) goto err;
-
- err = nvs_get_blob(handle, "knob_param", NULL, &length);
- err = nvs_get_blob(handle, "knob_param", knob.param, &length);
- if (err != ESP_OK) goto err;
-
- ESP_LOGI(TAG, "param read all finish!");
-
- err:
- // Close
- nvs_close(handle);
-
- #endif
- }
-
- //开机检查是否已经修改过,没修改过则跳过读配置步骤,用默认设置
- void eeprom_init()
- {
- #if 0
- eeprom.check = 0;
- eeprom.address = 0; for (uint8_t i = 0; i < EEPROM_CHECK; ++i) if (EEPROM.read(eeprom.address + i) != eeprom.check_param[i]) eeprom.check ++;
- if (eeprom.check <= 1) eeprom_read_all_data(); //允许一位误码
- else ui_param_init();
- #else
- nvs_handle handle;
- size_t length;
- int32_t err;
-
- uint8_t check_param[EEPROM_CHECK] = {0};
-
- // Open
- err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle);
- if (err != ESP_OK) goto err;
-
- err = nvs_get_blob(handle, "ui_param_ck", NULL, &length);
- err = nvs_get_blob(handle, "ui_param_ck", check_param, &length);
-
- if (err != ESP_OK) {
- ui_param_init();
- goto err;
- }
-
- eeprom.check = 0;
- eeprom.address = 0; for (uint8_t i = 0; i < EEPROM_CHECK; ++i) if (check_param[i] != eeprom.check_param[i]) eeprom.check ++;
- if (eeprom.check <= 1) eeprom_read_all_data(); //允许一位误码
- else ui_param_init();
-
- ESP_LOGI(TAG, "ui param check pass!");
-
- err:
- // Close
- nvs_close(handle);
- #endif
- }
-
- /************************************* 旋钮相关 *************************************/
-
- //可按下旋钮引脚
- #define AIO PB12
- #define BIO PB13
- //#define SW PB14
- #define SW 34
-
- //按键ID
- #define BTN_ID_CC 0 //逆时针旋转
- #define BTN_ID_CW 1 //顺时针旋转
- #define BTN_ID_SP 2 //短按
- #define BTN_ID_LP 3 //长按
-
- //按键变量
- #define BTN_PARAM_TIMES 2 //由于uint8_t最大值可能不够,但它存储起来方便,这里放大两倍使用
- struct
- {
- uint8_t id;
- bool flag;
- bool pressed;
- bool CW_1;
- bool CW_2;
- bool val;
- bool val_last;
- bool alv;
- bool blv;
- long count;
- } volatile btn;
-
- void knob_inter()
- {
- #if 0
- btn.alv = digitalRead(AIO);
- btn.blv = digitalRead(BIO);
- if (!btn.flag && btn.alv == LOW)
- {
- btn.CW_1 = btn.blv;
- btn.flag = true;
- }
- if (btn.flag && btn.alv)
- {
- btn.CW_2 = !btn.blv;
- if (btn.CW_1 && btn.CW_2)
- {
- btn.id = ui.param[KNOB_DIR];
- btn.pressed = true;
- }
- if (btn.CW_1 == false && btn.CW_2 == false)
- {
- btn.id = !ui.param[KNOB_DIR];
- btn.pressed = true;
- }
- btn.flag = false;
- }
- #else
- if (btn.pressed == false) {
- if (motor_a.pos_spd_ltd.v2 > 60) {
- btn.id = !ui.param[KNOB_DIR];
- btn.pressed = true;
- } else if (motor_a.pos_spd_ltd.v2 < -60) {
- btn.id = ui.param[KNOB_DIR];
- btn.pressed = true;
- } else {
- btn.pressed = false;
- }
- }
- #endif
- }
-
- void btn_scan()
- {
- btn.val = digitalRead(SW);
- if (btn.val != btn.val_last)
- {
- btn.val_last = btn.val;
- delay(ui.param[BTN_SPT] * BTN_PARAM_TIMES);
- btn.val = digitalRead(SW);
- if (btn.val == LOW)
- {
- btn.pressed = true;
- btn.count = 0;
- while (!digitalRead(SW))
- {
- btn.count++;
- delay(1);
- }
- if (btn.count < ui.param[BTN_LPT] * BTN_PARAM_TIMES) btn.id = BTN_ID_SP;
- else btn.id = BTN_ID_LP;
- ESP_LOGI(TAG, "btn_scan:%d/%d=%d", btn.count, (ui.param[BTN_LPT] * BTN_PARAM_TIMES), btn.id);
- }
- }
- }
-
- void btn_init()
- {
- #if 0
- pinMode(AIO, INPUT);
- pinMode(BIO, INPUT);
- pinMode(SW, INPUT_PULLUP);
- attachInterrupt(digitalPinToInterrupt(AIO), knob_inter, CHANGE);
- #else
-
- #endif
- }
-
- /************************************ 初始化函数 ***********************************/
-
- /********************************* 初始化数据处理函数 *******************************/
-
- //显示数值的初始化
- void check_box_v_init(uint8_t *param)
- {
- check_box.v = param;
- }
-
- //多选框的初始化
- void check_box_m_init(uint8_t *param)
- {
- check_box.m = param;
- }
-
- //单选框时的初始化
- void check_box_s_init(uint8_t *param, uint8_t *param_p)
- {
- check_box.s = param;
- check_box.s_p = param_p;
- }
-
- //多选框处理函数
- void check_box_m_select(uint8_t param)
- {
- check_box.m[param] = !check_box.m[param];
- eeprom.change = true;
- }
-
- //单选框处理函数
- void check_box_s_select(uint8_t val, uint8_t pos)
- {
- *check_box.s = val;
- *check_box.s_p = pos;
- eeprom.change = true;
- }
-
- //弹窗数值初始化
- void window_value_init(char title[], uint8_t select, uint8_t *value, uint8_t max, uint8_t min, uint8_t step, MENU *bg, uint8_t index)
- {
- strcpy(win.title, title);
- win.select = select;
- win.value = value;
- win.max = max;
- win.min = min;
- win.step = step;
- win.bg = bg;
- win.index = index;
- ui.index = M_WINDOW;
- ui.state = S_WINDOW;
- }
-
- /*********************************** UI 初始化函数 *********************************/
-
- //在初始化EEPROM时,选择性初始化的默认设置
- void ui_param_init()
- {
- ui.param[DISP_BRI] = 255; //屏幕亮度
- ui.param[TILE_ANI] = 30; //磁贴动画速度
- ui.param[LIST_ANI] = 60; //列表动画速度
- ui.param[WIN_ANI] = 25; //弹窗动画速度
- ui.param[SPOT_ANI] = 50; //聚光动画速度
- ui.param[TAG_ANI] = 60; //标签动画速度
- ui.param[FADE_ANI] = 30; //消失动画速度
- ui.param[BTN_SPT] = 25; //按键短按时长
- ui.param[BTN_LPT] = 150; //按键长按时长
- ui.param[TILE_UFD] = 1; //磁贴图标从头展开开关
- ui.param[LIST_UFD] = 1; //菜单列表从头展开开关
- ui.param[TILE_LOOP] = 0; //磁贴图标循环模式开关
- ui.param[LIST_LOOP] = 0; //菜单列表循环模式开关
- ui.param[WIN_BOK] = 0; //弹窗背景虚化开关
- ui.param[KNOB_DIR] = 0; //旋钮方向切换开关
- ui.param[DARK_MODE] = 1; //黑暗模式开关
- }
-
- //列表类页面列表行数初始化,必须初始化的参数
- void ui_init()
- {
- ui.num[M_MAIN] = sizeof( main_menu ) / sizeof(M_SELECT);
- ui.num[M_EDITOR] = sizeof( editor_menu ) / sizeof(M_SELECT);
- ui.num[M_KNOB] = sizeof( knob_menu ) / sizeof(M_SELECT);
- ui.num[M_KRF] = sizeof( krf_menu ) / sizeof(M_SELECT);
- ui.num[M_KPF] = sizeof( kpf_menu ) / sizeof(M_SELECT);
- ui.num[M_VOLT] = sizeof( volt_menu ) / sizeof(M_SELECT);
- ui.num[M_SETTING] = sizeof( setting_menu ) / sizeof(M_SELECT);
- ui.num[M_ABOUT] = sizeof( about_menu ) / sizeof(M_SELECT);
- }
-
- /********************************* 分页面初始化函数 ********************************/
-
- //进入磁贴类时的初始化
- void tile_param_init()
- {
- ui.init = false;
- tile.icon_x = 0;
- tile.icon_x_trg = TILE_ICON_S;
- tile.icon_y = -TILE_ICON_H;
- tile.icon_y_trg = 0;
- tile.indi_x = 0;
- tile.indi_x_trg = TILE_INDI_W;
- tile.title_y = tile.title_y_calc;
- tile.title_y_trg = tile.title_y_trg_calc;
- }
-
- //进入睡眠时的初始化
- void sleep_param_init()
- {
- //#ifdef ARDUINO
- #if 0
- u8g2.setDrawColor(0);
- u8g2.drawBox(0, 0, DISP_W, DISP_H);
- u8g2.setPowerSave(1);
- #else
- u8g2_SetDrawColor(&u8g2, 0);
- u8g2_DrawBox(&u8g2, 0, 0, DISP_W, DISP_H);
- //u8g2_SetPowerSave(&u8g2, 1);
- #endif
- ui.state = S_NONE;
- ui.sleep = true;
- if (eeprom.change)
- {
- eeprom_write_all_data();
- eeprom.change = false;
- }
- }
-
- //旋钮设置页初始化
- void knob_param_init() { check_box_v_init(knob.param); }
-
- //旋钮旋转页初始化
- void krf_param_init() { check_box_s_init(&knob.param[KNOB_ROT], &knob.param[KNOB_ROT_P]); }
-
- //旋钮点按页初始化
- void kpf_param_init() { check_box_s_init(&knob.param[KNOB_COD], &knob.param[KNOB_COD_P]); }
-
- //电压测量页初始化
- void volt_param_init()
- {
- volt.text_bg_r = 0;
- volt.text_bg_r_trg = VOLT_TEXT_BG_W;
- }
-
- //设置页初始化
- void setting_param_init()
- {
- check_box_v_init(ui.param);
- check_box_m_init(ui.param);
- }
-
- /********************************** 通用初始化函数 *********************************/
-
- /*
- 页面层级管理逻辑是,把所有页面都先当作列表类初始化,不是列表类按需求再初始化对应函数
- 这样做会浪费一些资源,但跳转页面时只需要考虑页面层级,逻辑上更清晰,减少出错
- */
-
- //弹窗动画初始化
- void window_param_init()
- {
- win.bar = 0;
- win.y = WIN_Y;
- win.y_trg = win.u;
- ui.state = S_NONE;
- }
-
- //进入更深层级时的初始化
- void layer_init_in()
- {
- ui.layer ++;
- ui.init = 0;
- list.y = 0;
- list.y_trg = LIST_LINE_H;
- list.box_x = 0;
- list.box_y = 0;
- list.bar_y = 0;
- ui.state = S_FADE;
- switch (ui.index)
- {
- case M_MAIN: tile_param_init(); break; //睡眠进入主菜单,动画初始化
- case M_KNOB: knob_param_init(); break; //旋钮设置页,行末尾文字初始化
- case M_KRF: krf_param_init(); break; //旋钮旋转页,单选框初始化
- case M_KPF: kpf_param_init(); break; //旋钮点按页,单选框初始化
- case M_VOLT: volt_param_init(); break; //主菜单进入电压测量页,动画初始化
- case M_SETTING: setting_param_init(); break; //主菜单进入设置页,单选框初始化
- }
- }
-
- //进入更浅层级时的初始化
- void layer_init_out()
- {
- ui.select[ui.layer] = 0;
- list.box_y_trg[ui.layer] = 0;
- ui.layer --;
- ui.init = 0;
- list.y = 0;
- list.y_trg = LIST_LINE_H;
- list.bar_y = 0;
- ui.state = S_FADE;
- switch (ui.index)
- {
- case M_SLEEP: sleep_param_init(); break; //主菜单进入睡眠页,检查是否需要写EEPROM
- case M_MAIN: tile_param_init(); break; //不管什么页面进入主菜单时,动画初始化
- }
- }
-
- /************************************* 动画函数 *************************************/
-
- //动画函数
- void animation(float *a, float *a_trg, uint8_t n)
- {
- if (fabs(*a - *a_trg) < 0.15) *a = *a_trg;
- if (*a != *a_trg) *a += (*a_trg - *a) / (ui.param[n] / 10.0);
- }
-
- //消失函数
- void fade()
- {
- delay(ui.param[FADE_ANI]);
- if (ui.param[DARK_MODE])
- {
- switch (ui.fade)
- {
- case 1: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 != 0) buf_ptr[i] = buf_ptr[i] & 0xAA; break;
- case 2: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 != 0) buf_ptr[i] = buf_ptr[i] & 0x00; break;
- case 3: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 == 0) buf_ptr[i] = buf_ptr[i] & 0x55; break;
- case 4: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 == 0) buf_ptr[i] = buf_ptr[i] & 0x00; break;
- default: ui.state = S_NONE; ui.fade = 0; break;
- }
- }
- else
- {
- switch (ui.fade)
- {
- case 1: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 != 0) buf_ptr[i] = buf_ptr[i] | 0xAA; break;
- case 2: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 != 0) buf_ptr[i] = buf_ptr[i] | 0x00; break;
- case 3: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 == 0) buf_ptr[i] = buf_ptr[i] | 0x55; break;
- case 4: for (uint16_t i = 0; i < buf_len; ++i) if (i % 2 == 0) buf_ptr[i] = buf_ptr[i] | 0x00; break;
- default: ui.state = S_NONE; ui.fade = 0; break;
- }
- }
- ui.fade++;
- }
-
- /************************************* 显示函数 *************************************/
-
- //磁贴类页面通用显示函数
- void tile_show(struct MENU arr_1[], const uint8_t icon_pic[][120])
- {
- //计算动画过渡值
- animation(&tile.icon_x, &tile.icon_x_trg, TILE_ANI);
- animation(&tile.icon_y, &tile.icon_y_trg, TILE_ANI);
- animation(&tile.indi_x, &tile.indi_x_trg, TILE_ANI);
- animation(&tile.title_y, &tile.title_y_trg, TILE_ANI);
-
- //设置大标题的颜色,0透显,1实显,2反色,这里用实显
- //u8g2.setDrawColor(1);
- u8g2_SetDrawColor(&u8g2, 1);
-
- //绘制大标题
- //u8g2.setFont(TILE_B_FONT);
- //u8g2.drawStr(((DISP_W - TILE_INDI_W) - u8g2.getStrWidth(arr_1[ui.select[ui.layer]].m_select)) / 2 + TILE_INDI_W, tile.title_y, arr_1[ui.select[ui.layer]].m_select);
- u8g2_SetFont(&u8g2, TILE_B_FONT);
- u8g2_DrawStr(&u8g2, ((DISP_W - TILE_INDI_W) - u8g2_GetStrWidth(&u8g2, arr_1[ui.select[ui.layer]].m_select)) / 2 + TILE_INDI_W, tile.title_y, arr_1[ui.select[ui.layer]].m_select);
-
- //绘制大标题指示器
- //u8g2.drawBox(0, TILE_ICON_S, tile.indi_x, TILE_INDI_H);
- u8g2_DrawBox(&u8g2, 0, TILE_ICON_S, tile.indi_x, TILE_INDI_H);
-
- //绘制图标
- if (!ui.init)
- {
- for (uint8_t i = 0; i < ui.num[ui.index]; ++i)
- {
- if (ui.param[TILE_UFD]) tile.temp = (DISP_W - TILE_ICON_W) / 2 + i * tile.icon_x - TILE_ICON_S * ui.select[ui.layer];
- else tile.temp = (DISP_W - TILE_ICON_W) / 2 + (i - ui.select[ui.layer]) * tile.icon_x;
- //u8g2.drawXBMP(tile.temp, (int16_t)tile.icon_y, TILE_ICON_W, TILE_ICON_H, icon_pic[i]);
- u8g2_DrawXBMP(&u8g2, tile.temp, (int16_t)tile.icon_y, TILE_ICON_W, TILE_ICON_H, icon_pic[i]);
- }
- if (tile.icon_x == tile.icon_x_trg)
- {
- ui.init = true;
- tile.icon_x = tile.icon_x_trg = - ui.select[ui.layer] * TILE_ICON_S;
- }
- }
- else for (uint8_t i = 0; i < ui.num[ui.index]; ++i)
- //u8g2.drawXBMP((DISP_W - TILE_ICON_W) / 2 + (int16_t)tile.icon_x + i * TILE_ICON_S, 0, TILE_ICON_W, TILE_ICON_H, icon_pic[i]);
- u8g2_DrawXBMP(&u8g2, (DISP_W - TILE_ICON_W) / 2 + (int16_t)tile.icon_x + i * TILE_ICON_S, 0, TILE_ICON_W, TILE_ICON_H, icon_pic[i]);
-
-
- //反转屏幕内元素颜色,白天模式遮罩
- //u8g2.setDrawColor(2);
- u8g2_SetDrawColor(&u8g2, 2);
- if (!ui.param[DARK_MODE])
- //u8g2.drawBox(0, 0, DISP_W, DISP_H);
- u8g2_DrawBox(&u8g2, 0, 0, DISP_W, DISP_H);
- }
-
- static u8g2_uint_t u8g2_cursor_x = 0;
- static u8g2_uint_t u8g2_cursor_y = 0;
-
- static void u8g2_setCursor(u8g2_uint_t x, u8g2_uint_t y) {
- u8g2_cursor_x = x;
- u8g2_cursor_y = y;
- }
-
- static u8g2_uint_t u8g2_print(const char *str) {
- u8g2_uint_t delta = u8g2_DrawStr(&u8g2, u8g2_cursor_x, u8g2_cursor_y, str);
- u8g2_cursor_x += delta;
- if (u8g2_cursor_x > DISP_W) u8g2_cursor_x=0;
- return delta;
- }
-
- #define DEC 10
- #define HEX 16
- #define OCT 8
- #define BIN 2
- static u8g2_uint_t printNumber(unsigned long n, uint8_t base)
- {
- char buf[8 * sizeof(n) + 1]; // Assumes 8-bit chars plus zero byte.
- char *str = &buf[sizeof(buf) - 1];
-
- *str = '\0';
- // prevent crash if called with base == 1
- if(base < 2) {
- base = 10;
- }
-
- do {
- char c = n % base;
- n /= base;
-
- *--str = c < 10 ? c + '0' : c + 'A' - 10;
- } while (n);
-
- return u8g2_print(str);
- }
-
- static u8g2_uint_t printNumber(long n, uint8_t base)
- {
- int t = 0;
- if (base == 10 && n < 0) {
- t = u8g2_print("-");
- n = -n;
- }
-
- return printNumber(static_cast<unsigned long>(n), base);
- }
-
- static u8g2_uint_t u8g2_print(char value) {
- return printNumber((long)value, DEC);
- }
-
- static u8g2_uint_t u8g2_print(unsigned char value) {
- return printNumber((unsigned long)value, DEC);
- }
-
- static u8g2_uint_t u8g2_print(int value) {
- return printNumber((long)value, DEC);
- }
-
- static u8g2_uint_t u8g2_print(unsigned int value) {
- return printNumber((unsigned long)value, DEC);
- }
-
- static u8g2_uint_t u8g2_print(long value) {
- return printNumber(value, DEC);
- }
-
- static u8g2_uint_t u8g2_print(unsigned long value) {
- return printNumber(value, DEC);
- }
-
- static u8g2_uint_t printFloat(double number, uint8_t digits) {
-
- u8g2_uint_t n = 0;
-
- if(isnan(number)) {
- return u8g2_print("nan");
- }
- if(isinf(number)) {
- return u8g2_print("inf");
- }
- if(number > 4294967040.0) {
- return u8g2_print("ovf"); // constant determined empirically
- }
- if(number < -4294967040.0) {
- return u8g2_print("ovf"); // constant determined empirically
- }
-
- // Handle negative numbers
- if(number < 0.0) {
- n += u8g2_print("-");
- number = -number;
- }
-
- // Round correctly so that print(1.999, 2) prints as "2.00"
- double rounding = 0.5;
- for(uint8_t i = 0; i < digits; ++i) {
- rounding /= 10.0;
- }
-
- number += rounding;
-
- // Extract the integer part of the number and print it
- unsigned long int_part = (unsigned long) number;
- double remainder = number - (double) int_part;
- n += u8g2_print(int_part);
-
- // Print the decimal point, but only if there are digits beyond
- if(digits > 0) {
- n += u8g2_print(".");
- }
-
- // Extract digits from the remainder one at a time
- while(digits-- > 0) {
- remainder *= 10.0;
- int toPrint = int(remainder);
- n += u8g2_print(toPrint);
- remainder -= toPrint;
- }
-
- return n;
- }
-
- static u8g2_uint_t u8g2_print(double value) {
- return printFloat(value, 3);
- }
-
-
- /*************** 根据列表每行开头符号,判断每行尾部是否绘制以及绘制什么内容 *************/
- //列表显示数值
- void list_draw_value(int n) {
- //u8g2.print(check_box.v[n - 1]);
- u8g2_print(check_box.v[n - 1]);
- }
-
- //绘制外框
- void list_draw_check_box_frame() {
- //u8g2.drawRFrame(CHECK_BOX_L_S, list.temp + CHECK_BOX_U_S, CHECK_BOX_F_W, CHECK_BOX_F_H, 1);
- u8g2_DrawRFrame(&u8g2, CHECK_BOX_L_S, list.temp + CHECK_BOX_U_S, CHECK_BOX_F_W, CHECK_BOX_F_H, 1);
- }
-
- //绘制框里面的点
- void list_draw_check_box_dot() {
- //u8g2.drawBox(CHECK_BOX_L_S + CHECK_BOX_D_S + 1, list.temp + CHECK_BOX_U_S + CHECK_BOX_D_S + 1, CHECK_BOX_F_W - (CHECK_BOX_D_S + 1) * 2, CHECK_BOX_F_H - (CHECK_BOX_D_S + 1) * 2);
- u8g2_DrawBox(&u8g2, CHECK_BOX_L_S + CHECK_BOX_D_S + 1, list.temp + CHECK_BOX_U_S + CHECK_BOX_D_S + 1, CHECK_BOX_F_W - (CHECK_BOX_D_S + 1) * 2, CHECK_BOX_F_H - (CHECK_BOX_D_S + 1) * 2);
- }
-
- //列表显示旋钮功能
- void list_draw_krf(int n)
- {
- switch (check_box.v[n - 1])
- {
- case 0: u8g2_print("OFF"); break;
- case 1: u8g2_print("VOL"); break;
- case 2: u8g2_print("BRI"); break;
- }
- }
-
- //列表显示按键键值
- void list_draw_kpf(int n)
- {
- if (check_box.v[n - 1] == 0) u8g2_print("OFF");
- else if (check_box.v[n - 1] <= 90) u8g2_print((char)check_box.v[n - 1]);
- else u8g2_print("?");
- }
-
- //判断列表尾部内容
- void list_draw_text_and_check_box(struct MENU arr[], int i)
- {
- //u8g2.drawStr(LIST_TEXT_S, list.temp + LIST_TEXT_H + LIST_TEXT_S, arr[i].m_select);
- //u8g2.setCursor(CHECK_BOX_L_S, list.temp + LIST_TEXT_H + LIST_TEXT_S);
- u8g2_DrawStr(&u8g2, LIST_TEXT_S, list.temp + LIST_TEXT_H + LIST_TEXT_S, arr[i].m_select);
- u8g2_setCursor(CHECK_BOX_L_S, list.temp + LIST_TEXT_H + LIST_TEXT_S);
-
- switch (arr[i].m_select[0])
- {
- case '~': list_draw_value(i); break;
- case '+': list_draw_check_box_frame(); if (check_box.m[i - 1] == 1) list_draw_check_box_dot(); break;
- case '=': list_draw_check_box_frame(); if (*check_box.s_p == i) list_draw_check_box_dot(); break;
- case '#': list_draw_krf(i); break;
- case '$': list_draw_kpf(i); break;
- }
- }
-
- /******************************** 列表显示函数 **************************************/
-
- //列表类页面通用显示函数
- void list_show(struct MENU arr[], uint8_t ui_index)
- {
- //更新动画目标值
- //u8g2.setFont(LIST_FONT);
- u8g2_SetFont(&u8g2, LIST_FONT);
-
- //list.box_x_trg = u8g2.getStrWidth(arr[ui.select[ui.layer]].m_select) + LIST_TEXT_S * 2;
- list.box_x_trg = u8g2_GetStrWidth(&u8g2, arr[ui.select[ui.layer]].m_select) + LIST_TEXT_S * 2;
- list.bar_y_trg = ceil((ui.select[ui.layer]) * ((float)DISP_H / (ui.num[ui_index] - 1)));
-
- //计算动画过渡值
- animation(&list.y, &list.y_trg, LIST_ANI);
- animation(&list.box_x, &list.box_x_trg, LIST_ANI);
- animation(&list.box_y, &list.box_y_trg[ui.layer], LIST_ANI);
- animation(&list.bar_y, &list.bar_y_trg, LIST_ANI);
-
- //检查循环动画是否结束
- if (list.loop && list.box_y == list.box_y_trg[ui.layer]) list.loop = false;
-
- //设置文字和进度条颜色,0透显,1实显,2反色,这里都用实显
- //u8g2.setDrawColor(1);
- u8g2_SetDrawColor(&u8g2, 1);
-
- //绘制进度条
- #if 0
- u8g2.drawHLine(DISP_W - LIST_BAR_W, 0, LIST_BAR_W);
- u8g2.drawHLine(DISP_W - LIST_BAR_W, DISP_H - 1, LIST_BAR_W);
- u8g2.drawVLine(DISP_W - ceil((float)LIST_BAR_W / 2), 0, DISP_H);
- u8g2.drawBox(DISP_W - LIST_BAR_W, 0, LIST_BAR_W, list.bar_y);
- #else
- u8g2_DrawHLine(&u8g2, DISP_W - LIST_BAR_W, 0, LIST_BAR_W);
- u8g2_DrawHLine(&u8g2, DISP_W - LIST_BAR_W, DISP_H - 1, LIST_BAR_W);
- u8g2_DrawVLine(&u8g2, DISP_W - ceil((float)LIST_BAR_W / 2), 0, DISP_H);
- u8g2_DrawBox(&u8g2, DISP_W - LIST_BAR_W, 0, LIST_BAR_W, list.bar_y);
- #endif
-
- //绘制列表文字
- if (!ui.init)
- {
- for (int i = 0; i < ui.num[ui_index]; ++ i)
- {
- if (ui.param[LIST_UFD]) list.temp = i * list.y - LIST_LINE_H * ui.select[ui.layer] + list.box_y_trg[ui.layer];
- else list.temp = (i - ui.select[ui.layer]) * list.y + list.box_y_trg[ui.layer];
- list_draw_text_and_check_box(arr, i);
- }
- if (list.y == list.y_trg)
- {
- ui.init = true;
- list.y = list.y_trg = - LIST_LINE_H * ui.select[ui.layer] + list.box_y_trg[ui.layer];
- }
- }
- else for (int i = 0; i < ui.num[ui_index]; ++ i)
- {
- list.temp = LIST_LINE_H * i + list.y;
- list_draw_text_and_check_box(arr, i);
- }
-
- //绘制文字选择框,0透显,1实显,2反色,这里用反色
- //u8g2.setDrawColor(2);
- //u8g2.drawRBox(0, list.box_y, list.box_x, LIST_LINE_H, LIST_BOX_R);
- u8g2_SetDrawColor(&u8g2, 2);
- u8g2_DrawRBox(&u8g2, 0, list.box_y, list.box_x, LIST_LINE_H, LIST_BOX_R);
-
- //反转屏幕内元素颜色,白天模式遮罩,在这里屏蔽有列表参与的页面,使遮罩作用在那个页面上
- if (!ui.param[DARK_MODE])
- {
- //u8g2.drawBox(0, 0, DISP_W, DISP_H);
- u8g2_DrawBox(&u8g2, 0, 0, DISP_W, DISP_H);
- switch(ui.index)
- {
- case M_WINDOW:
- case M_VOLT:
- //u8g2.drawBox(0, 0, DISP_W, DISP_H);
- u8g2_DrawBox(&u8g2, 0, 0, DISP_W, DISP_H);
- }
- }
- }
-
- //电压页面显示函数
- void volt_show()
- {
- //使用列表类显示选项
- list_show(volt_menu, M_VOLT);
-
- //计算动画过渡值
- animation(&volt.text_bg_r, &volt.text_bg_r_trg, TAG_ANI);
-
- //设置曲线颜色,0透显,1实显,2反色,这里用实显
- //u8g2.setDrawColor(1);
- u8g2_SetDrawColor(&u8g2, 1);
-
- //绘制电压曲线和外框
- volt.val = 0;
- //u8g2.drawFrame(WAVE_BOX_L_S, 0, WAVE_BOX_W, WAVE_BOX_H);
- //u8g2.drawFrame(WAVE_BOX_L_S + 1, 1, WAVE_BOX_W - 2, WAVE_BOX_H - 2);
- u8g2_DrawFrame(&u8g2, WAVE_BOX_L_S, 0, WAVE_BOX_W, WAVE_BOX_H);
- u8g2_DrawFrame(&u8g2, WAVE_BOX_L_S + 1, 1, WAVE_BOX_W - 2, WAVE_BOX_H - 2);
-
- if (list.box_y == list.box_y_trg[ui.layer] && list.y == list.y_trg)
- {
- for (int i = 0; i < WAVE_SAMPLE * WAVE_W; i++) volt.ch0_adc[i] = volt.val = (int)(motor_b.pos_spd_ltd.v2);//(int)(adc_data.voltage_mv);//analogRead(analog_pin[ui.select[ui.layer]]);
- for (int i = 1; i < WAVE_W - 1; i++)
- {
- //volt.ch0_wave[i] = lv_map(volt.ch0_adc[int(5 * i)], 0, 4095, WAVE_MAX, WAVE_MIN);
- //u8g2.drawLine(WAVE_L + i - 1, WAVE_U + volt.ch0_wave[i - 1], WAVE_L + i, WAVE_U + volt.ch0_wave[i]);
- volt.ch0_wave[i] = lv_map(volt.ch0_adc[int(5 * i)], -5000, 5000, WAVE_MIN, WAVE_MAX);
- u8g2_DrawLine(&u8g2, WAVE_L + i - 1, WAVE_U + volt.ch0_wave[i - 1], WAVE_L + i, WAVE_U + volt.ch0_wave[i]);
- }
- }
-
- #if 0
- //绘制电压值
- u8g2.setFontDirection(0);
- u8g2.setFont(VOLT_FONT);
- u8g2.setCursor(39, DISP_H - 6);
- u8g2.print(volt.val / 4096.0 * 3.3);
- u8g2.print("V");
-
- //绘制列表选择框和电压文字背景
- u8g2.setDrawColor(2);
- u8g2.drawBox(VOLT_TEXT_BG_L_S, DISP_H - VOLT_TEXT_BG_H, volt.text_bg_r, VOLT_TEXT_BG_H);
-
- //反转屏幕内元素颜色,白天模式遮罩
- if (!ui.param[DARK_MODE]) u8g2.drawBox(0, 0, DISP_W, DISP_H);
- #else
- //绘制电压值
- u8g2_SetFontDirection(&u8g2, 0);
- u8g2_SetFont(&u8g2, VOLT_FONT);
- u8g2_setCursor(32, DISP_H - 6);
- //u8g2_print(volt.val / 4096.0 * 3.3);
- //u8g2_print(volt.val/1000.0);
- //u8g2_print(motor_b.pos_spd_ltd.v2/1000.0);
- u8g2_print(volt.val);
- //u8g2_SetFont(&u8g2, LIST_FONT);
- u8g2_print("V");
-
- //绘制列表选择框和电压文字背景
- u8g2_SetDrawColor(&u8g2, 2);
- u8g2_DrawBox(&u8g2, VOLT_TEXT_BG_L_S, DISP_H - VOLT_TEXT_BG_H, volt.text_bg_r, VOLT_TEXT_BG_H);
-
- //反转屏幕内元素颜色,白天模式遮罩
- if (!ui.param[DARK_MODE]) u8g2_DrawBox(&u8g2, 0, 0, DISP_W, DISP_H);
- #endif
- }
-
- //弹窗通用显示函数
- void window_show()
- {
- //绘制背景列表,根据开关判断背景是否要虚化
- list_show(win.bg, win.index);
- if (ui.param[WIN_BOK]) for (uint16_t i = 0; i < buf_len; ++i) buf_ptr[i] = buf_ptr[i] & (i % 2 == 0 ? 0x55 : 0xAA);
-
- //更新动画目标值
- //u8g2.setFont(WIN_FONT);
- u8g2_SetFont(&u8g2, WIN_FONT);
- win.bar_trg = (float)(*win.value - win.min) / (float)(win.max - win.min) * (WIN_BAR_W - 4);
-
- //计算动画过渡值
- animation(&win.bar, &win.bar_trg, WIN_ANI);
- animation(&win.y, &win.y_trg, WIN_ANI);
-
- #if 0
- //绘制窗口
- u8g2.setDrawColor(0); u8g2.drawRBox(win.l, (int16_t)win.y, WIN_W, WIN_H, 2); //绘制外框背景
- u8g2.setDrawColor(1); u8g2.drawRFrame(win.l, (int16_t)win.y, WIN_W, WIN_H, 2); //绘制外框描边
- u8g2.drawRFrame(win.l + 5, (int16_t)win.y + 20, WIN_BAR_W, WIN_BAR_H, 1); //绘制进度条外框
- u8g2.drawBox(win.l + 7, (int16_t)win.y + 22, win.bar, WIN_BAR_H - 4); //绘制进度条
- u8g2.setCursor(win.l + 5, (int16_t)win.y + 14); u8g2.print(win.title); //绘制标题
- u8g2.setCursor(win.l + 78, (int16_t)win.y + 14); u8g2.print(*win.value); //绘制当前值
-
- //需要在窗口修改参数时立即见效的函数
- if (!strcmp(win.title, "Disp Bri")) u8g2.setContrast(ui.param[DISP_BRI]);
-
- //反转屏幕内元素颜色,白天模式遮罩
- u8g2.setDrawColor(2);
- if (!ui.param[DARK_MODE]) u8g2.drawBox(0, 0, DISP_W, DISP_H);
- #else
- //绘制窗口
- u8g2_SetDrawColor(&u8g2, 0); u8g2_DrawRBox(&u8g2, win.l, (int16_t)win.y, WIN_W, WIN_H, 2); //绘制外框背景
- u8g2_SetDrawColor(&u8g2, 1); u8g2_DrawRFrame(&u8g2, win.l, (int16_t)win.y, WIN_W, WIN_H, 2); //绘制外框描边
- u8g2_DrawRFrame(&u8g2, win.l + 5, (int16_t)win.y + 20, WIN_BAR_W, WIN_BAR_H, 1); //绘制进度条外框
- u8g2_DrawBox(&u8g2, win.l + 7, (int16_t)win.y + 22, win.bar, WIN_BAR_H - 4); //绘制进度条
- u8g2_setCursor(win.l + 5, (int16_t)win.y + 14); u8g2_print(win.title); //绘制标题
- u8g2_setCursor(win.l + 78, (int16_t)win.y + 14); u8g2_print(*win.value); //绘制当前值
-
- //需要在窗口修改参数时立即见效的函数
- //if (!strcmp(win.title, "Disp Bri")) u8g2_SetContrast(&u8g2, ui.param[DISP_BRI]);
-
- //反转屏幕内元素颜色,白天模式遮罩
- u8g2_SetDrawColor(&u8g2, 2);
- if (!ui.param[DARK_MODE]) u8g2_DrawBox(&u8g2, 0, 0, DISP_W, DISP_H);
-
- #endif
- }
-
- /************************************* 处理函数 *************************************/
-
- /*********************************** 通用处理函数 ***********************************/
-
- //磁贴类页面旋转时判断通用函数
- void tile_rotate_switch()
- {
- switch (btn.id)
- {
- case BTN_ID_CC:
- if (ui.init)
- {
- if (ui.select[ui.layer] > 0)
- {
- ui.select[ui.layer] -= 1;
- tile.icon_x_trg += TILE_ICON_S;
- tile.select_flag = false;
- }
- else
- {
- if (ui.param[TILE_LOOP])
- {
- ui.select[ui.layer] = ui.num[ui.index] - 1;
- tile.icon_x_trg = - TILE_ICON_S * (ui.num[ui.index] - 1);
- break;
- }
- else tile.select_flag = true;
- }
- }
- break;
-
- case BTN_ID_CW:
- if (ui.init)
- {
- if (ui.select[ui.layer] < (ui.num[ui.index] - 1))
- {
- ui.select[ui.layer] += 1;
- tile.icon_x_trg -= TILE_ICON_S;
- tile.select_flag = false;
- }
- else
- {
- if (ui.param[TILE_LOOP])
- {
- ui.select[ui.layer] = 0;
- tile.icon_x_trg = 0;
- break;
- }
- else tile.select_flag = true;
- }
- }
- break;
- }
- }
-
- //列表类页面旋转时判断通用函数
- void list_rotate_switch()
- {
- if (!list.loop)
- {
- switch (btn.id)
- {
- case BTN_ID_CC:
- if (ui.select[ui.layer] == 0)
- {
- if (ui.param[LIST_LOOP] && ui.init)
- {
- list.loop = true;
- ui.select[ui.layer] = ui.num[ui.index] - 1;
- if (ui.num[ui.index] > list.line_n)
- {
- list.box_y_trg[ui.layer] = DISP_H - LIST_LINE_H;
- list.y_trg = DISP_H - ui.num[ui.index] * LIST_LINE_H;
- }
- else list.box_y_trg[ui.layer] = (ui.num[ui.index] - 1) * LIST_LINE_H;
- break;
- }
- else break;
- }
- if (ui.init)
- {
- ui.select[ui.layer] -= 1;
- if (ui.select[ui.layer] < - (list.y_trg / LIST_LINE_H))
- {
- if (!(DISP_H % LIST_LINE_H)) list.y_trg += LIST_LINE_H;
- else
- {
- if (list.box_y_trg[ui.layer] == DISP_H - LIST_LINE_H * list.line_n)
- {
- list.y_trg += (list.line_n + 1) * LIST_LINE_H - DISP_H;
- list.box_y_trg[ui.layer] = 0;
- }
- else if (list.box_y_trg[ui.layer] == LIST_LINE_H)
- {
- list.box_y_trg[ui.layer] = 0;
- }
- else list.y_trg += LIST_LINE_H;
- }
- }
- else list.box_y_trg[ui.layer] -= LIST_LINE_H;
- break;
- }
-
- case BTN_ID_CW:
- if (ui.select[ui.layer] == (ui.num[ui.index] - 1))
- {
- if (ui.param[LIST_LOOP] && ui.init)
- {
- list.loop = true;
- ui.select[ui.layer] = 0;
- list.y_trg = 0;
- list.box_y_trg[ui.layer] = 0;
- break;
- }
- else break;
- }
- if (ui.init)
- {
- ui.select[ui.layer] += 1;
- if ((ui.select[ui.layer] + 1) > (list.line_n - list.y_trg / LIST_LINE_H))
- {
- if (!(DISP_H % LIST_LINE_H)) list.y_trg -= LIST_LINE_H;
- else
- {
- if (list.box_y_trg[ui.layer] == LIST_LINE_H * (list.line_n - 1))
- {
- list.y_trg -= (list.line_n + 1) * LIST_LINE_H - DISP_H;
- list.box_y_trg[ui.layer] = DISP_H - LIST_LINE_H;
- }
- else if (list.box_y_trg[ui.layer] == DISP_H - LIST_LINE_H * 2)
- {
- list.box_y_trg[ui.layer] = DISP_H - LIST_LINE_H;
- }
- else list.y_trg -= LIST_LINE_H;
- }
- }
- else list.box_y_trg[ui.layer] += LIST_LINE_H;
- break;
- }
- break;
- }
- }
- }
-
- //弹窗通用处理函数
- void window_proc()
- {
- window_show();
- if (win.y == WIN_Y_TRG) ui.index = win.index;
- if (btn.pressed && win.y == win.y_trg && win.y != WIN_Y_TRG)
- {
- btn.pressed = false;
- switch (btn.id)
- {
- case BTN_ID_CC: if (*win.value < win.max) *win.value += win.step; eeprom.change = true; break;
- case BTN_ID_CW: if (*win.value > win.min) *win.value -= win.step; eeprom.change = true; break;
- case BTN_ID_SP: case BTN_ID_LP: win.y_trg = WIN_Y_TRG; break;
- }
- }
- }
-
- /********************************** 分页面处理函数 **********************************/
-
- //睡眠页面处理函数
- void sleep_proc()
- {
- while (ui.sleep)
- {
- //睡眠时循环执行的函数
-
- //睡眠时需要扫描旋钮才能退出睡眠
- btn_scan();
-
- delay(1);
-
- //当旋钮有动作时
- if (btn.pressed) {
- btn.pressed = false;
- switch (btn.id) {
- #if 0
- //睡眠时顺时针旋转执行的函数
- case BTN_ID_CW:
- switch (knob.param[KNOB_ROT])
- {
- case KNOB_ROT_VOL: Consumer.press(HIDConsumer::VOLUME_UP); Consumer.release(); break;
- case KNOB_ROT_BRI: Consumer.press(HIDConsumer::BRIGHTNESS_UP); Consumer.release(); break;
- }
- break;
-
- //睡眠时逆时针旋转执行的函数
- case BTN_ID_CC:
- switch (knob.param[KNOB_ROT])
- {
- case KNOB_ROT_VOL: Consumer.press(HIDConsumer::VOLUME_DOWN); Consumer.release(); break;
- case KNOB_ROT_BRI: Consumer.press(HIDConsumer::BRIGHTNESS_DOWN); Consumer.release(); break;
- }
- break;
-
- //睡眠时短按执行的函数
- case BTN_ID_SP: Keyboard.press(knob.param[KNOB_COD]); Keyboard.release(knob.param[KNOB_COD]); break;
- #endif
- //睡眠时长按执行的函数
- //case BTN_ID_LP: ui.index = M_MAIN; ui.state = S_LAYER_IN; u8g2.setPowerSave(0); ui.sleep = false; break;
- case BTN_ID_LP: ui.index = M_MAIN; ui.state = S_LAYER_IN; /*u8g2_SetPowerSave(&u8g2, 0);*/ ui.sleep = false; break;
- }
- }
- }
- }
-
- //主菜单处理函数,磁贴类模板
- void main_proc()
- {
- tile_show(main_menu, main_icon_pic);
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: tile_rotate_switch(); break; case BTN_ID_SP: switch (ui.select[ui.layer]) {
-
- case 0: ui.index = M_SLEEP; ui.state = S_LAYER_OUT; break;
- case 1: ui.index = M_EDITOR; ui.state = S_LAYER_IN; break;
- case 2: ui.index = M_VOLT; ui.state = S_LAYER_IN; break;
- case 3: ui.index = M_SETTING; ui.state = S_LAYER_IN; break;
- }
- }
- if (!tile.select_flag && ui.init) { tile.indi_x = 0; tile.title_y = tile.title_y_calc; }
- }
- }
-
- //编辑器菜单处理函数
- void editor_proc()
- {
- list_show(editor_menu, M_EDITOR);
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: list_rotate_switch(); break; case BTN_ID_LP: ui.select[ui.layer] = 0; case BTN_ID_SP: switch (ui.select[ui.layer]) {
-
- case 0: ui.index = M_MAIN; ui.state = S_LAYER_OUT; break;
- case 11: ui.index = M_KNOB; ui.state = S_LAYER_IN; break;
- }
- }
- }
- }
-
- //旋钮编辑菜单处理函数
- void knob_proc()
- {
- list_show(knob_menu, M_KNOB);
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: list_rotate_switch(); break; case BTN_ID_LP: ui.select[ui.layer] = 0; case BTN_ID_SP: switch (ui.select[ui.layer]) {
-
- case 0: ui.index = M_EDITOR; ui.state = S_LAYER_OUT; break;
- case 1: ui.index = M_KRF; ui.state = S_LAYER_IN; check_box_s_init(&knob.param[KNOB_ROT], &knob.param[KNOB_ROT_P]); break;
- case 2: ui.index = M_KPF; ui.state = S_LAYER_IN; check_box_s_init(&knob.param[KNOB_COD], &knob.param[KNOB_COD_P]); break;
- }
- }
- }
- }
-
- //旋钮旋转功能菜单处理函数
- void krf_proc()
- {
- list_show(krf_menu, M_KRF);
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: list_rotate_switch(); break; case BTN_ID_LP: ui.select[ui.layer] = 0; case BTN_ID_SP: switch (ui.select[ui.layer]) {
-
- case 0: ui.index = M_KNOB; ui.state = S_LAYER_OUT; break;
- case 1: break;
- case 2: check_box_s_select(KNOB_DISABLE, ui.select[ui.layer]); break;
- case 3: break;
- case 4: check_box_s_select(KNOB_ROT_VOL, ui.select[ui.layer]); break;
- case 5: check_box_s_select(KNOB_ROT_BRI, ui.select[ui.layer]); break;
- case 6: break;
- }
- }
- }
- }
-
- #define KEY_LEFT_CTRL 0x80
- #define KEY_LEFT_SHIFT 0x81
- #define KEY_LEFT_ALT 0x82
- #define KEY_LEFT_GUI 0x83
- #define KEY_RIGHT_CTRL 0x84
- #define KEY_RIGHT_SHIFT 0x85
- #define KEY_RIGHT_ALT 0x86
- #define KEY_RIGHT_GUI 0x87
-
- #define KEY_UP_ARROW 0xDA
- #define KEY_DOWN_ARROW 0xD9
- #define KEY_LEFT_ARROW 0xD8
- #define KEY_RIGHT_ARROW 0xD7
- #define KEY_BACKSPACE 0xB2
- #define KEY_TAB 0xB3
- #define KEY_RETURN 0xB0
- #define KEY_ESC 0xB1
- #define KEY_INSERT 0xD1
- #define KEY_DELETE 0xD4
- #define KEY_PAGE_UP 0xD3
- #define KEY_PAGE_DOWN 0xD6
- #define KEY_HOME 0xD2
- #define KEY_END 0xD5
- #define KEY_CAPS_LOCK 0xC1
- #define KEY_F1 0xC2
- #define KEY_F2 0xC3
- #define KEY_F3 0xC4
- #define KEY_F4 0xC5
- #define KEY_F5 0xC6
- #define KEY_F6 0xC7
- #define KEY_F7 0xC8
- #define KEY_F8 0xC9
- #define KEY_F9 0xCA
- #define KEY_F10 0xCB
- #define KEY_F11 0xCC
- #define KEY_F12 0xCD
- #define KEY_F13 0xF0
- #define KEY_F14 0xF1
- #define KEY_F15 0xF2
- #define KEY_F16 0xF3
- #define KEY_F17 0xF4
- #define KEY_F18 0xF5
- #define KEY_F19 0xF6
- #define KEY_F20 0xF7
- #define KEY_F21 0xF8
- #define KEY_F22 0xF9
- #define KEY_F23 0xFA
- #define KEY_F24 0xFB
-
- //旋钮点按功能菜单处理函数
- void kpf_proc()
- {
- list_show(kpf_menu, M_KPF);
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: list_rotate_switch(); break; case BTN_ID_LP: ui.select[ui.layer] = 0; case BTN_ID_SP: switch (ui.select[ui.layer]) {
-
- case 0: ui.index = M_KNOB; ui.state = S_LAYER_OUT; break;
- case 1: break;
- case 2: check_box_s_select(KNOB_DISABLE, ui.select[ui.layer]); break;
- case 3: break;
- case 4: check_box_s_select('A', ui.select[ui.layer]); break;
- case 5: check_box_s_select('B', ui.select[ui.layer]); break;
- case 6: check_box_s_select('C', ui.select[ui.layer]); break;
- case 7: check_box_s_select('D', ui.select[ui.layer]); break;
- case 8: check_box_s_select('E', ui.select[ui.layer]); break;
- case 9: check_box_s_select('F', ui.select[ui.layer]); break;
- case 10: check_box_s_select('G', ui.select[ui.layer]); break;
- case 11: check_box_s_select('H', ui.select[ui.layer]); break;
- case 12: check_box_s_select('I', ui.select[ui.layer]); break;
- case 13: check_box_s_select('J', ui.select[ui.layer]); break;
- case 14: check_box_s_select('K', ui.select[ui.layer]); break;
- case 15: check_box_s_select('L', ui.select[ui.layer]); break;
- case 16: check_box_s_select('M', ui.select[ui.layer]); break;
- case 17: check_box_s_select('N', ui.select[ui.layer]); break;
- case 18: check_box_s_select('O', ui.select[ui.layer]); break;
- case 19: check_box_s_select('P', ui.select[ui.layer]); break;
- case 20: check_box_s_select('Q', ui.select[ui.layer]); break;
- case 21: check_box_s_select('R', ui.select[ui.layer]); break;
- case 22: check_box_s_select('S', ui.select[ui.layer]); break;
- case 23: check_box_s_select('T', ui.select[ui.layer]); break;
- case 24: check_box_s_select('U', ui.select[ui.layer]); break;
- case 25: check_box_s_select('V', ui.select[ui.layer]); break;
- case 26: check_box_s_select('W', ui.select[ui.layer]); break;
- case 27: check_box_s_select('X', ui.select[ui.layer]); break;
- case 28: check_box_s_select('Y', ui.select[ui.layer]); break;
- case 29: check_box_s_select('Z', ui.select[ui.layer]); break;
- case 30: break;
- case 31: check_box_s_select('0', ui.select[ui.layer]); break;
- case 32: check_box_s_select('1', ui.select[ui.layer]); break;
- case 33: check_box_s_select('2', ui.select[ui.layer]); break;
- case 34: check_box_s_select('3', ui.select[ui.layer]); break;
- case 35: check_box_s_select('4', ui.select[ui.layer]); break;
- case 36: check_box_s_select('5', ui.select[ui.layer]); break;
- case 37: check_box_s_select('6', ui.select[ui.layer]); break;
- case 38: check_box_s_select('7', ui.select[ui.layer]); break;
- case 39: check_box_s_select('8', ui.select[ui.layer]); break;
- case 40: check_box_s_select('9', ui.select[ui.layer]); break;
- case 41: break;
- case 42: check_box_s_select( KEY_ESC, ui.select[ui.layer]); break;
- case 43: check_box_s_select( KEY_F1, ui.select[ui.layer]); break;
- case 44: check_box_s_select( KEY_F2, ui.select[ui.layer]); break;
- case 45: check_box_s_select( KEY_F3, ui.select[ui.layer]); break;
- case 46: check_box_s_select( KEY_F4, ui.select[ui.layer]); break;
- case 47: check_box_s_select( KEY_F5, ui.select[ui.layer]); break;
- case 48: check_box_s_select( KEY_F6, ui.select[ui.layer]); break;
- case 49: check_box_s_select( KEY_F7, ui.select[ui.layer]); break;
- case 50: check_box_s_select( KEY_F8, ui.select[ui.layer]); break;
- case 51: check_box_s_select( KEY_F9, ui.select[ui.layer]); break;
- case 52: check_box_s_select( KEY_F10, ui.select[ui.layer]); break;
- case 53: check_box_s_select( KEY_F11, ui.select[ui.layer]); break;
- case 54: check_box_s_select( KEY_F12, ui.select[ui.layer]); break;
- case 55: break;
- case 56: check_box_s_select( KEY_LEFT_CTRL, ui.select[ui.layer]); break;
- case 57: check_box_s_select( KEY_LEFT_SHIFT, ui.select[ui.layer]); break;
- case 58: check_box_s_select( KEY_LEFT_ALT, ui.select[ui.layer]); break;
- case 59: check_box_s_select( KEY_LEFT_GUI, ui.select[ui.layer]); break;
- case 60: check_box_s_select( KEY_RIGHT_CTRL, ui.select[ui.layer]); break;
- case 61: check_box_s_select( KEY_RIGHT_SHIFT, ui.select[ui.layer]); break;
- case 62: check_box_s_select( KEY_RIGHT_ALT, ui.select[ui.layer]); break;
- case 63: check_box_s_select( KEY_RIGHT_GUI, ui.select[ui.layer]); break;
- case 64: break;
- case 65: check_box_s_select( KEY_CAPS_LOCK, ui.select[ui.layer]); break;
- case 66: check_box_s_select( KEY_BACKSPACE, ui.select[ui.layer]); break;
- case 67: check_box_s_select( KEY_RETURN, ui.select[ui.layer]); break;
- case 68: check_box_s_select( KEY_INSERT, ui.select[ui.layer]); break;
- case 69: check_box_s_select( KEY_DELETE, ui.select[ui.layer]); break;
- case 70: check_box_s_select( KEY_TAB, ui.select[ui.layer]); break;
- case 71: break;
- case 72: check_box_s_select( KEY_HOME, ui.select[ui.layer]); break;
- case 73: check_box_s_select( KEY_END, ui.select[ui.layer]); break;
- case 74: check_box_s_select( KEY_PAGE_UP, ui.select[ui.layer]); break;
- case 75: check_box_s_select( KEY_PAGE_DOWN, ui.select[ui.layer]); break;
- case 76: break;
- case 77: check_box_s_select( KEY_UP_ARROW, ui.select[ui.layer]); break;
- case 78: check_box_s_select( KEY_DOWN_ARROW, ui.select[ui.layer]); break;
- case 79: check_box_s_select( KEY_LEFT_ARROW, ui.select[ui.layer]); break;
- case 80: check_box_s_select( KEY_RIGHT_ARROW, ui.select[ui.layer]); break;
- case 81: break;
- }
- }
- }
- }
-
- //电压测量页处理函数
- void volt_proc()
- {
- volt_show();
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: list_rotate_switch(); break;
-
- case BTN_ID_SP: case BTN_ID_LP: ui.index = M_MAIN; ui.state = S_LAYER_OUT; break;
- }
- }
- }
-
- //设置菜单处理函数,多选框列表类模板,弹窗模板
- void setting_proc()
- {
- list_show(setting_menu, M_SETTING);
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: list_rotate_switch(); break; case BTN_ID_LP: ui.select[ui.layer] = 0; case BTN_ID_SP: switch (ui.select[ui.layer]) {
-
- //返回更浅层级,长按被当作选择这一项,也是执行这一行
- case 0: ui.index = M_MAIN; ui.state = S_LAYER_OUT; break;
-
- //弹出窗口,参数初始化:标题,参数名,参数值,最大值,最小值,步长,背景列表名,背景列表标签
- case 1: window_value_init("Disp Bri", DISP_BRI, &ui.param[DISP_BRI], 255, 0, 5, setting_menu, M_SETTING); break;
- case 2: window_value_init("Tile Ani", TILE_ANI, &ui.param[TILE_ANI], 100, 10, 1, setting_menu, M_SETTING); break;
- case 3: window_value_init("List Ani", LIST_ANI, &ui.param[LIST_ANI], 100, 10, 1, setting_menu, M_SETTING); break;
- case 4: window_value_init("Win Ani", WIN_ANI, &ui.param[WIN_ANI], 100, 10, 1, setting_menu, M_SETTING); break;
- case 5: window_value_init("Spot Ani", SPOT_ANI, &ui.param[SPOT_ANI], 100, 10, 1, setting_menu, M_SETTING); break;
- case 6: window_value_init("Tag Ani", TAG_ANI, &ui.param[TAG_ANI], 100, 10, 1, setting_menu, M_SETTING); break;
- case 7: window_value_init("Fade Ani", FADE_ANI, &ui.param[FADE_ANI], 255, 0, 1, setting_menu, M_SETTING); break;
- case 8: window_value_init("Btn SPT", BTN_SPT, &ui.param[BTN_SPT], 255, 0, 1, setting_menu, M_SETTING); break;
- case 9: window_value_init("Btn LPT", BTN_LPT, &ui.param[BTN_LPT], 255, 0, 1, setting_menu, M_SETTING); break;
-
- //多选框
- case 10: check_box_m_select( TILE_UFD ); break;
- case 11: check_box_m_select( LIST_UFD ); break;
- case 12: check_box_m_select( TILE_LOOP ); break;
- case 13: check_box_m_select( LIST_LOOP ); break;
- case 14: check_box_m_select( WIN_BOK ); break;
- case 15: check_box_m_select( KNOB_DIR ); break;
- case 16: check_box_m_select( DARK_MODE ); break;
-
- //关于本机
- case 17: ui.index = M_ABOUT; ui.state = S_LAYER_IN; break;
- }
- }
- }
- }
-
- //关于本机页
- void about_proc()
- {
- list_show(about_menu, M_ABOUT);
- if (btn.pressed) { btn.pressed = false; switch (btn.id) { case BTN_ID_CW: case BTN_ID_CC: list_rotate_switch(); break; case BTN_ID_LP: ui.select[ui.layer] = 0; case BTN_ID_SP: switch (ui.select[ui.layer]) {
-
- case 0: ui.index = M_SETTING; ui.state = S_LAYER_OUT; break;
- }
- }
- }
- }
-
- //总的UI进程
- void ui_proc()
- {
- //u8g2.sendBuffer();
- //u8g2_SendBuffer(&u8g2);
- //u8g2_FirstPage(&u8g2);
- switch (ui.state)
- {
- case S_FADE: fade(); break; //转场动画
- case S_WINDOW: window_param_init(); break; //弹窗初始化
- case S_LAYER_IN: layer_init_in(); break; //层级初始化
- case S_LAYER_OUT: layer_init_out(); break; //层级初始化
-
- case S_NONE: u8g2_ClearBuffer(&u8g2);//u8g2.clearBuffer();
- switch (ui.index) //直接选择页面
- {
- case M_WINDOW: window_proc(); break;
- case M_SLEEP: sleep_proc(); break;
- case M_MAIN: main_proc(); break;
- case M_EDITOR: editor_proc(); break;
- case M_KNOB: knob_proc(); break;
- case M_KRF: krf_proc(); break;
- case M_KPF: kpf_proc(); break;
- case M_VOLT: volt_proc(); break;
- case M_SETTING: setting_proc(); break;
- case M_ABOUT: about_proc(); break;
- }
- }
- u8g2_NextPage(&u8g2);
- }
-
- //OLED初始化函数
- void oled_init()
- {
- //u8g2.setBusClock(1000000); //硬件IIC接口使用
- //u8g2.begin();
- //u8g2.setContrast(ui.param[DISP_BRI]);
-
- u8g2_SetContrast(&u8g2, ui.param[DISP_BRI]);
-
- //buf_ptr = u8g2.getBufferPtr();
- //buf_len = 8 * u8g2.getBufferTileHeight() * u8g2.getBufferTileWidth();
-
- buf_ptr = u8g2_GetBufferPtr(&u8g2);
- buf_len = 8 * u8g2_GetBufferTileHeight(&u8g2) * u8g2_GetBufferTileWidth(&u8g2);
- }
-
- void flex_ui_setup()
- {
- eeprom_init();
- ui_init();
- oled_init();
- btn_init();
-
- ESP_LOGI(TAG, "flex ui setup!");
- }
-
- void flex_ui_loop()
- {
- btn_scan();
- knob_inter();
- ui_proc();
- }
-
-
-
~小结:
这次主要记录了WouoUI框架在esp32 idf环境下的移植,WouoUI的框架原本是在arduino下面实现的,最终用丙正正实现了移植,移植过程主要难点在于arduino框架u8g2类各种方法的丙语言实现替换,其中又属print重载函数的实现最麻烦,还好最终一一克服,将这优雅的UI呈现在小黑上面;
以下是一些和本文相关的文章链接和U8g2的wiki链接:
一、~~呆萌的瓦力平衡机器人~~链接:
二、 ~~U8g2图形库使用技巧记录~~链接:
三、U8g2 wiki链接:
1.U8g2_wiki;
2.WouoUI框架,可以直接搜索;
后续的计划:
目前UI的大体框架已经定型,后续会基于该框架实现小车参数的设置和增加一些动效页面的;
大家如果也感兴趣,可以来这交流学习(这里提供了丰富的esp32资料):
燥起来吧!!!!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。