Forum: Mikrocontroller und Digitale Elektronik Atmega128 16-bit Timer


von Tanja H. (hoefme)


Lesenswert?

Hallo zusammen

Zwar habe ich ein Problem mit meinem 16-bit timer vom Atmega128 ( Quarz 
7372800 Hz) . Kann mir jemand helfen wieso er nicht läuft, was mache ich 
an der Initalisierung falsch? Will eine Frequenz von ca. 122.88kHz am 
Port OC1B.

//Initalisierung

    TCCR1A = 0x40; // ( COM1A1 = 0 ¦ COM1A0 = 1 ¦ WGM11 = 0 ¦ WGM10 = 0)
    TCCR1B = 0x01; // ( CS10 = 1)

    OCR1A = 0x001E; //(122.88kHz ->Berechnung 7372800Hz/((2*1228800)-1)




Besten dank für eure Hilfe.

von Timmo H. (masterfx)


Lesenswert?

Lädst du TCNT1 auch bei jedem interrupt wieder neu? Interrupt überhaupt 
aktiviert?

von Tanja H. (hoefme)


Lesenswert?

Ja setzte die Interrupt, habe die vergessen hier zu erwähnen.

Setzte diese so:

       TIMSK = (1<<TOIE1);
       TIMSK = (1<<TICIE1);

Nein das TCNT1 setzt ich nicht neu, da ich ja über Compare Outpurt A 
arbeite. Ist das falsch?

von Johannes M. (johnny-m)


Lesenswert?

> TIMSK = (1<<TOIE1);
> TIMSK = (1<<TICIE1);
...und mit der zweiten Anweisung löschst Du das 
Overflow-Interrupt-Enable wieder. Das kann so nicht funktionieren. 
Übrigens hat das TICIE1 nichts mit dem zu tun, was Du oben beschrieben 
hast.

von Johannes M. (johnny-m)


Lesenswert?

Tanja Hofmann wrote:
> Nein das TCNT1 setzt ich nicht neu, da ich ja über Compare Outpurt A
> arbeite. Ist das falsch?
Dann musst Du den Timer aber im CTC-Modus betreiben und die WGM-Bits 
entsprechend setzen! Und dann den Compare-Interrupt benutzen und nicht 
den Overflow. So wie Du es oben eingestellt hast, läuft der Timer immer 
bis zum Overflow weiter und die Interrupt-Frequenz wäre F_CPU/65536, 
weil nach 65536 Zyklen der Overflow auftritt.

AVR-Tutorial, AVR-GCC-Tutorial

von Tanja H. (hoefme)


Lesenswert?

Mhh irgendwie scheint mir das noch nicht so klar zu sein. Gibts evt. ein 
beispiel wie im meinen 16bit timer für 122 kHz einstellen muss damit ich 
das signal am OC1B nutzen kann?

von AVRFan (Gast)


Lesenswert?

>       TIMSK = (1<<TOIE1);
>       TIMSK = (1<<TICIE1);

Hier kannst Du Dir die erste Zeile sparen, weil die zweite Zeile die 
TIMSK-Einstellung der ersten ja einfach überschreibt.

Ich bevorzuge diese Notation:
1
TIMSK = 0<<OCIE2 | 0<<TOIE2 | 1<<TICIE1 | 0<<OCIE1A | 0<<OCIE1B | 1<<TOIE1 | 0 | 0<<TOIE0

Das "Gerüst" ist dabei immer fest (alle Gerüste für alle I/O-Register 
stehen bei mir in einer Extra-Datei, wo ich sie bei Bedarf rauskopiere). 
Als Modifikationen an dieser Zeile sind nur Änderungen von 0en in 1en 
oder umgekehrt erlaubt.  So kann man bequem I/O-Bits setzen und löschen 
und dabei stets mühelos sehen, welche es sind.

>Nein das TCNT1 setzt ich nicht neu, da ich ja über Compare Outpurt A
>arbeite. Ist das falsch?

Ja.  Dann läuft der Timer ja immer bis 65536, was Du nicht willst.  Du 
musst den CTC-Mode verwenden.

von Tanja H. (hoefme)


Lesenswert?

