Forum: Mikrocontroller und Digitale Elektronik ATmega8 Timer1+Timer2 PWM


von Tanja M. (Gast)


Lesenswert?

Guten morgen Jungs!
Ich bin recht neu in der Mikrocontroller-Welt und habe kleine 
Verständnissprobleme. Desweiteren programmiere ich in der Sprache C und 
arbeite mit dem CoderVisionAVR, dem STK500 Board und einem ATmega8.

Hierbei geht es um die beiden Timer 1 und Timer 2 die beide die PWM 
Funktion haben.
Ich habe mich durch das Datenblatt gewurschtelt und versucht zu 
verstehen.
Die Register zu schreiben ist mir denk ich ganz gut gelungen, mein 
Problem liegt viel mehr bei dem Verständniss des mathematischen bzw. 
physischen Teil.

Timer 2 ist relativ einfach wobei mir da der Prescaler Probleme 
bereitet, da ich nicht verstehe, wie ich zu rechnen habe um auf meine 
gewünschten 10Hz zu kommen. Ich zeig euch mal was ich bis jetzt mit den 
Timer 2 erreicht habe.
1
// Timer/Counter 2 initialization
2
// Clock source: System Clock
3
// Clock value: 1000,000 kHz
4
// Mode: Fast PWM top=FFh
5
// OC2 output: Non-Inverted PWM
6
ASSR=0x00;
7
TCCR2=0x6F;       
8
TCNT2=0x3C;
9
OCR2=0x50;

TCCR2=0b01111111 heißt:
- Bit 7: FOC2 aus
- Bit 6 und 3: Fast PWM Mode
- Bit 5 und 4: OC2 setzen bei Compare Match, OC2 bei Top löschen (die 
Einstellung irritiert mich etwas, da ich mit dem Overflow Interrupt 
arbeiten möchte)
- Bit 2 und 1 und 0: Prescaler 1024

Mein Problem ist nun, dass ich die Register TCNT2 und ORC2 nicht richtig 
setzte. Ich vertsehe nicht wie ich die Bits setzten muss, um meine 
gewünschten 10Hz zu erlangen.
Ich weiß schonmal das TCNT2 für die feste Frequenz zuständig ist und 
OCR2 für die Pulsweiter. Nur wie errechne ich das so, dass ich 10Hz 
bekomme?


Kommen wir zu Timer 1, bei dem verstehe ich noch viel weniger als bei 
Timer 2. Ich steige durch diese ganzen Lows und Highs nicht mehr durch 
(OCR1AL/OCR1AH, TCNT1H/TCNT1L usw.).
Aber ich hoffe das ich zumindest die Register TCCR1A und TCCR1B richtig 
geschrieben habe, auch hier soll mit einem Interrupt gearbeitet werden, 
deswegen bringen mich diese ganzen Compare Matchs total durcheinander.
Aber auch hier möchte ich euch das erarbeitete nicht vorenthalten.
1
// Timer/Counter 1 initialization
2
// Clock source: System Clock
3
// Clock value: 1000,000 kHz
4
// Mode: Fast PWM top=00FFh
5
// OC1A output: Non-Inv.
6
// OC1B output: Non-Inv.
7
// Noise Canceler: Off
8
// Input Capture on Falling Edge
9
// Timer 1 Overflow Interrupt: On
10
// Input Capture Interrupt: Off
11
// Compare A Match Interrupt: Off
12
// Compare B Match Interrupt: Off
13
TCCR1A=0xA1;
14
TCCR1B=0x09;
15
TCNT1H=0x00;
16
TCNT1L=0x3C;
17
ICR1H=0x00;
18
ICR1L=0x00;
19
OCR1AH=0x00;
20
OCR1AL=0xFE;
21
OCR1BH=0x00;
22
OCR1BL=0x7A;

TCCR1A=0b10100001 heißt:
- Bit 7 und 6: OC1A/OC1B bei Compare Match löschen und auf TOP setzten
- Bit 5 und 4: OC1A/OC1B bei Compare Match löschen und auf TOP setzten
- Bit 3 und 2: Kein FOC1A und FOC1B
- Bit 1 und 0: Fast PWM Mode

TCCR1B=0b00001001 heißt:
- Bit 7: Input Capture Noise Canceler aus
- Bit 6: Input Capture Edge aus
- Bit 5: Reserve Bit
- Bit 4 und 3: Fast PWM Mode
- Bit 1 und 0: Prescaler aus

Ich verstehe nun nicht in welchen Verhältnissen die Register 
TCNT1H/TCNT1L, ICR1H/ICR1L, OCR1AH/OCR1AL, OCR1BH/OCR1BL zueinander 
stehen.
Ich hab zwar verstanden, dass ich mit TCNT1H/TCNT1L glaub ich die 
Frequenz vorgebe und OCR1AH/OCR1AL seinen Wert mit dem Wert von 
TCNT1H/TCNT1L abgleicht, aber irgendwie komm ich mit den anderen beiden 
Registern umsoweniger klar.
Auch bei diesem Timer hätte ich gern eine Taktfrequenz von 10Hz, kann 
man sich das irgendwie errechnen oder fehlt mir in dem Punkt das 
logische Denken?

Ich würde mich über eure Unterstützung sehr freuen!

Viele liebe Grüße
Tanja M.

von Stefan (Gast)


Lesenswert?

Hi Tanja,
bevor dir hier irgenjemand helfen kann solltest du erst mal erklären was 
du eigentlich willst.
Benötigdt du ein bestimmtes PWM Signal ?
Was ist mit diesen 10 Hz, wofür?
........
Dann kann man erst mal die prinzipielle Idee für eine Umsetzung 
diskutieren und erst dann wird es Zeit für Codeschnipsel.

Ich glaube im Augenblick besteht wirklich ein Logik-Problem
Gruß
Stefan

von Johannes M. (johnny-m)


Lesenswert?

Du hast anscheinend bei beiden Timern eine 8-Bit-Fast-PWM eingestellt. 
Die hat einen festen TOP-Wert (nämlich 0xFF). Da es aber der TOP-Wert 
ist, der die Frequenz des Signals bestimmt (in Zusammenarbeit mit dem 
Prescaler) wirst Du vermutlich nie auf exakt 10 Hz kommen. Bei einem 
8-Bit-Timer sind Frequenzen in dem Bereich sowieso nur bei relativ 
geringen Oszillator-Takten möglich (10*256*1024 = ca. 2,6 MHz). Da Du 
nicht schreibst, mit welchem Takt Du den Controller betreibst, kann ich 
nicht sagen, ob das in Deinem Fall überhaupt funktionieren kann. Um 
allerdings eine bestimmte Frequenz möglichst genau einstellen zu können, 
brauchst Du einen PWM-Modus, der es gestattet, den TOP-Wert selbst 
festzulegen. Diese Möglichkeit gibt es aber nur bei Timer 1.

