Forum: Mikrocontroller und Digitale Elektronik delay problem


von HieberMar (Gast)


Lesenswert?

Hallo,
ich habe ein Problem bei einem Programm und ich hoffe, dass mir jemand 
weiter helfen kann. Ich habe einen WS2812 LED Streifen und einen 
Durchflusssensor (YF-S201). Der LED Streifen soll ein Lauflicht machen 
welches schneller durchläuft desto größer der gemessene Durchfluss.
Jetzt zum Problem:
Der Durchflusssensor alleine misst alles korrekt und der LED-Streifen 
alleine funktioniert auch einwandfrei doch wenn ich die beiden Header 
Dateien im Main aufrufe und Parametriere spuckt der Durchflusssensor nur 
noch falsche Werte aus. Ich habe den Fehler bereits eingegrenzt.
1
#ifndef LED_PUMP_1
2
#define LED_PUMP_1
3
4
#include <Arduino.h>
5
#include <Adafruit_NeoPixel.h>
6
7
#define PIN_1 6         // Data Output-Pin
8
#define LED_pixels_1 20 // Number of LED's max. 256
9
10
Adafruit_NeoPixel strip_1 = Adafruit_NeoPixel(LED_pixels_1, PIN_1, NEO_GRB + NEO_KHZ800); // LED-Stripe initalisation
11
12
void LED_pump_1(int LED_speed, int LED_length)
13
{
14
15
    int old_val[LED_pixels_1];
16
    uint32_t color = 0x00BFFF;
17
18
    for (int count = LED_pixels_1 - 1; count >= -LED_length; count--)
19
    {
20
        strip_1.setPixelColor(count, color);
21
        old_val[count] = color;
22
23
        for (int x = count; x <= LED_pixels_1 + LED_length; x++)
24
        {
25
            old_val[x + LED_length] = 0;
26
            strip_1.setPixelColor(x + LED_length, old_val[x + LED_length]);
27
        }
28
        strip_1.show();
29
        delay(LED_speed);
30
    }
31
}
32
33
#endif

Der Fehler liegt am delay sobald dieses auskommentiert ist funktioniert 
der Sensor wieder. Jetzt ist die Frage ob dieses delay irgendwie ersetzt 
werden kann. Ich hab schon viel überlegt aber noch keine funktionierende 
Lösung gefunden.
Danke im voraus.
LG Mario

von Martin (Gast)


Lesenswert?

Du musst auf eine millis()-Abfrage umstellen, siehe das berühmte „blink 
without delay“-Beispiel.

von Stefan F. (Gast)


Lesenswert?

Vermutlich hat Martin recht, auch wenn das noch nicht die ganze Lösung 
ist.

Ich finde schade dass du den Code, welcher den Sensor abfragt, nicht 
gezeigt hast. Ich würde gerne sehen was nicht funktioniert, bevor ich 
dazu Verbesserungsvorschläge mache.

von HieberMar (Gast)


Lesenswert?

Das ist der Code welche ich für den Durchflusssensor nutze
1
#ifndef DURCHFL_P1
2
#define DURCHFL_P1
3
4
#include <Arduino.h>
5
6
int flow_freq; // Measures flow sensor pulses
7
int l_min;     // Calculated litres/hour
8
long currentTime;
9
long cloopTime;
10
int PIN = 2;
11
12
void flow()
13
{
14
    flow_freq++;
15
}
16
17
int durchfl_P1()
18
{
19
20
    pinMode(PIN, INPUT_PULLUP);
21
    attachInterrupt(digitalPinToInterrupt(PIN), flow, RISING);
22
    sei();
23
24
    currentTime = millis();
25
26
    if (currentTime >= (cloopTime + 1000))
27
    {
28
        currentTime = millis();
29
        cloopTime = currentTime;
30
        l_min = (flow_freq / 7.5);
31
        flow_freq = 0;
32
        return l_min;
33
    }
34
}
35
36
#endif

