Zeitablaufanzeige eines Timers mit millis() über LED

Hallo ,
ich besitze noch keine große Programmiererfahrung, aber es macht Spaß. Jetzt habe ich eine Zeitablaufanzeige mit LEDs und millis() begonnen.

Ein Timer (im Sketch fest 60 sec.) wird per Taster gestartet. Zu Beginn leuchten 6 LEDs. Nach jeweils einem Zeitintervall von 10 Sekunden erlischt eine LED nach der anderen.
Problem 1: Das 1. Zeitintervall hat nicht genau 10 Sekunden (Wert ca. 6-8 Sek.).Intervall 2 - 6 sind dagegen immer genau 10 Sek. lang. Durch den Fehler im 1. Intervall wird aber schon nach 56 - 58 Sek. ausgeschaltet.
Problem 2:Ein definierter Zustand bei Drücken des Tasters wird z. Zt. nur mit Reset erreicht.

Kann man diese Fehler beseitigen oder ist der Ansatz falsch.

Über hilfreiche Tipps würde ich mich freuen.

sketch_apr05b_millis_test_6_Leds_Ablaufanzeige.ino (2.17 KB)

rexonator:
... ich besitze noch keine große Programmiererfahrung, aber es macht Spaß. ...
Über hilfreiche Tipps würde ich mich freuen.

Ich finde, dass Dein Code schlecht lesbar ist. Ich habe allerdings fast keine Erfahrung im Lesen fremder Codes. Aber vielleicht hilft ja: Wenn Du den Code so formatierst (Einrückungen, Zeilenlängen), dass er gut les- und nachvollziehbar ist, findest Du den Fehler wahrscheinlich auf Anhieb. Mir geht’s jedenfalls immer wieder so.

Gruß

Gregor

PS: Lerne fluchen :slight_smile:

Noch besser wäre es, den Sketch in code tags </> zu posten.

Hallo rexonator,
erstmal herzlich willkommen im Forum.

Bei deinem Sketch sind t1 bis t6 nach dem Start des Arduino =0, während der Laufzeit werden sie gesetzt, daher ist die Zeit nach dem Start bis zum drücken des Tasters für t1 schon vorbei. Vermutlich brauchst du ca. 4 sek. bis der Taster gedrückt ist. Wenn du den Arduino neu startest und lange genug (>60 sek) wartest, läuft alles nicht mehr wie es soll.

void setup() {

  DDRB &= ~(1<<PB0);          // PORTB pin 0 als Eingang
  PORTB |= (1<<PB0);          // pull-up in PORTB pin 0 aktivieren
  DDRB |= (1<<PB5);           // PORTB pin5 als Ausgang (digital 13  Arduino )
  DDRD = 0b11111100;          // PortD Pin 2  - Pin 7 als Ausgang setzen

  unsigned long now = millis();
}
  • Du solltest dich entscheiden, ob du Arduino Pin Bezeichnungen oder atmega PORT/BIT Namen verwenden willst. Für deine LED nimmst du digitalWrite, entsprechend wäre
 DDRB |= (1<<PB5); // PORTB pin5 als Ausgang (digital 13  Arduino )

einfach

 pinMode(13,OUTPUT);

( PORTB &=~ (1<<PB5); heisst in der "Arduino Sprache" digitalWrite(13, LOW); )

  • Die lokale Variable now in setup ist eine andere als die in loop. ( Die in setup ist also unnötig )

Problem 2:Ein definierter Zustand bei Drücken des Tasters wird z. Zt. nur mit Reset erreicht.
Kann man diese Fehler beseitigen oder ist der Ansatz falsch.

Korrigieren kann man auch einen falschen Ansatz :wink:

Die Zeit seit Tastendruck wird durch ( now - t1 ) gemessen, also muss die Zeit t1 auch beim Tastendruck neu gesetzt werden.
Wofür du t2 .. t6 brauchst, weiss ich nicht.

Die LEDs sollen ausgehen, wenn (now - t1) > 10, 20, 30, 40 sec ist, richtig ?
Wenn egal ist , was passiert wenn du 50 Tage lang den Taster nicht drückst, kannst du den Wert von t1 auch "für immer" so lassen, wie er beim jeweiligen Tastendruck gesetzt wurde.

Problem 1 ist die Zeit zwischen Reset und deinem ersten Test-Tastendruck.

