U8g2菜单界面+按键操作在线模拟

U8g2菜单界面+按键操作在线模拟控制


在这里插入图片描述

✨利用U8g2库在线模拟菜单功能,可以很方便的快速调试效果。

🌼Demo1代码

  • 📌仿真地址:https://wokwi.com/projects/291572875238834696
/*
 * Very simple menu on an OLED display (with 8 lines of text).
 * Displays menu items from the array menu. Max. number of items is 7.
 * 
 * This sketch uses the library "U8g2", "Bounce2" and uses 3 buttons (up/down/select).
 * 
 */

#include <U8g2lib.h>
#include <Bounce2.h>

byte button_pins[] = {9, 5, 6}; // button pins, 4,5 = up/down, 6 = select
#define NUMBUTTONS sizeof(button_pins)
Bounce * buttons = new Bounce[NUMBUTTONS];

U8X8_SSD1306_128X64_NONAME_HW_I2C display(U8X8_PIN_NONE);

#define MENU_SIZE 5
char *menu[MENU_SIZE] = { "Option 1", "Option 2", "Option 3", "Option 4", "Option 5" };

int cursor=0;

void setup() {
  Serial.begin(9600);

  // Make input & enable pull-up resistors on switch pins
  for (int i=0; i<NUMBUTTONS; i++) {
    buttons[i].attach( button_pins[i], INPUT_PULLUP); // setup the bounce instance for the current button
    buttons[i].interval(25); // interval in ms
  }
  
  display.begin();
  display.setPowerSave(0);
  display.setFont(u8x8_font_pxplusibmcgathin_f);

  showMenu();
}

void loop() {
  // process button press:
  for (int i = 0; i<NUMBUTTONS; i++) {
    buttons[i].update(); // Update the Bounce instance
    if ( buttons[i].fell() ) { // If it fell
      if (i==2) { // select
         display.clearLine(7);
         display.setCursor(0,7);
         display.print(">>");
         display.print(menu[cursor]);
         executeChoice(cursor);
      }
      else {
        // erase previous cursor:
        display.setCursor(0,cursor);
        display.print(' ');
        if (i==0) { // up
          cursor++;
          if (cursor>(MENU_SIZE-1)) cursor=0;
        }
        else { // down
          cursor--;
          if (cursor<0) cursor=(MENU_SIZE-1);
        }
        // show cursor at new line:
        display.setCursor(0,cursor);
        display.print('>');
      }
    } // end if button fell...
  } // end for-loop of button check
}

/**
 * Clear display and show the menu.
 */
void showMenu() {
  cursor=0;
  display.clearDisplay();
  // show menu items:
  for (int i = 0; i<MENU_SIZE; i++) {
    display.drawString(2,i,menu[i]);
  }
  display.setCursor(0,0);
  display.print('>');
}

/**
 * Execute the task which matches the chosen menu item.
 */
void executeChoice(int choice) {
  switch(choice) {
      case 0 :
                Serial.print("Execute choice "); Serial.print(choice); Serial.print(" - "); Serial.println(menu[choice]);
                break;
      case 1 :
                Serial.print("Execute choice "); Serial.print(choice); Serial.print(" - "); Serial.println(menu[choice]);
                break;
      case 2 :
                Serial.print("Execute choice "); Serial.print(choice); Serial.print(" - "); Serial.println(menu[choice]);
                break;
      case 3 :
                Serial.print("Execute choice "); Serial.print(choice); Serial.print(" - "); Serial.println(menu[choice]);
                break;
      case 4 :
                Serial.print("Execute choice "); Serial.print(choice); Serial.print(" - "); Serial.println(menu[choice]);
                break;
      default :
                Serial.print("Execute choice "); Serial.print(choice); Serial.print(" - "); Serial.println(menu[choice]);
                break;
  }
  
}

🌻Demo2代码

  • 📍滚动菜单
    在这里插入图片描述
    在这里插入图片描述

  • 📌https://wokwi.com/projects/353353893815793665


#include <U8g2lib.h>
#include <Wire.h>
#include <math.h>

typedef struct
{
  byte val;
  byte last_val;
}KEY_T;
typedef struct
{
  byte id;
  byte press;
  byte update_flag;
  byte res;
}KEY_MSG;

typedef struct
{
  char* str;
  byte len;
}SETTING_LIST;

SETTING_LIST list[] = 
{
  {"hello",5},
  {"menu",4},
  {"flowers",7},
  {"perseverance",12},
};
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);//该驱动是1.3寸的OLED屏幕。---------U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);这是比较常用的0.9寸的OLED显示器的驱动
short x,x_trg; //x当前位置数值,x_trg 目标坐标值
short y = 15,y_trg = 15;

short frame_len,frame_len_trg;//框框的宽度
short frame_y,frame_y_trg;//框框的y

char ui_select = 0;

int state;
KEY_T key[2] = {0};
KEY_MSG key_msg = {0};

byte get_io_val(byte ch)
{
  if(ch == 0)
  {
    return digitalRead(2);
  }
  else
  {
    return digitalRead(3);
  }
}

