www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem mit Interrupt bei Timer ATtiny24


Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wollte eine PWM-Zeitschaltuhr bauen - PWM wird durch Potti geregelt 
und mit ADC gelesen und umgesetzt. Funzt gut.

Jetzt soll der 2. Timer dazu dienen Das Signal An/Aus zu schalten nach 
einer Festen Zeit.

Momentan wollte ich nur mal den Interrupt Testen und die Schaltung EIN 
schalten. Aber nichts passiert.

Der Interrupt scheint nicht ausgeführt zu werden.

Hier mein Code:
#include "headers.h"

// Globaler Status AN/Aus
  int status;



ISR(SIG_OUTPUT_COMPARE1A)
{

    status = 1;
}




int main (void)

{

  uint16_t MyADC;
  uint8_t tast;

  // OC0A is Output
  DDRB |= (1<<PB2);

  // Timer 1 Vorbereiten für Ein/Aus
  // Clear on Compare Match, Vorteiler 256
  TCCR1B = (1<<WGM12) | (1<<CS12);

  // Compare Match Interrupt an!
  TIMSK1 = (1<<OCIE1A);

  // Setze Compare Wert für genaue Sekunde
  OCR1A = 0x3BFF;


  sei();



  while (1)
  {


    if (status==1)
    {

      // ADC holen, konvertieren und PWM einstellen
      MyADC = getADC(PWM);

      tast = convertADC(MyADC);

      SetPWM(tast);

    }
    else
    {
    // Schalte PWM ab!
    TCCR0A = 0;
    }


  }

  return 0;
}


und hier die Funktionen:
uint16_t getADC(uint8_t mux)
{

  // Kleinste gemessene Spannung 2,64 V

  uint8_t i;
  uint16_t result;
 
  ADMUX = mux;                      // Kanal waehlen
  
 
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0);    // Frequenzvorteiler 
                               // setzen auf 32 (1) und ADC aktivieren (1)
 
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
  while ( ADCSRA & (1<<ADSC) ) {
     ;     // auf Abschluss der Konvertierung warten 
  }
  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.
 
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
  result = 0; 
  for( i=0; i<4; i++ )
  {
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) {
      ;   // auf Abschluss der Konvertierung warten
    }
    result += ADCW;        // Wandlungsergebnisse aufaddieren
  }
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
 
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert
 
  return result;
}



void SetPWM (uint8_t intense)
{



    // Phase Correct PWM
    TCCR0A = (1<<COM0A1) | (1<<WGM00);

    // Clock / 64 = 121 Hz
    TCCR0B = (1<<CS01) | (1<<CS00);
 
     
    //Tastverhältnis ändern
    OCR0A = intense;

    TIMSK0 = (1<<OCIE0A);

    sei();

}


uint8_t convertADC(uint16_t MyADC)
{

  uint16_t dummy16;
  uint8_t dummy8;

  // Minimaler ADC wert in dieser Schaltung ist 490
  dummy16 = MyADC - 490;

  // Um eine 10er Potenz anheben
  dummy16 = dummy16*10;

  // So teilen, dass max. 255 herauskommen kann!
  dummy8 = dummy16 / 21;


  return dummy8;

}


Ich hab auch schon im Datenblatt geschaut - der richtige Interrupt 
Vector ist Vector 7 - das deckt sich mit den io files und stimmt.

Warum geht das nicht?
Kann jemand einen Fehler entdecken oder weiß jemand was ich falsch 
mache?

Gruß
Chris

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
status muss volatile sein.

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab es geändert, leider ohne Erfolg.
Trotzdem danke für den Tip.

Jetzt steht:
volatile int status;

Nach wie vor schaltet sich das PWM nicht ein.


Gruß
Chris

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TIMSK0 = (1<<OCIE0A)

Du aktivierst den IQR für Output Compare Kanal A vom Timer 0, aber wo 
ist die ISR in deinem Source dazu ? Es wird bei nicht deklarierten ISR 
Handlern ein Default Vector durch GCC erzeugt der auf den RESET Vektor 
zeigt. Beim OC0A-IRQ machst du also einen Reset.

Statt das Status Register zu setzen probiere mal

DDRB &= ~(1 << PB2);

