Funktionen parallel ausführen

Hallo,

ich versuche mit einem Arduino Nano zwei Funktionen parallel auszuführen. Das ganze soll für ein Lego Projekt dienen. Einerseits steuere ich ein Shift Register (74HC595) an, welches zufällig LED's ein- und ausschaltet mit langer Verzögerung.
Die zweite Funktion soll dazu dienen einzelne PIN's via PWM als flackern für ein Feuer zu steuern (schnell). Grundsatzfrage ob das überhaupt funktioniert und wenn ja, wo ist bei meinem Code der Fehler?! Ich benutze kein delay, sondern millis().

Hinweis, wenn ich die Funktion allein ausführefunktionieren sie einzeln wunderbar.

Hier mein Code:

int datapin = 10; 
int clockpin = 8;
int latchpin = 9;
int firepin = 6;

int Bit_Folge[] = {0,0,0,0,0,0,0,0};

int Bit_Nr;

int Zufallszahl, i, j, k;

//int delayTime;
unsigned int settimeLED, settimeFIRE;
unsigned int intervalLED, intervalFIRE;

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
  pinMode(datapin, OUTPUT);
  pinMode(clockpin, OUTPUT);  
  pinMode(latchpin, OUTPUT);
  pinMode(firepin, OUTPUT);
}

void loop() {
  
  looping();
}


void looping() {
  // Ausgabe an das Shiftregister
  if (millis() - settimeLED >= intervalLED) {
    randomLED();
    settimeLED = millis();
    intervalLED = random(1000,10000);
  }
  //LED Ausgang 6 flackern
  if (millis() - settimeFIRE >= intervalFIRE) {
    fireLED();
    settimeFIRE = millis();
    intervalFIRE = random(10, 180);
  }
}

// Einzel LED flackern
void fireLED() {
  int brightness = random(10,200);
  analogWrite(firepin, brightness);
}

// Funktion zum abschicken an den 74HC595
void send() {
  digitalWrite(latchpin, LOW);
  for (Bit_Nr=7; Bit_Nr > -1; Bit_Nr--) {
     digitalWrite(clockpin, LOW);            
     digitalWrite(datapin, Bit_Folge[Bit_Nr]);
     Serial.print(Bit_Folge[Bit_Nr]);       
     digitalWrite(clockpin, HIGH);            
  }
  digitalWrite(latchpin, HIGH);
}

//Zufallsfunktion LED Ausgänge
void randomLED() {
  for (i = 1; i < 51; i++) {
    for (j = 0; j < 8; j++) {
      Bit_Folge [i] = 0;
      };
  Zufallszahl = random(8);
  Bit_Folge [Zufallszahl] = 1;  
  send();
  }
}

Du möchtest diese Variablen "unsigned long" machen.
Warum möchtest du das tun?
Weil decltype(millis()) auch unsigned long ist!

z.B. so:

//int delayTime;
using Millis = decltype(millis());
Millis settimeLED,  settimeFIRE;
Millis intervalLED, intervalFIRE;

Und deine Zufallszahlen sollten sicherlich auch unsigned sein.
Denn: Ein negativer Arrayindex macht wohl nie Sinn.

Du greifst weit über das Array Ende hinaus zu und zerstörst unschuldige Datenbereiche.

Ich habe die Variablen deklaration angepasst, aber es änder an dem grundsätzlichem Problem erst einmal nichts. Ich hab den Code aus dem Netz aufgeschnappt und an meine bedürnisse angepasst.

Wie kann ich das ändern? Das übersteigt gerade mein Verständnis :-S

Wie ist denn das Fehlerbild?

Deine Funktion randomLED blockiert bis die 3 ineinander verknüpften for-Schleifen abgearbeitet sind. In der Zeit kann fireLED nicht ausgeführt werden, wenn du es so lässt.

Dein Array Bit_Folge besteht 8 Elementen. Du greifst aber in Schleife auf 52 Elemente zu. Wie von combie schon gezeigt.

Vielleicht sollte das i auch ein j sein?

