Forum: Mikrocontroller und Digitale Elektronik Arduino: Bei erfüllter Bedingung Anweisung nur einmal ausführen


von Joe J. (neutrino)


Lesenswert?

Hallo Leute,

Zum Einarbeiten in die Arduino-Welt habe ich Neuling auf dem Steckbrett 
eine Lüftersteuerung simuliert - mit Poti statt Sensor, LED und Oszi 
statt Lüfter. Bei Erreichen einer bestimmten Temperatur startet PWM mit 
etwa 10 % und mit zunehmender Temperatur werden die Pulse breiter.
Klappt so weit wunderbar.

Nun möchte ich aber, dass auch ein älterer, verstaubter Lüfter sicher 
startet. Daher soll der Lüfter nicht mit nur 10 % Pulsbreite starten, 
sondern für die ersten ein oder zwei Sekunden mit 100 %.
Ich krieg das einfach nicht hin, egal was ich auch versuche. :(

Hier der Code:
1
int pwmPin = 6;                   // Lüfter
2
int t1Pin = A1;                   // Temperatursensor
3
int t1ValC(0);                    // Begrenzter Wert für Temperatursensor
4
int pwmVal(0);                    // Variable für die Pulsbreite
5
6
void setup()
7
{
8
  pinMode(pwmPin, OUTPUT);        // setzt Pin als Ausgang
9
}
10
11
void loop()
12
{
13
int t1Val = analogRead(t1Pin);
14
t1ValC = constrain(t1Val, 100, 800);  // brgrenzt min. und max. Wert
15
16
{  
17
  pwmVal = map(t1ValC,100,800,24,255);   // rechnet begrenzten Wert von 100 - 800
18
}                                        // in PWM 24 - 255 um (entspricht 10 - 100 % Pulsbreite)
19
20
 { 
21
  if (pwmVal >=25) {
22
  analogWrite(pwmPin, pwmVal);
23
  } else {
24
  analogWrite(pwmPin,0);
25
  }

Gruß, Joe

von Frank L. (hermastersvoice)


Lesenswert?

kleiner Tipp: was im Setupbereich steht wird nur einmal ausgeführt. 
Ansonsten macht man sich eine Variable die als Flag dient. Ist dieses 
Flag nicht gesetzt wird die Funktion ausgeführt, bei gesetztem Flag 
nicht.

von Joachim B. (jar)


Lesenswert?

bei 0% oder 100% setzt die PWM aus wenn ich mich recht erinnere, es geht 
nur von 1%-99%, genauer von 1-255 oder war es 1-254 weil 255 keine PWM 
mehr ist?

0 oder 255 ist Dauer low/high und keine PWM

alternativ, PWM Port nur auf out als PORT und nach Anlaufzeit auf PWM 
umstellen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Joachim B. (jar)

>bei 0% oder 100% setzt die PWM aus wenn ich mich recht erinnere,

Was soll da aussetzen? 0% = dauerhaft LOW, 100% dauerhaft HIGH.

>es geht nur von 1%-99%

Nö. Ausserdem geht der Parameter von analog_write von 0-255.

>alternativ, PWM Port nur auf out als PORT und nach Anlaufzeit auf PWM
>umstellen.

Nö, denn der Arduino nutzt die PWM im phase correct mode, da sind 0 und 
100% sprich 0 und 255 kein Problem.

von Falk B. (falk)


Lesenswert?

@ Joe J. (neutrino)

1
int pwmPin = 6;                   // Lüfter
2
int t1Pin = A1;                   // Temperatursensor
3
int t1ValC(0);                    // Begrenzter Wert für Temperatursensor
4
int pwmVal(0);                    // Variable für die Pulsbreite
5
6
void setup()
7
{
8
  pinMode(pwmPin, OUTPUT);        // setzt Pin als Ausgang
9
  analogWrite(pwmPin, 255);
10
  delay(2000);
11
}
12
13
void loop()
14
{
15
  int t1Val = analogRead(t1Pin);
16
  t1ValC = constrain(t1Val, 100, 800);  // brgrenzt min. und max. Wert
17
  
18
  pwmVal = map(t1ValC,100,800,24,255);   // rechnet begrenzten Wert von 100 - 800
19
                                         // in PWM 24 - 255 um (entspricht 10 - 100 % Pulsbreite)
20
 
21
  if (pwmVal >=25) {
22
    analogWrite(pwmPin, pwmVal);
23
  } else {
24
    analogWrite(pwmPin,0);
25
  }
26
}

: Bearbeitet durch User
von Joe J. (neutrino)


Lesenswert?

Im Setup möchte ich das aber nicht reinmachen. Denn der Lüfter soll ja 
nicht beim Einschalten des Gerätes starten, sondern erst beim Erreichen 
einer bestimmten Temperatur.

Ähm, was ist ein Flag, wie setzt man das und wo kommt das hin? Ich habe 
bereits folgenden versucht:
Eine Variable namens "state" gesetzt und dann mit dem if-Befehl bei 
analogwert > 100 state auf 1 gesetzt. Hat aber auch nicht geklappt. 
Irgendwie steh ich auf dem Schlauch.

Danke inzwischen.

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
> Was soll da aussetzen? 0% = dauerhaft LOW, 100% dauerhaft HIGH.

mir war so bei einer invertierten LED Fading Geschichte ein 0 oder 255 
machte nicht dunkel sondern volle Helligkeit, ich musste ja die original 
LED Fading Tabelle bei einem LCD umdrehen weil es LCD mit HG Beleuchtung 
gibt die invers arbeiten, die Kennlinie also nicht passte und mit 0 oder 
255 war nix mit gedimmt weil der Zustand statisch wurde und eben volle 
Helligkeit war statt voll dunkel.

von Nobody (Gast)


Lesenswert?

Joe J. schrieb:
> Eine Variable namens "state" gesetzt
Das ist schon mal eine gute Idee.

Der erste Schritt zu einem endlichen Automaten.

Mehr Zustände einführen!
1. Aus (startbedingung)
2. Anlauf (kurz auf Vollgas)
3. Regelung

von Falk B. (falk)


Lesenswert?

@Joe J. (neutrino)

>Im Setup möchte ich das aber nicht reinmachen. Denn der Lüfter soll ja
>nicht beim Einschalten des Gerätes starten, sondern erst beim Erreichen
>einer bestimmten Temperatur.

Das sollte man sagen ;-)

>Ähm, was ist ein Flag, wie setzt man das und wo kommt das hin? Ich habe
>bereits folgenden versucht:
>Eine Variable namens "state" gesetzt und dann mit dem if-Befehl bei
>analogwert > 100 state auf 1 gesetzt.

Erspar uns diese Lyrik, poste originalen Quelltext.

> Hat aber auch nicht geklappt.
>Irgendwie steh ich auf dem Schlauch.

Statemachine

1
int pwmPin = 6;                   // Lüfter
2
int t1Pin = A1;                   // Temperatursensor
3
int t1ValC;                       // Begrenzter Wert für Temperatursensor
4
int pwmVal;                       // Variable für die Pulsbreite
5
int fan_state;                    // State machine
6
int delay_cnt;
7
8
#define FAN_STATE_OFF    0
9
#define FAN_STATE_ON     1
10
#define FAN_STATE_DELAY  2
11
12
void setup()
13
{
14
  pinMode(pwmPin, OUTPUT);        // setzt Pin als Ausgang
15
  fan_state = FAN_STATE_OFF;
16
}
17
18
void loop()
19
{
20
  int t1Val = analogRead(t1Pin);
21
  t1ValC = constrain(t1Val, 100, 800);    // begrenzt min. und max. Wert
22
23
  switch(fan_state) {
24
    case FAN_STATE_OFF:
25
      if (t1ValC > 200) {
26
        fan_state = FAN_STATE_DELAY;
27
        delay_cnt = 2;
28
        pwmVal = 0;
29
      }
30
    break;
31
32
    case FAN_STATE_DELAY:
33
      delay_cnt--;
34
      if (delay_cnt == 0) {
35
        fan_state = FAN_STATE_ON;
36
      }
37
    break;
38
39
    case FAN_STATE_ON:
40
      if (t1ValC < 200) {
41
        fan_state = FAN_STATE_OFF;
42
        pwmVal = 0;
43
      } else {
44
        pwmVal = map(t1ValC,100,800,24,255);    // rechnet begrenzten Wert von 100 - 800
45
                                                // in PWM 24 - 255 um (entspricht 10 - 100 % Pulsbreite)
46
      }
47
48
    break;
49
  }
50
  if (pwmVal < 25) pwmVal=0;
51
  analogWrite(pwmPin, pwmVal);    
52
  delay(1000);                                   // Taktzyklus 1s
53
}

von Oller (Gast)


Lesenswert?

Das wäre ein schöner Troll-Thread für unseren Asm-Fanatiker.
Ein Tipp: schnapp dir ein Blatt Papier und mach ein Ablaufdiagrm. Dann 
proggst du das schön nach...

von Joe J. (neutrino)


Lesenswert?

Falk B. schrieb:
> Das sollte man sagen ;-)

Ich dachte, das ging aus dem Eingangspost hervor...


Falk B. schrieb:
> Erspar uns diese Lyrik, poste originalen Quelltext.

Es gibt nur den von mir bereits geposteten. Alle anderen Quelltexte, 
welche ich mit ergoogelten Codestückchen zu erweitern versuchte, habe 
ich frustriert wieder verworfen.

Dass ich ein Neuling bin, habe ich geschrieben. Vielleicht hätte ich 
noch erwähnen sollen, dass ich von Programmiersprachen bis vor wenigen 
Wochen absolut keine Ahnung hatte. Ich programmierte meine PICs bis 
jetzt (bitte nicht lachen) immer mit Parsic.
Nun, mit den Begriffen #define, switch, case und break bin ich noch 
absolut nicht vertraut. Ich werde mich morgen etwas damit beschäftigen 
und versuchen deinen Code zu verstehen. :)