Hast du den ein einfaches Beispiel für ein 16-Bit timer der für den OC1B 
eingestellt ist ?

von Johannes M. (johnny-m)


Lesenswert?

Tanja Hofmann wrote:
> Hast du den ein einfaches Beispiel für ein 16-Bit timer der für den OC1B
> eingestellt ist ?
Schau Dir im Datenblatt die Tabelle mit den Timer-Betriebsarten an. Da 
steht drin, welche Bits in TCCR1A und TCCR1B gesetzt werden müssen. In 
Deinem Fall kämen Modus 4 oder 12 in Frage.

von Tanja H. (hoefme)


Lesenswert?

Ja habe es nach dem Datenlatt versucht, läuft aber leider nicht ...... 
Niemand ein brauchbares beispiel ?

von Timmo H. (masterfx)


Lesenswert?

>Ja habe es nach dem Datenlatt versucht, läuft aber leider nicht ......
Macht er gar nichts, oder einfach nur zu schnell/langsam? Geht er 
überhaupt in die ISR? Hast mal debuggt?

von Tanja H. (hoefme)


Lesenswert?

Ja hab es versucht, bekomme nur ca 57Hz.

von Timmo H. (masterfx)


Lesenswert?

Wie sieht deine ISR denn aus?
Ich hätte jetzt einfach das TCCR mit 0x1E oder was auch immer geladen 
und dann immer beim TIMER1_OVF_vect das TCCR wieder neu geladen, anstatt 
es mit dem Compare zu machen.
Müsste eigentlich so gehen:
1
int main(){
2
    TCCR1A = 0;
3
    TCCR1B = 0x01; // ( CS10 = 1)
4
5
    TCNT1 = 0xFFFF-0x001E;
6
    TIMSK |= (1<<TOIE1);
7
    sei();
8
    while(1);
9
10
}
11
12
13
ISR(TIMER1_OVF_vect){
14
    TCNT1 = 0xFFFF-0x001E;
15
}
Konnte jetzt nur Simulieren, aber zumindest gibt mir das alle 30 Takte 
oder so ein Interrupt. Was bei 7372800 Hz eben 122880/2 Hz entspricht. 
Man muss aber auch bedenken, dass das hin und herspringen auch einige 
Takte kostet.

von Johannes M. (johnny-m)


Lesenswert?

Timmo H. wrote:
> Wie sieht deine ISR denn aus?
> Ich hätte jetzt einfach das TCCR mit 0x1E oder was auch immer geladen
> und dann immer beim TIMER1_OVF_vect das TCCR wieder neu geladen, anstatt
> es mit dem Compare zu machen.
Und warum? Wozu hat der AVR denn wohl den CTC-Modus? Exakt: Damit man 
keinen Timer-Reload machen muss!

Außerdem ist das "TCCR" ein Steuerregister und da wird nix "geladen".

von Timmo H. (masterfx)


Lesenswert?

Naja, wenns funktioniert. Kann man doch erstmal so machen. Ob der jetzt 
dafür 2 Takte länger braucht als mit Autoreload. Der Thread-Ersteller 
postet ja auch nur Bruchteile des Codes. Ohne was zusammenhängendes ist 
halt doof.

von Johannes M. (johnny-m)


Lesenswert?

Ich verstehe nicht, was an dem, was ich oben schon gesagt habe, so 
schwer ist. OK, der CTC-Modus wird im Tutorial nicht beschrieben (wenn 
ich Zeit habe, ändere ich das vielleicht mal), aber ich habe doch 
deutlich genug auf das Datenblatt hingewiesen, und da steht doch wohl 
eindeutig, was man tun muss.

Wenn man z.B. CTC-Modus 4 in der Tabelle "Waveform Generation Mode Bit 
Description" (im neuesten Datenblatt ist das Tabelle Nr. 61 auf S. 135) 
anschaut, dann steht da ganz exakt, welche der WGM-Bits gesetzt werden 
müssen, um diesen Modus einzustellen. In der Register-Beschreibung steht 
auch, welche der Bits in TCCR1A und welche in TCCR1B stehen. Wenn das 
geschehen ist, dann kannst Du in OCR1A einen Wert schreiben. Wenn der 
Timer beim Hochzählen diesen Wert erreicht, wird er automatisch 
zurückgesetzt.

