mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Programablauf durch Taster nur Sporatisch


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht 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?
                           

#include <avr/sleep.h>
#include <avr/interrupt.h>
#define BODS 7                   //BOD Sleep bit in MCUCR
#define BODSE 2                  //BOD Sleep enable bit in MCUCR
uint8_t mcucr1, mcucr2;
const int tasterPin = 2;     // Taster an Pin 4 angeschlossen
int LED = 0;
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by
    // Variablen
boolean gedrueckt = false;
int lichtModusAlt = 0;
int lichtModus = 0;          // Variable für die verschiedenen festgelegten modi
int tasterStatus = LOW;
void goToSleep(void) {
    ACSR |= _BV(ACD);                         //disable the analog comparator
    ADCSRA &= ~_BV(ADEN);                     //disable ADC
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    cli();
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;
    MCUCR = mcucr2;
    sei();                         //ensure interrupts enabled so we can wake up again
    sleep_cpu();                   //go to sleep
    cli();                         //wake up here, disable interrupts
    sleep_disable();               
    sei();                         //enable interrupts again (but INT0 is disabled from above)
}
void setup()
{
  pinMode(tasterPin, INPUT);      // Setzt den TasterPin als Eingang
  pinMode(LED, OUTPUT);
}
void loop()
{ 
  tasterStatus = digitalRead(tasterPin);
   if (tasterStatus == HIGH)
   {
    if (!gedrueckt) {  // war vorher nicht gedrueckt
      gedrueckt = true;
      lichtModusAlt = lichtModus;
      lichtModus++;     // Lichtmodus +1
      delay(10);       // 10ms warten zum Entprellen
    }
  }
    else 
    {   gedrueckt = false; // losgelassen
  }
    delay(20); // entprellzeit für Taster
    //+++++++++++++++ LEUCHTPROGRAMME +++++++++++++++++
    // Modus 0 = Licht aus
    if (lichtModus == 0)
    {
      analogWrite(LED, 255);   // turn the LED on (HIGH is the voltage level)
      delay(10);           
    }
    // Modus 1
    else if (lichtModus == 1)
    {
      analogWrite(LED, 80);   // turn the LED on (HIGH is the voltage level)
      delay(10);           
    }
    // Modus 2
    else if (lichtModus == 2)
    {
      analogWrite(LED, 20);   
      delay(10);           
    }
    //Modus 3
     else if (lichtModus == 3)
     {
      analogWrite(LED, 2);  
      delay(10);           
    }
     else if (lichtModus == 4)
     {
       analogWrite(LED, brightness);

  
  brightness = brightness + fadeAmount;

  
  if (brightness <= 0 || brightness >= 150) 
{
    fadeAmount = -fadeAmount;
    }
     delay(50);
} 

else if  (lichtModus == 5) // Blizer

{   
 digitalWrite(LED, HIGH);   
  delay(10);                       
  digitalWrite(LED, LOW);  
  delay(3000);  
 

}
 
  else
    {
      lichtModus = 0;
       { goToSleep(); }
    }
  }

