Mit Taster den Modus wechseln

Hallo Leute,

Ich bin nun seid einer Woche dabei das Arduino Handwerk zu erlernen. Nach vielen Beispielen mit dem Starter Kit. Wurde es nun Zeit für etwas eigenes.

Mein Projekt /Ziel :
Ich möchte zwischen 3 Modi mit einem Taster durchschalten. Zunächst ganz simpel. M1 = LED an, M2 = LED blinken, M3 = LED aus.

Eigentlich funktioniert das. Aber recht sporadisch. Manchmal wechselt die Modusrichtung, manchmal schaltet er nicht um wenn man drückt. Wenn man zu lange drückt können Modi übersprungen werden.

Ich habe viel im Internet gelesen. Habe viele Themen dazu gelesen doch nichts hat mich zufrieden gestellt.
Ich weiß dass das man den Taster im richtigen Moment drücken muss das registriert wird das er gedrückt ist, da das Signal nur einmal ausgelesen wird und das Programm sturr durchläuft.
Bei einem kleinen Modus geht das ja noch.....

Gibt es nicht etwas welches das Signal vom Taster ständig überwacht und den Modus unterbricht?
Oder kann man ein HIGH Signal registrieren und speichern bis es gebraucht wird? (Modus läuft bis zum Ende und schaltet dann um. Wäre nicht optimal aber der Zufalls Faktor wäre weg)

Ich hoffe ihr habt eine schöne Lösung für mich.

anbei noch mein Sketch

Gruß
Alex

Buttontest mit 2.ino (1.93 KB)

Ohne Sketch und Schaltbild können wir nur raten.
Hast du den Taster zum Modus umschalten denn entprellt? Per Software, oder Hardware? Sonst wird der Modus durch das Kontaktprellen eben zufällig oft weitergeschaltet.

Gruß Gerald

Ja, es gibt "sowas". Nen Interupt.
Interrupts unterbrechen das laufende Programm und arbeiten nen eigenes "Unterprogramm" ab (ISR-Interrupt-Service-Routine), danach wird das laufende Programm an der vorherigen Stelle fortgesetzt.

Da eine ISR so kurz wie möglich sein muss (es gibt gewaltige Probleme, wenn eine ISR durch nen Interrupt unterbrochen wird, wenn du drüber nachdenkst, wird dir klar, wieso), setzt man dort einfach nur eine Variable auf HIGH.
Die wird dann im Hauptprogramm zyklisch abgefragt, und wenn sie HIGH ist, wird der Modus gewechselt, und sie wieder LOW gesetzt.

Zusätzlich muss der Taster natürlich entprellt werden (per Hard-oder Software). Noch besser funktioniert es, wenn statt "gedrückt" das "losgelassen" als Signal genommen wird.
Ungefähr so:
Druck löst ISR aus-
Hauptprogramm sieht das gesetzte Flag-
prüft nun ob der Taster noch gedrückt ist-
wenn nicht, wird der Modus gewechselt.
So in etwa.

Man kann auch als Auslöser für den Interrupt direkt das "losgelassen" benutzen, muss dann aber anders entprellen.

Auf so eine Art und Weise kann kein Modus mehr übersprungen werden, da erst reagiert wird, nachdem gedrückt UND wieder losgelassen wurde. Funktioniert aber NUR wenn entprellt wird!

@Rabenauge
Danke für die Antwort. Das klingt soweit ganz gut. Ich werde mir das als Anfänger 2-3 mal durchlesen müssen. Werde dann darauf antworten wenn ich einigermaßen das durchschaue.

Im Anhang das Bild vom aufbau und hier das Sketch wellches im Anhang war:

                               // Buttontest mit 2.ino

int mode         = 3;          // Beim Start LED aus
int Blau         = 9;
int Gelb         = 6;

int Button       = 7;

int Buttonstatus = 0;

                               // Variables will change:
int ledState        = LOW;     // ledState used to set the LED
long previousMillis = 0;       // will store last time LED was updated

                               // the follow variables is a long because the time, measured in miliseconds,
                               // will quickly become a bigger number than can be stored in an int.
long interval = 300;           // interval at which to blink (milliseconds)


void setup() {
pinMode(Blau, OUTPUT);         // LED Blau
pinMode(Gelb, OUTPUT);         // LED Gelb

pinMode(Button, INPUT);        // Signal - Taster
}