void key_init(void)
{
  for(int i = 0;i<2;i++)
  {
    key[i].val = key[i].last_val = get_io_val(i);
  }
}

void key_scan(void)
{
  for(int i = 0;i<2;i++)
  {
    key[i].val =  get_io_val(i);
    if(key[i].val != key[i].last_val)
    {
      key[i].last_val = key[i].val;
      if(key[i].val == 0)
      {
        key_msg.id = i;
        key_msg.press = 1;
        key_msg.update_flag = 1;
      }
    }
  }
}

int ui_run(short *a,short *a_trg,u8 step,u8 slow_cnt)
{  
  u8 temp;

  temp = abs(*a_trg-*a) > slow_cnt ? step : 1;
  if(*a < *a_trg)
  {
    *a += temp;
  }
  else if( *a > *a_trg)
  {
    *a -= temp;  
  }
  else
  {
    return 0;
  }
  return 1;
}

void setup(void) 
{
 	pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  key_init();
  u8g2.begin();
  u8g2.setFont(u8g2_font_t0_16_tf ); //设置字体
  frame_len = frame_len_trg = list[ui_select].len*10;
}

void ui_show(void)
{
  int list_len = sizeof(list) / sizeof(SETTING_LIST);
  u8g2.clearBuffer();         // 清除内部缓冲区
  for(int i = 0 ;i < list_len;i++)
  {
    u8g2.drawStr(x+2,y+i*14,list[i].str);  // 第一段输出位置
  }
  u8g2.drawRFrame(x,frame_y+2,frame_len,16,3);
  ui_run(&frame_y,&frame_y_trg,5,4);
  ui_run(&frame_len,&frame_len_trg,10,5);
  u8g2.sendBuffer();          // transfer internal memory to the displa
}

void ui_proc(void)
{
  int list_len = sizeof(list) / sizeof(SETTING_LIST);

  if(key_msg.update_flag && key_msg.press)
  {
    key_msg.update_flag = 0;
    if(key_msg.id)
    {
     ui_select++;
     if(ui_select >= list_len)
     {
        ui_select = list_len - 1;  
     }
    }
    else
    {
      ui_select--;
      if(ui_select < 0)
      {
        ui_select = 0;  
      }
    }
    frame_y_trg = ui_select*14;
    frame_len_trg = list[ui_select].len*10;
  }
  ui_show();
}

void loop(void) 
{
  key_scan();
  ui_proc();  
}

📘基于OLED_SSD1306_-_SH1106库按键菜单demo

  • 📍库地址:https://github.com/durydevelop/arduino-lib-oled
  • 🌿例程名:arduino-onebutton-menu-DEMO​

在使用1.3寸SH1106 I2C oled,需要修改库oled.cpp文件中的416行,低位地址改为0x02(默认是0x00)
程序代码:

#include "Arduino.h"
#include "DMenu.h"
#include "DDigitalButton.h"

#include <oled.h>       // **** OLED ****
//#include <U8x8lib.h>  // **** U8g2 ****

// For compatibility with U8g2 font
#define COLS 16
#define ROWS 8

DMenu* CreateMainMenu(void);
DMenu* CreateSubMenu1(void);
DMenu* CreateSubMenu2(void);
void PrintMenu(DMenu *Menu, uint8_t X = 0, uint8_t Y = 0);
void Debug(const String& msg);

//OLED display(18,19,NO_RESET_PIN,OLED::W_128,OLED::H_64);            // ****ssd1306  OLED ****
//OLED display(18,19,NO_RESET_PIN,OLED::W_128,OLED::H_64,tDisplayCtrl::CTRL_SSD1306, 0x3C);//
OLED display(18,19,NO_RESET_PIN,OLED::W_128,OLED::H_64,OLED::CTRL_SH1106, 0x3C);//****SH1106  OLED ****
//U8X8_SSD1306_128X64_NONAME_HW_I2C display(U8X8_PIN_NONE,19,18);   // **** U8g2 ****

// Button
DDigitalButton *Button=NULL;
// Menu
DMenu *CurrMenu=NULL;

void setup()
{
	// Begin display
	display.begin();
	//display.setFont(u8x8_font_chroma48medium8_r); // **** only for U8g2 ****

	// Begin serial debug
	Serial.begin(115200);
	Debug("Start");

	// Create Button
	Button=new DDigitalButton(0);
	Debug("Button on input pin 0");

	// Create MainMenu
	CurrMenu=CreateMainMenu();
	PrintMenu(CurrMenu);
}

// Poll Button and handle read status
void loop()
{
	DMenu *SelItem;

	switch (Button->Read()) {
		case DDigitalButton::PRESSED:
			Debug("<PRESSED>");
			CurrMenu->Down();
			PrintMenu(CurrMenu);
			break;
		case DDigitalButton::LONG_PRESSED: {
			Debug("<LONG_PRESSED>");
			SelItem=CurrMenu->Select();
			String ItemName=SelItem->GetName();
			Debug("Item "+ItemName);
			if (ItemName == "SubMenu 1") {
				CurrMenu=CreateSubMenu1();
				PrintMenu(CurrMenu);
			}
			else if (ItemName == "SubMenu 2") {
				CurrMenu=CreateSubMenu2();
				PrintMenu(CurrMenu);
			}
			else if (ItemName == "Back") {
				if (String(CurrMenu->GetName()) == "SubMenu 1" || String(CurrMenu->GetName()) == "SubMenu 2") {
					CurrMenu=CreateMainMenu();
				}
				PrintMenu(CurrMenu);
			}
			break;
		}
		default:
			break;
	}
}

