Hallo,
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.
Pinout Übersichten:
Board Pinout Überblick
UNO Pinout
Mega Pinout
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;
}
}