www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Wahrscheinlich einfache Timerfrage


Autor: zaphod_beebelbrox (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe vor, ein Positionslicht für ein Modell zu bauen.
Dieses soll drei unterschiedliche Modi bisitzen:
Mode 0: 50ms an, 1450ms aus;
Mode 1: 50ms an, 50ms aus, 50ms an, 1350ms aus;
Mode 2: 50ms an, 50ms aus.

Sinn dahinter:
0 steht für "Modell im Standby, soweit alles roger";
1 ist normaler Betrieb (Doppelblitz);
2 ist das Signal für einen Fehler.

Das ganze hab ich mir mit Delayschleifen schnell hinprogrammiert. Aber 
das ist ja nicht so das Gelbe...
Ich würde das gerne mit einem Timer im Hintergrund machen. Da ich aber 
doch noch sehr neu in der ganzen Sach bin, würde ich mich über einen 
Denkanstoß freuen... Keine komplette Lsg.

Ich hab jetzt schon rausgefunden, dass es Timervectoren gibt, in denen 
ich Code ausführen lassen kann, wenn ein Timer überläuft. Aber so recht 
bringt mich das noch nicht weiter...

Hier ist erstmal der Code mit Trödelschleifen:

uint8_t status = 0;
uint8_t lde = 0;

if (status == 0) {
  if (led == 0) {
    PORTD ^= (1 << PD5);
    _delay_ms(50);
    led = 1;
  }
  if (led == 1) {
    PORTD ^= (1 << PD5);
    _delay_ms(1450);
    led = 0;
  }
} else if (status == 1) {
  if (led == 0) {
    PORTD ^= (1 << PD5);
    _delay_ms(50);
    led = 1;
  }
  if (led == 1) {
    PORTD ^= (1 << PD5);
    _delay_ms(50);
    led = 2;
  }
  if (led == 2) {
    PORTD ^= (1 << PD5);
    _delay_ms(50);
    led = 3;
  }
  if (led == 3) {
    PORTD ^= (1 << PD5);
    _delay_ms(1350);
    led = 0;
  }

} else if (status == 2) {
  if (led == 0) {
    PORTD ^= (1 << PD5);
    _delay_ms(50);
    led = 1;
  }
  if (led == 1) {
    PORTD ^= (1 << PD5);
    _delay_ms(50);
    led = 0;
  }
} else {
  PORTD &= ~(1 << PD5);
}



Viele Grüße,
Matthias

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stell dir einen Timer auf 50ms Periodendauer (CTC-Mode) ein.
In der ISR zählst du dann eine Variable herunter, die dir den 
Umschaltzeitpunkt signalisiert.
Wurde umgeschaltet, lädt man die Variable mit dem nächsten 
Countdownwert...
Die Werte schreibt man vorher in ein Array und muss dann nur noch den 
Wert, der duch den Index beschrieben wird in die Zähövariable laden.

Autor: zaphod_beebelbrox (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super, danke!

Bin jetzt schon mal ein ganzes Stück weiter und freunde mich mit
ISR(TIMER2_COMP_vect){
TCCR2 |= (1<<WGM21) | (1<<COM20) | (1<<CS20) | (1<<CS22);
TIMSK |= (1<< OCIE2);
und Co. an.

Wird heut noch was :-)

VG,
Matthias

Autor: zaphod_beebelbrox (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich habe fertig :-)

Das ist bei rausgekommen:
  uint16_t leuchtzeiten[3][4] = {
      { 30, 860, 0, 0 },
      { 30, 30, 30, 800 },
      { 30, 30, 0, 0 } };
  TCCR2 |= (1<<WGM21) | (1<<COM20) | (1<<CS20) | (1<<CS22);
  TIMSK |= (1<< OCIE2);
  OCR2=255;
  sei();
  PORTD |= (1<<PD5);
  while (1) {
    if (Taster.t1)
      status = 1;
    else
      status = 0;

    if (counter >= leuchtzeiten[status][phase]) {
      counter = 0;
      if (phase < 3) {
        phase++;
      } else
        phase = 0;
      PORTD ^= (1<<PD5); // LED toggeln
    }
  }


Ist sicherlich noch nicht so 100% aber es funktioniert!

Viele Grüße & danke nochmal für den Tipp,
Matthias

Autor: zaphod_beebelbrox (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Natürlich noch das dazu:
ISR(TIMER2_COMP_vect) {
  counter++;
}

Autor: Ulf Rolf (roolf)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut, dass schonmal etwas läuft.

* Du hast immer noch im Hauptprogramm eine Schleife, die sich um alles 
kümmern muss.

Ausgehend von obiger Lösung verlegst Du jetzt noch einen Teil in die 
Interrupt-Routine. Vorschlag: Die Kommunikation erfolgt über Variablen: 
status wird von main geschrieben und vom Interrupt gelesen, phase 
wird alleine vom Interrupt benutzt, ebenso counter.

Damit ist main völlig unabhängig und braucht außer dem Schreiben von 
status bei einem Statuswechsel sich überhaupt nicht mehr mit dem Blinken 
zu befassen.

* Du setzt COM20 und das sorgt dafür, dass am IO-Port "OC2" ein Signal 
ausgegeben wird (falls dieser Pin auch als Ausgang geschaltet ist). Das 
ist für Debugzwecke oder in anderen Zusammenhängen nützlich, hat aber 
mit Deinem Blinken nichts zu tun und ist daher überflüssig.

Autor: zaphod_beebelbrox (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, danke für den Tipp, hört sich sehr sinnig an!

Aber da komm ich an meine C-Grenze...
Ich habe das jetzt so gemacht:

blinker.c:

volatile uint8_t status;

int main(void) {
  DDRD = 0b11100011;
  TCCR2 |= (1<<WGM21) | (1<<CS20) | (1<<CS22);
  TIMSK |= (1<< OCIE2);
  OCR2=255;

  sei();
  PORTD |= (1<<PD5);
  while (1) {
    if (Taster.t1)
      status = 1;
    else
      status = 0;

}
interruptVectors.c:
uint8_t counter = 0;
uint8_t phase = 0;
volatile uint8_t status;
const uint16_t leuchtzeiten[3][4] = { 
    { 30, 860, 0, 0 }, 
    { 30, 30, 30, 800 }, 
    { 30, 30, 0, 0 } };


ISR(TIMER2_COMP_vect)
{  counter++;

  if (counter >= leuchtzeiten[status][phase]) {
    counter = 0;
    if (phase < 3)
      phase++;
    else
      phase = 0;
    PORTD ^= (1<<PD5);
  }
}

Aber es tut sich nichts... Bei einem TAstendruck leuchtet die LED 
einmal, beim Loslassen ein weiteres mal...

Ist der Fehler für jemanden von euch ersichtlich?

Viele Grüße,
Matthias

Autor: zaphod_beebelbrox (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, Problem gelößt. Falscher Datentyp. uint8 kann schwer die gewünschte 
Pausenzeit von 860 erreichen O_o

Jetzt aber mal ne andere Frage:

Warum funktioniert das Programm auch, wenn ich vor keine der Variabeln 
extern, volatile oder ähnliches schreibe. Es compiliert und läuft in 
dieser Form:

intteruptVectors.c:
uint8_t status;
const uint16_t leuchtzeiten[3][4] = { { 30, 860, 0, 0 }, { 30, 30, 30, 800 }, {
    30, 30, 0, 0 } };
uint8_t phase = 0;
uint16_t timer = 0;

ISR(TIMER2_COMP_vect)
{
  timer++;
  if (timer >= leuchtzeiten[status][phase]) {
    timer = 0;
    if (phase < 3)
      phase++;
    else
      phase = 0;
    PORTD ^= (1<<PD5);
  }
}

blinker.c
uint8_t status;
int main(void) {
  DDRD = 0b11100011;
  TCCR2 |= (1<<WGM21) | (1<<CS20) | (1<<CS22);
  TIMSK |= (1<< OCIE2);
  OCR2=255;

  sei();
  PORTD |= (1<<PD5);
  while (1) {
    if (Taster.t1)
      status = 1;
    else
      status = 0;
  }
}

Viele Grüße & schönen Nikolaus!

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hast du die Codeoptimierung an??

Wenn nicht, dann liegt es daran. volatile saget dem Compiler nur, dass 
er diese Variable nicht irgendwie optimieren darf, da sich diese während 
der Programmabarbeitung ändern kann (z. B. durch eine ISR)

Autor: zaphod_beebelbrox (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe mit OPT={s|0|3} probiert. Der Code ist immer gleich groß und 
verhält sich immer gleich.

Naja, ich mach erstmal an anderen Baustellen weiter.

Danke jedenfalls allen Helfern :-)

Viele Grüße,
Matthias

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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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