Außerdem solltest Du Dir vielleicht das AVR-GCC-Tutorial mal näher 
ansehen. Da stehen die Grundfunktionen drin. Und der Code Generation 
Wizard von CodeVision ist zwar ne tolle Sache, wenn man mal eben schnell 
einen Programmrumpf erzeugen will, aber erstens sind die erzeugten 
Codeschnipsel sehr schwer zu warten (Wenn was geändert werden soll, muss 
auch der Kommentar entsprechend angepasst werden, die Darstellung der 
Bitzustände in Hexadezimalzahlen ist ohne Datenblattlektüre selbst für 
erfahrenere Programmierer unlesbar) und zweitens sorgt er dafür, dass 
keiner sich noch wirklich im Datenblatt (oder im oben erwähnten 
Tutorial) die entsprechenden Abschnitte gründlich genug durchliest, um 
die Zusammenhänge zu verstehen.

BTW:
> TCCR2=0x6F;
> ...
> TCCR2=0b01111111 heißt:
Da ist schon der erste Widerspruch: 0x6F entspricht 0b01101111. Bei Dir 
ist da eine 1 zuviel und eine 0 zu wenig.

von Tanja M. (Gast)


Lesenswert?

Oh entschuldigung. Natürlich sollte ich vielleicht erstmal den 
Sachverhalt erklären.
Es geht um volgendes. Ich möchte mit einem Timer eine 10Hz Frequenz 
erzeugen und per PWM  die Pulsweite ändern.
Dazu kommt noch ein AD Wandler den ich mit dem PWM Signal zusammenführen 
möchte, umd über einen 10-Gang-Poti die Pulsweite zwischen 0 und 200µs 
einzustellen.
Das ganze soll dann letztendlich einen MOSFET ansteuern.
Dazu möchte ich per LED die Frequenz zeigen nur die Pulsweite soll da 
dann x10 sein.

Ich hoffe ihr versteht in etwa was ich vorhabe.
Das ganze hat kein bestimmtes Ziel, es soll nur einen Lerneffekt geben.

Vielen Dank und liebe Grüße
Tanja

von Johannes M. (johnny-m)


Lesenswert?

Ich sehe grundsätzlich keine Probleme bei der Realisierung. Allerdings 
ändert das nichts an der Tatsache, dass gerade die Grundlagen in oben 
erwähntem AVR-GCC-Tutorial (und eben auch im Datenblatt) beschrieben 
sind und es wenig Sinn macht, alles noch mal zu schreiben. Außerdem 
stehen im AVR-Tutorial, genauer im Abschnitt AVR-Tutorial: Timer 
und im Artikel AVR PWM einige für Einsteiger wissenswerte 
Informationen (Auch wenn letztere sich nicht auf die Programmierung in C 
beziehen). Schau erst mal da nach und versuche, die Basics zu verstehen. 
Entweder kommst Du dann selber drauf, wie Du das alles zu einem Projekt 
zusammenschustern kannst, oder Du meldest Dich hier noch mal, wenn 
offene Fragen bestehen.

von Tanja M. (Gast)


Lesenswert?

Hi Johannes.
Ich hab mich sehr bemüht durch das Datenblatt zum Ziel zu kommen. Ich 
hab mir das Tutorial schon durchgelesen nur selbst da verstehe ich das 
nicht so wirklich. Deshalb wende ich mich ja nun auch direkt an euch, 
damit man mir das vielleicht nochmal spezifisch erklärt.

Mit welchem Takt ich den Controller betreibe stand ja im Code als 
Kommentar.
// Clock value: 1000,000 kHz

Deshalb dachte ich das ich das nicht nochmal erwähnen muss, tut mir 
leid.
Also ich betreibe den Controller mit seinen 1MH.

Das ist richtig, CideVision hat ein Wizardprogramm der dir die 
Grundeinstellungen abnimmt, aber wenn ich es nicht selbst verstehen 
wollen würde, was der da jetzt genau macht, würd ich mir ja nicht das 
Datenblatt zur Hand nehmen und jedes Bit was gesetzt wurde selber 
nochmal durchgehen und mit dem vergleichen was ich gerne möchte.
Hab ja nicht umsonst die Register für mich nochmal in Bits geschrieben.

> TCCR2=0x6F;
> ...
> TCCR2=0b01111111 heißt:

Ohja das war ein Tippfehler von mir, du hast natürlich vollkommen recht, 
0x6F ist nicht 0b01111111 sondern 0b01101111, danke!

Liebe Grüße
Tanja

von Peter P. (bonsaibaum)


Lesenswert?

hallo tanja ...

wie möchtest du den pwm denn einstellen ?
in % (0-100)
von 0-255
oder von 0-65535

ich frage nur, weil du den pwm ja auch in software machen könntest ... 
schliesslich ist 10Hz ja nicht gerade schnell ....

nebenbei könntest du dann ja auch mehr als 2 pwm laufen lassen ...

lg
  peter

kannst mir gerne mailen: peter (at) cyberbonsai (dot) de

von Johannes M. (johnny-m)


Lesenswert?

Nur so als kleiner Tip am Rande:
Und TOP ist, wie schon oben angedeutet, in einigen PWM-Modi bei einigen 
Timern frei wählbar.

Bei Deinen Einstellungen oben:
Das ergäbe so eine PWM-Frequenz von 3,9 kHz...

von Tanja M. (Gast)


Lesenswert?

Hallo Peter.

Also am besten wäre natürlich 0-100% und ob nun 0-255 oder 0-65536 ist 
nicht so wichtig, mit 0-65536 kann man sicherlich feiner einstellen aber 
die 0-255 reichen auch vollkommen aus. Wichtig ist halt auch, dass wenn 
das Poti ganz am Anschlag ist, also höchsten Widerstandswert, soll das 
Signal durchgehen 0 sein und andersrum dann durchgehend 1 also 5V.

Danke für deine Angebot bezüglich des mailens.

Liebe Grüße
Tanja

von Tanja M. (Gast)


Lesenswert?

Entschuldige Johannes, aber ich erkenne auf deinen Bildern irgendwie 
nichts, dass sind so Punkte und Striche, sehr pixelig....
Was wolltest du mir damit denn sagen?

Richtig ich wollte gern TOP selber bestimmen können. Und beim rechnen 
habe ich nicht einen Wert von 3,9kH bekommen sondern 3,8Hz. Mein 
Rechnung sieht so aus:

0,000001µs (meine 1MH) * 256 (die Schritte die der Timer dann zählt) * 
1024 (Prescaler) = 0.262144

1 / 0.262144 = 3,81Hz.

Wenn ich da jetzt nicht falsch gerechnet habe oder einen Denkfehler 
habe.
Wie kommst du denn auf 3,9kH?

