Fragen zum Programmablauf

Hallo,
da dies hier mein erster Post hier im Forum ist, kurz etwas über meine bisherigen Erfahrungen mit dem Arduino :
Ich habe vor kurzen angefangen , mich mit dem Arduino Uno und der C/C++ Programmierung zu beschäftigen , stehe also noch ganz am Anfang
mein Hauptaugenmerk liegt im Moment (noch) auf der Programmierung von einfachen Sequenzen mit maximal 8 LEDs. Den Arduino Uno will ich in Zukunft unter anderem dazu nutzen, Modelle (eventuell mit dem Nano) usw, zu beleuchten.

Nun zu meinen Anliegen:
Ich habe jetzt ein Programm geschrieben, dass per Push Button verschiedene LED-Muster bzw. Programme wiedergibt. Zuden habe ich die SoftPWM-Library zum Ein- und Ausfaden eingebunden und statt delay() die millis()-Funktion benutzt.
Das Programm funktioniert soweit , allerdings gibt es noch ein paar Probleme:

  1. Im ersten Programm (Case 1) sollen alle Programme mittels einer For-Schleife eine bestimmte Anzahl oft wiederholt werden. Leider klappt das irgendwie nicht. Normalerweise sollte die Funktion doch bis zum Ablauf der Schleife iteriert werden um dann zur nächsten For-Schleife springen etc. WIe kann ich das Problem beheben?

  2. Zwischen den Übergängen der einzelnen Programme bleiben die zuletzt geleuchteten LEDs immer noch eine kurz Zeit stehen, sehr gut sichtbar beim Übergang von case 2 zu case 3.
    Wie bekomme ich einen flüssigen Übergang hin?

Ich hoffe , das ich meine Probleme verständlich dargestellt habe. Würde mich auch sehr über Vorschläge, wie man den Code eventuell besser und effizenter gestalten kann, freuen.
anbei der Code und eine Fritzings-skizze

vielen Dank schonmal im Voraus

Gruß

Hendrik

#include <SoftPWM.h>
#define BUTTON  10
const int ledPin[8] = {2,3,4,5,6,7,8,9};
int cntr1 = 0;
int cntr2 = 3;
int cntr3 = 4;
int cntr4 = 0;
int cntr5 = 0;
int haltCounter1 = 0; // Wartezeit bis der Schweif erloschen ist
int haltCounter2 = 0; // Wartezeit bis der Schweif erloschen ist
int ledDirection = 1;
byte state = 0; 
byte old = 0;
byte buttonPoll = 0;
byte ledState = 0; 
unsigned long previousMillis = 0; 
const long interval = 400;  

void setup()
{  
  pinMode(BUTTON, INPUT); 
  SoftPWMBegin();    
  
  for (int i = 0; i < 8; i++)
  {
    SoftPWMSet(ledPin[i], 0);
  }

  //Fadezeiten
  for (int i = 0; i < 8; i++)
  {
    SoftPWMSetFadeTime(ledPin[i], 0, 400);
  }      
}

void loop()
{
  // Button entprellen  
  buttonPoll = digitalRead(BUTTON);  

  if(buttonPoll == 0)
  {
    delay(50);
    buttonPoll = digitalRead(BUTTON);
    if(buttonPoll == 1)
    {
      state = old+1;
    }  
  }
    else
  {
    delay(50);
  }   

  // Programauswahl
  switch (state)
  {
    case 1: 
      // Alle Programme in einer Dauerschleife
      program1();
      old = state;      
      break; 
    case 2: 
      // Alarm
      program2(); 
      old = state;      
      break;       
    case 3: 
      // Larson Scanner
      program3();
      old = state;      
      break;   
    case 4: 
      // von Innen nach Aussen  
      program4();
      old = state;            
      break;    
    default:   
      // alle LEDs aus    
      for (int i = 0; i < 8; i++)
      {
       SoftPWMSet(ledPin[i], 0);
      }
      old = 0;
      break;     
  }
}  

 // Alle Programme in einer Dauerschleife
void program1()
{  
  for (int i = 0; i < 2; i++)
  {
    program2();
  }

  for (int i = 0; i < 2; i++)
  {
    program3();
  }

  for (int i = 0; i < 2; i++)
  {
    program4();
  }
  
}

// Alarm
void program2()
{   
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 800)
  {
    previousMillis = currentMillis;
     if (ledState == 0)
    {
	  ledState = 255;
    }	
    else
    {
      ledState = 0;
    }

    for (int i = 0; i < 8; i++)
    {
     SoftPWMSet(ledPin[i], ledState);
    }  
	
  }

}

