Forum: Mikrocontroller und Digitale Elektronik Problem mit Timer1/Compare Atmega32


von Harald (Gast)


Lesenswert?

Hallo,

ich bekomme die Compare-Funktion am Timer1(16-Bit) einfach nicht zum 
Laufen.
PD4 und PD5 werden einfach nur gesetzt, und dann passiert nix mehr.

Möglicherweise mache ich beim Schreibzugriff auf die 
16bit-Compare-Register was falsch?

Hier mal der Code:

Initialisierung:
1
void init()
2
{
3
  DDRD = 0xFF; //Port D als Ausgang; Compare-Ausgänge liegen auf PD4 und PD5
4
  TCCR1A |= (1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0); //Compare Match setzt die Ausgänge
5
  TCCR1B |= (1<<CS12);    //Timer mit clk/256
6
}

Main:
1
int main()
2
{
3
  OCR1AH = 0xAA;
4
  OCR1AL = 0x00;
5
  OCR1BH = 0x33;
6
  OCR1BL = 0x00;
7
  init();
8
  while(1);
9
}

Gruß,
Harald

von Johannes M. (johnny-m)


Lesenswert?

Harald wrote:
> Möglicherweise mache ich beim Schreibzugriff auf die
> 16bit-Compare-Register was falsch?
Nicht direkt falsch, aber Du solltest, wenn Du schon komfortabel in C 
programmierst, auch die Möglichkeiten der 16-Bit-Zugriffe, die der 
Compiler bietet, nutzen. Dann macht der Compiler nämlich die 
Zugriffsreihenfolge automatisch korrekt. Also
1
OCR1A = 0xAA00;
2
OCR1B = 0x3300;
Und wenn Du das ganze noch übersichtlich machen willst, dann schreib 
direkt den Dezimalwert rein, also
1
OCR1A = 43520;
2
OCR1B = 13056;
Dann hast Du direkt die Zykluszahlen vor Augen, und das ist doch das, 
was man will...

Allerdings werden mit Deiner Konfiguration die Ausgänge tatsächlich nur 
einmal gesetzt (so steht es im Kommentar), wenn das jeweilige 
Compare-Ereignis eintritt, und dann passiert nix mehr. Wenn Du noch 
sagst, was der Controller Deiner Meinung nach machen sollte , dann 
kann man vielleicht noch weiterhelfen.

von Harald (Gast)


Lesenswert?

Hallo Johannes,

vielen Dank für Deine Antwort.
Ich finde die Stelle im Datenblatt jetzt leider nicht mehr, aber ich 
könnte schwören, daß ich was gelesen hätte, daß die Ausgänge beim 
Zählerüberlauf zurückgesetzt werden... ...wenn ich mich da täusche, ist 
anatürlich klar, daß die gesetzt bleiben...

Gruß,
Harald

von Johannes M. (johnny-m)


Lesenswert?

Harald wrote:
> Ich finde die Stelle im Datenblatt jetzt leider nicht mehr, aber ich
> könnte schwören, daß ich was gelesen hätte, daß die Ausgänge beim
> Zählerüberlauf zurückgesetzt werden...
Wenn Du einen PWM-Modus einstellst, dann werden sie auch bei Erreichen 
des TOP-Wertes zurückgesetzt. Du hast aber keine PWM-Betriebsart 
eingestellt, also klappt das so nicht. Schau mal in die Tabelle im 
Datenblatt bei der Beschreibung der Steuerregister von Timer 1. Da 
stehen die ganzen Modi und wie man die WGM-Bits entsprechend setzen 
muss.

von Harald (Gast)


Lesenswert?

Hallo Johannes,

dann muss ich das verwechselt haben.
Ich möchte eigentlich den normalen Mode benutzen.
Wie bekomme ich die Ports dann zurückgesetzt? Die Compare Unit 
überschreibt ja die "normale" Funktion der Pins, müsste ein einfaches 
Zurücksetzen funktionieren, wenn man es an den Überlauf-Interrupt 
bindet?

Gruß,
Harald

von Johannes M. (johnny-m)


Lesenswert?

Harald wrote:
> Ich möchte eigentlich den normalen Mode benutzen.
> Wie bekomme ich die Ports dann zurückgesetzt? Die Compare Unit
> überschreibt ja die "normale" Funktion der Pins, müsste ein einfaches
> Zurücksetzen funktionieren, wenn man es an den Überlauf-Interrupt
> bindet?
Klar kann man den Zustand des Pins jederzeit "von Hand" (also im 
Programm) ändern, aber wozu der Umstand? Der µC kann das auch ganz 
allein, ohne Interrupt und so.

von Harald (Gast)


Lesenswert?

Hallo,