Liebe Grüße
Tanja

von Peter P. (bonsaibaum)


Lesenswert?

indem er statt prescaler 1024 den prescaler 1 genommen hat

von Stefan (Gast)


Lesenswert?

Bei 1MHz Taktfrequenz hat man in 10ms 10.000 Taktzyklen.

Wenn der Timer 1 verwendet wird mit 16bit (65535) kann man das direkt 
zählen (ohne Prescale).

Mein Ansatz wäre folgender:

1) TCNT1H/L auf 65.535-10.000 setzen, damit erfolgt ein Überlauf des 
Timers nach 10ms
2) OCR1H/L (on compare match) auf einen Wert TCNT1 + X setzen,
  mit  0 < X < 10.000 . Damit wird die Pulslänge definiert.
3) Aktiviern des Interrupts für TC1 overflow und einen zugehörigen 
Interrupthandler schreiben, der die  Aktionen in 1) und 2) durchführt.


Das ganze ist schnell und präzise.

Gruß
Stefan

von Tanja M. (Gast)


Lesenswert?

Ups, ohja, hast recht!

von Tanja M. (Gast)


Lesenswert?

Danke Stefan das klingt schon sher plausibel, nur jetzt bekomme ich das 
Problem was ich wärend des ganze Projektes hatte. DU schreibst TCNT1H/L 
auf 65.535-10.000 setzten. Soll das jetzt heißen ich solle TCNT1H=65535 
und TCNT1L=10000 setzten? So hab ich das nämlich verstenden.... Kann 
sein das ich das falsch verstanden habe.

Punkt 2 klingt sehr logisch für mich und das Verständnis kommt langsam 
auf.
Nur OCR1H/L ist ja jeweils ein eigenes Register und muss ich Wetre bei 
OCR1A oder OCR1B setzten? Oder ist es egal?

>OCR1H/L (on compare match) auf einen Wert TCNT1 + X setzen,
>mit  0 < X < 10.000 . Damit wird die Pulslänge definiert.

Den Teil müsste ich dann im Interrupt definieren richtig? Was müsste ich 
OCR1(A? B?)H und OCR1(A? B?)L denn zuweisen? Wenn ich im Interrupt nur 
TCNT1 schreibe, weiß der Microkontroller dann was ich meine?

Danke für deine Hilfe.

Liebe Grüße
Tanja

von Tanja M. (Gast)


Lesenswert?

Kleine Ergenzung. Teil 1 hab ich verstanden. 65535-10000 ergibt 55535 
und das ist in Hex D8EF, dass D8 muss ich dann bei TCNT1H schreiben und 
das EF muss ich bei TCNT1L reinschreiben, richtig so?

Liebe Grüße
Tanja

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:
> Danke Stefan das klingt schon sher plausibel, nur jetzt bekomme ich das
> Problem was ich wärend des ganze Projektes hatte. DU schreibst TCNT1H/L
> auf 65.535-10.000 setzten. Soll das jetzt heißen ich solle TCNT1H=65535
> und TCNT1L=10000 setzten? So hab ich das nämlich verstenden.... Kann
> sein das ich das falsch verstanden habe.

Ja das hast du falsch verstanden.
Mit TCNT1H/L  ist das Registerpärchen TCNT1H und TCNT1L in seiner
Gesamtheit gemeint, den nur beide zusammen bilden den Timer.

> TCNT1H=65535
Wie soll das gehen? TCNT1H ist, wie alle Register, ein 8 Bit Register.
Da gehen maximal Zahlen bis 255 rein.

Aber: Wenn man die beiden physikalischen Register TCNT1H und TCNT1L
zusammen als ein logisches 16 Bit Register auffasst, dann ist das ein
16 Bit Register, in dem man bis 65535 zählen kann. Eine 16 Bit
Zahl besteht aus 2 Bytes, das Highbyte davon ist im Register TCNT1H
abzulegen, das Lowbyte davon im Register TCNT1L

65535 - 10000 = 55535
Als Hexzahl ausgedrückt: D8EF

Also kommt 0xD8 in das Register TCNT1H
und 0xEF in das Register TCNT1L

oder in Code

  TCNT1H = ( 65535 - 10000 ) >> 8;   // das Highbyte berechnen
  TCNT1L = ( 65535 - 10000 );        // das Lowbyte berechnen

manche Compiler erlauben auch, das man das einfacher schreiben
kann:

  TCNT1 = 65535 - 10000;

die haben sich dann einen seziellen Namen, TCNT1, für das
Registerpärchen TCNT1H und TCNT1L eingeführt und wissen, dass
sie bei der Zuweisung einer 16 Bit Zahl an dieses fiktive Register
eine Zerlegung in Highbyte und Lowbyte machen müssen und in die
einzelnen 8Bit Register schreiben müssen.

von Johannes M. (johnny-m)


Lesenswert?

Tanja M. wrote:
> Entschuldige Johannes, aber ich erkenne auf deinen Bildern irgendwie
> nichts, dass sind so Punkte und Striche, sehr pixelig....
Ach, Du benutzt vermutlich Internet Explorer. Da soll es Probleme mit 
der Darstellung der Formeln geben. Was da stehen sollte (und in anderen 
Browsern auch steht) ist
f_PWM = f_CPU / (Prescaler * (TOP + 1)) (obere Formel)
und das Beispiel mit den Zahlenwerten aus Deinem Code:
1 MHz / (1 * (255 + 1)) = 3906,25 Hz

Stefans Vorschlag ist bis auf das Vorladen von TCNT1 für die Erzeugung 
einzelner Impulse auch brauchbar. Allerdings ist es bei den AVRs 
sinnvoller, dafür den CTC-Modus und den entsprechenden Compare-Interrupt 
zu benutzen.

von Tanja M. (Gast)


Lesenswert?

Ja Johannes, bemutze den Internet Explorer, aber danke für das 
übersetzten der Zeichen.

Okay soweit so gut, die TCCR1A und TCCR1B Register sind geschrieben, 
TCNT1H und TCNT1L sind auch gesetzt.

>Stefans Vorschlag ist bis auf das Vorladen von TCNT1 für die Erzeugung
>einzelner Impulse auch brauchbar.

Was spricht dagegen? Ist es über den CTC weniger aufwendig oder besser 
zu verstehen? Also wärst du der Meinung ich solle statt Fast PWM Mode 
den CTC Mode nehmen oder?
Wenn ich das Datenblatt richtig verstanden habe, dann löscht der CTC das 
register auf 0 wenn TCNT1 und OCR1 einen Compare Match haben richtig? 
Der Wert in OCR1 ist dann der Wert der TOP vorgibt beim Zähler oder?
Fragen über Fragen...

Danke für eure tolle Unterstüzung!

Liebe Grüße
Tanja

von Tanja M. (Gast)