void loop() {


if(digitalRead(Button)==HIGH){ // Wenn Taster gedrückt, Modus um 1 erhöhen
    mode++;
if (mode==4){mode = 1;}        // Wenn Modus > 3, dann zurück zu Modus 1
                               // else {mode = 1;}
  } 
  if (mode==1){
    digitalWrite(Blau,HIGH);   // Modus 1 = LED an
    digitalWrite(Gelb,HIGH); 
  }
else if (mode==2){             // Modus 2 = LED blinken
 
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
                               // speichert das letzte mal als die LED geblinkt hat
    previousMillis = currentMillis;   

                               // Wenn die LED nicht leuchtet, wird sie umgestellt und leuchtet
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

                               // setzt die LED mit 'ledState'
    digitalWrite(Blau, ledState);
    digitalWrite(Gelb, ledState);

  }
 }

else if (mode==3){             // Modus 3 = aus
    digitalWrite(Blau,LOW);
    digitalWrite(Gelb,LOW);
  }
  
delay(250);                    // kurzes Delay, um mehrere Anschläge durch 1x drücken zu verhindern
}

Einen Interrupt für eine Tastenabfrage zu verwenden finde ich falsch.

@Wick3d

Du kontrollierst ob der Zustand des Tasters sich geändert hat und wenn er von LOW nch HIGH gewechselt hast zählst Du den Modus weiter. Eine kleine Pause, mittels millis() realsiert, entprellt.

http://www.arduino.cc/en/tutorial/switch

Grüße Uwe

Wick3d:
Mein Projekt /Ziel :
Ich möchte zwischen 3 Modi mit einem Taster durchschalten. Zunächst ganz simpel. M1 = LED an, M2 = LED blinken, M3 = LED aus.

Eigentlich funktioniert das. Aber recht sporadisch. Manchmal wechselt die Modusrichtung, manchmal schaltet er nicht um wenn man drückt. Wenn man zu lange drückt können Modi übersprungen werden.

Deinem Sketch nach zu urteilen muss der Button mit einem PullDown-Widerstand angeschlossen sein.
Ohne diesen korrekt beschalteten PullDown-Widerstand am Button funktioniert der Sketch nicht.

Wenn Du keinen PullDown-Widerstand verbauen möchtest, müßtest Du als pinMode "INPUT_PULLUP" setzen, und dann mit vertauschter Programmlogik arbeiten, d.h. gedrückter Taster wäre LOW und unbetätigter Taster wäre HIGH.

Für ein interaktives Programm sind delay-Werte von einer viertel Sekunde auch viel zu lang. Wenn Du während eines delay(250), also während die Programmausführung für eine Viertelsekunde komplett blockiert wird, den Taster sowohl drückst als auch losläßt, bekommt das Programm von Deinem Tastendruck nichts mit.

Alternativer Programmverschlag für den Fall, dass Du einen PullDown-Widerstand verbaut hast:

enum {ONMODE, BLINKMODE, OFFMODE}; // symbolische Konstanten für die Betriebsarten
int mode = OFFMODE;          // Beim Start LED aus

int blauPin         = 13;
int gelbPin         = 9;
int buttonPin    = 7;

long interval = 300;           // interval at which to blink (milliseconds)

void setup() {
  pinMode(blauPin, OUTPUT);         // LED Blau
  pinMode(gelbPin, OUTPUT);         // LED Gelb
  pinMode(buttonPin, INPUT);        // Signal - Taster
}

boolean buttonPressed() // Taster abfragen auf drücken des Buttons
{
  static boolean lastButtonState;
  boolean buttonState=digitalRead(buttonPin);
  if (buttonState!=lastButtonState) // Status hat sich geändert
  {
    lastButtonState=buttonState;  // letzten Status merken
    if (buttonState==HIGH) return true; // Status hat sich auf "gedrückt" geändert
  }
  return false;
}

void loop() { // Loopfunktion nach dem EVA-Prinzip: Eingabe - Verarbeitung - Ausgabe
  // Eingabe (Taster abfragen)
  if (buttonPressed())
  {
    mode++; 
    if (mode>OFFMODE) mode=ONMODE;
  }
  // Verarbeitung
  int blinkState=LOW; // von OFFMODE ausgehen
  if (mode==ONMODE) blinkState=HIGH;  // einschalten bei ONMODE
  else if (mode==BLINKMODE) blinkState=(millis()/interval)%2; // Blinkstatus bei BLINKMODE
  // Ausgabe
  digitalWrite(blauPin,blinkState);
  digitalWrite(gelbPin,blinkState);
  delay(5);  // kurzes delay zum Entprellen des Tasters
}

