PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Vorstellung: Arduino C++ Menu Lib (ARM oder ESP, ggf auch AVR)



HaWe
16.12.2018, 12:53
so,
nach den vielen Problemen bei der Programmierung der Objekte und Arrays, die wir hier schon besprochen haben, und dank der zahlreichen gegebenen Tipps und Hinweise (vielen Dank nochmals dafür!), hier nun als mein eigenes 2. C++ OOP Projekt eine weitere Vorstellung:
eine Arduino C++ Menu Lib (ARM oder ESP, vlt auch AVR)

Einbindung:
#include <MenuClass.h>

Es ist nicht auf Speicherplatzoptimierung hin programmiert, sondern für eher mittelgroße MCUs, die eh Speicher satt haben.
Es bietet Multilayer-Menüs, die einfach zu instanziieren, zu initialisieren, und zu bedienen und auszuwerten sind.

Die Lib bietet eine Class tMenu, die beliebig häufig instanziiert werden kann.
Sie ist im Beispielprogramm ausgelegt auf OLEDs 128x64 an ESP8266, auch andere OLEDs/TFTs an anderen Arduinos mit Adafruit-TFT Drivern sind bereits vorgesehen oder können angepasst werden.

Außerdem erfolgt die Menü-Darstellung zusätzlich noch per Serial.print(), es ist daher auch ohne TFT zu benutzen.


Steuerung:

Es werden 3 Buttons zu Steuerung benötigt für Cursor auf, ab, und Enter (Auswahl).

Nicht notwendig (aber empfehlenswert) ist die bereits in einem anderen Topic erwähnte ButtonClass.
https://www.roboternetz.de/community/threads/72805-Vorstellung-Arduino-C-Button-Lib-%28ARM-oder-ESP-ggf-auch-AVR%29

Mit Enter Long-Press kann markiert werden (tag/untag),
wenn markiert (tagged), dann per Enter Doppelclick Übernahme/Rückgabe der Liniennummer ans Hauptprogramm.

Die Auswertungsfunktion bekommt den Click-Status der 3 Buttons übermittelt
tMenu::checkbtn(btnUp, btnDown, btnEnter)
und gibt dann, falls eine Auswahl per Enter-Button erfolgt ist, die ausgewählte Linien-Nummer zurück.

Einträge können im Namen per '>' oder '<' als letzter "Buchstabe" als Verzweigung zu Untermenü/Vorgängermenü konfiguriert werden, dann wird per Longpress oder Doppelclick sofort die Liniennummer zurückgegeben ohne extra vorherige Markierung (tag)
(nicht notwendigerweise erforderlich, aber es macht das Springen zu anderen Menüs einfacher).

Alles andere im readme.txt in der Lib.

Jetzt auf Github: https://github.com/dsyleixa/Arduino/tree/master/MenuClass

Share and enjoy! 8)

HaWe
03.01.2019, 20:24
neues, ganz einfaches Beispiel, nur 1 Menü-Ebene, z.B. auch zum LED ein- und ausschalten:




// TFT Menu
// (C) 2018 by HaWe

// This example code is in the public domain for private use.
// Use for professional or business purpose: only
// by personal written permission by the author.

// default TFT: OLED 128x64, compatible to Adafruit (R) Libs
// in this example: using an ESP8266 NodeMCU 1.0 board
// using ButtonClass for button action (up, down, enter, single/double/long press)

// history:
// 0.0.1 tMenu new list

// simple menu example
// ver 0.0.1


// i2c
#include <Wire.h> // Incl I2C comm, but needed for not getting compile error


//-----------------------------------------------------------------------
// display driver
//-----------------------------------------------------------------------
#include <Adafruit_GFX.h> // https://github.com/adafruit/Adafruit-GFX-Library
// Adafruit Arduino OLED driver
#include <Adafruit_SSD1306.h> // https://github.com/esp8266/arduino

#include <Fonts/FreeSans9pt7b.h> // optional
#include <Fonts/FreeMono12pt7b.h> // optional
#include <Fonts/FreeMono9pt7b.h> // used here

// Pin definitions

#define OLED_RESET 10 // GPIO10=D12 Pin RESET signal (virtual)

//Adafruit_SSD1306 display(OLED_RESET); // old Adafruit lib (tested OK)
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET); // new Adafruit lib


//-----------------------------------------------------------------------
// OLED menu
//-----------------------------------------------------------------------
#include <MenuClass.h>

char * mlist1[7] = {"Menu1 L0","L1","L2","LED ON","LED OFF", "L5", "L6"};
tMenu menu1(7,11, (char**)mlist1, &menu1, 1);
// numEntries, lineLength, menu_list, preMenu, menu-ID

tMenu * actMenu = &menu1;

//-----------------------------------------------------------------------
// ButtonClass buttons
//-----------------------------------------------------------------------

#include <ButtonClass.h>
// 3 buttons for menu control
tButton btnUp;
tButton btnDown;
tButton btnEnter;




//-----------------------------------------------------------------------
// setup
//-----------------------------------------------------------------------