Lesenswert?

Ähm kleine Ergenzung von mir, bei dem CTC Mode, der soll doch eine 
komische Art zu zählen haben oder?

Ahja im übrigen hab ich verstanden, dass der CTC die Werte aus TCNT1 und 
OCR1 vergleicht und wenn die übereinstimmen dann setzt der TCNT1 auf 0 
und fängt dann wieder von vorne an zu zählen, aber wie gesagt, der soll 
doch ne seltsame Art zu zählen haben...

Liebe Grüße
Tanja

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:

> Ahja im übrigen hab ich verstanden, dass der CTC die Werte aus TCNT1 und
> OCR1 vergleicht und wenn die übereinstimmen dann setzt der TCNT1 auf 0
> und fängt dann wieder von vorne an zu zählen, aber wie gesagt, der soll
> doch ne seltsame Art zu zählen haben...

Überhaupt nicht. Wie kommst du darauf?

Wenn du deine 10 ms besonders exakt einstellen möchtest, dann
ist das das Mittel zur Wahl. Vor allen Dingen, weil man dann
auch auf das 'seltsame' Vorladen des Timers verzichten kann :-)

von Johannes M. (johnny-m)


Lesenswert?

Tanja M. wrote:
> Ähm kleine Ergenzung von mir, bei dem CTC Mode, der soll doch eine
> komische Art zu zählen haben oder?
>
> Ahja im übrigen hab ich verstanden, dass der CTC die Werte aus TCNT1 und
> OCR1 vergleicht und wenn die übereinstimmen dann setzt der TCNT1 auf 0
> und fängt dann wieder von vorne an zu zählen, aber wie gesagt, der soll
> doch ne seltsame Art zu zählen haben...
Nö, eigentlich ist daran nichts seltsam. Der CTC-Modus arbeitet nur 
"andersrum" als die Variante mit dem Zähler-Vorladen. Im CTC-Modus fängt 
der Zähler bei Null an zu zählen und zählt (wie Du ja schon selbst 
vermutet hast), bis er den eingestellten TOP-Wert erreicht. Dann wird 
der Zähler mit dem jeweils folgenden Timertakt(*) zurückgesetzt und das 
Spielchen beginnt von vorn, ohne dass irgendwas nachgeladen werden muss.

Außerdem gibt man im CTC-Modus als TOP-Wert quasi direkt die gewünschte 
Anzahl Takte bis zum Ereignis (Interrupt und/oder Umschalten eines 
Portpins) vor und nicht "Überlaufwert minus Anzahl der Takte". Ich halte 
daher eher die andere Variante für "seltsamer", weil man da den Zähler 
auf einen bestimmten Wert setzen muss, damit er nach einer bestimmten 
Anzahl Takte überläuft. Das hat besonders bei präzisen Timing-Aufgaben 
den großen Nachteil, dass das Nachladen des Timers nie direkt beim 
Überlauf passiert, sondern erst dann, wenn das Programm auf den Überlauf 
reagiert hat. Und das kann u.U. dauern. Außerdem kann man mit dem 
Overflow-Ereignis keinen I/O-Pin hardwaremäßig umschalten. Das geht nur 
über die Compare-Einheiten.

(*)Da das Rücksetzen des Timers erst beim jeweils folgenden Timertakt 
geschieht, muss der TOP-Wert um eins niedriger angegeben werden als die 
gewünschte Anzahl der Timertakte.

von Tanja M. (Gast)


Lesenswert?

Hallo Karl Heinz.

Wie ich darauf komme? Das steht hier in dem Tutorial.

Hmm was meinst du mit seltsames Vorladen des Timers?
Welches Register ist denn für das Vorladen zuständig? Ich dachte das 
TCNT1 Register.
Was hab ich bei dem CTC Mode zu beachten und was muss ich letztendlich 
an den schon geschriebenen Registern ändern?

Um das ganze in den CTC Mode umzustellen müsste ich im TCCR1B 2 Bits 
tauschen, also wäre TCCR1B statt 0b00001001 jetzt 0b00010001 richtig? In 
Hex wäre das dann 0x11 hoffe so stimmts.

Auch bei dir möchte ich mich für deine Hilfe bedanken.

Liebe Grüße
Tanja

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:
> Hallo Karl Heinz.
>
> Wie ich darauf komme? Das steht hier in dem Tutorial.

?
Hast du da eine Referenz drauf. Das würde ich mir gerne ansehen.

>
> Hmm was meinst du mit seltsames Vorladen des Timers?
> Welches Register ist denn für das Vorladen zuständig? Ich dachte das
> TCNT1 Register.

Nein.
TCNT1 ist das Timer Zählregister. In diesem Register, ähm,
zählt der Timer so vor sich hin.

> Was hab ich bei dem CTC Mode zu beachten und was muss ich letztendlich
> an den schon geschriebenen Registern ändern?

Da gibts nicht viel zu beachten.
Du stellst die Timerzählrate mit dem Vorteiler ein, wie gehabt.
Aktivierst den CTC Modus und stellst die gewünschte Endzahl - 1
im OCR1A Register ein und schon zählt der Timer nur noch von 0
bis zu dieser Zahl. Einfacher gehts nicht.

>
> Um das ganze in den CTC Mode umzustellen müsste ich im TCCR1B 2 Bits
> tauschen, also wäre TCCR1B statt 0b00001001 jetzt 0b00010001 richtig? In
> Hex wäre das dann 0x11 hoffe so stimmts.

Gewöhn dir das Schreiben von Hex-Zahlen an dieser Stelle gleich
wieder ab. Das Bitgepfriemel ist ja nicht auszuhalten.

Um den CTC Modus im Timer1 zu aktivieren, müssen, laut Datenblatt
die Bits WGM12 und CS10 (für einen Vorteiler von 1) gesetzt werden.
Also schreiben wir das auch so:

   TCCR1B = ( 1 << WGM12 ) | ( 1 << CS10 );

Welche Bedeutung das setzen der einzelnen Bits hat, muss man immer
noch im Datenblatt nachsehen (so man sie nicht auswendig kann). Aber
zumindest das stumpfsinnige und fehlerträchtige Im-Kopf-die-Hex-Zahl-
in-Bits-aufdröseln-und-abzählen-welche-Bitnummer-das-1-Bit-hat
fällt damit weg.

von Tanja M. (Gast)


Lesenswert?

Johannes deine Erklärung ist wirklich sehr gut und hilfreich! Danke.
Also wenn ich das richtig verstanden habe, muss ich dem Timer nicht mehr 
sagen "zähle bis 55535 (65535-10000)" sondern muss dem Timer nur sagen 
das er beim 10000 Takt den Interrupt auslösen soll, ist das soweit 
richtig?
Da du angemerkt hast, dass er einen Takt weniger brauch für das 
Zurücksetzen, müsste ich meinem Timer den Wert 9999 zuweisen oder?