und mache ansonsten per ADC eine Dauermessung. Dh. dein ADC Code + PWM 
läuft immer nur der Ausgang PB2=OC0A wird aktiviert und deaktiviert.

Gruß Hagen

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

danke das war schon mal ein Teil des Fehlers! Ich wollte TIMSK0 gar 
nicht setzten! Danke.

Habe also das TIMSK0 in der Funktion entfernt und die Main so umgebaut:

ISR(_VECTOR(6))
{

PORTB |= (1<<PB2);
}




int main (void)

{

  uint16_t MyADC;
  uint8_t tast;

  // OC0A is Output
  DDRB |= (1<<PB2);

  // Timer 1 Vorbereiten für Ein/Aus
  // Clear on Compare Match, Vorteiler 256
  TCCR1B = (1<<WGM12) | (1<<CS12);

  // Compare Match Interrupt an!
  TIMSK1 = (1<<OCIE1A);

  // Setze Compare Wert für genaue Sekunde
  OCR1A = 0x3BFF;



  sei();



  while (1)
  {




  }

  return 0;
}


Er tut zwar jetzt etwas, aber laut Code sollte PB2 angeschalten werden 
und an bleiben. Es gibt nichts gegenteiliges - es soll in einer 
Dauerschleife "Enden".

Was ich bekomme ist aber ein Blinken - anscheinend wird jedesmal ein 
Reset ausgelöst.

Im Datenblatt steht InterruptVector 7 - es geht aber nur mit Vector 6.

Irgendwie ist da noch der Wurm drinn.

Weiß noch jemand etwas?

Gruß
Chris

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh man, ich wollte gerade meinen Platz aufräumen und alles aus machen - 
da mach ich den ISP stecker von der Schaltung und siehe da - es läuft 
wie erwartet!

Was kann der ISP Stecker damit zu tun haben? Hab ich trotzdem noch nen 
Fehler in der Software?

Gruß
Chris

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Im Datenblatt steht InterruptVector 7 - es geht aber nur mit Vector 6.

Das ist bloß eine unterschiedliche Zählung.
Benutze einfach den richtigen Namen (in diesem Fall TIM1_COMPA_vect) und 
kümmer dich nicht um die Nummern.

> Was kann der ISP Stecker damit zu tun haben?

Nun, der hängt immerhin auch mit an Reset. Entweder der Programmer macht 
da Dinge, die er nicht machen sollte, oder du fängst dir einfach über 
die Leitung Störungen ein, die zu Resets führen.

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
in der jetzigen ISR hast du

PORTB |= (1<<PB2);

stehen, warum nicht

DDRB &= ~(1 << PB2);

wie von mir vorgeschlagen ? Du möchtest doch das an diesem Pin eine 
zuschaltbare PWM möglich wird. Dann wirst du mit PORTB |= (1<<PB2); nur 
diesen Pin auf High Pegel setzen statt ihn als Ausgang ein/aus zu 
schalten.

Wenn das später funktioniert musst du dich fragen ob das vom Timing her 
so passt. Mit dieser Lösung schaltest du uU. mitten in einem PWM Zyklus 
diese am Pin ein oder aus. Das könnte uU. störend sein, hätte aber den 
Vorteil das du deine PWM exakt im Timing vom Timer1 ein/aus schalten 
kannst. Möchtest du die PWM phasensynchron ein/aus schalten so musst du 
im TIM1_COMPA_vect erstmal eine globale als volatile deklarierte 
Variable setzen. Dann benutzt du den TIM0_OVF_vect um diese Variable 
abzufragen und entsprechend das DDRB.PB2 Bit setzen.

Gruß Hagen

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Leute, Danke Hagen.

Also dass ich den Pin gesetzt habe, war jetzt einfach nur mal zum 
testen.

Wenn ich das Programm jetzt fertig mache, werd ich es Phasenrichtig 
machen, da es Schaltzeiten von mehreren Sekunden, bzw. Minuten sind - da 
kommt es auf das 10tel da nicht an. Ist völlig unkritisch hier.

Daher werd ich wohl Phasenrichtig abschalten.

Jetzt funktioniert auf jeden Fall alles so, wie es soll.

Gruß
Chris

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.