// Larson Scanner
void program3() 
{ 
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)  
  {
   previousMillis = currentMillis;
   if (ledDirection == 1)
   {
     SoftPWMSet(ledPin[cntr1-1], 0);
     SoftPWMSet(ledPin[cntr1], 255);
     cntr1++;
     haltCounter1++;

     if (cntr1 > 7)
     {
      cntr1 = 7;
      if (haltCounter1 > 12)
      {        
        haltCounter1 = 0;
        ledDirection = 2; 
      }
       
     }
   }

   if (ledDirection == 2)
   {
    SoftPWMSet(ledPin[cntr1+1], 0);
    SoftPWMSet(ledPin[cntr1], 255);

    cntr1--;
    haltCounter1++;
     if (cntr1 < 0)
     {
      cntr1 = 0;
      if (haltCounter1 > 11)
      {        
        haltCounter1 = 0;
        ledDirection = 1; 
      }   
     
    } 
  }
 }  
}

// von Innen nach Aussen  
void program4()
{
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval)  
  {
   previousMillis = currentMillis;                

   if (cntr2 == 3 || cntr3 == 4 )   
   {
     SoftPWMSet(ledPin[0], 0);       
     SoftPWMSet(ledPin[7], 0);           
   }
   else
   {
    SoftPWMSet(ledPin[cntr2+1], 0);
    SoftPWMSet(ledPin[cntr3-1], 0);
   }

   SoftPWMSet(ledPin[cntr2], 255);
   SoftPWMSet(ledPin[cntr3], 255);
   cntr2--;
   cntr3++;

   if (cntr2 < 0 || cntr3 > 7)
   {    
    cntr2 = 0;
    cntr3 = 7;
    haltCounter2++;
     
    if (haltCounter2 > 2)
    {
      
      cntr2 = 3;
      cntr3 = 4;
      haltCounter2 = 0;
    }
  }
 }
}

Moin,
schick der Code, aber da geht noch einiges.
Ich hab jetzt nur kurz drauf geschaut, aber es sind mir schon ein paar Dinge ins Auge gefallen. (bytes aus dem rechten Auge reibend... :slight_smile: )

Dein switch / case benutzt magische Zahlen. Das kann man machen, es geht aber auch verständlicher. Und wenn Du schon magische Zahlen verwendest, dann fange nicht mit 1 an, sondern mit 0. Du kommst später durcheinander, wenn Du mit Elementen arbeitest.
(Das erste Element eines Array zum Beispiel wird mit 0 angesprochen - Eine Zeichenkette ist ein array of char...)

Du hast eine variable 0ld. Die braucht es nicht.
Du kannst state aufaddieren ohne das hilfsbyte.

Dann hast Du noch eine Runde delays bei der tastenabfrage. Vermutlich um das prellen zu unterdrücken. Das geht auch genauso blockadefrei.

Im default rufst Du softpwm auf um den Pin abzuschalten.
Das geht einfacher, wenn Du einfach ein digitalWrite() mit LOW auf den Pin machst.

Deine Übergänge bekommst Du nicht, weil Du nicht wartest bis das fade zu Ende ist.
programm1() müsste ebenfalls eine Schrittkette enthalten, in der die Wartezeit bis zum fadeout berücksichtigt wird.
Da ich die lib überhaupt noch nciht kenne, muss ich mich erstmal einlesen was da passiert, um ansatzweise irgendwas sagen zu können, wie das gelöst werden kann...

Mal sehen; ich bin ja auch für neues zu haben.

1 Like

Hallo Hendrik,

zum Beleuchten von Modellen fallen mir diese Hinweise ein:

  • Mit der Bibliothek MobaTools kannst Du LEDs faden, Tasten entprellen, Schrittmotoren und Servos bewegen.
  • Das Noiasca Tool Kit for LEDs erleichtert ebenfalls das Programmieren. Der selbe Autor bietet eine Bibliothek für LCDs mit deutschen Umlauten an.
  • Beim UNO, Nano usw. darf man die Gesamtverlustleistung nicht überschreiten, weshalb das direkte Ansteuern von LEDs problematisch werden könnte. Es gibt aber Zusatzboards wie Adafruit 16x9 Charlieplexed PWM LED Matrix Driver oder Adafruit 12-Channel 16-bit PWM LED Driver.
  • Außerdem gibt es WS2812, WS2815 und APA102, die nur einen Arduino-Pin benötigen, als Streifen oder einzelnes Pixel.
2 Likes

Bei nur 8 LED könnte man die Widerstände so wählen, dass z.B. max 8 * 10 mA fließen.

Wenn aus den 8 LED mal wesentlich mehr werden, sollte man das in einem anderen Thread behandeln. Und dort über Charlieplexing vs. WS8212 etc. diskutieren.

