Forum: Mikrocontroller und Digitale Elektronik Programablauf durch Taster nur Sporatisch


von Markus R. (markus_r131)


Lesenswert?

Hallo ich habe einen ATTiny85 mit einem LED Program bespielt die Modi 
werden mit einem Taster weiter geschaltet, alles läuft soweit auch,nur 
in der letzten Zeile vom blinken zum Shutdownmodus geht es nur 
sporatisch immer genau dann wenn das Programm die zeile (Blizen) neu 
startet was hab ich falsch gemacht?
1
                           
2
3
#include <avr/sleep.h>
4
#include <avr/interrupt.h>
5
#define BODS 7                   //BOD Sleep bit in MCUCR
6
#define BODSE 2                  //BOD Sleep enable bit in MCUCR
7
uint8_t mcucr1, mcucr2;
8
const int tasterPin = 2;     // Taster an Pin 4 angeschlossen
9
int LED = 0;
10
int brightness = 0;    // how bright the LED is
11
int fadeAmount = 5;    // how many points to fade the LED by
12
    // Variablen
13
boolean gedrueckt = false;
14
int lichtModusAlt = 0;
15
int lichtModus = 0;          // Variable für die verschiedenen festgelegten modi
16
int tasterStatus = LOW;
17
void goToSleep(void) {
18
    ACSR |= _BV(ACD);                         //disable the analog comparator
19
    ADCSRA &= ~_BV(ADEN);                     //disable ADC
20
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
21
    sleep_enable();
22
    cli();
23
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
24
    mcucr2 = mcucr1 & ~_BV(BODSE);
25
    MCUCR = mcucr1;
26
    MCUCR = mcucr2;
27
    sei();                         //ensure interrupts enabled so we can wake up again
28
    sleep_cpu();                   //go to sleep
29
    cli();                         //wake up here, disable interrupts
30
    sleep_disable();               
31
    sei();                         //enable interrupts again (but INT0 is disabled from above)
32
}
33
void setup()
34
{
35
  pinMode(tasterPin, INPUT);      // Setzt den TasterPin als Eingang
36
  pinMode(LED, OUTPUT);
37
}
38
void loop()
39
{ 
40
  tasterStatus = digitalRead(tasterPin);
41
   if (tasterStatus == HIGH)
42
   {
43
    if (!gedrueckt) {  // war vorher nicht gedrueckt
44
      gedrueckt = true;
45
      lichtModusAlt = lichtModus;
46
      lichtModus++;     // Lichtmodus +1
47
      delay(10);       // 10ms warten zum Entprellen
48
    }
49
  }
50
    else 
51
    {   gedrueckt = false; // losgelassen
52
  }
53
    delay(20); // entprellzeit für Taster
54
    //+++++++++++++++ LEUCHTPROGRAMME +++++++++++++++++
55
    // Modus 0 = Licht aus
56
    if (lichtModus == 0)
57
    {
58
      analogWrite(LED, 255);   // turn the LED on (HIGH is the voltage level)
59
      delay(10);           
60
    }
61
    // Modus 1
62
    else if (lichtModus == 1)
63
    {
64
      analogWrite(LED, 80);   // turn the LED on (HIGH is the voltage level)
65
      delay(10);           
66
    }
67
    // Modus 2
68
    else if (lichtModus == 2)
69
    {
70
      analogWrite(LED, 20);   
71
      delay(10);           
72
    }
73
    //Modus 3
74
     else if (lichtModus == 3)
75
     {
76
      analogWrite(LED, 2);  
77
      delay(10);           
78
    }
79
     else if (lichtModus == 4)
80
     {
81
       analogWrite(LED, brightness);
82
83
  
84
  brightness = brightness + fadeAmount;
85
86
  
87
  if (brightness <= 0 || brightness >= 150) 
88
{
89
    fadeAmount = -fadeAmount;
90
    }
91
     delay(50);
92
} 
93
94
else if  (lichtModus == 5) // Blizer
95
96
{   
97
 digitalWrite(LED, HIGH);   
98
  delay(10);                       
99
  digitalWrite(LED, LOW);  
100
  delay(3000);  
101
 
102
103
}
104
 
105
  else
106
    {
107
      lichtModus = 0;
108
       { goToSleep(); }
109
    }
110
  }

