U8g2庫為XFP1116-07AY(128x64 OLED)實現菜單功能[ep:esp8266]

使用U8g2庫為XFP1116-07AY(128x64 OLED)實現菜單功能,核心是通過按鍵控制菜單切換光標移動選項選中,結合U8g2的繪圖/文本函數實現交互邏輯支持多級菜單(主菜單→子菜單→功能執行),并兼容ESP8266的按鍵輸入。

一、核心思路

  1. 菜單結構設計:采用“數組+索引”管理菜單(主菜單包含多個選項,部分選項跳轉至子菜單);
  2. 交互控制:通過2個按鍵(上/下移動光標、確認進入子菜單/執行功能);
  3. 顯示邏輯:每次按鍵后清空緩沖區,重新繪制當前菜單和光標位置;
  4. 狀態保存:記錄當前菜單層級和光標位置,確保切換不丟失狀態。

二、硬件接線

組件ESP8266引腳說明
上移按鍵D5一端接D5,一端接GND(下拉)
下移按鍵D6一端接D6,一端接GND(下拉)
確認按鍵D7一端接D7,一端接GND(下拉)
XFP1116-07AYSDA=D2、SCL=D1OLED的I2C引腳(不變)

三、完整代碼(多級菜單+按鍵控制)

#include <Wire.h>
#include <U8g2lib.h>// 1. 初始化U8g2(適配XFP1116-07AY:SH1106控制器,128x64,I2C引腳D2=SDA、D1=SCL)
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, D1, D2);// 2. 定義菜單結構(菜單層級:0=主菜單,1=子菜單1,2=子菜單2)
// 菜單選項格式:{選項名稱, 子菜單層級(-1=無子類,執行功能)}
const struct MenuItem {const char* name;    // 選項文字int subMenuLevel;    // 子菜單層級(-1=執行功能,0=主菜單,1=子菜單1,2=子菜單2)
} menuList[3][4] = {// 主菜單(層級0):4個選項{{"1. 系統設置", 1},    // 進入子菜單1(系統設置){"2. 顯示控制", 2},    // 進入子菜單2(顯示控制){"3. 關于設備", -1},   // 無子類,執行“關于”功能{"4. 退出", -1}        // 無子類,執行“退出”功能},// 子菜單1(系統設置,層級1):3個選項{{"1.1 亮度調節", -1},  // 執行“亮度調節”{"1.2 恢復默認", -1},  // 執行“恢復默認”{"1.3 返回上一級", 0}, // 返回主菜單(層級0){NULL, -1}             // 占位符(無更多選項)},// 子菜單2(顯示控制,層級2):3個選項{{"2.1 字體切換", -1},  // 執行“字體切換”{"2.2 清屏測試", -1},  // 執行“清屏測試”{"2.3 返回上一級", 0}, // 返回主菜單(層級0){NULL, -1}             // 占位符}
};// 3. 菜單狀態變量(記錄當前狀態)
int currentMenuLevel = 0;  // 當前菜單層級(默認主菜單0)
int currentCursor = 0;     // 當前光標位置(默認第1個選項)
int menuItemCount[3] = {4, 3, 3}; // 各層級的選項數量(主菜單4個,子菜單1/2各3個)// 4. 按鍵引腳定義
const int KEY_UP = D5;
const int KEY_DOWN = D6;
const int KEY_CONFIRM = D7;// 5. 函數聲明(提前聲明,避免編譯錯誤)
void drawMenu();          // 繪制當前菜單和光標
void handleKeyInput();    // 處理按鍵輸入
void executeMenuAction(); // 執行選中選項的功能void setup() {// 初始化OLEDu8g2.begin();u8g2.enableUTF8Print(); // 啟用UTF8(支持中文)u8g2.setFont(u8g2_font_wqy12_t_gb2312); // 中文支持字體// 初始化按鍵引腳(下拉輸入:按鍵未按則為高電平,按下為低電平)pinMode(KEY_UP, INPUT_PULLUP);pinMode(KEY_DOWN, INPUT_PULLUP);pinMode(KEY_CONFIRM, INPUT_PULLUP);// 初始繪制主菜單drawMenu();
}void loop() {handleKeyInput(); // 持續檢測按鍵delay(100);       // 消抖,避免按鍵誤觸發
}// 繪制當前菜單:標題+選項+光標
void drawMenu() {u8g2.clearBuffer(); // 清空緩沖區// 1. 繪制菜單標題(不同層級顯示不同標題)u8g2.setCursor(0, 15); // 標題位置(y=15,避免頂部裁切)switch (currentMenuLevel) {case 0: u8g2.print("主菜單"); break;case 1: u8g2.print("系統設置"); break;case 2: u8g2.print("顯示控制"); break;}u8g2.drawHLine(0, 20, 128); // 標題下方畫一條橫線(分隔標題和選項)// 2. 繪制當前菜單的所有選項(從y=35開始,每個選項間隔18像素)for (int i = 0; i < menuItemCount[currentMenuLevel]; i++) {int yPos = 35 + i * 18; // 選項y坐標(間隔18像素,適配12號字體)u8g2.setCursor(10, yPos); // 選項左移10像素,避免貼邊// 光標位置:當前選中的選項前加“> ”標記if (i == currentCursor) {u8g2.print("> "); // 光標符號} else {u8g2.print("  "); // 非選中項留空,對齊格式}// 繪制選項文字u8g2.print(menuList[currentMenuLevel][i].name);}u8g2.sendBuffer(); // 刷新屏幕,顯示菜單
}// 處理按鍵輸入:上移、下移、確認
void handleKeyInput() {// 上移按鍵(按下時電平為LOW)if (digitalRead(KEY_UP) == LOW) {delay(50); // 消抖(避免按鍵抖動導致多次觸發)if (digitalRead(KEY_UP) == LOW) {currentCursor--; // 光標上移// 邊界處理:光標到頂部后,循環到最后一個選項if (currentCursor < 0) {currentCursor = menuItemCount[currentMenuLevel] - 1;}drawMenu(); // 重新繪制菜單// 等待按鍵釋放(避免長按連續觸發)while (digitalRead(KEY_UP) == LOW);}}// 下移按鍵if (digitalRead(KEY_DOWN) == LOW) {delay(50);if (digitalRead(KEY_DOWN) == LOW) {currentCursor++; // 光標下移// 邊界處理:光標到頂部后,循環到第一個選項if (currentCursor >= menuItemCount[currentMenuLevel]) {currentCursor = 0;}drawMenu();while (digitalRead(KEY_DOWN) == LOW);}}// 確認按鍵(進入子菜單或執行功能)if (digitalRead(KEY_CONFIRM) == LOW) {delay(50);if (digitalRead(KEY_CONFIRM) == LOW) {executeMenuAction(); // 執行當前選中選項的邏輯while (digitalRead(KEY_CONFIRM) == LOW);}}
}// 執行當前選中選項的功能(進入子菜單或顯示功能提示)
void executeMenuAction() {// 獲取當前選中選項的“子菜單層級”int targetLevel = menuList[currentMenuLevel][currentCursor].subMenuLevel;if (targetLevel != -1) {// 情況1:有子菜單,切換到目標層級,光標重置為0currentMenuLevel = targetLevel;currentCursor = 0;drawMenu(); // 繪制子菜單} else {// 情況2:無子類,執行對應功能(顯示提示信息2秒后返回當前菜單)u8g2.clearBuffer();u8g2.setCursor(10, 30); // 提示文字居中// 根據當前選項執行不同提示if (currentMenuLevel == 0) {switch (currentCursor) {case 2: u8g2.print("設備:XFP1116-07AY"); break; // 關于設備case 3: u8g2.print("已退出!"); break;          // 退出}} else if (currentMenuLevel == 1) {switch (currentCursor) {case 0: u8g2.print("亮度已調節為50%"); break;  // 亮度調節case 1: u8g2.print("已恢復默認設置"); break;   // 恢復默認}} else if (currentMenuLevel == 2) {switch (currentCursor) {case 0: u8g2.print("字體已切換為默認"); break; // 字體切換case 1: u8g2.clearBuffer(); u8g2.print("清屏測試中..."); break; // 清屏}}u8g2.sendBuffer(); // 顯示提示delay(2000);       // 提示顯示2秒drawMenu();        // 返回當前菜單}
}