Mir fällt auf, dass program2..4 ein gemeinsames previousMillis benutzen. Das geht, weil eh alle die gleichen LED verwenden und daher nur nacheinander drankommen können.
Dann sollten sie aber nicht void zurückliefern, sondern ob sie fertig sind oder nicht.
program1 könnte dann tatsächlich die anderen abwechselnd in Dauerschleife laufen lassen.

Wie bei SoftPWM Library faden funktioniert , wenn nur gelegentlich SoftPWMSet für einen der Pins, und dann nur mit den Werten 0 oder 255 aufgerufen wird, weiß ich allerdings nicht.

1 Like

Das case 1: etc.
Wenn Du an irgendeiner Stelle versehentlich state mit einer Zahl füllst, bekommst Du eigenartige Effekte. Bei einem Kurzsketch mit der Handvoll zeilen vielleicht noch auf Anhieb zu finden, aber wenn es dann mehr wird, ist großes suchen angesagt. Und Vertipper sind auch ganz einfach möglich.

Ups- weg war der Post auf den ich antworten wollte...
Na denne

1 Like

danke erstmal für die tipps. verstehe allerdings nicht genau was du mit magischen Zahlen meinst ?
Die Idee mit der Wartezeit bis dem Fadeout kam mir auch schon, aber das ist nicht das (Haupt-)Problem

hier noch ein link zur SoftPWM-library : GitHub - bhagman/SoftPWM: A Wiring (and Arduino) Library to produce PWM signals on arbitrary pins.

sorry, versteh nicht ganz, wie ich hier auf Kommentare antworten kann

Warum löscht du deine Posts ?
Und Antworten geht mit antworten.

1 Like

@agmue

Danke für die Links. Die WS2812 Strips habe ich auch schon im Auge, allerdings eher für Deko

@michael_x

Mit zurückliefern meinst einen Rückgabewert ?
Das faden bei SoftPWM läuft über diese Funktion:

//Fadezeiten
  for (int i = 0; i < 8; i++)
  {
    SoftPWMSetFadeTime(ledPin[i], 0, 400);
  }      

Der Wert  für die Fade-In-Zeit steht im Code bei Null

Ist deine Tastatur kaputt?
Denn bei mit findet Google die magischen Zahlen sofort!

1 Like
const byte ledPin[] = {2,3,4,5,6,7,8,9};
for (const byte pin:ledPin)    SoftPWMSetFadeTime(pin, 0, 400);   
1 Like

SoftPWMSetFadeTime wird einmal (je Pin) beim Programmstart gesetzt. Wie tatsächlich die LED-Pins aus- bzw. eingeschaltet werden um einen Fade-Effekt zu erzielen, weiß ich nicht; werde ich mir bei Gelegenheit mal ansehen. Danke für den Link.

1 Like

okay, Danke .Das mit den magischen Zahlen lese ich heute zum ersten Mal.
was genau soll "pin: " bedeuten?

byte pin definiert eine Variable welche in der Schleife mit jedem Arrayelement gefüllt wird.
Siehe in der C++ Referenz: "range based for loop"

1 Like

sorry, jetzt fällt mir erst jetzt auf , dass das eine foreach-Schleife ist.

Ich bitte um etwas mehr Sorgfalt/Mühe/Exaktheit
foreach gibts in C++ nicht!

https://en.cppreference.com/w/cpp/algorithm/for_each
https://en.cppreference.com/w/cpp/algorithm/for_each_n
https://en.cppreference.com/w/cpp/algorithm/transform

1 Like

okay sorry, dann habe ich da irgendwas verwechselt.

Hast du nicht.

Selbst wenn es demnächst etwas gibt, das std::for_each_n heisst, kannst du gerne
umgangssprachlich feststellen, dass
for (auto& x: xarray) {...}
das macht, was in anderen Programmiersprachen als foreach bezeichnet wird und auch zu diesem Zweck erfunden wurde.

1 Like

So, erstmal nochnmal danke für eure Tipps. Habs jetzt so halbwegs hinbekommen, wie ichs mir vorgestellt habe, allerdings nicht mit der millis()-Funktion. Zudem habe ich noch ein paar Sachen verbessert, die von euch angesprochen worden.
Ich habe allerdings noch eine Verständnisfrage: Wie genau unterscheiden sich die millis() - Funktion und eine Variable, die inkrementiert wird, auch in Bezug auf Timinggenauigkeit und welche Variante zu zeitlichen Abläufen ist zu bevorzugen?

gruß

hendrik