Das Problem ist dass ich nicht weiß wie ich das machen kann da bei den 
ganzen blink ohne delay codes immer nachher noch etwas kommt.

von Schlaumaier (Gast)


Lesenswert?

Ich würde in einer Void schleife,  den Sensor relativ permanent 
abfragen, dann seine Werte mit den alten_Wert (von der letzten abfrage) 
vergleichen. Bei unterschieden die led-kette mit neuen Werten versehen.

Diese Werte wären dann in Millis. !!!

Eine CASE Anweisung oder eine Formel berechnet dann den neuen Wert.

von Falk B. (falk)


Lesenswert?

HieberMar schrieb:
> Das Problem ist dass ich nicht weiß wie ich das machen kann da bei den
> ganzen blink ohne delay codes immer nachher noch etwas kommt.

Tja, was wohl daran liegt, das du nur wild Zeug zusammenkopiert hast, 
ohne es verstanden zu haben. Wer zum geier macht bei JEDEM Aufruf einer 
Funktion eine Neuinitialisierung des Interrupts? Totaler Unsinn, sowas 
macht man EINMALIG im setup().

Und wo ist der kombinierte Qelltext? Wo ist das berühmte setup() und 
loop()?

von Falk B. (falk)


Lesenswert?

Schlaumaier schrieb:
> Ich würde in einer Void schleife,


Jaja, void schleife. Das passt zu deinem Hirninhalt, der ist auch void!

von EAF (Gast)


Lesenswert?

HieberMar schrieb:
> if (currentTime >= (cloopTime + 1000))

Damit handelst du dir einen Überlauf ein, welcher nicht kompensiert 
wird!
Beachte das "blink without delay" Beispiel. Dort wird es richtig 
gemacht.

HieberMar schrieb:
> attachInterrupt(digitalPinToInterrupt(PIN), flow, RISING);
Vermutlich sperrt die Stripe Ausgabe die Interrupts. Du könntest also 
Werte/Pulse verlieren.
Drum würde ich vermutlich einen Timer/Counter zum zählen verwenden.

Am Rande:
Dann kannste auch dein delay beibehalten.

von HieberMar (Gast)


Lesenswert?

Ich will, dass das jetzt nicht ungut herüber kommt aber wie würde das 
aussehen weil ich bin Anfänger auf dem Gebiet und brauch das für ein 
Projekt in der Schule. Daher besteht das ganze zum Großteil aus 
Beispielprogrammen aus dem Internet

von EAF (Gast)


Lesenswert?

Schlaumaier schrieb:
> Ich würde in einer Void schleife,
Was ist das?
Meinst du evtl. eine Funktion?

Schlaumaier schrieb:
> Eine CASE Anweisung oder eine Formel berechnet dann den neuen Wert.
switch/case rechnet nicht.

von Schlaumaier (Gast)


Lesenswert?

Falk B. schrieb:
> Und wo ist der kombinierte Qelltext? Wo ist das berühmte setup() und
> loop()?

GENAU das meinte ich.

Ich rufe in der "VOID Loop ()" Dauerschleife die Abfrage des Sensors via 
Funktion auf. Die übergibt mir die Geschwindigkeit. Danach berechne ich 
wie ich es will halt Pause_wert in mills und übergebe ihn als Parameter 
an den Aufruf der led_sub_routine.

Fertig ist die ganze Geschichte.

von EAF (Gast)


Lesenswert?

Schlaumaier schrieb:
> "VOID Loop ()"

Wer void groß schreibt, hat offensichtlich irgendwas wichtiges nicht 
begriffen.

von HieberMar (Gast)


Lesenswert?