Wenn Du den zu OCR1A gehörenden Portpin (OC1A) noch entsprechend 
konfigurierst (über die COM-Bits), dann wird der Pin bei jedem Erreichen 
von OCR1A umgeschaltet. Alternativ (oder auch zusätzlich) kannst Du 
selbstverständlich auch den entsprechenden Compare-Interrupt aktivieren 
und im Interrupt-Handler irgendwas machen (z.B. einen anderen Pin 
umschalten). Das ist allerdings mit viel Overhead verbunden, weshalb da 
die erreichbaren Frequenzen nicht sehr hoch sind. Das Umschalten von 
OCR1A geht aber verzögerungsfrei. Und dran denken: Wenn Du 122 kHz haben 
willst, musst Du mit der doppelten Frequenz den Portpin umschalten 
(also mit 244 kHz)!

von Johannes M. (johnny-m)


Lesenswert?

Timmo H. wrote:
> Naja, wenns funktioniert. Kann man doch erstmal so machen. Ob der jetzt
> dafür 2 Takte länger braucht als mit Autoreload. Der Thread-Ersteller
> postet ja auch nur Bruchteile des Codes. Ohne was zusammenhängendes ist
> halt doof.
Timer Reload macht man beim AVR nicht, genau dafür gibt's den 
CTC-Schiss. Außerdem bringt allein der Interrupt Handler 20-30 Takte 
Overhead mit, weshalb das bei den geforderten Frequenzen mit großer 
Wahrscheinlichkeit in die Hose geht (schließlich soll hier schon nach 30 
Takten umgeschaltet werden, und da machen nebenbei auch 2 Takte 
Unterschied schon ganz schön was aus(*))! Bei 8051ern, die eine 
Auto-Reload-Funktion haben, kannste mit sowas kommen, aber bitte erzähl 
keinem AVR-Anfänger so was!

Bei dem Post-Verhalten von "Tanja" gebe ich Dir allerdings Recht...

(*) Bedenke, dass beim Aufruf eines Interrupt Handlers erstmal der 
aktuell laufende Befehl zu Ende abgearbeitet wird, und wenn der 
Interrupt mal bei einem 1-Zyklen-Befehl und mal in einem 2-Zyklen-Befehl 
reinhaut, dann hat man schon Abweichungen im Prozentbereich.

von Timmo H. (masterfx)


Angehängte Dateien:

Lesenswert?

So ich war mal so frei. Hab jetzt einfach das gemacht wie es im 
Datenblatt steht und es scheint zu gehen:
1
#include <avr/io.h> 
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
int main(){
6
    TCCR1A = (1<<COM1A1);
7
    TCCR1B = (1<<CS10) | (1<<WGM12);
8
9
    TCNT1 = 0;
10
    OCR1A = 0x1E;
11
    TIMSK |= (1<<OCIE1A);
12
    sei();
13
    while(1);
14
15
}
16
17
18
ISR(TIMER1_COMPA_vect){
19
....
20
}
Der Fehler ist wohl das WGM12 gewesen (siehe Bild)

von Tanja H. (hoefme)


Lesenswert?

Danke für deine Hilfe Timmo. Jedoch habe ich ein weiteres problem mit 
deine Lösung, meine Frequenz springt zwischen 80Khz und ca 118khz herum.

An was liegt das??

von Johannes M. (johnny-m)


Lesenswert?

Timmo H. wrote:
So weit so gut, aber warum schreibst Du da...
>     OCR1A = 0x1E;
ein 0x1E hin? Eine 30 hätte es auch getan, und jeder Anfänger merkt 
erstens, dass der Compiler in der Lage ist, dezimal zu verstehen (*) und 
man sieht außerdem sofort, was da gemacht wird. Für Bitmasken nehme ich 
auch direkt Hexadezimalwerte, weil man sich aus denen direkt die 
Bitmuster ableiten kann, aber für Sachen wie Zykluszahlen sollte man 
auch dezimal bleiben.