: Bearbeitet durch User
von Uwe K. (ukhl)


Lesenswert?

Bei einem DELAY macht der Controller nix. Auch keine Tasten abfragen.
Läuft also alles wie erwartet.

Am besten die DELAYs ausschmeissen und das ganze mit einem Timer 
steuern.

von BS (Gast)


Lesenswert?

LichtModus wird immer weiter erhöht.
Nur wenn der auf 6 steht, kommt das Programm in die letzte Klammer.

Beitrag #5691678 wurde von einem Moderator gelöscht.
von Markus R. (markus_r131)


Lesenswert?

Also müsste ich noch einen 6. Modus hinzufügen?? Wenn ich den Blitzmodus 
weg lasse läuft alles so wie es sein soll. Ps. neu gestartet wird mit 
reset Pin.

: Bearbeitet durch User
Beitrag #5691696 wurde von einem Moderator gelöscht.
von BS (Gast)


Lesenswert?

Deine Kette von  if ... else sorgt dafür, dass für lichtModus 0 bis 5
immer einer der Fälle zutrifft; das Programm kommt dann nicht in die 
letzte Klammer.
Das passiert erst, wenn keiner der Fälle mehr zutrifft, weil nämlich 
durch Tastendruck im lichtModus 5 der lichtModus auf 6 geht.
In dem Fall wird dann LichtModus wieder auf 0 gesetzt und goToSleep() 
aufgerufen.

Wenn Du einen anderen Ablauf willst, könntest Du einen zweiten Taster 
einbauen, der das Gerät schlafen schickt, oder auch die Dauer des 
Tastendrucks auswerten (kurz = lichtModus hochzählen, lang = schlafen 
gehen).

von Markus R. (markus_r131)


Lesenswert?

BS schrieb:
Das passiert erst, wenn keiner der Fälle mehr zutrifft, weil nämlich
> durch Tastendruck im lichtModus 5 der lichtModus auf 6 geht.
> In dem Fall wird dann LichtModus wieder auf 0 gesetzt und goToSleep()
> aufgerufen.




Ok aber wenn ich 5 weg lasse funktioniert es ?

Wie kann ich den Sprung in 5 von Blitz auf sleep also am besten lösen 
bzw. Warum funktioniert es von 4 auf sleep? Mfg

Beitrag #5691712 wurde von einem Moderator gelöscht.
von Holger L. (max5v)


Lesenswert?

Markus R. schrieb:
> Ok aber wenn ich 5 weg lasse funktioniert es ?
1
else if  (lichtModus == 5) // Blizer
2
{   
3
  digitalWrite(LED, HIGH);   
4
  delay(10);                       
5
  digitalWrite(LED, LOW);  
6
  delay(3000);  
7
}

Wie bereits oben erwähnt wird das Programm durch delay(x) angehalten.
Funktionieren könnte es wenn der Taster so lange gedrückt wird bis die 
drei Sekunden Wartezeit herum sind. Nur den richtigen Zeitpunkt 
abzupassen bevor der Sleepmodus wider deaktiviert wird ist wohl eher 
Glücksache.

In diesem Fall wirst du wohl um einen Timer nicht herum kommen.
Evt. wäre es möglich den INT0 zu verwenden und das Flag als Tastendruck 
Indikator auszuwerten, in wie fern es mit der delay Funktion läuft kann 
ich leider nicht sagen.

Das if...else ist, zumindest für mich, eher schwer zu lesen. Es würde 
sich eine switch case Syntax anbieten:
https://www.programiz.com/c-programming/c-switch-case-statement

Wenn die Möglichkeit wie bei Arduino besteht Daten an den PC 
zurückzusenden ist es immer hilfreich sich Werte wie den lichtModus bei 
Änderung anzeigen zu lassen.

von Markus R. (markus_r131)


Lesenswert?

Ok danke! Aber ich benötige ja die 3Sek delay da es ja die Wartezeit für 
die LED ist. Giebts es da keine Anweisung die nebenbei wartet bis die 
tasterabfrage kommt? Und ja wenn ich 3 Sek. Tastern drücke geht er in 
den sleep Modus.