So sieht mein Code im Main Programm aus dort werden die beiden Header 
Dateien Importiert.
Danke für die bisherigen Informationen ich werde mich nochmals hinsetzen 
und probieren es umzusetzen.
1
#include <Arduino.h>
2
#include <Adafruit_NeoPixel.h>
3
4
#include <LED_PUMP_1>
5
#include <DURCHFL_P1>
6
7
void setup()
8
{
9
  strip_1.begin();
10
  strip_1.clear();
11
12
  Serial.begin(9600);
13
}
14
15
void loop()
16
{
17
  int L_min_P1 = durchfl_P1();
18
  Serial.print(L_min_P1, DEC);
19
  Serial.println(" L/min (P1)");
20
21
  LED_pump_1(70, 3); // LED_pump_1(speed, length); // speed - how fast one cycle is // length - how long the trail effect is
22
  
23
}

von HieberMar (Gast)


Lesenswert?

Das Problem ist dass ich insgesamt 4 Durchflusssensoren und 4 LED 
Streifen hab und noch einige dazu kommen (2x Ultraschall, 2x IBT_2 
Treiber und ein Netzwerkmodul) daher auch die Header Dateien. Jetzt kann 
ich in den Header Dateien das void loop nicht wirklich nutzen sondern 
muss die Funktion darin aufrufen wenn ich das System richtig verstanden 
hab.

von Falk B. (falk)


Lesenswert?

HieberMar schrieb:
> Ich will, dass das jetzt nicht ungut

"ungut"? Herr Orwell läßt grüßen, nicht wahr? Früher (tm), hieß das 
"schlecht".

> herüber kommt aber wie würde das
> aussehen weil ich bin Anfänger auf dem Gebiet

Ist keine Schande. Faulheit aber schon.

> und brauch das für ein
> Projekt in der Schule. Daher besteht das ganze zum Großteil aus
> Beispielprogrammen aus dem Internet

Haha! Der war gut! Ist dir vielleicht in den Sinn gekommen, daß der SINN 
der Übung im Selbermachen und dadurch selber VERSTEHEN liegen könnte?

Das Zauberwort lautet Mulitasking und damit nicht blockierende 
Programmierung. Lies den Artikel, denk drüber nach und versuch es SELBER 
umzusetzen. Zeig und dann deinen Fortschritt als Quelltext, 
sinnvollerweise als Anhang. Viel Erfolg!

von Falk B. (falk)


Lesenswert?

HieberMar schrieb:
> Das Problem ist dass ich insgesamt 4 Durchflusssensoren und 4 LED
> Streifen hab und noch einige dazu kommen (2x Ultraschall, 2x IBT_2
> Treiber und ein Netzwerkmodul) daher auch die Header Dateien.

Das ist eine normale Trennung von Modulen, wie sie in C bzw. C++ üblich 
ist.

> Jetzt kann
> ich in den Header Dateien das void loop nicht wirklich nutzen sondern
> muss die Funktion darin aufrufen wenn ich das System richtig verstanden
> hab.

Lass dich vom Schlaumeier nicht irritieren, der erzählt immer nur 
Unsinn.

von Falk B. (falk)


Lesenswert?

HieberMar schrieb:
> #include <LED_PUMP_1>
> #include <DURCHFL_P1>

Sowas ist zwar technisch MÖGLICH, ist aber entgegen den üblichen 
Vereinbahrungen (Konventionen). Die Namen von Headerdateien enden 
sinnvollerweise auf .h und sind im Normalfall in Kleinschreibung, 
machmal gemischt Groß/Klein, aber sicher NICHT alles Groß! Außerdem 
nimmt man für NICHT Systemheader, also selber geschriebene "" Zeichen, 
nicht <>. Eher so.

#include "led_pump_1.h"
#include "durchfl_p1.h"

von Falk B. (falk)


Lesenswert?


von HieberMar (Gast)


Lesenswert?

Falk B. schrieb:
> Das Zauberwort lautet Mulitasking und damit nicht blockierende
> Programmierung. Lies den Artikel, denk drüber nach und versuch es SELBER
> umzusetzen. Zeig und dann deinen Fortschritt als Quelltext,
> sinnvollerweise als Anhang. Viel Erfolg!