void setup(void)
{
// Start Serial

Serial.begin(115200);
delay(3000); // wait for Serial()
Serial.println("Serial started");

pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, !LOW); // inverted LED_BUILTIN signal logic

btnUp.init(D6, INPUT_PULLUP);
btnDown.init(D3, INPUT_PULLUP);
btnEnter.init(D4, INPUT_PULLUP);

// Start Wire (SDA, SCL)
//Wire.begin(ESPSDA,ESPSCL); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Wire.begin();

// SSD1306 Init
//display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // old Adafruit lib
display.begin(SSD1306_SWITCHCAPVCC, 0x3C, true, false); // new Adafruit lib

display.setRotation(2);
display.clearDisplay(); // Clear the buffer.

// text display tests
display.setTextSize(1);
display.setFont();
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Hello, world!");
display.display();
delay(500);

//--------------------------------------
// test + debug

display.setFont(&FreeMono9pt7b);

display.clearDisplay();
display.display();

Serial.println("menu init:");

actMenu = &menu1; //
actMenu->mdisplay();

Serial.println("\n\n");
}

//-----------------------------------------------------------------------
// loop
//-----------------------------------------------------------------------

void loop() {
int32_t ID;
int16_t ln;
char buf[20];

ln = actMenu->checkbtn(btnUp.click(), btnDown.click(), btnEnter.click() );

if(ln!=-1) { // double click btnEnter: do if selected
sprintf(buf, "select: line=%d ID=%d contents=%s", ln, ID, actMenu->list[ln]);
Serial.println(buf);

if(ln==0) { // menu ID 1, line 0
// do something
}
else
if(ln==1) { // menu ID 1, line 1
// do something
}
else
if(ln==2) { // menu ID 1, line 2: > next menu
// do something
}
else
if(ln==3) { // menu ID 1, line 3
digitalWrite(LED_BUILTIN, !HIGH); // inverted LED_BUILTIN signal logic
}
else
if(ln==4) { // menu ID 1, line 4
digitalWrite(LED_BUILTIN, !LOW); // inverted LED_BUILTIN signal logic
}
// etc.
}
}

// end of file




https://github.com/dsyleixa/Arduino/tree/master/MenuClass

HaWe
14.01.2019, 16:09
Bisher nutzt die MenuLib Class Lib eine (public) Methode zur zeilenweisen Ausgabe der menü-Einträge:


// Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
//
display.setColor(BLACK);
display.setCursor(FONTWI, line);
display.print(list[i]);

Nicht alle Display Libs (für LCD1602, ILI9341,...)unterstützen aber diese Syntax.
Es wäre nun eine schöne Erweiterung, wenn die MenuLib Class auch verschiedene Displays nutzen könnte, indem man eine interne, "allgemein gehaltene" ("virtuelle" ?) Schreibmethode verwendet, die erst bei der Instanziierung mit einer bestimmten TFT Lib mit der jeweiligen speziellen Syntax "assoziiert" wird.
Diese könnte dann gezwungen sein, z.B.
statt
display.setColor(BLACK);
display.setCursor(x,y);
display.print(cstring);
display.display();

etwas in dieser Form aufrufen:
TextOut(x,y, cstring, TFT_BLACK);
// schreibt uU sofort, ohne ein zusätzliches display.display(); zu benötigen

Sieht jemand eine Möglichkeit, so etwas umzusetzen?




class tMenu {

//...

public:

tMenu (...) : {
//...


void mdisplay() {
if(actln>VISLNUM-1) firstvln=_min(actln-1, MENULEN-VISLNUM);
else firstvln=0;
lastvln=min(firstvln+VISLNUM-1, firstvln+MENULEN-1) ;

display.clearDisplay();

for(int i=firstvln; i<=lastvln; i++) {
displn=(FONTHI-3) + (i-firstvln)*FONTHI;
display.setCursor(0, displn);

if(i!=actln && i==tagged) {
display.print('*');
}
else
if(i==actln && i==tagged) {
display.print('#');
}
else
if(i==actln && i!=tagged) {
display.print('>');
}
else {
display.print(' ');
}
display.setCursor(FONTWI, displn);
display.print(list[i]);
}
display.display();

}



//...

};

HaWe
09.02.2019, 14:01
das Problem mit stark unterschiedlicher TFTLib-Syntax ist noch nicht gelöst, aber die Zuordnung von Menü-Zeilen und den zugehörigen Exec-Commandos ist deutlich vereinfacht:

Passend zur Liste mit den einzelnen Zeilen des Menüs
wird eine entsprechende Exec-Funktion mit den jew. Zeilen der zugehörigen Befehle geschrieben.

Dadurch ist das Handling der Menü-Funktionen in der loop() deutlich vereinfacht (es können auch optional Strings als Rückgabewerte empfangen werden für spezielle Anforderungen).


--------------------------
Update!

Neu:
Es können nun auch Variablenwerte in Menüzeilen angezeigt, geupdated und nach Markieren (tag) per Buttons verändert werden, und das sogar für mehrere verschiedene Variablen im selben Menü.

Beispielcodes hier:

https://github.com/dsyleixa/Arduino/tree/master/MenuClass