mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ISR(TIM0_COMPA_vect)


Autor: Franz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte alle 16µs einen Pin togglen. Leider macht der Pin mit 
folgendem Code an meinem ATtiny13 überhaupt nichts. Wenn ich ihn in der 
while(1)-Schleife toggle, dann funktioniert es wunderbar. Es scheint 
also, als würde die ISR nicht aufgerufen werden. Wo liegt der Fehler in 
meinem Code?
#include <avr/io.h>
#include <avr/interrupt.h>

#define PORT PORTB
#define DDR  DDRB
#define PIN  PB2

ISR(TIM0_COMPA_vect)
{
  PORT ^= (1 << PIN);
}

int main()
{
  // CPU
  CLKPR = (1 << CLKPCE);        // CPU-Frequenz-Umschalter: Ein
  CLKPR = (0 << CLKPCE);        // CPU-Frequenz auf 9.6MHz

  // Timer
  TIMSK0   |= (1 << OCIE0A);    // Compare Match Interrupt
  TCCR0A   |= (1 << WGM01);     // CTC-Modus
  TCCR0B   |= (1 << CS00);      // Vorteiler: 8
  OCR0A     = 17;               // Alle 16µs ein Interrupt

  // Port
  DDR |= (1 << PIN);

  while(1)
  {
    asm volatile("nop");
  }
}

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sei fehlt...

Autor: Franz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> sei fehlt...
Danke. Jetzt funktioniert es!

Nächste Frage: Ich möchte, dass der Port mit 72kHz togglet (alle 14µs) 
um IR-Licht zu modulieren, das mit einem TSOP1736 empfangen werden soll. 
Leider liegt die aktuelle Frequenz bei 263kHz (toggle alle 3.8µs).

Meine Berechnung für OCR0A habe ich wie folgt angegangen:

Der Timer läuft mit 9.6MHz/8:
TCCR0B   |= (1 << CS00);      // Vorteiler: 8
Er erhöht also seinen Zählwert alle 0.8µs. Nach 17-maligem Hochzählen 
sind 14µs vergangen:
OCR0A     = 17;               // Alle 14µs ein Interrupt

Meine Fragen:
1. Ist meine Vorgehensweise für die Lichtmodulation sinnvoll?
2. Warum ist meine Toggle-Frequenz zu hoch?

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du könntest eine PWM mit 1:1 Tastverhältnis nehmen,
da muss der mc nicht so malochen ...

Autor: Franz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Du könntest eine PWM mit 1:1 Tastverhältnis nehmen

Daran habe ich auch schon gedacht, aber leider kann ich die nicht auf 
36kHz einstellen. :-(

Autor: Jörg G. (joergderxte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besser wäre es, wenn du PB0 benutzen würdest/könntest, den kann der 
Timer im CTC-Modus von alleine togglen:
// #define F_CPU 1200000 // SOLLTE bereits definiert sein
#define FREQ 36000  // Ausgabefrequenz in Hz
// init.:
  DDRB = (1<<PB0);
  OCR0A = (F_CPU + FREQ)/ (FREQ * 2); //korrekt runden
  TCCR0A = (1<<COM0A0)|(1<<WGM01); //toggle OC0A on match, CTC-mode
  TCCR0B = (1<<CS00); // kein Prescaler
Jetzt gibt der attiny die 36kHz (35,2kHz - FALLS der interne oszillator 
so genau ist) aus, ohne interrupt, etc.
An-/Ausschalten (zum modulieren) geht über das COMxyz- oder das 
CSxz-Bit.

hth, Jörg

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>aber leider kann ich die nicht auf 36kHz einstellen.

und warum nicht?

Autor: Franz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen herzlichen Dank! :-)

Autor: Franz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe das ganze jetzt auf einen ATmega8 portiert, da ich die Daten, 
welche gesendet werden sollen, auf der UART empfangen möchte. Die 
CPU-Frequenz liegt bei 8MHz.
#include <avr/io.h>
#include <avr/interrupt.h>

#define FREQ 36000
#define PIN  PB1
#define DDR  DDRB
#define PORT PORTB

int main()
{
  // Port
  DDR |= (1 << PIN);

  // Timer
  OCR1A  = (F_CPU + FREQ) / (FREQ * 2); // Frequenz korrekt runden
  TCCR1A = (1 << COM1A0)|(1 << WGM12);  // OC1A togglen, CTC-mode
  TCCR1B = (1 << CS10);                 // Vorteiler: 1

  // Interrupts: An
  sei();

  while(1)
  {

  }
}
Leider togglet der Pin mit 14Hz (alle 70ms) und nicht mit 72kHz.

Wo liegt mein Fehler?

Danke für die aufschlussreichen Antworten! :-)

Autor: Jörg G. (joergderxte)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
WGM12 steht in einem anderen Register. (Du  toggelst im Moment alle 
65536 Takte)

hth, Jörg
edit: Mist gelöscht

Autor: Franz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles klar, ich habe es angepasst. WGM12 steht in TCCR1B

Jetzt habe ich folgenden Code:
#include <avr/io.h>
#include <avr/interrupt.h>

#define FREQ 36000

#define PIN  PB1
#define DDR  DDRB
#define PORT PORTB

int main()
{
  // Port
  DDR |= (1 << PIN);

  // Timer
  OCR1A  = (F_CPU + FREQ) / (FREQ * 2); // Frequenz korrekt runden
  TCCR1A = (1 << COM1A0);               // OC1A togglen
  TCCR1B = (1 << CS10) | (1 << WGM12);  // Vorteiler: 1, CTC-Modus

  // Interrupts: An
  sei();

  while(1)
  {

  }
}
Leider togglet der Pin jetzt alle 120µs (8.3kHz).

Autor: Franz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die CPU-Frequenz war auf 1MHz eingestellt. Jetzt funktioniert es 
einwandfrei! :-)

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.