(*) Wie war das noch? Es gibt auf der Welt genau 10 Sorten Menschen: 
Diejenigen, die binär verstehen und diejenigen, die es nicht können...

von Johannes M. (johnny-m)


Lesenswert?

Tanja Hofmann wrote:
> Danke für deine Hilfe Timmo. Jedoch habe ich ein weiteres problem mit
> deine Lösung, meine Frequenz springt zwischen 80Khz und ca 118khz herum.
Dann solltest Du vielleicht endlich mal Deinen Code posten!

von Timmo H. (masterfx)


Lesenswert?

>So weit so gut, aber warum schreibst Du da...
>     OCR1A = 0x1E;
>ein 0x1E hin? Eine 30 hätte es auch getan, und jeder Anfänger merkt
>erstens, dass der Compiler in der Lage ist, dezimal zu verstehen (*) und
Ist mir auch klar, dass der Compiler das versteht. Nur so bringt man 
Tanja nicht so durcheinander, weil sie ja mit Hex angefangen hat.

von Johannes M. (johnny-m)


Lesenswert?

Timmo H. wrote:
> Ist mir auch klar, dass der Compiler das versteht. Nur so bringt man
> Tanja nicht so durcheinander, weil sie ja mit Hex angefangen hat.
Ich glaube nicht, dass sie in der Schule mit Hex angefangen hat, es sei 
denn, sie ist auf eine Hexenschule gegangen...

SCNR

von Timmo H. (masterfx)


Lesenswert?

>Ich glaube nicht, dass sie in der Schule mit Hex angefangen hat, es sei
>denn, sie ist auf eine Hexenschule gegangen...
Ne, aber in ihrem ersten Posting. Hex-Hex...

von Tanja H. (hoefme)


Lesenswert?

Mhhh lassmer das mal mit dem dem Hexen-Zeugs ..... Habe das halt nie so 
gelehrnt das man register nicht mit hex beschreiben sollte. Nun mein 
programm erzeugt immer noch nicht die gewünnschten 122 kHz. Es macht mit 
diesen Einstellungen nur 24kHz.


    TCCR1B = 0x00; //stop
    TCNT1H = 0xFF; //load counter HIGH value
    TCNT1L = 0xE1; //load counter LOW value

    TCCR1A = 0x00;
    TCCR1B = 0x01; //start Timer
    TIMSK = 0x04;  //timer interrupt sources


    ISR(TIMER1_OVF_vect){
  TCNT1H = 0xFF; //load counter HIGH value
         TCNT1L = 0xE1; //load counter LOW value
    }


Was mache ich falsch? Habe mit diesem Problem seit tagen schon zu 
kämpfen und bin sehr sehr froh für weiter hilfe.

grüssel

von Johannes M. (johnny-m)


Lesenswert?

Ich habe mich doch oben ganz klar und unmissverständlich zu dem Thema 
ausgelassen: Auf diese Weise bekommst Du keine 122 kHz! Erstens ist der 
Timer Reload Murks (wie schon mehrfach angedeutet) und zweitens hat 
der Interrupt Handler zu viel Overhead. Und warum beschreibst Du jetzt 
plötzlich die Timer-Zähl-Register in zwei Schritten? Die Reihenfolge 
stimmt zwar (zufälligerweise?), aber in C kann man TCNT1 als ganzes 
beschreiben und muss (bzw. sollte) nicht das Low- und High-Byte getrennt 
schreiben! Oben wurden Beispiele geliefert, wie das ganze mit der 
Compare-Einheit zu realisieren ist. Bist Du dermaßen lernresistent 
oder tust Du nur so? Langsam glaube ich das alles nicht mehr!

von Simon K. (simon) Benutzerseite


Lesenswert?

Aber angeschaut hast du dir den Code von Timmo H. schon, oder?

von Tanja H. (hoefme)


Lesenswert?

Ja sicher habe ich das, jedoch sprint mir dann die frequenz 80Khz 
-118khz herum. Meine langsam bin ich ja auch am verzweifeln denn einen 
Timer zu realisieren sollte nicht so schwierig sein.

von Johannes M. (johnny-m)


Lesenswert?