Da steckt ein delay drin, da du nur so schnell schreiben kannst wie die Baudrate (9600 = 1ms/Zeichen) zulässt.
Allerdings brauchst du ein bisschen Zeit für den Schieberegister-Takt

Danke schon mal für die Hilfe :slight_smile:

Stimmt, hab es gelöscht, das war zur Kontrolle mal drin.

Okay, aber wie kann ich es besser machen? Ich hab ja selbst bemerkt, das randomLED() blockiert, ich weiß nur nicht wo genau, aber vielleicht sind die for-Schleifen ja das Problem. Nur wie ändern?!

Hab es abgeändert auf 8, zumindest flackert es jetzt schon mal, ich muss nur noch einmal das Shiftregister ausprobieren. Wenn es geht, gebe ich bescheid :-).

Schau dir mal shiftOut an. Dazu bitSet, wenn du immer nur eine einzelne Led setzen willst.

So, ich hab mal alles dran geklemmt an meinen Arduino, und es funktioniert leider nicht ganz wie erwartet. Das flackern der einzelnen LED (Feuer) funktioniert jetzt, unabhängig vom Shiftregister. Das macht mir jetzt Probleme. Nach dem hochladen des Scripts funktioniert die Schaltung ganze zweimal danach blitzen alle LED's etwas alle sSekunde einmal auf und das wars. Nach dem Reset blitzen alle dirtekt auf einmal auf und das im Sekundentakt :frowning:

Mein Code jetzt:

int datapin = 10; 
int clockpin = 8;
int latchpin = 9;
int firepin = 6;

int Bit_Folge[] = {0,0,0,0,0,0,0,0};

int Bit_Nr;

int i, j, k;
unsigned int Zufallszahl;

//int delayTime;
using Millis = decltype(millis());
Millis settimeLED,  settimeFIRE;
Millis intervalLED, intervalFIRE;

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
  pinMode(datapin, OUTPUT);
  pinMode(clockpin, OUTPUT);  
  pinMode(latchpin, OUTPUT);
  pinMode(firepin, OUTPUT);
}

void loop() {
  
  //LED Ausgang 6 flackern 

  fireLED();


  // Ausgabe an das Shiftregister
  randomLED();
}

// Einzel LED flackern
void fireLED() {
  if (millis() - settimeFIRE >= intervalFIRE) {
    int brightness = random(10,200);
    analogWrite(firepin, brightness);
    settimeFIRE = millis();
    intervalFIRE = random(10, 180);
  }
}

// Funktion zum abschicken an den 74HC595
void send() {
  digitalWrite(latchpin, LOW);
  for (Bit_Nr=7; Bit_Nr > -1; Bit_Nr--) {
     digitalWrite(clockpin, LOW);            
     digitalWrite(datapin, Bit_Folge[Bit_Nr]);       
     digitalWrite(clockpin, HIGH);            
  }
  digitalWrite(latchpin, HIGH);
}

//Zufallsfunktion LED Ausgänge
void randomLED() {
  if (millis() - settimeLED >= intervalLED) {
    for (i = 1; i < 8; i++) {
      for (j = 0; j < 8; j++) {
        Bit_Folge [i] = 0;
        };
    Zufallszahl = random(8);
    Bit_Folge [Zufallszahl] = 1;  
    send();
    settimeLED = millis();
    intervalLED = random(5000,10000);
    }
  }
}

Ich hatte die IF - milis() -Schleife auch schon im Loop, keine unterschied.

In der Schleife wird 8 mal das gleiche Bit auf 0 gesetzt.
Hat das einen besonderen Grund?
Ich kann mir keinen vorstellen.

Hier wird ja zufällig eine 1 gesetzt um so verschiedene Zustände des Shiftregisters zu setzen. Somit werden die vorherigen Nullen zufällig ersetzt.

Ja, das ist mir klar!
(bin ja nicht nur doof)

Das beantwortet allerdings keinesfalls meine Frage/Ansage.