DMenu* CreateMainMenu(void)
{
	if (CurrMenu != NULL) {
		// Only one menu must be in memory
		delete CurrMenu;
	}

	CurrMenu=new DMenu("Main Menu");
	CurrMenu->Loop=true;

	CurrMenu->AddItem("SubMenu 1",true);
	CurrMenu->AddItem("SubMenu 2");

	return(CurrMenu);
}

DMenu* CreateSubMenu1(void)
{
	if (CurrMenu != NULL) {
		// Only one menu must be in memory
		delete CurrMenu;
	}

	CurrMenu=new DMenu("SubMenu 1");
	CurrMenu->Loop=true;

	CurrMenu->AddItem("Execute",true);
	CurrMenu->AddItem("Back");

	return(CurrMenu);
}

DMenu* CreateSubMenu2(void)
{
	if (CurrMenu != NULL) {
		// Only one menu must be in memory
		delete CurrMenu;
	}

	CurrMenu=new DMenu("SubMenu 2");
	CurrMenu->Loop=true;

	CurrMenu->AddItem("Execute",true);
	CurrMenu->AddItem("Back");

	return(CurrMenu);
}

void PrintMenu(DMenu* Menu, uint8_t X, uint8_t Y)
{
	display.clear();
	// Line buffer
	char Line[COLS+1];
	memset(Line,' ',COLS+1);

	// Create centered menu title line
	uint8_t nameLen=strlen(Menu->GetName());
	uint8_t startCol=(COLS-nameLen)/2;
	memcpy(&Line[startCol],Menu->GetName(),nameLen);
	Line[COLS]='\0';

	// Print menu title
	display.drawString(X,Y,Line);

	// Starts from second line
	for (uint8_t iY=Y; iY<Menu->GetItemsCount();iY++) {
		DMenu* Item=CurrMenu->GetItem(iY);
		// Starts with item name 
		uint8_t itemLen=strlen(Item->GetName());
		memcpy(Line,Item->GetName(),itemLen);
		// Fill with spaces
		memset(&Line[itemLen],' ',COLS-itemLen);
		// Add NULL
		Line[COLS]='\0';
		if (iY == CurrMenu->GetCurrItemIndex()) {
			// Draw selected
			display.inverse();
			//display.drawString(X,iY+2,">");
			display.drawString(X,iY+2,Line);
			display.noInverse();
		}
		else {
			// Draw not selected
			//display.drawString(X,iY+2," ");
			display.drawString(X,iY+2,Line);
		}
		//display.drawString(X+2,iY+2,Line);
	}
	display.display();  // **** only for OLED ****
}

void Debug(const String& msg)
{
	Serial.println(msg);
}

u8g2是一款用于驱动各种OLED和LCD显示屏的库,而esp-idf是Espressif Systems开发的官方开发框架,用于开发ESP32和ESP8266芯片的应用程序。在esp-idf中使用u8g2库可以方便地控制和显示各种图形和文本。 要在esp-idf中使用u8g2库,首先需要在项目中添加u8g2的依赖。可以通过在项目的CMakeLists.txt文件中添加以下代码来实现: ``` idf_component_register(SRCS "main.c" INCLUDE_DIRS "" REQUIRES u8g2) ``` 然后,在代码中引入u8g2库的头文件,并使用相应的函数来初始化和控制显示屏。以下是一个简单的示例代码: ```c #include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "u8g2.h" void app_main(void) { u8g2_t u8g2; // 初始化u8g2u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, /* reset=*/U8X8_PIN_NONE); // 初始化I2C总线 i2c_config_t i2c_config = { .mode = I2C_MODE_MASTER, .sda_io_num = I2C_SDA_GPIO, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_io_num = I2C_SCL_GPIO, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = I2C_MASTER_FREQ_HZ, }; i2c_param_config(I2C_NUM_0, &i2c_config); i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0); // 初始化显示屏 u8g2_InitDisplay(&u8g2); u8g2_SetPowerSave(&u8g2, 0); // 显示文本 u8g2_ClearBuffer(&u8g2); u8g2_SetFont(&u8g2, u8g2_font_ncenB14_tr); u8g2_DrawStr(&u8g2, 0, 20, "Hello, World!"); u8g2_SendBuffer(&u8g2); while (1) { vTaskDelay(1000 / portTICK_PERIOD_MS); } } ``` 这是一个简单的示例,通过I2C总线连接一个128x64的OLED显示屏,并在屏幕上显示"Hello, World!"。你可以根据自己的需求修改和扩展代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值