Hmmm der CTC arbeitet also auch nur mit den Werten in den Registern 
TCNT1 und OCR1 oder?

Was muss ich dem OCR1 Register eigentlich sagen, was er zu tun hat? Löst 
er den Interrupt aus?

Liebe Grüße
Tanja

von Johannes M. (johnny-m)


Lesenswert?

Kleine Rechnung:
Du willst einen Pin auf High-Pegel setzen und nach jeweils 125 
Timertakten umschalten (toggeln).

Variante 1: TIMER-VORLADEN
0.) Timer konfigurieren (Prescaler einstellen, Overflow-Interrupt 
aktivieren)
1.) Pin auf High setzen
2.) TCNT1 mit 65536-125 (65411) laden
3.) Auf Interrupt warten
4.) Im Interrupt Handler Pin toggeln
5.) Timerregister TCNT1 wieder mit 65411 laden

Bei 4.) und 5.) kann es zu den oben erwähnten Problemen kommen, weil das 
Pin-Toggeln und Timerregister-Neu-Laden nicht sofort nach dem 
Overflow-Ereignis geschehen.

Variante 2: CTC-MODUS
0.) Timer konfigurieren (Prescaler und CTC-Modus einstellen, Pin OC1x 
toggeln bei Compare-Match, Interrupt wird für die Aufgabe an sich nicht 
gebraucht)
1.) Compare-Register mit gewünschtem Wert (Taktzahl - 1) beschreiben
2.) Irgendwas anderes machen. Pin toggeln macht der Controller von jetzt 
an selbst, Interrupt gibts auch nicht.

Wenn Toggel-Frequenz geändert werden soll, neuen Wert in 
Compare-Register schreiben (OK, das sollte man dann schon im 
Interrupt-Handler machen, damit es synchron ist)

Welche Methode einfacher und sinnvoller ist, musst Du jetzt selbst 
entscheiden.

EDIT:
Das Einzige, worauf man im CTC-Modus achten muss, ist die Zuweisung 
eines neuen TOP-Wertes an OCR1A. Dabei muss man eben aufpassen, dass man 
OCR1A keinen Wert zuweist, der kleiner oder gleich dem aktuellen Stand 
von TCNT1 ist, da in einem solchen Fall das Compare-Ereignis ausbleibt 
und der Timer einmal komplett bis zum Überlauf durchrennt, bevor er 
wieder das macht, was er soll. Deshalb kann man für diesen Fall den 
Compare-A-Interrupt freigeben und die Aktualisierung von OCR1A im 
Interrupt Handler machen. Dann kann man davon ausgehen, dass TCNT1 sich 
noch nicht allzu weit von 0 entfernt hat, wenn OCR1A aktualisiert wird.

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:
> Johannes deine Erklärung ist wirklich sehr gut und hilfreich! Danke.
> Also wenn ich das richtig verstanden habe, muss ich dem Timer nicht mehr
> sagen "zähle bis 55535 (65535-10000)"

Das hast du ihm auch bisher nicht gesagt.
Du hast ihm gesagt: Zähle von 55535 bis 65535, denn wenn
du das tust hast du 10000 Zählvorgänge ausgeführt.

Und deswegen empfinden wir (Johannes und ich) das als etwas seltsam.

> sondern muss dem Timer nur sagen
> das er beim 10000 Takt den Interrupt auslösen soll, ist das soweit
> richtig?

Nicht Takt.
Der Timer soll mit seiner Taktrate von 0 bis 10000 zählen.
Und wenn er dort angelangt ist, soll er wieder bei 0 anfangen.

> Da du angemerkt hast, dass er einen Takt weniger brauch für das
> Zurücksetzen, müsste ich meinem Timer den Wert 9999 zuweisen oder?

Yep.

>
> Hmmm der CTC arbeitet also auch nur mit den Werten in den Registern
> TCNT1 und OCR1 oder?

Yep. CTC ist nur ein Betriebsmodus des Timers.
Der Timer zählt immer im Register TCNT1. In einem gewissen
Sinne könnte man sagen: TCNT1 ist der Timer1.
Alles andere drumherum dreht sich nur um die Auswertung der
Zahl die gerade im TCNT1 ist. Bei bestimmten Zahlen (die
über andere Register einstellbar sind), können Aktionen
ablaufen.

von Tanja M. (Gast)


Lesenswert?

Karl Heinz, wenn ich denn jetzt dem OCR1 Register den TOP Wert zuteile 
also die 9999, dann weiß ich jetzt gar nicht mehr was ich dem TCNT1 
Register sagen soll. Der TCNT1 muss doch die Frequenz vorgeben oder 
nicht? und da ich doch ne Frequenz von 10Hz gern hätte müsste ich dem 
doch den Wert D8EF zuteilen oder nicht?
Jetzt komme ich gazn durcheinander...

Hihi, ich rechne die Hex zahlen nicht im Kopf aus sondern hab dafür 
einen Taschenrechner.

>TCCR1B = ( 1 << WGM12 ) | ( 1 << CS10 );

Diese Schreibweise erkennt mein CodeVision nicht. Das ist doch Assambler 
oder?

Soll ich mir abgewöhnen in Hexzahlen zu schreiben oder in soll ich mir 
abgewöhnen in Binärzahlen zu schreiben?

>Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt >sich je 
nach eingestelltem Vorteiler ein etwas anderes Zählverhalten.

Das stand im Tutorial, mein fehler, der zählt nur anders und nicht 
"seltsam".

Danke und liebe Grüße
Tanja

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:
> Karl Heinz, wenn ich denn jetzt dem OCR1 Register den TOP Wert zuteile
> also die 9999, dann weiß ich jetzt gar nicht mehr was ich dem TCNT1
> Register sagen soll.

Gar nichts.

> Der TCNT1 muss doch die Frequenz vorgeben oder
> nicht?

Nein.
In TCNT1 zählt der Timer so vor sich hin.
Lass dieses Register einfach nur in Ruhe zählen.

> da ich doch ne Frequenz von 10Hz gern hätte müsste ich dem
> doch den Wert D8EF zuteilen oder nicht?

Du hast es immer noch nicht. Die D8EF waren ja die 10000. Bis
zu dieser Zahl soll der Timer zählen. Das ist also die Obergrenze
und wenn diese Zahl erreicht ist, dann soll der Timer wieder bei
0 anfangen. Die D8EF (oder eben die 10000) müssen daher in das
Register, welches steuert wie weit der Timer zählen soll bevor
er wieder bei 0 anfängt. Das macht das Register OCR1


>> TCCR1B = ( 1 << WGM12 ) | ( 1 << CS10 );
>
> Diese Schreibweise erkennt mein CodeVision nicht. Das ist doch Assambler
> oder?