Nicht ganz, "Bit_Folge" wird als Array auf 0 gesetzt, deshalb Variable i und nicht j, und nicht ein einzelnes Bit. So hab ich es verstanden.
Ich verstehe auch deine Frage und würde ich nur eine For-Schleife lassen, würde auch die Schleife funktionieren, nur würde immer nur eine einzelne LED aufleuchten, aber es sollen ja immer zufällig verschiedene aufleuchten, auch mal mehere gleichzeitig usw. deshalb die zweite Schleife.

Dennoch muss irgendwo in der Zeitschleife der Wurm sein, denn Anfangs funktioniert ja die Schleife ein, zweimal, und irfgendwann blitzen die alle LED'S nur noch auf.

Bit_Folge [i] = 0;

Erkläre mal bitte den Unterschied zwischen diesen beiden Codes. Für was genau (ausser für Zeit zu verbraten) ist die for Schleife gut?

Du setzt ein und das gleiche, einzelne Bit acht mal hintereinander auf Null.
Ohne zwischendurch was anderes zu tun. Das ist sinnfrei!
Gaube es, oder glaube es nicht, ist mir egal.

constexpr byte datapin {10};
constexpr byte clockpin{8};
constexpr byte latchpin{9};
constexpr byte firepin {6};
byte bitFolge;
using Millis = decltype(millis());
Millis settimeLED,  settimeFIRE;
Millis intervalLED, intervalFIRE;

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(A0));
  pinMode(datapin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  digitalWrite(clockpin, HIGH);
  pinMode(latchpin, OUTPUT);
  digitalWrite(latchpin, HIGH);
  pinMode(firepin, OUTPUT);
}

void loop()
{

  //LED Ausgang 6 flackern

  fireLED();


  // Ausgabe an das Shiftregister
  randomLED();
}

// Einzel LED flackern
void fireLED()
{
  if (millis() - settimeFIRE >= intervalFIRE)
  {
    int brightness = random(10, 200);
    analogWrite(firepin, brightness);
    settimeFIRE = millis();
    intervalFIRE = random(10, 180);
  }
}

// Funktion zum abschicken an den 74HC595
void send(const byte value)
{
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, value);
  digitalWrite(latchpin, HIGH);
}

//Zufallsfunktion LED Ausgänge
void randomLED()
{
  if (millis() - settimeLED >= intervalLED)
  {
    bitFolge ^= 1 << random(8);
    send(bitFolge);
    Serial.println(bitFolge,BIN);
    settimeLED = millis();
    intervalLED = random(5000, 10000);
  }
}

ICH glaube es DIR, sofort!! Und ich liebe dich, denn es funktioniert!!! Perfekt!! Also war mein Ansatz etwas veraltet und Fehlerbehaftet, aber so lernt man doch einiges. Danke an alle die sofort geschrieben haben. :blush:

Eine Wissenfrage hab ich dennoch, in jedem Lehrbuch und online in den Einstiegskursen werden die Pins am Anfang mit int deklariert, wieso benutzt du in deinem Lösungsansatz

constexpr byte

Würde es gerne verstehen

int 16 bit, byte nur 8 bit (was ausreichend ist) und mit constexpr wird der Wert vor dem (versehentlichen) überschreiben geschützt.

2 Likes

Vor dem (versehentlichen) überschreiben schützt das Schlüsselwort const.
constexpr stellt sicher, dass der Compiler den Wert schon beim Übersetzen kennt, und gar keine Variable dafür anlegt.
Naheres z.B. hier: c++ - What's the difference between constexpr and const? - Stack Overflow

Trau keinem Tutorial, in dem Pin-Nummern als int deklariert werden :slight_smile:
Jedes int trägt den Verdacht in sich, dass der Verfasser mindestens schreibfaul ist.

2 Likes

int ist in der Regel der Datentype, mit dem Berechnungen(und vieles weitere) am schnellsten ausgeführt werden. Das ist ein guter Grund int zu bevorzugen.
Ausnahme: z.B. der 8Bit µC, hier der auf dem Nano.

Weil ich mein schönes dickes C++ Buch gelesen habe.
Somit viele hübsche Features der Sprache kenne, und diese gerne nutze.
Zudem ungerne Byte verplempere, wenn man/ich das ohne nennenswerten Umstand erreichen kann

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.