Aber mein Posting von gestern, 18:54 hast Du gelesen, ja?

von Tanja H. (hoefme)


Lesenswert?

Also mein code sieht momentan folgendermassen aus:

    TCNT1  = 0;     //load timer

    TCCR1A = 0x00;
    TCCR1B = 0x01; //start Timer
    TIMSK |= (1<<TOIE1);
    TIMSK |= (1<<OCIE1A);
    OCR1A = 30;


In die Compare - Interrupt routine kommt er aber macht mir nicht die 
gewünschte 122.8kHz !

von AVRFan (Gast)


Lesenswert?

>Was mache ich falsch?

Du probierst auf gut Glück herum ohne über ein gründliches theoretisches 
Verständnis der µC-Komponente Timer zu verfügen.

>In die Compare - Interrupt routine kommt er aber macht mir nicht die
>gewünschte 122.8kHz !

Dann versuch doch mal herauszufinden, was genau der Timer bei dieser 
Konfiguration tut.

von Timmo H. (masterfx)


Lesenswert?

>In die Compare - Interrupt routine kommt er aber macht mir nicht die
>gewünschte 122.8kHz !
Was ist denn mit WGM12? Ich habs drin und bei mir gehts (zumindest beim 
Simulieren). Ohne WGM12 kommt imho kein Auto-Clear
1
 TCCR1B = (1<<CS10) | (1<<WGM12);

von Tanja H. (hoefme)


Lesenswert?

So komme glaub dem fehler auf die Spur .... Also der Interrupt wird
ausgeführt, jedoch habe ich kein Signal am OC1A obwohl ich im Programm
mit DDRB = (1<<PB5) den pin als Output deklariere. Zudem habe ich noch 
TCCR1A = (1<<COM1A0) geändert um am OC1A zu togglen.

Was habe ich vergessen oder mache ich da falsch?

von Timmo H. (masterfx)


Lesenswert?

Wie änderst du denn das Signal am pin?
Du hättest dir und uns ne Menge arbeit erspart, wenn du einmal deinen 
ganzen Quellcode gepostest hättest!!! Und was ist mit WGM12?

von Tanja H. (hoefme)


Lesenswert?

Das ist der Code für die Timer initaliserung. Das Signal ändere ich ja 
indem ich COM1A0 auf 1 legge, sprich dann wird getogglet. Müsste doch so 
laufen oder?  Respektiv der Interrupt wird schon aufgerufen, jedoch habe 
ich nichts am Pin 0C1A.

    // Timer Init

    DDRB = (1<<PB5)

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

    TCNT1 = 0;
    OCR1A = 0x1E;
    TIMSK = (1<<OCIE1A);

von Timmo H. (masterfx)


Lesenswert?

Wow, so kurz ist dein GANZES Programm? So ohne Main Funktion und so? Was 
ist daran so schwer ALLES zu Posten. Wenigstens Main und deine ISR? So 
kann man doch das alles nicht vernünftig überblicken!!! Das haben doch 
jetzt schon mehrere gesagt.
Zudem ist COM1A0 auch nicht PB5 sondern PB6. Kann ja nicht funzen wenn 
du das DDR falsch setzt.
Und eigentlich sollte man auch
1
DDRB |= (1<<DDB0);
Schreiben anstatt PB0. Ist zwar das selbe, kann aber ggf. Verwirrung 
stiften.

von Tanja H. (hoefme)


Lesenswert?

Habe gemeint das COM1A0 und COM1A1 für den Compare Output Mode Channel A 
sind. Das heisst OC1A enspricht PB5, laut datenblatt. Oder sehe ich das 
falsch?

von Johannes M. (johnny-m)


Lesenswert?

Jo, PB5 stimmt schon. Aber es ist wirklich an der Zeit, mal endlich 
einen kompletten, compilierbaren Code zu schicken!

von crazy horse (Gast)


Lesenswert?

??
Was bitte hat die Bitstelle im control-Register mit dem Hardware-Pin zu 
tun?
Richtig, nichts.

von Timmo H. (masterfx)


Lesenswert?

Stimmt PB5 ist richtig, bin jetzt selbst durcheinandergekommen, so ganz 
ohne Code :-). Kommt der eigentlich nocht? Wahrscheinlich nicht. Ich 
steige mal aus...