Nein, das ist C.
Kann aber sein, dass die Bits bei CodeVision anders heissen.
Beim gcc heissen sie so, wie im Datenblatt.

>Da die Übereinstimmung im Takt nach dem Vergleich behandelt wird, ergibt
>sich je nach eingestelltem Vorteiler ein etwas anderes Zählverhalten.

Ja das stimmt schon.
Da du aber mit einem Vorteiler von 1 arbeiten kannst, braucht dich
das nicht weiter kümmern.

von Tanja M. (Gast)


Lesenswert?

Okay Johannes ich wag es jetzt mal und versuche das was ich meine 
verstanden zu haben umzusetzten.

Die Register müssten dann folgend aussehen:
1
TCCR1A=0xA1;
2
TCCR1B=0x11;
3
TCNT1H=0xD8;        
4
TCNT1L=0xEF;
5
ICR1H=0x00;
6
ICR1L=0x00;
7
OCR1AH=0x27;
8
OCR1AL=0x0F;
9
OCR1BH=0x00;
10
OCR1BL=0x00;

In OCR1 hab ich jetzt die 9999 reingeschrieben und in TCNT1 hab ich das 
so gelassen mit den Wert 55535 für die 10Hz. TCCR1B hab ich 
dementsprechend natürlich auch auf den CTC Modus gestellt.

Liebe Grüße
Tanja

von Johannes M. (johnny-m)


Lesenswert?

Tanja M. wrote:
> Karl Heinz, wenn ich denn jetzt dem OCR1 Register den TOP Wert zuteile
> also die 9999, dann weiß ich jetzt gar nicht mehr was ich dem TCNT1
> Register sagen soll.
Gar nichts. TCNT1 ist das Zählregister, das von der Hardware mit jedem 
Timertakt (Also mit der Frequenz f_CPU/Prescaler) erhöht wird.

> Der TCNT1 muss doch die Frequenz vorgeben oder
> nicht?
Nein, siehe oben. Die Frequenz gibt der Prescaler vor. Und mit dieser 
Frequenz wird TCNT1 erhöht.

> und da ich doch ne Frequenz von 10Hz gern hätte müsste ich dem
> doch den Wert D8EF zuteilen oder nicht?
> Jetzt komme ich gazn durcheinander...
Du denkst auch immer noch falschrum. Du zählst nicht mehr von einem 
Ausgangswert bis zum Überlauf, sondern (wie man es ja eigentlich auch im 
wahren Leben macht) von 0 bis zu einem Vorgegebenen Wert. Oder wie 
machst Du das beim Verstecken-Spielen, wenn es heißt: "Auf hundert"? 
Fängst Du dann bei 912345 an zu zählen und fängst bei 912444 an zu 
suchen?

> Hihi, ich rechne die Hex zahlen nicht im Kopf aus sondern hab dafür
> einen Taschenrechner.
Der Compiler versteht auch dezimal...

>>TCCR1B = ( 1 << WGM12 ) | ( 1 << CS10 );
>
> Diese Schreibweise erkennt mein CodeVision nicht. Das ist doch Assambler
> oder?
Nein, das ist C, und zwar ANSI-C. Allerdings sind die Makros für die 
Bits im CodeVision anders definiert, weshalb das da u.U. nicht 
funktioniert

von Peter P. (bonsaibaum)


Lesenswert?

das setzen von TCNT kannst du weglassen ... das ist einfach nur ein 
register für den timer, in dem der timer selbst zählt ... das brauchst 
du nicht zu beschreiben.

von Tanja M. (Gast)


Lesenswert?

Hm verdammt, jetzt hab ich die Antwort von Karl Heinz nicht mehr 
berücksichtigen können in meinem ersten Anlauf, also hier dann nochmal 
unter der Berücksichtigung von Karl Heinz' Annmerkung wegen des Timers.
1
TCCR1A=0xA1;
2
TCCR1B=0x11;
3
TCNT1H=0x00;        
4
TCNT1L=0x00;
5
ICR1H=0x00;
6
ICR1L=0x00;
7
OCR1AH=0x27;
8
OCR1AL=0x0F;
9
OCR1BH=0x00;
10
OCR1BL=0x00;

Vielen vielen Dank für eure Geduld.

Liebe Grüße
Tanja

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:

> in TCNT1 hab ich das
> so gelassen mit den Wert 55535 für die 10Hz.

Nochmal: Lass das TCNT1 Register in Ruhe. Dieses Register
hat dich nicht zu interessieren!

Wenn du mir die Aufgabe gibst bis 100 zu zählen, hat es dich
ja auch nicht zu interessieren ob ich im Kopf zähle, oder
ob ich auf einem Papier Stricherl mache, oder ob ich am Taschenrechner
immer 1 addiere oder ......

Wie und wo ich zähle ist mein Bier. Der Timer zählt halt
im Register TCNT1. Aber das hat dich genausowenig zu interessieren,
wie dich meine Zählweise zu interessieren hat. Für dich ist einzig
und alleine interessant, dass ich mich wieder melde, wenn die
100 erreicht sind!

von Tanja M. (Gast)


Lesenswert?

Okay, okay entschuldigung, meinen ersten Anlauf hab ich geschrieben, als 
ihr noch nicht auf meine TCNT1 Antwort geantwortet hattet. Sorry, habs 
ja jetzt geändert.

Wegen Dezimalzahlen, da kann ich den Wert direkt schreiben ohne ein 0b 
oder 0x vor der Zahl oder?

Entschuldigt bitte, wenn ich eure Geduld etwas überstrapaziert habe.

Ganz liebe Grüße
Tanja

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:
> Wegen Dezimalzahlen, da kann ich den Wert direkt schreiben ohne ein 0b
> oder 0x vor der Zahl oder?

Ja.

>
> Entschuldigt bitte, wenn ich eure Geduld etwas überstrapaziert habe.

Kein Problem.
Niemand wird gezwungen hier zu antworten :-)

von Johannes M. (johnny-m)


Lesenswert?

Und noch mal: Wenn es um Anzahlen geht (also um Takte o.ä.), dann ist es 
besser, erstens die 16-Bit-Register als ganzes anzusprechen (anstelle 
von TCNT1H und TCNT1L also einfach TCNT1, für OCR1AL und OCR1AH eben 
OCR1A) und dann auch Dezimalzahlen zu verwenden. Der Code Generation 
Wizard macht das zwar in Einzelzugriffen, aber wie schon weiter oben 
angedeutet, ist das nicht das Gelbe vom Ei, was die Lesbarkeit betrifft. 
Außerdem ist bei diesen Registern die Zugriffsreihenfolge extremst 
wichtig (beim Lesen erst das Low-Byte, beim Schreiben erst das 
High-Byte). Wenn man das 16-Bit-Register als Ganzes anspricht, nimmt 
einem der Compiler das ab, so dass schon mal eine mögliche Fehlerquelle 
weniger da ist.