Allerdings ist das Verbauen von PullDown-Widerständen ein unnötig hoher Hardwareaufwand für die Schaltung: Sofern die Taster nur mit kurzen Leitungen bis ca. 50 cm Länge an der Schaltung angeschlossen sind, würde man eher ein Programm mit aktiviertem internen PullUp-Widerstand verwenden (pinMode "INPUT_PULLUP" setzen) und mit negierter Programmlogik auf das Drücken des Tasters abfragen.

Von der Programmlogik der loop-Funktion her solltest Du Dich um die Umsetzung des EVA-Prinzips bemühen,

  • Eingabe (alle Eingänge auf Status bzw. Änderungen abfragen, je nach Bedarf)
  • Verarbeitung (aus den Eingangszuständen die logischen Ausgangszustände ermitteln)
  • Ausgabe (Ausgangszustände am Controller setzen, Ausgaben auf Serial, LCD etc. machen)

Zunächst vielen dank an euch und an jurs.
Das klappt genau so wie ich es wollte :smiley: Musste zwar gefühlte 50 mal lesen bis ich kapiert was einem der Code sagt.
Das EVA prinzip finde ich eigentlich sehr einleuchtend. Aber ich kam schon in manche Situationen in denen es schwer umzusetzen ist. vielleicht mi etwas mehr Übung und wissen bekommt man es hin :smiley:

Das nächste Problem steht an. Aber dazu wird es wohl einen neuen Thread geben.

Gruß
Alex

Hallo zusammen,

der Thread ist zwar schon älter, aber ich habe was ähnliches vor... Mein Sketch ist ein wenig umfangreicher, jedoch funktioniert der Tastendruck nicht.. Kann das jemand testen? Oder sogar einen Fehler finden?

#include "FastLED.h"                      // Bibliothek der LEDs laden.
#include <EEPROM.h>                       // EEPROM-Lib für die Speicherung des aktuellen Zustandes
 
#define NUM_LEDS 63                       // Wie viele LEDs sind in dem Strang verkettet?
#define DATA_PIN 7                        // Welcher Pin gibt den Signalausgang?
#define debounce_delay 15                 //Entprellzeit für den Taster
 
CRGB leds[NUM_LEDS];   

bool taster_state, taster_state_alt;      // Variablendeklaration (global)
const int tasterPin = 2;                  //Taster an Pin 2 angeschlossen
const int ledPin = 7;                     //Signalausgang
int lichtmodus = 0;                       //Variable für den Ablauf
int tasterStatus = LOW;                     //Variable zum Speichern des Tasterstatus
int einsLed = 63;
int LED = 0;
byte brightness = 255;                    // Helligkeit zwischen 0 und 255
long lWaitMillis = 0;                     // Hilfsvariable zur Zeitmessung bei effekten
uint8_t gHue = 0;                         // rotatierende "base color" von sämtlichen effekten
byte maxModi = 5;                         // Anzahl der Modi (ist modi der plural von modus?!)

int buttonState = LOW;         // variable for reading the pushbutton status
int buttonread = 0;
 
void setup()                  // Folgende Funktion schaltet die LEDs und übermittelt die Informationen an den Arduino
{
  // sanity check delay - allows reprogramming if accidently blowing power w/leds
  delay(2000);
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  pinMode(ledPin, OUTPUT);      //Setzt den LEDpin als Ausgang
  pinMode(tasterPin, INPUT);    //Setzt den Taster als Eingang
  loadFromEEPROM();             // Lade werte aus dem EEPROM
  AllOff();                     // Egal welche LED zufällig leuchten sollte: ALLES AUS!

  
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(tasterPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  // read the state of the pushbutton value:
  buttonread = digitalRead(tasterPin);
 
  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonread == HIGH) { //Check if Button was pressed before and being pressed now
 
    if (buttonState == LOW)
    {
      // turn LED on:
      digitalWrite(ledPin, HIGH);
      buttonState = HIGH;
      Serial.println(tasterStatus);
    }
  }
  else {
    if (buttonState == HIGH) {
      digitalWrite(ledPin, LOW);
      buttonState = LOW;
    }
  }

      getButtons();
    FastLED.setBrightness(brightness);
    switch (lichtmodus) // Hier werden die einzelnen voids für die Lichtprogramme aufgerufen. Jede Void hat ihren eigenen Takt in der eine aktualisierung stattfindet der nicht das komplette Programm blockt.
    {
      case 1:
        modusOrange();
        break;
      case 2:
        modus2();
        break;
      case 3:
        modus3();
        break;
      case 4:
        modus4();
        break;
      case 5:
        modus5();
        break;
    }
}
 