四、代碼說明

1. 菜單結構擴展

若需增加更多菜單層級或選項,只需:

  • menuList數組中新增層級(如menuList[3][...]作為“子菜單3”);
  • 同步更新menuItemCount數組(記錄新層級的選項數量);
  • executeMenuAction()中添加新層級的功能邏輯。
2. 字體與顯示優化
  • 若需更大字體,可替換u8g2.setFont()的參數(如u8g2_font_wqy16_t_gb2312),但需同步調整選項的yPos間隔(避免選項重疊);
  • 若需支持英文,可改用英文字體(如u8g2_font_ncenB12_tr),無需啟用enableUTF8Print()
3. 按鍵優化
  • 若按鍵觸發不靈敏,可調整delay(50)的消抖時間(如改為delay(30));
  • 若需支持“長按快速移動光標”,可在handleKeyInput()中添加長按檢測邏輯(如判斷按鍵按下時間超過500ms后,每100ms移動一次光標)。

五、運行效果

  1. 上電后顯示“主菜單”,光標默認停在“1. 系統設置”;
  2. 按“上/下鍵”移動光標,光標前的“> ”標記跟隨移動;
  3. 按“確認鍵”:
    • 選中“1. 系統設置”→ 進入“系統設置”子菜單;
    • 選中“3. 關于設備”→ 顯示設備信息2秒后返回主菜單;
    • 選中“1.3 返回上一級”→ 從子菜單返回主菜單。