von Tanja M. (Gast)


Lesenswert?

Hmmmm jetzt bin ich ein wenig stutzig. Ihr habt euch so bemüht und jetzt 
blinkt die LED noch nicht mal....

Hab ich irgendwas falsch gemacht? Ich hab zum testen des Interrupts auch 
gesagt, der soll die LED an Port P5 blinken lassen mit einem Delay.
Hmm wo könnte noch der fehler stecken...
Ich hab keinen Compare Match bei CodeVision eingestellt, könnte es daran 
liegen? Was anderes fällt mir grad nicht ein....

Kleine Anmerkung, wenn man einen Wert OCR1A zuweist, dann gibt er das 
Ergebnis an PORT B2 aus, also da wo eigentlich OC1B steht und wenn ich 
den Wert in OCR1B eingebe, dann gibt er das Ergebnis an PORT B1, also da 
wo OC1A steht, wieso ist das so?

Liebe Grüße
Tanja

P.S. Danke für dein Verständniss Karl Heinz! =)

von Johannes M. (johnny-m)


Lesenswert?

Tanja M. wrote:
> Hmmmm jetzt bin ich ein wenig stutzig. Ihr habt euch so bemüht und jetzt
> blinkt die LED noch nicht mal....
>
> Hab ich irgendwas falsch gemacht? Ich hab zum testen des Interrupts auch
> gesagt, der soll die LED an Port P5 blinken lassen mit einem Delay.
> Hmm wo könnte noch der fehler stecken...
> Ich hab keinen Compare Match bei CodeVision eingestellt, könnte es daran
> liegen? Was anderes fällt mir grad nicht ein....
Verstehe ich jetzt nicht ganz, was Du da machst. Was für ein Delay?

> Kleine Anmerkung, wenn man einen Wert OCR1A zuweist, dann gibt er das
> Ergebnis an PORT B2 aus, also da wo eigentlich OC1B steht und wenn ich
> den Wert in OCR1B eingebe, dann gibt er das Ergebnis an PORT B1, also da
> wo OC1A steht, wieso ist das so?
Das sind die Ausgangspins der Compare-Units. Die sind intern fest 
verdrahtet. Wenn Du einen anderen Pin toggeln willst, musst Du das im 
Interrupt-Handler per Software machen.

von Tanja M. (Gast)


Lesenswert?

1
// Timer/Counter 1 initialization
2
// Clock source: System Clock
3
// Clock value: 1000,000 kHz
4
// Mode: Fast PWM top=00FFh
5
// OC1A output: Non-Inv.
6
// OC1B output: Non-Inv.
7
// Noise Canceler: Off
8
// Input Capture on Falling Edge
9
// Timer 1 Overflow Interrupt: On
10
// Input Capture Interrupt: Off
11
// Compare A Match Interrupt: Off
12
// Compare B Match Interrupt: Off
13
TCCR1A=0xA1;
14
TCCR1B=0x11;
15
TCNT1H=0x00;
16
TCNT1L=0x00;
17
ICR1H=0x00;
18
ICR1L=0x00;
19
//OCR1AH=0x27;
20
//OCR1AL=0x0F;
21
OCR1A=9999;
22
OCR1BH=0x00;
23
OCR1BL=0x00;

Ohja, hab die OCR1AH/L auskommentiert und dennoch leuchtet die LED 
zumindest, sie blinkt zwar nicht, aber sie tut zumindest dasselbe wie 
mit den OCR1AH/L Registern im einzenen betrachtet! Danke für den tollen 
Tip! Das erleichtert das ganze natürlich ein bisschen.

Liebe Grüße
Tanja

von Tanja M. (Gast)


Lesenswert?

Also der Delay ist nur im Interrupt um zu testen ob der Interrupt 
überhaupt tut. Moment zeige dir den Codeabschnitt eben.
1
// Timer 1 overflow interrupt service routine
2
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
3
{
4
PORTB.5=0;
5
delay_ms(50);
6
PORTB.5=1;
7
}

Ahhhhmmm, ich glaub das ist kein wunder, dass der keinen Interrupt 
auslöst, schließlich besteht ja kein overflow mehr.
Aber wie löse ich denn jetzt einen Interrupt aus? Per Compare Match? 
Dafür müsste ich dem CodeVision aber erstmal sagen, dass er einen 
Compare Match auszuführen hat oder?

Hmpf.. Naja wenigstens an ist die LED zumindest schonmal.

Liebe Grüße
Tanja

von Johannes M. (johnny-m)


Lesenswert?

Tanja M. wrote:
> Ahhhhmmm, ich glaub das ist kein wunder, dass der keinen Interrupt
> auslöst, schließlich besteht ja kein overflow mehr.
> Aber wie löse ich denn jetzt einen Interrupt aus? Per Compare Match?
Genau!

> Dafür müsste ich dem CodeVision aber erstmal sagen, dass er einen
> Compare Match auszuführen hat oder?
Tja, das ist jetzt der oben angedeutete Nachteil von CodeVision bzw. der 
Schreibweise. Jetzt heißt es: Datenblatt rauskramen, nachsehen, welche 
Bits gesetzt werden müssen und welche nicht, das ganze als Hexadezimal- 
oder Binärzahl da eingeben, wenn man weiß, wo es hingehört...

von Tanja M. (Gast)


Lesenswert?

Oh Gott oh Gott.... Na gut! Da muss ich jetzt durch, also ich meld mich 
jetzt vorerst ab und versuche dem jetzt erstmal irgendwie beizubringen, 
wie man einen Compare Match Interrupt auslöst! =)

Wenn ich irgendeine neue Eingebung hab, melde ich mich bei euch!

Nochmals vielen vielen Dank für eure Hilfe und eurer Geduld, wirklich 
sehr lieb, da macht das Programmieren nochmal doppelt so viel spaß, wenn 
man versteht was man da macht! =)

Ganz liebe Grüße
Tanja

von Tanja M. (Gast)


Lesenswert?

Ich meld mich schon früher als erwartet.
Mir ist aufgefallen, dass ich mit dem CTC Mode ja recht viel im 
Interrupt schreiben muss. Das möchte ich eigentlich nicht, deswegen kam 
ich wohl auch nicht auf die Idee den CTC Mode zu benutzt, da ich so 
wenig wie möglich per Software machen möchte. Ich möchte mein PWM signal 
mit 10Hz über die Hardware laufen lassen.

Entschuldigt, wenn ich mich einfach ungeschickt ausgedrückt habe in dem 
was ich eigentlich vor hatte...

Liebe Grüße
Tanja

von Tanja M. (Gast)


Lesenswert?

