Zähler Funktion

Hallo zusammen, mein Zähler benötigt sehr lange Zählimpulse an seinem Digitaleingang.
Woran liegt dieses?
Ich möchte über einen Digitaleingang einen Zahlenwert hochzählen und darüber in durch verschiedene Case Abschnitte im Programm gelangen.


void loop() 
{
 buttonState = digitalRead(xI1);
  if(buttonState == HIGH){
    if(counter < 6)
    {
      counter++;
    }
    else
    {
      counter = 0;
    }
    delay(10);
  }
  changeLights();

}
void changeLights() 
{
  switch(counter)
  {

    case 0:                                                     //*Initiaisieren der LED´s und Ausgänge*
    
    digitalWrite(LED_D0, LOW);
    digitalWrite(LED_D1, LOW);
    digitalWrite(LED_D2, LOW);
    digitalWrite(LED_D3, LOW);
    
    digitalWrite(xD0, LOW);
    digitalWrite(xD1, LOW);
    digitalWrite(xD2, LOW);
    digitalWrite(xD3, LOW);

    break;

    case 1:                                                     //*Wechselblinker*
     
      digitalWrite(LED_D0, HIGH);
      digitalWrite(LED_D1, HIGH);
      digitalWrite(xD0, HIGH);
      digitalWrite(xD1, HIGH);

      digitalWrite(LED_D2, LOW);
      digitalWrite(LED_D3, LOW);
      digitalWrite(xD2, LOW);
      digitalWrite(xD3, LOW);

      delay(800);
      digitalWrite(LED_D0, LOW);
      digitalWrite(LED_D1, LOW);
      digitalWrite(xD0, LOW);
      digitalWrite(xD1, LOW);

      digitalWrite(LED_D2, HIGH);
      digitalWrite(LED_D3, HIGH);
      digitalWrite(xD2, HIGH);
      digitalWrite(xD3, HIGH);
      delay(800);
      

      break;
// Forensketch: Weil weihnachten ist

void loop()
{
  buttonState = digitalRead(xI1);
  if (buttonState == HIGH)
  {
    if (counter >= 6)
    { counter = 0; }
    else
    { counter++; }
  }
  changeLights();
}
//
void changeLights()
{
  static bool lastCounter = 0;
  switch (counter)
  {
    case 0:                                                     //*Initiaisieren der LED´s und Ausgänge*
      digitalWrite(LED_D0, LOW);
      digitalWrite(LED_D1, LOW);
      digitalWrite(LED_D2, LOW);
      digitalWrite(LED_D3, LOW);
      digitalWrite(xD0, LOW);
      digitalWrite(xD1, LOW);
      digitalWrite(xD2, LOW);
      digitalWrite(xD3, LOW);
      break;
    case 1:                                                     //*Wechselblinker*
      if (lastCounter != counter)
      {
        allOn();
        lastMillis = millis();
      }
      blinker(800);
      break;
    default:
      counter = 0;
      break;
  }
  lastCounter = counter;
}
//
void allOn()
{
  {
    lastBlink = millis();
    digitalWrite(LED_D0, HIGH);
    digitalWrite(LED_D1, HIGH);
    digitalWrite(xD0, HIGH);
    digitalWrite(xD1, HIGH);
    digitalWrite(LED_D2, HIGH);
    digitalWrite(LED_D3, HIGH);
    digitalWrite(xD2, HIGH);
    digitalWrite(xD3, HIGH);
  }
}
//
void blinker(const uint32_t intervall)
{
  static uint32_t lastBlink = 0;
  if (millis() - lastBlink > intervall)
  {
    lastBlink = millis();
    digitalWrite(LED_D0, !digitalRead(LED_D0));
    digitalWrite(LED_D1, !digitalRead(LED_D1));
    digitalWrite(xD0, !digitalRead(xD0));
    digitalWrite(xD1, !digitalRead(xD1));
    digitalWrite(LED_D2, !digitalRead(LED_D2));
    digitalWrite(LED_D3, !digitalRead(LED_D3));
    digitalWrite(xD2, !digitalRead(xD2));
    digitalWrite(xD3, !digitalRead(xD3));
  }
}
1 Like

Vielen Dank für den hilfreichen Code.
Über einen Schalter schalte ich 24V DC auf den Zähleingang.
Ich bekomme das Problem, das ich von Case 3 nach Case 4 erst nach mehrmaligen Schalten springen kann. Woran liegt das ?
Der Start klappt immer, der Wechsel zwischen Case 1 und Case 2 erfolgt problemlos..
Manchmal muss ich den Schalter auch erst 4 - 5mal betätigen bevor in den nächsten Case gesprungen wird und das nächste Lichtbild signalisiert wird.

Ich hoffe nicht direkt, sondern über einen Spannungsteiler.

Das wird Kontaktprellen sein. Du musst den Taster / Schalter entprellen. Nimm dazu die Library "Debounce"

In den gezeigten Schnippseln gibt es doch gar kein case 3 oder 4.

Ich habe jetzt nochmal den gesamten Code eingefügt.
Wie muss ich die Debounce Bibliothek in meinen Code einbinden?
Kannst du mir das beispielhaft einmal in meinem Code zeigen?

# include "OneButton.h"



int TASTER = A1;

// Array für die LEDs
int LED[4] = {LED_D0, LED_D1, LED_D2, LED_D3};
int Relay[4] = {D0 ,D1 ,D2, D3};


OneButton NameTaster(TASTER, true);
// LEDs sind beim Start ausgeschaltet
bool Status = LOW;

int buttonState = 0;
int counter = 0;
int i = 0;
int i_2 = 0;
int buttonStateHIGH = 0;


// EINGÄNGE deklarieren
char xI1 = A0;  //Eingang 1 Piezo Wohnzimmer
char xI2 = A1;  //Eingang 2 Schalter Abstellraum
char xI3 = A2;  //Eingang 3
char xI4 = A3;  //Eingang 4
char xI5 = A4;  //Eingang 5
char xI6 = A5;  //Eingang 6
char xI7 = A6;  //Eingang 7
char xI8 = A7;  //Eingang 8

bool xI1_Status = LOW; //Tasterstatus auf "0" setzen
bool xI2_Status = LOW; //Tasterstatus auf "0" setzen
bool xI3_Status = LOW; //Tasterstatus auf "0" setzen
bool xI4_Status = LOW; //Tasterstatus auf "0" setzen

// AUSGÄNGE  deklarieren
char xD0 = D0;   //Lampengruppe 1
char xD1 = D1;   //Lampengruppe 2
char xD2 = D2;   //Lampengruppe 3
char xD3 = D3;   //Lampengruppe 4

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

  pinMode( xI1, INPUT);   //Deklarierung Eingang
  pinMode( xI2, INPUT);
  pinMode( xI3, INPUT);
  pinMode( xI4, INPUT);

  pinMode(BTN_USER, INPUT);

  pinMode(xD0, OUTPUT);   //Deklarierung Ausgang
  pinMode(xD1, OUTPUT);
  pinMode(xD2, OUTPUT);
  pinMode(xD3, OUTPUT);

  pinMode(LED_D0, OUTPUT);    //Deklarierung LED´s Steuerung
  pinMode(LED_D1, OUTPUT);
  pinMode(LED_D2, OUTPUT);
  pinMode(LED_D3, OUTPUT);

   // LEDs als OUTPUT setzen
  for (int i = 0; i <= 5; i ++)
  {
    pinMode(LED[i], OUTPUT);
  }
for (int i = 0; i <= 5; i ++)
  {
    pinMode(Relay[i], OUTPUT);
  }

 
}

void loop() 
{
 buttonState = digitalRead(xI1);
  if(buttonState == HIGH) 
    {
      if (counter >= 6)
      {counter = 0;}
      
      else
      {counter++;}
  }

    changeLights();

}
void changeLights() 
{
  static bool lastCounter = 0;
  switch(counter)
  {

    case 0:                                                     //*Initiaisieren der LED´s und Ausgänge*
    
    digitalWrite(LED_D0, LOW);
    digitalWrite(LED_D1, LOW);
    digitalWrite(LED_D2, LOW);
    digitalWrite(LED_D3, LOW);
    
    digitalWrite(xD0, LOW);
    digitalWrite(xD1, LOW);
    digitalWrite(xD2, LOW);
    digitalWrite(xD3, LOW);

    break;

    case 1:                                                     //*Wechselblinker*
     
      digitalWrite(LED_D0, HIGH);
      digitalWrite(LED_D1, HIGH);
      digitalWrite(xD0, HIGH);
      digitalWrite(xD1, HIGH);

      digitalWrite(LED_D2, LOW);
      digitalWrite(LED_D3, LOW);
      digitalWrite(xD2, LOW);
      digitalWrite(xD3, LOW);

      delay(800);
      digitalWrite(LED_D0, LOW);
      digitalWrite(LED_D1, LOW);
      digitalWrite(xD0, LOW);
      digitalWrite(xD1, LOW);

      digitalWrite(LED_D2, HIGH);
      digitalWrite(LED_D3, HIGH);
      digitalWrite(xD2, HIGH);
      digitalWrite(xD3, HIGH);
      delay(800);
      

      break;
      
    case 2:                                                       //*Aufbau- Abbaulicht*
                                   
      digitalWrite(LED_D0, HIGH);
      digitalWrite(xD0, HIGH);
      delay(800);
      digitalWrite(LED_D1, HIGH);
      digitalWrite(xD1, HIGH);
      delay(800);
      digitalWrite(LED_D2, HIGH);
      digitalWrite(xD2, HIGH);
      delay(800);
      digitalWrite(LED_D3, HIGH);
      digitalWrite(xD3, HIGH);
      delay(800);

      digitalWrite(LED_D3, LOW);
      digitalWrite(xD3, LOW);
      delay(800);
      digitalWrite(LED_D2, LOW);
      digitalWrite(xD2, LOW);
      delay(800);
      digitalWrite(LED_D1, LOW);
      digitalWrite(xD1, LOW);
      delay(800);
      digitalWrite(LED_D0, LOW);
      digitalWrite(xD0, LOW);
      delay(800);

      break;

      case 3:                                               //*Durchaufendes Licht*

      digitalWrite(LED_D0, LOW);
      digitalWrite(LED_D1, LOW);
      digitalWrite(LED_D2, LOW);
      digitalWrite(LED_D3, LOW);

      digitalWrite(xD0, LOW);
      digitalWrite(xD1, LOW);
      digitalWrite(xD2, LOW);
      digitalWrite(xD3, LOW);


      for (int i_2 = 0 ; i_2 <= 4; i_2 ++)            //Hochzählen der Ausgänge
      {
      // aktuelles Ausgang einschalten
      
      digitalWrite(Relay[i_2], HIGH);
      delay(800);

      // aktuelle LED i ausschalten
      digitalWrite(Relay[i_2], LOW);
      }
      
      for (int i_2 = 4; i_2 >= 0; i_2 --)      //Runterzählen der Ausgänge
      {
     // aktuelle LED i einschalten
     
      digitalWrite(Relay[i_2], HIGH);
       delay(800);
     

      // aktuelle LED i ausschalten
      digitalWrite(Relay[i_2], LOW);
      digitalWrite(LED[i], LOW);
      }
      
      break;


      case 4:                                  //*Komplettes Blinklicht*
      digitalWrite(LED_D0, HIGH);
      digitalWrite(LED_D1, HIGH);
      digitalWrite(LED_D2, HIGH);
      digitalWrite(LED_D3, HIGH);
      digitalWrite(xD0, HIGH);
      digitalWrite(xD1, HIGH);
      digitalWrite(xD2, HIGH);
      digitalWrite(xD3, HIGH);

      delay(500);
      digitalWrite(LED_D0, LOW);
      digitalWrite(LED_D1, LOW);
      digitalWrite(LED_D2, LOW);
      digitalWrite(LED_D3, LOW);
      digitalWrite(xD0, LOW);
      digitalWrite(xD1, LOW);
      digitalWrite(xD2, LOW);
      digitalWrite(xD3, LOW);
      delay(500);
   
      break;



                        
    } 

    } 






Hmm...

Ich bin mir fast sicher, das da ausserhalb des Array nicht das steht, was du willst...

und das Delay() sorgt dann dafür das der Arduino 8 Sekunden einfach nur Taub ist.

Ok ich werde das Delay() in jedem case am Ende entfernen.
Aber wie bringe ich das mit dem Entprellen in meinen Code rein, das ich einwandfrei durch meine case springen kann?

Ich kenne die "OneButton-Library" nicht, vermute aber, das die schon eine Entprellung beinhaltet.

Aber woran kann es dann noch liegen, dass ich in case 1 & case 2 springen kann und in case 3 & 4 den Taster teilweise über 4 sec. lang dauerhaft betätigen muss?

Springen tut man mit goto oder longjmp

Das liegt an den delay und den for-Schleifen. Beides blockiert.

ich zähle aber über einen digitaleingang einen Zähler hoch und über dieseb wert springe ich in die einzelnen case anweisungen

wie kann ich es besser machen?

Kann ich keine for Schleifen in eine Switch Case Anweisung einbauen?

Springen tut man mit goto oder longjmp
Vielleicht ist switch/case das falsche Verfahren für dich.

In jedem Fall willst du endliche Automaten bauen.
Auch wenn dir das jetzt noch nicht klar ist.

So viele du willst.
Ob das die Heilung ist?
Ich glaube nicht.

Das Hauptproblem ist, deine Switch-Case Anweisung wird sofort ausgeführt. Somit wird immer erst die 1 ausgeführt und danach die 2.
Du musst deine Struktur ändern, damit eine 4 direkt ausgeführt wird wenn du 4 mal drückst und nicht erst die vorherigen.
Entweder du machst es mittels einer erzwungenen Wartezeit oder mittels Startbutton.

Der Code hat kein case > 1
Damit bekommst Du immer nur 0 oder 1.

Nehmen wir mal an, dass es das prellen des Kontaktes ist. Es könnte sein.
Nein, eine lib ist dazu nicht notwendig. Für den einen Eingang kann man das auch zu Fuß machen und lernt noch was dabei.
So wie alles andere auch.

Wie ist denn Dein Eingang beschaltet?
Ist das auslösende Ereignis die Flanke von HIGH nach LOW oder von LOW nach HIGH?
Und wie ist der Eingang in Ruhezustand? LOW oder HIGH?

Das könnte dann so abgebildet werden:

// Forensketch
// https://forum.arduino.cc/

constexpr byte btnPin {2};
bool lastState = false;
uint32_t switchTime;
constexpr uint32_t debounceTime {50};

void setup()
{
  Serial.begin(115200);
  delay(300);
  Serial.println(F("\r\nStart...\r\n"));
  pinMode(btnPin, INPUT_PULLUP);
}

void  loop()
{
  if (taster())
  {
    Serial.println(F("ausgelöst"));
  }
}

bool taster()
{
  bool rtn = false;
  if (!digitalRead(btnPin))
  {
    if (!lastState)
    {
      rtn = true;
      lastState = true;
      switchTime = millis();
    }
  }
  else if (lastState)
  {
    if (millis() - switchTime > debounceTime)
    { lastState = false; }
  }
 return rtn;
}

Aber mir fehlt dazu noch etwas input...

1 Like

Du darfst deinen Code nicht blockieren. Du liest, richtigerweise, an einer Stelle im Code deinen Taster ein. Erst wenn du wieder an dieser Stelle im Code angekommen bist, kannst du erneut den Taster einlesen. Jetzt kommt dein Problem. In der Zeit von einem Delay hältst du deinen Code an. Er kommt also nicht mehr an die Stelle zum Taster einlesen. Somit reagiert dein Code erst auf einen Tastendruck, wenn du den Taster gedrückt hältst, bis die Codestelle erreicht ist, wo dein Taster eingelesen wird.

Ziel ist es also, den Code so schnell und oft wie Möglich zu durchlaufen. Deinen Code nur zu blockieren, wenn es anders nicht möglich ist.

Du darfst also kein Delay verwenden, was deinen Code zum warten veranlasst. Sondern du musst Dinge ausführen erst wenn eine gewisse Zeit verstrichen ist. In der Zwischenzeit lässt du diese Dinge einfach liegen.

Doch, dies ist nicht dein Problem.

1 Like

Hallo t-programmer

Schaue hier mal rein:

//https://forum.arduino.cc/t/zahler-funktion/1202927
//https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
#define ProjectName "Zähler Funktion"
#define NotesOnRelease "Arduino MEGA tested"
// make names
enum Cases {Case0, Case1, Case2, Case3, CaseMax};
// make variables
constexpr uint8_t ButtonPin {A0};
// make support
void heartBeat(const uint8_t LedPin, uint32_t currentMillis)
{
  static bool setUp = false;
  if (setUp == false) pinMode (LedPin, OUTPUT), setUp = true;
  digitalWrite(LedPin, (currentMillis / 500) % 2);
}
// make application
void setup()
{
  Serial.begin(115200);
  Serial.print("Source: "), Serial.println(__FILE__);
  Serial.print(ProjectName), Serial.print(" - "), Serial.println(NotesOnRelease);
  pinMode (ButtonPin, INPUT_PULLUP);
  Serial.println(" =-> and off we go\n");
}
void loop()
{
  uint32_t currentMillis = millis();
  heartBeat(LED_BUILTIN, currentMillis);
  constexpr uint8_t Interval {20};
  static uint32_t now;
  static uint8_t stateOld = LOW;
  static uint8_t cases = 0;
  if (currentMillis - now >= Interval)
  {
    now = currentMillis;
    uint8_t stateNew = digitalRead(ButtonPin) ? LOW : HIGH;
    if (stateOld != stateNew)
    {
      stateOld = stateNew;
      if (stateNew == HIGH)
      {
        switch (cases)
        {
          case Case0:
            Serial.println("case Case0:");
            break;
          case Case1:
            Serial.println("case Case1:");
            break;
          case Case2:
            Serial.println("case Case2:");
            break;
          case Case3:
            Serial.println("case Case3:");
            break;

        }
        cases = (cases + 1) % CaseMax;
      }
    }
  }
}

Ein wenig Feintuning mit Timern, die über Befehle aus dem Swich/Case gesteuert werden, um die LED-Animation zu starten oder zu stoppen.

Ich wünsche einen geschmeidigen Tag und viel Spass beim Programmieren in C++.