Danke ich werd mich einfach nochmal hinsetzen und alles von null nochmal 
aufbauen

von J. S. (jojos)


Lesenswert?

Und int / 7.5 macht auch nicht das was du möchtest. Als das Kapitel mit 
integer und floating point Variablen auch mal lesen.

von J. S. (jojos)


Lesenswert?

Und globale und lokale Variablen. Wenn man eine Funktion benutzt, dann 
macht man die return Werte nicht global.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Haaach, scheiß Tipfehler. Hier sit der Artikel Multitasking.

von Wolfgang (Gast)


Lesenswert?

Schlaumaier schrieb:
> Ich rufe in der "VOID Loop ()" Dauerschleife die Abfrage des Sensors via
> Funktion auf.

Loop () gibt es beim Arduino nicht, schon gar nicht als Dauerschleife.
Meinst du vielleicht die Funktion loop()?

von Schlaumaier (Gast)


Lesenswert?

EAF schrieb:
> Schlaumaier schrieb:
>> "VOID Loop ()"
>
> Wer void groß schreibt, hat offensichtlich irgendwas wichtiges nicht
> begriffen.

Du hast nicht begriffen das ich das nur als Erklärung geschrieben habe.


Davon abgesehen. Es ist mir egal ob der TO mein Rat annimmt oder nicht. 
Es gibt viele Wege nach ROM.

Ich würde es so machen, weil ich gerne Routinen unabhängig code, so das 
ich den Code + Aufruf einfach in andere Projekte kopieren kann.

Es hat schon sein Grund warum mal DLL + Co. erfunden hat. ;)

von Stefan F. (Gast)


Lesenswert?

Schlaumaier schrieb:
> Ich würde in einer Void schleife,  den Sensor relativ permanent
> abfragen

Leuchtet mir nicht ein, denn er hat bereits einen Interrupt-Zähler 
programmiert. Die Konfiguration des Eingangs und des Interrupthandler 
würde ich aber nur einmal in der setup() Funktion machen.

Ich sehe dass das Schlüsselwort "volatile" fehlt und dass du (HieberMar) 
beim Lesezugriff die Interrupts sperren musst damit die Variable nicht 
verändert wird während du sie liest.

> volatile int flow_freq;

Der folgende Ausdruck wird nicht funktionieren, wenn der Timer 
überläuft:

> if (currentTime >= (cloopTime + 1000))

Benutze stattdessen die Subtraktion. Also

> if (currentTime-cloopTime >= 10000)

Ich schätze, dass es dann schon funktionieren wird, auch mit delay().

von EAF (Gast)


Lesenswert?

Schlaumaier schrieb:
> Du hast nicht begriffen das ich das nur als Erklärung geschrieben habe.
>
> Davon abgesehen. Es ist mir egal ob der TO mein Rat annimmt oder nicht.

Sollen Erklärungen nicht erklären, zur Klärung beitragen?
Mich hat es ehr verwirrt.....

Deine Erklärung lässt mich vermuten, dass dir nicht ganz klar ist, was 
void an der Stelle bedeutet.

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

Wenn man Impulse von Sensoren misst, gibts prinzipiell zwei Wege:

a) man zählt die Impulse über ein vorgegebenes Zeitfenster (vorzugsweise 
bei relativ hoher Impulsfrequenz)

b) man misst den Abstand zwischen zwei Impulsen (vorzugsweise bei 
relativ geringer Impulsfrequenz)*

Ich denke, Letzteres würde hier besser mit der Ansteuerung des LED-Strip 
zusammenpassen ...

* genau genommen nimmt man den Impulsabstand als Zeitfenster und zählt 
"fremde" Impulse, z.B. millis() oder einen Timer.

: Bearbeitet durch User
von Ein T. (ein_typ)


Lesenswert?

Schlaumaier schrieb:
> Es gibt viele Wege nach ROM.

Nach RAM aber auch.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.