Beitrag #5691836 wurde vom Autor gelöscht.
von S. R. (svenska)


Lesenswert?

Markus R. schrieb:
> Giebts es da keine Anweisung die nebenbei wartet bis die
> tasterabfrage kommt?

Es gibt sogenannte "Timer". Mit denen macht man das.

Den kannst du brav im Hintergrund zählen lassen und dein Delay durch 
eine "Wenn Taste nicht gedrückt UND Wartezeit noch nicht abgelaufen ist, 
dann warte"-Schleife ersetzen. Das wäre der einfachste Fall.

Informationen dazu gibt es genug hier im Forum.

von Uwe K. (ukhl)


Lesenswert?

Uwe K. schrieb:
> Bei einem DELAY macht der Controller nix. Auch keine Tasten abfragen.
> Läuft also alles wie erwartet.
>
> Am besten die DELAYs ausschmeissen und das ganze mit einem Timer
> steuern.

Irgendwie hat er ja recht.

Du kannst aber auch das mal probieren:
1
int blitzCounter = 0;
2
.
3
.
4
.
5
else if  (lichtModus == 5) // Blizer
6
{   
7
  
8
  if blitzCounter == 0 {
9
    digitalWrite(LED, HIGH);   
10
    delay(10);                       
11
    digitalWrite(LED, LOW);  
12
  }
13
  blitzCounter += 1;
14
  if blitzCounter >= 150 blitzCounter = 0; // nutzt die 20 ms von der Tastenentprellung
15
}

Nicht schön, weil hier ein DELAY genutzt wird, der eigendlich nicht für 
das Blinken gedacht ist. Aber es sollte klappen.

von Markus R. (markus_r131)


Lesenswert?

Ok vielen Dank ich werde es morgen gleich ausprobieren ?

von Markus R. (markus_r131)


Lesenswert?

leider funktioniert es so nicht folgendes wird als fehler angezeigt:

C:\Users\Notebook\Desktop\test\test.ino: In function 'void loop()':