Johannes, Karl Heinz wo seid iiihr?
So wie ich das sehe darf ich nochmal ganz von vorne anfangen.... =(

Liebe Grüße
Tanja

von Karl H. (kbuchegg)


Lesenswert?

Tanja M. wrote:
> Ich meld mich schon früher als erwartet.
> Mir ist aufgefallen, dass ich mit dem CTC Mode ja recht viel im
> Interrupt schreiben muss.

Wenn du die vorgesehenen Output Pins des Prozessors benutzen
kannst, dann brauchst du noch nicht mal eine Interrupt
Funktion.

Ansonsten brauchst du 2 Interrupt Funktionen:
* Eine die den Pin auf 1 setzt, wenn der Timer auf 0 gesetzt wird.
* Eine die den Pin wieder auf 0 setzt, wenn die (Hinweis!)
  2. Compare Einheit des Timers1 eine übereinstimmung feststellt.

Das ist doch nicht viel.

von Johannes M. (johnny-m)


Lesenswert?

Tanja M. wrote:
> Ich meld mich schon früher als erwartet.
> Mir ist aufgefallen, dass ich mit dem CTC Mode ja recht viel im
> Interrupt schreiben muss. Das möchte ich eigentlich nicht, deswegen kam
> ich wohl auch nicht auf die Idee den CTC Mode zu benutzt, da ich so
> wenig wie möglich per Software machen möchte. Ich möchte mein PWM signal
> mit 10Hz über die Hardware laufen lassen.
Wenn es über die Hardware laufen soll, dann geht es nur mit den 
entsprechenden Ausgangspins OC1A bzw. OC1B. Und wenn es tatsächlich ein 
echtes PWM-Signal sein soll (also nicht nur einzelne Impulse, sondern 
ein kontinuierlich laufendes Rechteck-Signal), dann nimmt man natürlich 
auch nicht den CTC-Modus, sondern einen der PWM-Modi. Die machen im 
Prinzip fast dasselbe, nur ist bei denen auch die Synchronisation der 
Registeraktualisierung automatisiert (zumindest bei den PWM-Modi, die 
OCR1A als TOP-Wert benutzen). Nimm am besten eine PWM mit OCR1A als TOP 
und dann eben OC1B als Ausgang. Dann kannst Du über OCR1A die 
PWM-Frequenz vorgeben und über OCR1B das Tastverhältnis. Wenn Du das so 
konfigurierst, dann brauchst Du eigentlich gar keinen Interrupt Handler. 
Dann macht der Timer alles selbst, ohne dass das Programm nach der 
Initialisierung noch eingreifen muss.

Oben war nur nach den ersten paar Postings nicht ganz klar, ob Du 
tatsächlich eine PWM machen, oder ob Du nur einzelne Impulse einer 
bestimmten Länge generieren willst.

Wenn Du natürlich den OC1B-Pin aus verdrahtungstechnischen Gründen nicht 
verwenden kannst, dann siehe letztes Posting von Karl heinz. Dann 
brauchst Du zwei Interrupt Handler, in denen aber jeweils nur eine 
einzige Anweisung steht, nämlich in der einen "Portpin auf High-Pegel 
setzen" und in der anderen "Portpin auf Low-Pegel setzen".

von Tanja M. (Gast)


Lesenswert?

Ich muss das ja auch noch alles mit dem ADC in einklang bringen...
Manno, hatte so ein aufschwung und nun sowas. Holt einen ganz schön 
wieder auf den Boden der Tatsachen... X(

Ich wollt eigentlich einfach nur 10Hz mit den Timer1 über die Hardware 
des µC erzeugen. 10Hz sind ja gleich 100ms. In den 100ms muss es eine 
Highzeit und eine Lowzeit geben. Aber diese 100ms sollen fest sein und 
sich nicht ändern, dann möchte ich nur diese High und Lowzeiten per Poti 
verändern können.

Hät echt nicht gedacht, dass das so schwer geht.

Liebe Grüße
Tanja

von Tanja M. (Gast)


Lesenswert?

Danke das ihr mir immernoch beisteht.
Also ich nehme dann den Phase Correct PWM Mode, der hat auch einen OCR1A 
als Top.

Wie errechne ich die PWM frequenz? Muss ich da schon irgendwie mein 10Hz 
unterbringen? Welches Register ist für die PWM Frequenz zuständig?
Und über OCR1B das Tastverhältnis bestimmen? Also sagen wie lang er High 
und wie lang er Low sein soll?

Beide Ausgänge sind frei und können benutzt werden.

Wirklich vielen Dank euch beiden.

Liebe Grüße
Tanja

von Johannes M. (johnny-m)


Lesenswert?

Rechne mal durch:
10 Hz entsprechen einer Periodendauer von 100 ms. Der Timer muss also so 
konfiguriert werden, dass die Compare-Einheit A, die ja die Frequenz 
festlegen soll, alle 100 ms ein Compare Match hat. Bei 1 MHz CPU-Takt 
sind 100 ms 100000 CPU-Takte. Also: Ein Compare-Match alle 100000 Takte. 
Der Prescaler des Timers erlaubt Teilungen durch 1, 8, 64, 256 und 1024. 
1 MHz / 8 wären 125 kHz für den Timer. Bei 125 kHz brauchts für 100 ms 
noch 12500 Timertakte. Also muss OCR1A so konfiguriert werden, dass nach 
12500 Takten ein Compare Match auftritt. Oben hatte ich den Zusammenhang 
irgendwo erwähnt, es muss also
1
OCR1A = 12499;
da stehen. Damit hätten wir schon mal die Frequenz. Der Rest ist 
Spielerei. In OCR1B kannst Du jetzt irgendeinen Wert zwischen 0 und 
12499 reinschreiben, und erhältst dementsprechend Tastverhältnisse von 
0...100 %.

Nur der Timer und die Compare-Einheit müssen noch entsprechend 
konfiguriert werden, dass der Timer auch im richtigen PWM-Modus arbeitet 
(z.B. Modus 15). Dazu müssen erstmal die WGM-Bits nach der Tabelle im 
Datenblatt entsprechend gesetzt werden. Dann kommen (bei reiner 
Hardware-PWM) noch die Bits COM1B0 und COM1B1 dazu, die bestimmen, was 
mit dem Ausgangspin bei den jeweiligen Compare-Ereignissen gemacht 
werden soll. Die Information steht in der entsprechenden Tabelle im 
Datenblatt (Da ein Fast-PWM-Modus eingestellt ist, müssen die Bits nach 
der Tabelle für Fast-PWM gesetzt werden. In meiner Version vom 
Datenblatt wäre das Tabelle 37 auf Seite 98...)

von Tanja M. (Gast)


Lesenswert?

Hey Johannes!
Vielen Dank für deine Mühen. Es funktioniert nun endlich! =)
1000 Dank!
Auch an dich Karl Heinz!

Liebe Grüße
Tanja

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.