so sollte es laufen

    const int ledPin2 =  2;         
    const int ledPin3 =  3;         
    const int ledPin4 =  4;         
    const int ledPin5 =  5;         
    const int ledPin6 =  6;         
    const int ledPin7 =  7;         

    unsigned long onTime6 = 60000;        //Nach Tastendruck  60 sec. an
   
    unsigned long t1;                     //Zeit 1, 
    
void setup() {
  Serial.begin(115200);

  DDRB &= ~(1<<PB0);          // PORTB pin 0 als Eingang
  PORTB |= (1<<PB0);          // pull-up in PORTB pin 0 aktivieren
  DDRB |= (1<<PB5);           // PORTB pin5 als Ausgang (digital 13  Arduino )
  DDRD = 0b11111100;          // PortD Pin 2  - Pin 7 als Ausgang setzen
}
 
uint8_t readButton(void)
{
 if((PINB & (1<<PB0)) == 0){        
 _delay_ms(25); }                    //Entprellen
 if((PINB & (1<<PB0)) == 0){         
 return 1; }                         
 else return 0;
 }

void loop()
{

 if(!readButton()==0){                                                                                                                                                  
   _delay_ms(200);                                                          
  PORTB |=(1<<PB5);                                                                                                                  
  PORTD =0b11111100;  
  t1=millis();
 }
 
   unsigned long now = millis();
  
if( ( now - t1 ) >= (onTime6*1/6) )       // Multiplikation mit 1/6 bezieht sich auf 6 LEDs
  { 
    digitalWrite(ledPin2, LOW);
  }

if( ( now - t1  ) >= (onTime6*2/6) )
  {  
     digitalWrite(ledPin3, LOW);
   }

if( ( now - t1 ) >= (onTime6*3/6) )
  {
   digitalWrite(ledPin4, LOW);
  }

if( ( now - t1 ) >= (onTime6*2/3) )
  {
   digitalWrite(ledPin5, LOW);
  }

if( ( now - t1 ) >= (onTime6*5/6) )
  {
   digitalWrite(ledPin6, LOW);
  }

if( ( now - t1 ) >= onTime6 ) 
  {
    digitalWrite(ledPin7, LOW);
    PORTB &=~ (1<<PB5);
  } 
}

Hallo Community,

danke für die schnelle und kompetente Hilfe. Es funktioniert! Entscheidend war es, in die "if"-Schleife des Tasters den Zeitstempel t1=millis() einzubringen.

void loop()
{

 if(!readButton()==0){                                                                                                                                                  
   _delay_ms(200);                                                          
  PORTB |=(1<<PB5);                                                                                                                  
  PORTD =0b11111100;  
  [color=red]t1=millis();[/color]
 }

Ich lese mich parallel auch in C und die hardwarenahe Programmierung des Atmega 328 ein. Deshalb wurden von mir teilweise Befehle der Bitmanipulation verwendet. Zur Übung.
Der Arduino-Compiler kann beides.

Die millis()-Funktion habe ich durch eure Hinweise jetzt wohl verstanden :slight_smile: .

Gruß
rexonator

du hast schon gemerkt, dass du hier eine doppelte Negation hast

if(!readButton()==0){

auf LOW prüfen --> if(!readButton()){
auf HIGH prüfen --> if(readButton()){

in die "if"-Schleife

http://www.if-schleife.de/

Domainabfrage-Ergebnis

Domain
if-schleife.de
Letzte Aktualisierung
09.05.2007

Domaininhaber
Der Domaininhaber ist der Vertragspartner der DENIC und damit der an der Domain materiell Berechtigte.

Domaininhaber
Stefan [...]

Schon fast eine ewige Wahrweit des Internets und ich erfahre erst jetzt davon.

... das ist doch glatt eine Tasse Kaffee und einen Eintrag in die Favoriten wert ...
:wink:

Hoffentlich erlaubt sein 1und1 Tarif genug Traffic für die tolle Webseite. :wink:

Und hoffentlich wertet er seine Logs aus, um zu merken, wie berühmt seine Domain geworden ist :stuck_out_tongue:

Hallo ardubu,
danke für den Hinweis mit der doppelten Negation.

if(!readButton()==0){

Bei Prüfung auf "HIGH" ist

if(readButton()){

natürlich kürzer und besser :frowning: .