該代碼可直接上傳使用,也可根據實際需求(如增加參數調節、數據顯示)擴展executeMenuAction()中的功能邏輯。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/100269.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/100269.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/100269.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

easy-dataset 框架綜合技術分析:面向領域特定 LLM 指令數據的合成

摘要 本報告對 easy-dataset 框架 進行全面技術剖析&#xff0c;該框架旨在解決大型語言模型&#xff08;LLM&#xff09;在特定領域應用中的核心瓶頸——高質量指令微調數據的稀缺性。隨著 LLM 技術發展&#xff0c;其應用能力不再僅依賴模型參數規模&#xff0c;而是更依賴通…

【開題答辯全過程】以 4s店汽車銷售系統為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

測試中的Bug

文章目錄軟件測試的生命周期軟件測試的各個階段線上環境測試中的BUG描述測試BUGBUG的級別為啥要定義BUG的級別&#xff1f;BUG有哪些級別呢&#xff1f;BUG的生命周期測試與開發發生爭執怎么辦&#xff1f;測試與開發會發生啥爭執&#xff1f;為啥會發生這樣的爭執&#xff1f;…

aws共享一個鏡像并有畫圖功能

這樣可以方便的把系統安裝好&#xff0c;不會重復勞動了。 這個是frequi 單獨安裝 wget https://github.com/freqtrade/frequi/releases/download/2.0.7/freqUI.zip freqtrade install-ui pip install -U -r requirements-plot.txt 在AWS上把已經安裝好的環境共享給其他用戶。…

C語言---goto語句

文章目錄基本語法代碼示例goto 的常見用途&#xff08;盡管不推薦&#xff09;為什么 goto 聲名狼藉&#xff1f;&#xff08;goto的缺點&#xff09;如何避免使用 goto&#xff1f;&#xff08;替代方案&#xff09;goto 語句是一種無條件跳轉語句&#xff0c;它用于將程序的控…

Flask框架的簡單了解

&#x1f91f;致敬讀者 &#x1f7e9;感謝閱讀&#x1f7e6;笑口常開&#x1f7ea;生日快樂?早點睡覺 &#x1f4d8;博主相關 &#x1f7e7;博主信息&#x1f7e8;博客首頁&#x1f7eb;專欄推薦&#x1f7e5;活動信息 文章目錄1. 前言2. 簡介3. 核心特點4. 代碼實例5. 主要…

——貪心算法——

目錄 1 檸檬水找零 2 將數組和減半的最少操作次數 3 最大數 4 擺動序列 5 最長遞增子序列 6 遞增的三元子序列 7 最長連續遞增序列 8 買賣股票的最佳時機 9 買賣股票的最佳時機 II 10 K 次取反后最大化的數組和 11 按身高排序 12 優勢洗牌 13 最長回文串 14 增減…

網絡操作系統與分布式操作系統的區別

網絡操作系統與分布式操作系統的區別架構設計網絡操作系統&#xff08;NOS&#xff09;基于客戶端-服務器模型&#xff0c;通過共享資源&#xff08;如文件、打印機&#xff09;提供服務&#xff0c;各節點保留獨立的管理和數據處理能力。分布式操作系統&#xff08;DOS&#x…

RabbitMQ—運維篇

RabbitMQ安裝 RabbitMQ需要依賴erlang&#xff0c;如果普通安裝需要安裝erlang并保證二者兼容&#xff0c;因此選擇較為簡單的docker安裝方式 1.獲取rabbitmq鏡像 docker pull rabbitmq:3.11.19-management #rabbitmq-management表示帶有客戶端&#xff08;控制臺&#xff09; …

【學習K230-例程21】GT6700-UDP-Client

B站視頻 UDP 簡介 UDP 是 User Datagram Protocol 的簡稱&#xff0c;中文名是用戶數據報協議&#xff0c;是 OSI&#xff08;Open SystemInterconnection&#xff0c;開放式系統互聯&#xff09;參考模型中一種無連接的傳輸層協議&#xff0c;提供面向事務的簡單不可靠信息傳送…