Vielen Dank für deine Mühe, Falk Brunner (falk)!
Gruß, Joe

von Nobody (Gast)


Lesenswert?

Joe J. schrieb:
> Nun, mit den Begriffen #define, switch, case und break bin ich noch
> absolut nicht vertraut.
Darauf kann man verzichten.
Mit Zeiger auf Funktionen tuts das genau so gut.

von Falk B. (falk)


Lesenswert?

@ Nobody (Gast)

>> Nun, mit den Begriffen #define, switch, case und break bin ich noch
>> absolut nicht vertraut.
>Darauf kann man verzichten.
>Mit Zeiger auf Funktionen tuts das genau so gut.

Pädagogisch sehr sinnvoll für einen Anfänger . . .

von Kolja L. (kolja82)


Lesenswert?

Aber so ist es übersichtlicher.

case ist wie eine Akte voll Code zu verstehen
und switch die Entscheidungsmöglichkeit,
welche Akte voll Code ausgeführt wird.

Es werden also drei Fälle (engl. case) definiert,
für jeden deiner möglichen Zustände einer.
Und dann wird immer wieder (bei jedem loop) abgefragt, welcher Fall 
gerade behandelt werden soll.

: Bearbeitet durch User
von Joe J. (neutrino)


Lesenswert?

@ Falk Brunner:

Dein Code funktioniert leider nicht so wie gewünscht. "delay(1000)" ist 
ständig aktiv, so dass auch das Drehen am Poti verzögert reagiert. Und 
der Lüfter startet nicht mit Vollgas, sondern pwmVal entsprechend.
Aber Dank deines Codes und mit dem Link zur Statemachine (den Begriff 
hatte ich vorher noch nie gehört) habe ich es nun endlich hingekriegt! 
:-D

1
/*
2
Analoger Temperatureingang, PWM-Ausgang für Lüfter.
3
LCD ist nur für Testzwecke.
4
*/
5
6
#include <LiquidCrystal.h>
7
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // diese Pins werden benutzt (RS, E, D4, D5, D6, D7)
8
9
int pwmPin = 6;                   // Lüfter
10
int t1Pin = A1;                   // Temperatursensor
11
int t1ValC(0);                    // Begrenzter Wert für Temperatursensor
12
int pwmVal(0);                    // Variable für die Pulsbreite
13
unsigned char state = 1;          // globale Variable, die den Status repräsentiert
14
15
void setup()
16
{
17
  pinMode(pwmPin, OUTPUT);        // setzt Pin als Ausgang
18
  lcd.clear();                    // LCD löschen
19
  lcd.begin(16, 4);               // verfügbare Spalten und Zeilen
20
}
21
22
void loop()
23
{
24
25
int t1Val = analogRead(t1Pin);
26
t1ValC = constrain(t1Val, 100, 800);  // brgrenzt min. und max. Wert
27
pwmVal = map(t1ValC,100,800,24,255);  // rechnet begrenzten Wert von 100 - 800
28
                                      // in PWM 24 - 255 um (entspricht 10 - 100 % Pulsbreite)
29
  lcd.clear();  
30
  lcd.setCursor(0,0);
31
  lcd.print(t1Val);
32
  lcd.setCursor(0,1);
33
  lcd.print(pwmVal);
34
  lcd.setCursor(0,2);
35
  lcd.print(state);
36
  delay(50);
37
38
39
switch (state) {
40
  case 1:                             //Temperatur niedrig, Lüfter aus..
41
  if (t1Val < 100) 
42
  {
43
    analogWrite(pwmPin,0);
44
    state = 1;
45
  }  else  {                          //.. ansonsten schalte auf case 2
46
  state = 2;
47
  }
48
  break;
49
50
  case 2:                             //Lüfter startet für 2 s Vollgas
51
  if (t1Val >= 100) analogWrite(pwmPin, 255);
52
  delay(2000);
53
  state = 3;                          //schalte auf case 3
54
  break;
55
56
  case 3:                             //Lüfter läuft mit Wert "pwmVal"
57
  if (t1Val >= 100)
58
  {
59
    analogWrite(pwmPin, pwmVal);
60
  } else if (t1Val < 90) {            //Temperatur zu niedrig, schalte auf case 1
61
  state = 1;
62
  }
63
  break;
64
}
65
}

Toll ist auch, dass ich den Ausschaltwert in case 3 niedriger als den 
Einschaltwert setzen konnte; dadurch erhält man eine Hysterese. 
Womöglich setze ich diesen Code tatsächlich mal ein einem Labornetzteil, 
Ladegerät o.ä. ein.


Vielen Dank an falk und auch den anderen für die Beiträge!
Gruß, Joe

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.