: Bearbeitet durch User
Autor: Uwe K. (ukhl)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: BS (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
Autor: Markus R. (markus_r131)
Datum:

Bewertung
-1 lesenswert
nicht 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.
Autor: BS (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht 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.
Autor: Holger L. (max5v)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus R. schrieb:
> Ok aber wenn ich 5 weg lasse funktioniert es 🤔
else if  (lichtModus == 5) // Blizer
{   
  digitalWrite(LED, HIGH);   
  delay(10);                       
  digitalWrite(LED, LOW);  
  delay(3000);  
}

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.

Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht 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.
Autor: S. R. (svenska)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Uwe K. (ukhl)
Datum:

Bewertung
0 lesenswert
nicht 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:
int blitzCounter = 0;
.
.
.
else if  (lichtModus == 5) // Blizer
{   
  
  if blitzCounter == 0 {
    digitalWrite(LED, HIGH);   
    delay(10);                       
    digitalWrite(LED, LOW);  
  }
  blitzCounter += 1;
  if blitzCounter >= 150 blitzCounter = 0; // nutzt die 20 ms von der Tastenentprellung
}

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

Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok vielen Dank ich werde es morgen gleich ausprobieren 👍

Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht 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'
<
<
<
 // Konstanten                            // Helligkeits über Taster weiterschalten Attiny über reset aufwecken im 
                                         //schlafmodus ca. 0,4µA bei 5Volt
int blitzCounter = 0;
#include <avr/sleep.h>
#include <avr/interrupt.h>
#define BODS 7                   //BOD Sleep bit in MCUCR
#define BODSE 2                  //BOD Sleep enable bit in MCUCR
uint8_t mcucr1, mcucr2;
const int tasterPin = 2;     // Taster an Pin 4 angeschlossen
int LED = 0;
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by
    // Variablen
boolean gedrueckt = false;
int lichtModusAlt = 0;
int lichtModus = 0;          // Variable für die verschiedenen festgelegten modi
int tasterStatus = LOW;
void goToSleep(void) {
    ACSR |= _BV(ACD);                         //disable the analog comparator
    ADCSRA &= ~_BV(ADEN);                     //disable ADC
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    cli();
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;
    MCUCR = mcucr2;
    sei();                         //ensure interrupts enabled so we can wake up again
    sleep_cpu();                   //go to sleep
    cli();                         //wake up here, disable interrupts
    sleep_disable();               
    sei();                         //enable interrupts again (but INT0 is disabled from above)
}
void setup()
{
  pinMode(tasterPin, INPUT);      // Setzt den TasterPin als Eingang
  pinMode(LED, OUTPUT);
}
void loop()
{ 
  tasterStatus = digitalRead(tasterPin);
   if (tasterStatus == HIGH)
   {
    if (!gedrueckt) {  // war vorher nicht gedrueckt
      gedrueckt = true;
      lichtModusAlt = lichtModus;
      lichtModus++;     // Lichtmodus +1
      delay(100);       // 10ms warten zum Entprellen
    }
  }
    else 
    {   gedrueckt = false; // losgelassen
  }
    delay(20); // entprellzeit für Taster
    //+++++++++++++++ LEUCHTPROGRAMME +++++++++++++++++
    // Modus 0 = Licht aus
    if (lichtModus == 0)
    {
      analogWrite(LED, 255);   // turn the LED on (HIGH is the voltage level)
      delay(10);           
    }
    // Modus 1
    else if (lichtModus == 1)
    {
      analogWrite(LED, 80);   // turn the LED on (HIGH is the voltage level)
      delay(10);           
    }
    // Modus 2
    else if (lichtModus == 2)
    {
      analogWrite(LED, 20);   // turn the LED on (HIGH is the voltage level)
      delay(10);           
    }
    //Modus 3
     else if (lichtModus == 3)
     {
      analogWrite(LED, 2);   // turn the LED on (HIGH is the voltage level)
      delay(10);           
    }
     else if (lichtModus == 4)
     {
       analogWrite(LED, brightness);

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade:
  if (brightness <= 0 || brightness >= 150) {
    fadeAmount = -fadeAmount;
    }
     delay(50);
} 

else if  (lichtModus == 5) // Blizer
{    
  if blitzCounter == 0 {
  
    digitalWrite(LED, HIGH);   
    delay(10);                       
    digitalWrite(LED, LOW);  
  }
  blitzCounter += 1;
  if blitzCounter >= 150 blitzCounter = 0; // nutzt die 20 ms von der Tastenentprellung
}
 
  else
    {
      lichtModus = 0;
       { goToSleep(); }
    }
  }  

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke hab ich in der Eile übersehen,ich hatte es nur von oben kopiert

Autor: W.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#define LED1_ein  1
#define LED1_aus  2
#define LED2_ein  3
#define LED2_aus  4
.. na und so weiter je nach Gusto

und als Reaktion:
 switch (event)
{ case LED1_ein:
    SchalteLED1ein();
    Add_Delayed_Event(3000, LED1_aus);
    break;
  case LED1_aus:
    SchalteLED1aus();
    Add_Delayed_Event(1000, LED1_aus);
    break;
 ...
 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
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.

Autor: Forist (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Markus R. schrieb:
> ... sporatisch ...

Kann ein Moderator wenigstens mal den Titel einteutschen - grausig.

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Holger L. (max5v)
Datum:

Bewertung
0 lesenswert
nicht 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+ ;)

Autor: Markus R. (markus_r131)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.