test:96: error: expected '(' before 'blitzCounter'

   if blitzCounter == 0 {

      ^

test:103: error: expected '(' before 'blitzCounter'

   if blitzCounter >= 150 blitzCounter = 0; // nutzt die 20 ms von der 
Tastenentprellung

      ^

exit status 1
expected '(' before 'blitzCounter'
<
<
<
1
 // Konstanten                            // Helligkeits über Taster weiterschalten Attiny über reset aufwecken im 
2
                                         //schlafmodus ca. 0,4µA bei 5Volt
3
int blitzCounter = 0;
4
#include <avr/sleep.h>
5
#include <avr/interrupt.h>
6
#define BODS 7                   //BOD Sleep bit in MCUCR
7
#define BODSE 2                  //BOD Sleep enable bit in MCUCR
8
uint8_t mcucr1, mcucr2;
9
const int tasterPin = 2;     // Taster an Pin 4 angeschlossen
10
int LED = 0;
11
int brightness = 0;    // how bright the LED is
12
int fadeAmount = 5;    // how many points to fade the LED by
13
    // Variablen
14
boolean gedrueckt = false;
15
int lichtModusAlt = 0;
16
int lichtModus = 0;          // Variable für die verschiedenen festgelegten modi
17
int tasterStatus = LOW;
18
void goToSleep(void) {
19
    ACSR |= _BV(ACD);                         //disable the analog comparator
20
    ADCSRA &= ~_BV(ADEN);                     //disable ADC
21
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
22
    sleep_enable();
23
    cli();
24
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
25
    mcucr2 = mcucr1 & ~_BV(BODSE);
26
    MCUCR = mcucr1;
27
    MCUCR = mcucr2;
28
    sei();                         //ensure interrupts enabled so we can wake up again
29
    sleep_cpu();                   //go to sleep
30
    cli();                         //wake up here, disable interrupts
31
    sleep_disable();               
32
    sei();                         //enable interrupts again (but INT0 is disabled from above)
33
}
34
void setup()
35
{
36
  pinMode(tasterPin, INPUT);      // Setzt den TasterPin als Eingang
37
  pinMode(LED, OUTPUT);
38
}
39
void loop()
40
{ 
41
  tasterStatus = digitalRead(tasterPin);
42
   if (tasterStatus == HIGH)
43
   {
44
    if (!gedrueckt) {  // war vorher nicht gedrueckt
45
      gedrueckt = true;
46
      lichtModusAlt = lichtModus;
47
      lichtModus++;     // Lichtmodus +1
48
      delay(100);       // 10ms warten zum Entprellen
49
    }
50
  }
51
    else 
52
    {   gedrueckt = false; // losgelassen
53
  }
54
    delay(20); // entprellzeit für Taster
55
    //+++++++++++++++ LEUCHTPROGRAMME +++++++++++++++++
56
    // Modus 0 = Licht aus
57
    if (lichtModus == 0)
58
    {
59
      analogWrite(LED, 255);   // turn the LED on (HIGH is the voltage level)
60
      delay(10);           
61
    }
62
    // Modus 1
63
    else if (lichtModus == 1)
64
    {
65
      analogWrite(LED, 80);   // turn the LED on (HIGH is the voltage level)
66
      delay(10);           
67
    }
68
    // Modus 2
69
    else if (lichtModus == 2)
70
    {
71
      analogWrite(LED, 20);   // turn the LED on (HIGH is the voltage level)
72
      delay(10);           
73
    }
74
    //Modus 3
75
     else if (lichtModus == 3)
76
     {
77
      analogWrite(LED, 2);   // turn the LED on (HIGH is the voltage level)
78
      delay(10);           
79
    }
80
     else if (lichtModus == 4)
81
     {
82
       analogWrite(LED, brightness);
83
84
  // change the brightness for next time through the loop:
85
  brightness = brightness + fadeAmount;
86
87
  // reverse the direction of the fading at the ends of the fade:
88
  if (brightness <= 0 || brightness >= 150) {
89
    fadeAmount = -fadeAmount;
90
    }
91
     delay(50);
92
} 
93
94
else if  (lichtModus == 5) // Blizer
95
{    
96
  if blitzCounter == 0 {
97
  
98
    digitalWrite(LED, HIGH);   
99
    delay(10);                       
100
    digitalWrite(LED, LOW);  
101
  }
102
  blitzCounter += 1;
103
  if blitzCounter >= 150 blitzCounter = 0; // nutzt die 20 ms von der Tastenentprellung
104
}
105
 
106
  else
107
    {
108
      lichtModus = 0;
109
       { goToSleep(); }
110
    }
111
  }

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Markus R. schrieb:
> C:\Users\Notebook\Desktop\test\test.ino: In function 'void loop()':
>
> test:96: error: expected '(' before 'blitzCounter'
>
>    if blitzCounter == 0 {
>
>       ^
>
> test:103: error: expected '(' before 'blitzCounter'
>
>    if blitzCounter >= 150 blitzCounter = 0; // nutzt die 20 ms von der
> Tastenentprellung
>
>       ^
>
> exit status 1
> expected '(' before 'blitzCounter'

Das sind elementare Grundlagen der Programmiersprache, die Du da 
verwenden willst.

Der Ausdruck nach dem Schlüsselwort "if" muss in runden Klammern 
untergebracht werden.

Das steht in wirklich jedem Buch über C bzw. C++ drin, auch in jedem 
Arduino-Lehrgang.

von Markus R. (markus_r131)


Lesenswert?

danke hab ich in der Eile übersehen,ich hatte es nur von oben kopiert

von W.S. (Gast)


Lesenswert?

Markus R. schrieb:
> leider funktioniert es so nicht folgendes wird als...

So langsam wird dein Code zum Spaghetticode und sehr unleserlich.

Mein Rat: Mache es GANZ ANDERS.

Als erstes solltest du dir eine Art Systemuhr einrichten. Ob die nun 
alle 1 ms oder alle 10 ms weiterzählt, ist hier wohl schnurz für deine 
Led-Lichtorgel.

Als nächstes solltest du dich bekannt machen mit dem Verfahren, mit 
Events zu arbeiten und dein Programm ereignisgesteuert schreiben, also 
nichtblockierend schreiben.

Dann besteht dein Programm nämlich nicht mehr aus lauter blockierenden 
Schleifen, sondern wird ganz einfach:
- Es kreiselt immerzu in der Hauptschleife von main und guckt dort nach, 
ob in der Event-Warteschlange ein Event drin ist. Ebenso guckt es, ob 
irgend eine Taste gedrückt ist oder ein Zeichen am UART angekommen ist 
oder sonstwas noch eingetrudelt ist.

- Wenn ja, dann holt es diesen Event dort heraus und reagiert auf ihn.
Als Events würde ich beispielsweise sowas vorschlagen:
1
#define LED1_ein  1
2
#define LED1_aus  2
3
#define LED2_ein  3
4
#define LED2_aus  4
5
.. na und so weiter je nach Gusto
6
7
und als Reaktion:
8
 switch (event)
9
{ case LED1_ein:
10
    SchalteLED1ein();
11
    Add_Delayed_Event(3000, LED1_aus);
12
    break;
13
  case LED1_aus:
14
    SchalteLED1aus();
15
    Add_Delayed_Event(1000, LED1_aus);
16
    break;
17
 ...
18
 usw.
Damit blinkt deine LED 3 Sekunden ein, 1 Sekunde aus. Ist nur ein 
Beispiel.

- Die Systemuhr verwaltet eine kleine Liste von 3..5 "delayed" Events. 
Das ist wie eine Signalverzögerung. Man kann per Funktion
1
bool  Add_Delayed_Event ( integertyp aDelay, auch_integertyp aEvent);
so einen Event dort einsteuern und wenn die Verzögerungszeit um ist, 
dann nimmt der Timer-Interrupt-Handler diesen Event aus der Liste der 
Systemuhr heraus und stopft ihn in die gewöhnliche Event-Warteschlange.

Ob du nun deine Events als bytes oder int oder long deklarierst, ist 
deine Sache, ebenso ob du die Verzögerungszeit als int oder long 
deklarierst.

W.S.

von Forist (Gast)


Lesenswert?

Markus R. schrieb:
> ... sporatisch ...

Kann ein Moderator wenigstens mal den Titel einteutschen - grausig.

von Peter D. (peda)


Lesenswert?

Tastenabfrage macht man am besten per Timerinterrupt.
In der Mainloop gibt es regelmäßig Ärger oder sie ist wirklich extrem 
verdammt kurz (Ausführungszeit).

von Markus R. (markus_r131)


Lesenswert?

Danke für eure Hilfe der Sketch läuft jetzt ohne Probleme und Hänger. 
Ergänzend wollte ich noch sagen das es ein Selbstgebauter LED Schwimmer 
ist wo ich einem kleinen Akku und Tiny untergebracht und mit Giesharz 
ausgefüllt habe. Geladen wird mittels kleiner Induktionsspule Adafruit 
micro li-ion Laderegler mit 5V1 Zenerdiode vorgeschaltet damit bei 
ereichen der Ladeschlussspannung die Spannung nicht schlagartig ansteigt 
und die Elektronik bzw Akku beschädigt. Die Modi werden mit integrirtem 
Reedkontakt von außen mittels Magnet durchgeschalten.

von Holger L. (max5v)


Lesenswert?

Hört sich interessant an.
Gibt es dafür einen speziellen Grund oder ist das "nur" ein Blickfang 
wie ein schwimmendes Teelicht?
Wenn du magst und die Möglichkeit hast wäre ein Foto ganz nett.
So etwas ist immer sehr interessant, nicht nur um es nachzubauen sondern 
auch um ein paar kreative Ideen für eigene Projekte zu sammeln.

Der WAF Faktor bei einem entspannenden Bad liegt garantiert bei 10+ ;)

von Markus R. (markus_r131)


Lesenswert?

Bild kommt sobald ich alles zusammen habe ich hab den fürs Angeln 
gemacht da es mich gestört hat jede Stunde ein neues knicklicht dran zu 
machen und die Batterieschwimmer teuer Spezial Chinabatterien verwenden 
und manchmal auch undicht sind.dann ist es ärgerlich wenn man 12 Euro 
jedes mal für Schwimmer ausgiebt. Aber als schwimmlicht mit induktiver 
wiederaufladung auch gut müsste nur in ein anderes Gehäuse rein.

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.