von Tanja H. (hoefme)


Lesenswert?

Ja der Code sieht folgendermassen aus:


#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr\iom128.h>


void port_init(void)
{
  DDRB = (1<<PB5);
}

void timer1_init(void)
{


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

    TCNT1 = 0;
    OCR1A = 0x1E;
    TIMSK = (1<<OCIE1A);
}

void init_devices(void)
{
  port_init();
  timer1_init();
  sei();
}

ISR(TIMER1_COMP_vect){

}

int main(void)
{
  init_devices();
  while(1);
}

von Johannes M. (johnny-m)


Lesenswert?

Tanja Hofmann wrote:
> #include <avr\iom128.h>
Die Device-Header werden nie direkt eingebunden! Müsste aber eigentlich 
auch ne Warnmeldung geben. Der Controllertyp wird im Makefile bzw. im 
AVRStudio unter Configuration Options angegeben und nur die avr/io.h 
wird eingebunden.

> ISR(TIMER1_COMP_vect){
Und genau da liegt vermutlich der Hund begraben (oder zumindest einer 
von mehreren)! Der Interrupt-Vektor heißt mindestens TIMER1_COMPA_vect 
(hab jetzt nicht in die Doku geschaut). Da fehlt ein "A"! Das gibt jedes 
Mal einen Reset, wenn der Interrupt angesprungen wird, weil Du einen 
Interrupt freigegeben hast, zu dem es keinen Handler gibt!

Deaktiviere mal den Interrupt, den brauchst Du nämlich für die 
Signalerzeugung überhaupt nicht. Das macht der Timer alles allein. Also 
ISR raus, sei() und TIMSK = 1<<OCIE1A ebenfalls weg!

Verstehst Du jetzt vielleicht endlich, warum es wichtig ist, den 
kompletten Code zu schicken und nicht nur ein paar zusammenhanglose 
Zeilen?

von Tanja H. (hoefme)


Lesenswert?

Kann demfall die "#include <avr\iom128.h>" weglassen!

Jedoch funktioniert das Togglen am Pin PB5 nicht, obwohl die ISR methode 
aufgerufen wird. Habe ich vergessen irgendwo was zu setzten?

von Tanja H. (hoefme)


Lesenswert?

Ja leuchet mir ein, dachte halt das mein Feher in der Initalisierung 
war. Werde dies gegen den Abend mal versuchen ohne der ISR ,sei() und 
TIMSK = 1<<OCIE1A ! Hoffe klappt dann bald einmal.

von Timmo H. (masterfx)


Lesenswert?

Siehste, hättest du viel früher deinen Code gepostet hätte es und dir 
und uns ne Menge Zeit gespart. Wars denn so schwer?

von Tanja H. (hoefme)


Lesenswert?

Trau mich fast nicht mehr reinzuschreiben .... aber habe das Problem 
gefunden! Es hatte den Pin PB5 bei der Produktion nicht richtig verlötet 
mit dem Print.

Also besten dank für eure grossen Bemühungen. Schätze das sehr und weiss 
das es nicht selbstverständlich ist.

von Tanja H. (hoefme)


Lesenswert?

Habe zum schluss doch noch eine Frage. Sollte schon gehen mit einem 
Timer den CompareA, CompareB gleichzeitig mit unterschiedlichen 
Frequenzen zu betreiben oder was mache ich für ein Überlegungsfehler?

Hier mein Code:

#include <avr\io.h>
#include <avr\interrupt.h>


void port_init(void)
{
  DDRB = (1<<PB5);
  DDRB = (1<<PB6);
}

void timer1_init(void)
{


    TCCR1A = (1<<COM1A0)| (1<<COM1B0);
    TCCR1B = (1<<CS10) | (1<<WGM12);

    TCNT1 = 0;
    OCR1A = 0x1E;
    OCR1B = 0x0F10;
    TIMSK = (1<<OCIE1A);
    TIMSK = (1<<OCIE1B);
}

void init_devices(void)
{
  port_init();
  timer1_init();
  sei();
}

ISR(TIMER1_COMPA_vect){

}

ISR(TIMER1_COMPB_vect){

}

int main(void)
{
  init_devices();
  while(1);
}

von Johannes M. (johnny-m)


Lesenswert?

Nö, mit unterschiedlichen Frequenzen geht natürlich nicht. Wie soll denn 
ein Timer mit zwei unterschiedlichen Frequenzen laufen können?

Und noch mal: Wenn Du mit Hardware die Pins toggelst und beim Compare 
Match sonst nix zu tun ist, dann lass die Interrupt-Sachen weg! Leere 
Interrupt Handler erzeugen nur unnötigen Overhead.

von Timmo H. (masterfx)


Lesenswert?

Wieso, der Timer kann doch gleich bleiben. Sind doch nur 
unterschiedliche Compares.

von crazy horse (Gast)


Lesenswert?

man kann aber unterschiedliche compares nicht verschiedene Frequenzen 
erzeugen. Die Frequenz wird ausschliesslich vom Takt (ggf. mit Teiler) 
und dem Rücksetzwert bestimmt (kann ein Überlauf mit anschliessendem 
reload oder ein compare-Ereignis sein).

von Tanja H. (hoefme)


Lesenswert?

Will ja nicht 2 verschiedene Frequenzen am timer einstellen, sondern am 
PB5 und PB6 mit den CompareA und CompareB zwei verschiedene Frequenzen 
erzeugen.

OCR1A = 0x1E;
OCR1B = 0x0F10;

Soltte ja schon gehen sonst machen die Compares ja gar keinen sinn oder?

von Johannes M. (johnny-m)


Lesenswert?

Tanja Hofmann wrote:
> Will ja nicht 2 verschiedene Frequenzen am timer einstellen, sondern am
> PB5 und PB6 mit den CompareA und CompareB zwei verschiedene Frequenzen
> erzeugen.
>
> OCR1A = 0x1E;
> OCR1B = 0x0F10;
>
> Soltte ja schon gehen sonst machen die Compares ja gar keinen sinn oder?
NEIN !!! mit einem Timer (und die Compare-Einheiten gehören beide 
zum selben  Timer!) kann man keine zwei verschiedenen Frequenzen 
gleichzeitig fahren! Die Compare-Einheiten haben nichts mit 
unterschiedlichen Frequenzen zu tun. Man kann nur einen TOP-Wert für 
den Timer angeben, und der bestimmt die Frequenz!

von Johannes M. (johnny-m)


Lesenswert?

Falls das nicht klar sein sollte (was ich vermute): Die beiden 
Compare-Einheiten dienen u.a. der Erzeugung zweier synchroner 
PWM-Signale mit unterschiedlichen Tastverhältnissen und gleicher 
Frequenz.

von AVRFan (Gast)


Lesenswert?

>mit einem Timer (und die Compare-Einheiten gehören beide
>zum selben  Timer!) kann man keine zwei verschiedenen Frequenzen
>gleichzeitig fahren!

Man kann mit T/C1 über die beiden Compare-Einheiten auch zwei 
verschiedene Frequenzen erzeugen - innerhalb gewisser Grenzen und unter 
Verwendung der Compare-Match-Interrupts.

Dazu lässt man T/C1 im Mode 0 laufen (kein CTC!)  Sowohl bei Compare 
Match A als auch bei Compare Match B muss der entsprechende Interrupt 
ausgelöst werden.  Jetzt der "Trick": Im COMPA-Interrupthandler erhöht 
man OCR1A um einen bestimmten, festen Wert (z. B. 600), im 
COMPB-Interrupthandler dasselbe mit OCR1B (z. B. 800).

Zur Frequenzerzeugung werden COM1A0 und COM1B0 im TCCR1A gesetzt 
(Einstellung "Pin toggeln bei Compare Match").

Solange die Inkrementierwerte in den Handlern nicht zu klein und nicht 
zu groß sind (kein Compare-Match-Interrupt darf verloren gehen), werden 
an den Pins OC1A und OC1B zwei voneinander völlig unabhängige, durch die 
Inkrementierwerte festgelegte taktgenaue Frequenzen anliegen.

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.