Ich hab erst diese Tage mit dem Thema Arduino angefangen, daher verzeiht mir bitte meine Verständnisprobleme. Da ich niemanden kenne der sich dabei auskennt, daher wende ich mich an euch.
Mein Projekt soll 3 Sauerstoffsensoren auslesen und die Daten anzeigen bzw. weiterverarbeiten.
Da ich diese auch kalibrieren muss, wollte ich ein Menü erstellen, in dem dann kalibriert werden kann.
Ich besitze ein Adafruit Feather M0 Proto Board und ein Featherwing 2,4" TFT-Display.
Dort hab ich einen Homescreen erstellt der mir die 3 Sensorwerte anzeigen soll und den Mittelwert daraus.
Abgesehen davon dass ich keine schöne Schrift habe die mit Background arbeitet funktioniert das alles soweit.
Nun zum Thema Menü.
Ich hab schon einige Freds von euch durch, allerdings sind da immer andere Sachen mit drinnen die ich nicht verstehe und daher verliere ich immer den Faden.
Mein Plan wäre eine Bedienung über zwei Taster.
Wenn ich im Homescreen bin und beide Tasten gleichzeitig drücke, dann komm ich ins Menü.
Dort kann ich dann mit den beiden Tastern auf und ab blättern und beide gleichzeitig gedrückt ist select.
Ist sowas einigermaßen einfach realisierbar?
Weiters kommt dann das Problem der Kalibrierung.
Dachte an eine 2-Punkt-Kalibrierung über einen map-Befehl.
Aber wie bekommt man diese Werte in den Flash?
Sollen ja erhalten bleiben auch nach dem Ausschalten.
Angeblich hat das Board EEPROM-Emulation. Aber wie?
Könnte mir mal jemand ein paar Tipps geben und die Grundlagen eines Menüs erklären?
Das habe ich schon gefunden, aber da ist alles mit Lib's verschachtelt und da versteh ich dann kaum was.
Wie gesagt, ich bin noch am Anfang bei Arduino und versuche die Grundfunktionen zu verstehen.
Wenn ich Beispielsweise in meinem Loop eine Abfrage der Tasten mache, und beide gedrückt sind, dann kann ich auf ein Unterprogramm verweisen, das mein Menü ist. Gibt es irgendwelche Befehle für ein Menü?
Konnte in der Arduino-Referenz, die ich ganz brauchbar finde, nix dazu sehen.
Im Menü muss ich wohl eine Variable bestimmen, die meine Position bestimmt. Durch drücken der Tasten wird diese dann größer oder kleiner. So bewege ich mich auf und ab.
Oder so ähnlich!?
Was ich damit sagen will.
Ich hätte gerne gelernt wie man ein Menü erstellt, und nicht wie man fertige Libraries verwendet.
Die sind wiederum so umfangreich, dass man als Anfänger nicht durchblickt.
Da kommen Befehle vor die ich nicht kenne, aber auch nicht sagen kann ob es Library-bezogene Sachen sind, oder Standardbefehle die ich nur nicht kenne.
Wenn mir das jemand vermitteln könnte, dann wäre ich dankbar.
Für mich bitte so, als wenn man einem Kind erklärt wie es den Stift halten muss um auf einem Blatt papier zu malen. Aber auch erklären dass man nicht über den Rand malen darf, da sonst das Bild kaputt ist wenn man das Blatt anhebt.
Ich halte das Projekt: LCDMenuLib und LCDMenuLib2 (LCDML) für Anfänger ungeeignet.
Es ist bestimmt sehr ausgereift und kann eine Menge. Und der Support ist vorbildlich.
Ich halte sowas für einen Anfänger leichter zu verstehen.
Danke für den Link, das werd ich mal genauer begutachten.
@ HotSystems:
Mir gehts um die Menüfunktion direkt.
Wie macht man ein Menü mit zwei Punkten zwischen denen ich hin und her springen kann und auswählen.
Die Punte sollten farblich hervorgehoben sein wenn man darüber steht.
Wie oben schon erwähnt mit zwei Tastern bedienbar.
So nebenbei, wie integriert ihr eure Codeschnipsel mitten im Post?
Hausknecht:
Ich halte sowas für einen Anfänger leichter zu verstehen.
Hallo,
zum Link, mit verlaub, dass ist totaler Schrott wenn ich das sagen darf.
TO:
bevor du dich überhaupt ans Menü programmieren begeben kannst, solltest du Grundlagen lernen. Wie fragst du prellfrei deine Taster ab. Wie zählt man auf Tastendruck hin eine Variable hoch und runter. Wie erkennt man den Tastendruck zweier Tasten. Wenn das klappt kannste dir Gedanken machen über deine Menüsteuerung. Für all das benötigst du noch kein Display. Serielle reicht aus.
Doc_Arduino:
zum Link, mit verlaub, dass ist totaler Schrott wenn ich das sagen darf.
Ich hab diesen Schrott in abgewandelter Form im Einsatz und bin damit zufrieden.
Ich muss als Anfänger verstehen was passieren soll und nachprüfen können, ob es dies auch tut.
So lerne ich. Wenn ich etwas nicht verstehe, dann kann es noch so genial sein, es bringt mir nichts.
Es ist ganz leicht etwas schlecht zu machen, aber es ist nicht so leicht etwas anfängergerechtes rüber zu bringen.
Wenn sich große Jungs unterhalten, dann sollte ich mich zukünftig besser raus halten.
Sei mein Held und zeige mir Anfänger wie ein Menue aussehen kann, das auch ein Anfänger versteht und kein Schrott ist.
Beim Encoder auslesen kommt es darauf an, dass er auch bei mistigen Dingern noch sauber zählt. Das heißt ein Kontaktprellen kann man nicht unterdrücken, es darf nur den Encoderzähler nicht durcheinander bringen. Er darf mal kurz hin und her "pendeln" aber dabei keine wilden Sprünge machen oder dergleichen. Er korrigiert sich selbst.
Genau das sehe ich in dem Code von Wampo nicht. Darauf bezog sich meine Aussage. Wenn der Zähler funktioniert, dann ist ein kleines Menü auch nicht weit. switch-case wäre dein Freund. Und nein ich werde dir kein Menü bauen. Wenn du jedes Detail verstehen möchtest, dann musst du es selbst programmieren. Das ist auch nicht böse gemeint und ich möchte dich auch nicht ärgern, ich sage nur wie es ist.
Ich gebe dir recht, das Auslesen des Encoder hatte bei mir mit dem verlinkten Beispiel nicht geklappt. Ich habe sie dann durch eine Interrupt gesteuerte Abfrage ersetzt.
Dem TO ging es aber (so hatte ich das verstanden) um ein Menu und erst in zweiter Linie um die Steuerung . Die wollte er ja mit zwei Taster machen.
ich glaube man sollte das umdrehen. Erst die Steuerung programmieren und dann das Menü. Wenn man schnell zu Ergebnissen kommen möchte kann man die Bounce2 Lib für die Tasten verwenden.
Nun habe ich mich hinreißen lassen ein kleines Bsp. mit Encoder zu erstellen.
Das Ungewöhnliche ist noch bei den Encoderparametern die Port und Bit Angaben.
Mittels Pinouts sollte das jedoch kein Problem darstellen.
Da bin ich noch am überlegen wie ich die "CombiePin" am einfachsten nutzen kann.
In der Encoder Klasse findest du den Code von Peter Dannegger wieder aus dem Link zum Drehencoder.
Das mit der Menüauswahl und Tasterabfrage ist bewusst einfach gehalten und noch nicht perfekt. Soll nur ein Grundgedanke darstellen wie ich mir das vorstellen würde. Man könnte die Tasterabfrage noch zur Flankenerkennung umbauen oder eben Bounce2 verwenden, wem die Mehrfachausgabe während des drückens stört. Wie weit man das treibt muss jeder für sich ausmachen. Andere Menü Libs gibt es ja bereits.
class GrayEncoder // Klassenname "GrayEncoder"
{
protected: // private wird zu protected, nur intern zugängliche Elemente ...
volatile byte const *PORT; // verwendeter Port
byte const PinA; // Pin Port.Bit erste Phase
byte const PinB; // Pin Port.Bit zweite Phase
int relMin;
int relMax;
byte shift; // Zählerkorrektur wegen Steps pro Rastung
volatile long rel_counter; // relativer Zähler
volatile long abs_counter; // absoluter Zähler, nicht veränderbar
int enc_delta;
int last;
byte Phase_A; // erste Phase
byte Phase_B; // zweite Phase
long abs_old;
int getPhases() {
int n = 0; // new
Phase_A = (*PORT >> PinA & 1); // einzelnes Bit herausfischen
Phase_B = (*PORT >> PinB & 1);
if ( Phase_A ) n = 3;
if ( Phase_B ) n ^= 1; // convert gray to binary
return n;
}
void update_RelativCounter () {
long new_abs = abs_counter >> shift; // halbiert, geviertelt ... Steps pro Rastung
if ( new_abs != abs_old) {
if (new_abs > abs_old) {
rel_counter++;
}
else {
rel_counter--;
}
abs_old = new_abs;
}
if (rel_counter < relMin) {
rel_counter = relMax;
}
else if (rel_counter > relMax) {
rel_counter = relMin;
}
}
public: // von außen zugängliche Elemente ...
GrayEncoder (volatile byte *p_Port, byte _A, byte _B, int _max, byte _raster):
// Initialisierungsliste
PORT(p_Port),
PinA(_A),
PinB(_B),
relMin(0),
relMax(_max),
shift(_raster/2),
rel_counter(0), // Zähler
abs_counter(0), // Zähler
abs_old(0)
{ }
void init()
{
last = getPhases(); // power on state
enc_delta = 0;
}
void encode()
{
int n = getPhases();
int diff = last - n;
if ( diff & 1 ) { // bit 0 = value (1)
last = n; // store new as next last
enc_delta = (diff & 2) - 1; // bit 1 = direction (+/-), Zähler
abs_counter += (long) enc_delta;
}
update_RelativCounter();
}
long getRelCounter() {return rel_counter; } // relativen Zählwert abfragen, Rastung ist schon angepasst
};
// ---------------------------------------------------------------------------------------
/* Port
| Portbit Phase A
| | Portbit Phase B
| | | Zählumfang
| | | | Steps pro Rastung
| | | | | */
GrayEncoder ALPS_EC11 (&PING, 1, 0, 8, 2); // Port.G Bit.1 / Bit.0 / (Pin 40/41) / Zählumfang / Rastung
int ALPS_EC11_RelCounter;
const byte pin_Button = 2; // Menüauswahl Bestätigung
bool state_Button = true;
void setup() {
Serial.begin(9600);
pinMode(40, INPUT_PULLUP);
pinMode(41, INPUT_PULLUP);
ALPS_EC11.init();
pinMode(pin_Button, INPUT_PULLUP);
}
void loop() {
update_Encoder();
ausgabe();
update_Taster();
menue (ALPS_EC11_RelCounter, state_Button);
}
// ****** Funktionen ******
void update_Encoder ()
{
ALPS_EC11.encode();
ALPS_EC11_RelCounter = ALPS_EC11.getRelCounter();
}
void ausgabe()
{
static int enc_old = 0;
if (ALPS_EC11_RelCounter != enc_old) {
enc_old = ALPS_EC11_RelCounter;
Serial.println(ALPS_EC11_RelCounter);
}
}
void update_Taster()
{
static unsigned long last_ms = 0;
const unsigned int DEBOUNCE = 40; // Taster Entprellzeit
if (millis() - last_ms < DEBOUNCE) return;
last_ms = millis();
state_Button = digitalRead(pin_Button);
}
void menue (int number, bool state_Button)
{
if (state_Button) return; // keine Änderung, Funktion verlassen
switch (number) {
case 0: Serial.println(F("Grundstellung"));
break;
case 1: Serial.println(F("Seite 1"));
break;
case 2: Serial.println(F("Seite 2"));
break;
case 3: Serial.println(F("Seite 3"));
break;
case 4: Serial.println(F("Seite 4"));
break;
case 5: Serial.println(F("Seite 5"));
break;
case 6: Serial.println(F("Seite 6"));
break;
default: Serial.println(F("ungueltige Nummer"));
break;
}
}