LazyLLM教程 | 第9講:微調實踐:讓大模型和向量模型更懂你的領域

前面教程中&#xff0c;我們通過優化檢索策略、召回重排略以及基于大模型的查詢重寫策略來提升了RAG系統的檢索精度&#xff0c;但最終回復的結果還需要經過大模型的融合和處理&#xff0c;模型能力的強弱直接影響到最終的結果。這就好比一道好的菜不僅需要有高質量的食材&…

六、vue3后臺項目系列——頁面自適應設計+pinia,vuex的使用

前言&#xff1a;在頁面加入自適應是提高用戶體驗的一種形式&#xff0c;甚至有時候是手機用戶&#xff0c;我們就需要做一個自適應處理&#xff0c;其中肯定會涉及一些狀態條件的判斷&#xff0c;而這些關鍵的條件就是我們用來切換樣式的關鍵&#xff0c;所以我們需要使用狀態…

視頻講解|Python用ResNet殘差神經網絡在大腦出血CT圖像描數據預測應用

全文鏈接&#xff1a;https://tecdat.cn/?p43843 原文出處&#xff1a;拓端抖音號拓端tecdat 分析師&#xff1a;Zikun Zhang 視頻講解Python用ResNet殘差神經網絡在大腦出血CT圖像描數據預測在臨床醫療影像診斷中&#xff0c;大腦出血的快速準確識別直接關系到患者的救治效率…

Mysql中有那些鎖

按照鎖的力度分&#xff1a;1.行級鎖2.表級鎖3.全局鎖4.頁級鎖innodb不支持頁鎖全局鎖全局鎖指的是對整個數據庫實例加鎖&#xff0c;一般用于數據庫的表級鎖表鎖 是對整張表進行加鎖。表級鎖還有以下幾種&#xff1a;意向鎖&#xff1a;意向鎖是指&#xff0c;我們在事務請求表…

基于 CoT 思維鏈協調多 MCP 工具:依托亞馬遜云科技服務打造全流程智能的 Amazon Redshift 運維體系

基于 CoT 思維鏈協調多 MCP 工具&#xff1a;依托亞馬遜云科技服務打造全流程智能的 Amazon Redshift 運維體系 新用戶可獲得高達 200 美元的服務抵扣金 亞馬遜云科技新用戶可以免費使用亞馬遜云科技免費套餐&#xff08;Amazon Free Tier&#xff09;。注冊即可獲得 100 美元的…

手機群控平臺的智能管控技術深度解析

手機群控平臺作為數字化運營的核心工具&#xff0c;正在重塑移動設備管理的技術邊界。其核心價值在于通過集中化控制實現批量化操作&#xff0c;同時借助智能化算法提升管控效率。本文將深入探討其技術架構與實現方案。平臺架構與核心技術手機群控平臺采用分布式架構設計&#…

Spring Boot 生命周期與核心擴展點全解析(含實操案例)

在Spring Boot開發中,理解應用的生命周期是實現優雅啟動、資源管理與故障處理的關鍵。不同于傳統Spring框架需要繁瑣的XML配置,Spring Boot通過自動配置簡化了開發流程,但其生命周期的底層邏輯仍延續并增強了Spring的核心機制。本文將從“生命周期階段劃分”“核心擴展點原理…

69-SQLite應用

1. SQLite操作 1.1了解數據庫1.2 操作數據庫步驟# -*- coding: utf-8 -*- """ Project : 01-python-learn File : 03_SQLite3添加數據.py IDE : PyCharm Author : 劉慶東 Date : 2025/9/15 14:05 """ # 1. 導入模塊 import sqlite3 …

Nginx - 正向vs反向代理

參考: https://blog.csdn.net/william_n/article/details/127387009 AI問答?? Nginx 正向代理 vs 反向代理詳解?? ??1. 正向代理&#xff08;Forward Proxy&#xff09;?? ??定義?? ??客戶端主動配置??的代理服務器&#xff0c;代表客戶端向外部服務器發送請…

裝飾器模式在Spring中的案例

設計模式-裝飾器模式 裝飾器模式所解決的問題是&#xff0c;在不改變原來方法代碼的情況下對方法進行修飾&#xff0c;從而豐富方法功能。 Spring架構中的裝飾器模式 在Spring架構中&#xff0c;以線程池進行舉例。 線程池 線程池是一個對線程集中管理的對象&#xff0c;集中管…