#include <SoftPWM.h>
#define BUTTON                 10
const int ledPin[8]          = {2,3,4,5,6,7,8,9};
int cntr1                    = 0;
int cntr2                    = 3;
int cntr3                    = 4;
int counter1                 = 0;
int haltCounter1             = 0; // Wartezeit bis der Schweif erloschen ist
int haltCounter2             = 0; // Wartezeit bis der Schweif erloschen ist
int count_prog               = 0; // Zähler zum wechseln des Programms
int loop_prog                = 0;
int ledDirection             = 1;
int state                    = 0; 
int buttonPoll               = 0;
int ledState                 = 0; 
unsigned long previousMillis = 0; 
const long interval          = 200;   

enum program {Prog_1 = 1,Prog_2,Prog_3,Prog_4};

void setup()
{  
  Serial.begin(9600);
  pinMode(BUTTON, INPUT); 
  SoftPWMBegin();    
  for (const int led_set:ledPin) SoftPWMSet(led_set, 0);  
  for (const int pin_fade:ledPin) SoftPWMSetFadeTime(pin_fade, 0, 300);        
}

void loop()
{
  // Button entprellen  
  buttonPoll = digitalRead(BUTTON);  
  if(buttonPoll == 0)
  {
    delay(50);
    buttonPoll = digitalRead(BUTTON);

    if(buttonPoll == 1)  state++;
    else delay(50);        
  }    

  // Programauswahl
  switch (state)
  {
    case Prog_1: 
      program1();    
      break; 
    case Prog_2: 
      // Alarm
      program2();            
      break;       
    case Prog_3: 
      // Larson Scanner
      program3();          
      break;   
    case Prog_4: 
      // von Innen nach Aussen  
      program4();                
      break;    
    default:         
      // alle LEDs aus    
      for (int i = 0; i < 8; i++)
      {
       SoftPWMSet(ledPin[i], 0);
      }
      state = 0;
      break;     
  }
}  

void program1()
{
   if(loop_prog == 0)
      {
        program2(); 
        count_prog++;        
        if (count_prog > 100)
        {
          count_prog = 0;
          loop_prog = 1;
        }
      }

      if(loop_prog == 1)
      {
        program3(); 
        count_prog++;        
        if (count_prog > 200)
        {
          count_prog = 0;         
          loop_prog = 2;
        }
      }
      
      if(loop_prog == 2)
      {
        program4(); 
        count_prog++;        
        if (count_prog > 200)
        {
          count_prog = 0;         
          loop_prog = 0;
        }
      }            
}
// Alarm
void program2()
{ 
  
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 500)
  {
    previousMillis = currentMillis;     
  

    if (ledState == 0)
    {
	  ledState = 255;
    }	
    else
    {
      ledState = 0;
    }

    for (int i = 0; i < 8; i++)
    {
     SoftPWMSet(ledPin[i], ledState);     
    }  
	
  }  
}

// Larson Scanner
void program3() 
{   
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)  
  {
   previousMillis = currentMillis;          

   if (ledDirection == 1)
   {
     SoftPWMSet(ledPin[cntr1-1], 0);
     SoftPWMSet(ledPin[cntr1], 255);
     cntr1++;
     haltCounter1++;

     if (cntr1 > 7)
     {
      cntr1 = 7;
      if (haltCounter1 > 12)
      {        
        haltCounter1 = 0;
        ledDirection = 2; 
      }
       
     }
   }

   if (ledDirection == 2)
   {
    SoftPWMSet(ledPin[cntr1+1], 0);
    SoftPWMSet(ledPin[cntr1], 255);

    cntr1--;
    haltCounter1++;
     if (cntr1 < 0)
     {
      cntr1 = 0;
      if (haltCounter1 > 11)
      {        
        haltCounter1 = 0;
        ledDirection = 1; 
      }   
     
    } 
  }
 }  
}

// von Innen nach Aussen  
void program4()
{
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval)  
  {
   previousMillis = currentMillis;                

   if (cntr2 == 3 || cntr3 == 4 )   
   {
     SoftPWMSet(ledPin[0], 0);       
     SoftPWMSet(ledPin[7], 0);           
   }
   else
   {
    SoftPWMSet(ledPin[cntr2+1], 0);
    SoftPWMSet(ledPin[cntr3-1], 0);
   }

   SoftPWMSet(ledPin[cntr2], 255);
   SoftPWMSet(ledPin[cntr3], 255);
   cntr2--;
   cntr3++;

   if (cntr2 < 0 || cntr3 > 7)
   {    
    cntr2 = 0;
    cntr3 = 7;
    haltCounter2++;
     
    if (haltCounter2 > 2)
    {      
      cntr2 = 3;
      cntr3 = 4;
      haltCounter2 = 0;
    }
  }
 }
}




millis werden über Interrupt zum richtigen Zeitpunkt erhöht.

Ein Variable wird nur inkrementiert , wenn die entsprechende Codezeile erreicht wird. Das erreichen der Codezeile kann schneller oder langsamer als in einer Millisekunde passieren.

1 Like