void saveToEEPROM()
{
  EEPROM.write(0, lichtmodus);                      // Speichere an Position 0 im EEPROM den lichtmodus
  //EEPROM.write(1, brightness);                      // Speichere an Position 1 im EEPROM die helligkeit
}
 
void loadFromEEPROM()
{
  lichtmodus = EEPROM.read(0);
  //brightness = EEPROM.read(255);
}
 
void getButtons()
{
static uint32_t debounce_time;
 
if (millis()-debounce_time>debounce_delay)taster_state = digitalRead(tasterPin); //einlesen des Tasters
 
if (taster_state != taster_state_alt) // bei Pegelwechsel
  {
    debounce_time=millis();
    taster_state_alt = taster_state;
    if(!taster_state)//wenn Taster gedrückt
    {
      lichtmodus++;                             //Lichtmodus +1
      if (lichtmodus > maxModi) lichtmodus = 0; //beim vierten Tastendruck fängt das ganze von vorne an
    }
  }
}
 
void AllOff()
{
  fill_solid(leds, NUM_LEDS, CRGB::Black);
  FastLED.show();
}
 
void modusOrange()

 

 
 fill_solid(leds, NUM_LEDS, CRGB::Orange);
 FastLED.show();
}
 
void modus2()
{
   if ((long)(millis() - lWaitMillis) >= 0)
  {
    static byte heat[NUM_LEDS];
    for (int i = 0; i < NUM_LEDS; i++) heat[i] = qsub8(heat[i], random8(0, ((55 * 10) / NUM_LEDS) + 2));
    for (int k = NUM_LEDS - 1; k >= 2; k--) heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
 
    if (random8() < 120) {
      int y = random8(7);
      heat[y] = qadd8(heat[y], random8(160, 255));        // FARBE
    }
 
    for (int j = 0; j < NUM_LEDS; j++)
    {
      CRGB color = HeatColor(heat[j]);
      int pixelnummer;
      pixelnummer = j;
      leds[pixelnummer] = color;
    }
    lWaitMillis += 50;                                  // GESCHWINDIGKEIT
  }
  FastLED.show();
}
 
void modus3()
{
    fill_rainbow( leds, NUM_LEDS, gHue, 255 / NUM_LEDS);
}
 
void modus4()
{
  // built-in FastLED rainbow, plus glitzer
  modus3();
  addGlitter(80);
}
 
void addGlitter( uint8_t chanceOfGlitter)
{
  if ( random8() < chanceOfGlitter) {
    leds[ random16(NUM_LEDS) ] += CRGB::White;
  }
}
 
void modus5()
{
  fadeToBlackBy( leds, NUM_LEDS, 20);
  int pos = beatsin16(40, 0, NUM_LEDS);         // ERSTER WERT = GESCHWINDIGKEIT
  static int prevpos = 0;
  if ( pos < prevpos ) {
    fill_solid( leds + pos, (prevpos - pos) + 1, CHSV(gHue, 220, 255));
  } else {
    fill_solid( leds + prevpos, (pos - prevpos) + 1, CHSV( gHue, 220, 255));
  }
  prevpos = pos;
}

Habe das ganze mit dem Arduino ausprobiert und W2812B LEDs, welche ich selbst verlötet habe. Einen Fehler zeigt es mir keinen an. Beim ausprobieren, wird auch nicht auf den Taster reagiert und die Programme bzw. die LEDs spielen "verrückt".

Angschlossen wurde der Taster mit 10kOhm gegen Masse..

fusinoco:
der Thread ist zwar schon älter, ...

Genau deshalb solltest Du einen neuen Thread starten und auf den alten Verweisen (setze einen Link auf das erste Posting des alten Threads). Das ist erheblich besser, als einen Uralt-Thread von '14 wieder hochzuholen.

Gruß

Gregor