ich benötige die volle Auflösung des Timers für meine Anwendung, daher 
der Aufwand. Wenn ich das Datenblatt richtig interpretiere, stehen mir 
die vollen 16 bit nur im Mormalmodus zur Verfügung.

Gruß,
Harald

von Johannes M. (johnny-m)


Lesenswert?

Harald wrote:
> ich benötige die volle Auflösung des Timers für meine Anwendung, daher
> der Aufwand. Wenn ich das Datenblatt richtig interpretiere, stehen mir
> die vollen 16 bit nur im Mormalmodus zur Verfügung.
Falls Du kein Input Capture verwendest, kannst Du den PWM-Modus mit ICR1 
als TOP-Wert benutzen. Dann hast Du die volle Auflösung.

von Harald (Gast)


Lesenswert?

Hatte ich wohl überlesen.
Besten Dank! Funktioniert jetzt!

von Harald (Gast)


Lesenswert?

Hallo nochmal,

Bei dem ganzen geht es darum, daß ein Ventil, eine Zündvorrichtung und 
ein Messlaser in einer genau definierten zeitlichen Abfolge angesteuert 
werden sollen. Genau heißt in diesem Zusammenhang auf ca. 10...100us 
genau. Dabei soll die Sequenz als Reaktion auf ein externes 
Triggersignal ebenfalls innerhalb 10...100us gestartet und einmalig 
durchlaufen werden.

ich hab jetzt versucht, das ganze, wie beschrieben, in einem der 
PWM-Modi zu lösen, was daran scheitert, daß die Werte für die 
Compare-Register erst beim nächsten Timerüberlauf übernommen werden. Lt. 
Datenblatt ist das im Normalmodus nicht so; da werden die Werte sofort 
übernommen.

Mein momentaner Lösungsansatz sieht folgendermaßen aus:

- wenn das Triggersignal ankommt, wird Timer1 gestartet und soll dann zu 
den in den Comparregistern voreingestellten Werten die entsprechenden 
Ausgänge setzen. Es soll also fogender Ablauf stattfinden:

Eingabe der Zeiten -> Startsignal -> übernahme der aktuellen 
Compare-Werte in die Register -> Start des Timers -> Ausführen der 
Compare Matches -> Timerüberlauf -> stoppen des Timers -> Eingabe der 
Zeiten...

-In den PWM-Modi gibt es nun das Problem, daß die Werte erst beim 
nächsten Überlauf tatsächlich in die Register übernommen werden. Da der 
letzte Überlauf aber bereits eingetreten ist, wenn der Timer am Ende der 
Sequenz gestopt ist, läuft der Vorgang erst nochmal mit den alten Werten 
ab und erst beim übernächsten Durchlauf werden die neuen Werte 
verwendet.

Im Normalmodus werden werden die Werte zwar sofort übernommen; dafür 
konnte ich bisher nicht herausfinden, wie ich die Compare-Ausgänge 
wieder zurückgesetzt bekomme (Was in den PWM-Modi automatich beim 
Überlauf geschieht).

Oder ist der Timer überhaupt der falsche Lösungsansatz für diese Art 
Problem?

Gruß,
Harald

von Johannes M. (johnny-m)


Lesenswert?

Du kannst doch den Timer (im Normalmodus) einfach durchlaufen lassen und 
jeweils im Interrupt Handler einen neuen Wert in das betreffende 
Compare-Register laden. Den dazugehörigen Pin stellst Du auf "toggle at 
compare match". Dann kannst Du im Prinzip beliebige Sequenzen erzeugen.

Beispiel:
Es soll ein 500 µs langer Impuls ausgegeben werden. Anschließend 1 ms 
Pause. Dann ein 2 ms langer Impuls. Dann 5 ms Pause. Dann ein 200 µs 
langer Impuls.
0.: Timer wird so getaktet, dass ein Takt 1 µs entspricht
1.: OCR1A = 500, Timer starten, Pin setzen (1)
2.: Wenn TCNT1 500 erreicht -> Compare Match Interrupt, gleichzeitig 
wird der Pin automatisch auf Null gesetzt
3.: Im Interrupt Handler wird zu OCR1A 1000 hinzuaddiert (für 1 ms, in 
OCR1A steht dann 1500)
4.: Nach insgesamt 1500 µs (also 1000 µs nach dem letzten Interrupt) 
gibt's wieder ein Compare Match, Pin wird wieder 1
5.: Im Interrupt Handler zu OCR1A 2000 hinzuaddieren (für 2000 µs, also 
2 ms)
6.: usw. Rest dürfte klar sein...

Im Prinzip kannst Du auch mit beiden Compare-Einheiten gleichzeitig 
arbeiten, musst nur aufpassen, dass die sich bei zu kurzen Zeiten nicht 
in die Quere kommen (Interrupt-Latenzen, Overhead durch die Interrupt 
Handler).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.