Hallo Leute,
ich beschäftige mich gerade mit Timer1 des Atmega8. Hintergrund ist ein
einfacher Rechteckgenerator mit einstellbarer Frequenz. Minimum ist
eigentlich egal, liegt aktuell eh unter 1Hz. Maximum reichen 50kHz.
Der Timer läuft im CTC mit Output toggle bei match. Funktioniert auch
gut. Prescaler von 64 bringt mir 62,5kHz bei OCR1A=0 und 0,9567Hz bei
OCR1A=65535.
Nun hätte ich ja die 65535 Zähler um die Frequenz ein zu stellen. Das
läuft aber nicht linear.
Zählt er bis 1 sind es 31,33kHz.
Zählt er bis 2 sind es nur noch 20,1kHz.
Kommt man dann in die Region 65535 lässt sich dafür die Frequenz auf
0,0001Hz einstellen.
Rechnerisch ist das ja alles korrekt. Aber wie bekomme ich es nun hin
das ganze linear zu verteilen? Ich steh gerade ein wenig auf der
Leitung.
So sieht mein Versuch aus:
Das heißt z.b. auf nem Mega8 mit 16Mhz und deinem Vorteiler von 64 und
wie oben CTC sowie einer Ziel-Frequenz von 50 Herz:
1
OCR1A=16000000/50/2/64-1;
Aaaaaber.... mach das über eine Variable, weil wie du siehst, es ist ein
Uint32. Und durch die Division isses auch nicht sonderlich
Resourcensparend. Ich mach das immer so:
Hallo Rene,
danke für die schnelle Antwort.
Das Beispiel gefällt mir, werde ich sicherlich auch so übernehmen. Die
Berechnung funktioniert gut für 50Hz.
Will ich aber als Zielfrequenz nun 25kHz haben ergibt es rechnerisch
einen OCR1A von 1,5 (FCPU sind bei mir 8Mhz) Ich weiß nicht wie die 1,5
umgesetzt werden, denke da wird dann auf oder abgerundet. Geht man von 1
aus sind wir am unteren Ende der Skala und der Ausgang läuft mit
31,33kHz anstelle der 25kHz. Würde man die zwei nehmen wären es nur noch
20,1kHz. Wie treffe ich denn die Frequenz dazwischen dann?
Wenn ich mit Vorteiler auf 62,5kHz komme und bei dem 16 Bit Zähler bis
65535 Zählen kann müsste man doch meinen das es eine Möglichkeit gibt
das ganze auf ±1Hz genau zu verteilen.
Dann nimm einen anderen Vorteiler. Oder besser, teile diesen auf:
1
uint32_tocr=F_CPU/frequency/2-1;
2
3
if(ocr>65534)
4
{
5
ocr=F_CPU/frequency/2/64-1;
6
TCCR1B=(1<<WGM12)|(1<<CS10)|(1<<CS11);
7
}
8
else
9
{
10
TCCR1B=(1<<WGM12)|(1<<CS10);
11
}
12
13
OCR1A=ocr;
(Ich hab jetzt net geschaut ob da die Freq höher oder tiefer geht :D -
je nachdem einen höheren oder tieferen Prescaler nehmen)
EDIT: Code von 16Mhz auf F_CPU geändert.
Denkanstoß:
Mit den Timerwerten kannst Du nur die Periodendauer verstellen, dies
erfolgt linear, also proportional zum Timerwert. Die Frequenz ist aber
1/T und somit nicht linear. Vielleicht hilft Dir ja statt der Rechnerei
ein Array mit Timerwerten und ein Index, der in Frequenz skaliert ist.
Das lässt sich auch mit dem Vorteiler kombinieren, indem man Bereiche
nutzt, die sich mit verschiedenen Vorteilern wiederholen.
...
Florian K. schrieb:> Geht man von 1> aus sind wir am unteren Ende der Skala und der Ausgang läuft mit> 31,33kHz anstelle der 25kHz. Würde man die zwei nehmen wären es nur noch> 20,1kHz. Wie treffe ich denn die Frequenz dazwischen dann?
Garnicht natürlich. Die Hardware kann nur Ganzzahlen für die
Periodendauer. Und da der Zusammenhang zwischen Periodendauer und
Frequenz halt 1/x ist, sollte jedem, dem sie nicht sehr heftig in's Hirn
geschissen haben, klar sein, dass das mit der Frequenz unmöglich klappen
kann...
> Wenn ich mit Vorteiler auf 62,5kHz komme und bei dem 16 Bit Zähler bis> 65535 Zählen kann müsste man doch meinen das es eine Möglichkeit gibt> das ganze auf ±1Hz genau zu verteilen.
Nein. Dir fehlen offensichtlich die elementarsten Grundlagen der
Mathematik. Die nächstmögliche Lösung wurde im Thread bereits genannt:
Das DDS-Prinzip.
Aber auch die kann natürlich letztlich nicht gegen die Mathematik
anstinken. Bestenfalls kannst du damit kontinuierlich die 100% korrekte
Frequenz für jede gewünschte Frequenschritt-Größe absondern. Das aber
nur mit mehr oder weniger heftigen Phasenfehlern, die effektiv nichts
anderes darstellen als eine zum gewünschtne Signal hinzugemischte
Störfrequenz...
Wenn man C hasst und wohl BASIC bevorzugt (?), muss man doch
bei Grundsatz-Fragen nicht gleich so aggressiv werden.
Besser wäre es, dem TO klarzumachen, dass man durch TEILEN,
wobei der Teiler eine GANZE ZAHL ist, nun mal nicht jede
Frequenz herleiten kann. Zumindest, wenn man beim ATmega8 auf
<= 20 MHz beschränkt ist.
Vielleicht genügt da ein Beispiel:
20 MHz : 400 = 50.000 Hz
20 MHz : 401 = 49.875 Hz
und wenn es ein symmetrisches Rechteck sein soll, (Output
toggle), wird es noch gröber:
(20 MHz : 200) / 2 = 50.000 Hz
(20 MHz : 201) / 2 = 49.751 Hz
Genauer geht es nicht, denn es kann keine Tabelle geben, die
eine Ganzzahl zwischen 200 und 201 liefert.
FERTIG.
Jakob schrieb:> Wenn man C hasst
Ich mag auch kein C, von Hass kann aber keine Rede sein.
> und wohl BASIC bevorzugt (?),
Es gibt auch noch Assembler. Das traue ich dem C-Hasser sogar zu, nach
Allem, was ich so von ihm gelesen habe. Doof ist der nämlich nicht.
Übrigens kann man auch in Basic viele Probleme lösen. Man sollte aber
nicht alle Funktionsangebote von Bascom nutzen, da viele davon
blockierend arbeiten und somit kontraproduktiv wirken. So ist z.B. eine
kleine Modellbahn-Digitalzentrale (DCC) mit ATMega8 in Bascom kein
Problem. ;-)
> muss man doch> bei Grundsatz-Fragen nicht gleich so aggressiv werden.
Da hast Du allerdings nicht ganz unrecht. Ich kann mich mit diesem Stil
auch nicht so recht anfreunden. Bei diesem Tonfall verpufft meist die
Wirkung einer ansonsten sachlich richtigen Aussage.
Trotzdem habe ich seinen Hinweisen (in anderen Threads) schon diesen und
jenen wertvollen Tipp entnehmen können. Schräg angemacht fühlte ich mich
dabei aber nicht, da es nicht meine Fragen sind, auf die er so reagiert.
Ich stelle in diesem Forum hier schon sehr lange keine Fragen mehr.
>> Besser wäre es, dem TO klarzumachen, dass man durch TEILEN,> wobei der Teiler eine GANZE ZAHL ist, nun mal nicht jede> Frequenz herleiten kann.
Genau deshalb empfahl ich ja eine Tabelle (Array) mit einer etwas
groberen Auflösung und als Index die gerasterte Frequenz. Wenn man den
Timer-Vorteiler so wählt, dass man mit Timer-Intervallen den unteren
Bereich meidet, so bekommt man auch eine halbwegs lineare Skalierung
hin. Exakt genau geht es aber nicht. Ich denke aber auch, dass das gar
nicht nötig ist.
Wenn man den Timer-Vorteiler auch variabel macht, braucht man mit den
Timerwerten (Intervalle, halbe Periodendauer für Pintoggeln) nur den
Bereich von 1 zu 8 abdecken. Danach wird der Vorteiler verändert und das
Spiel beginnt von vorn.
> Zumindest, wenn man beim ATmega8 auf> <= 20 MHz beschränkt ist.
Bis 16 MHz, die 20 MHz gibt es erst bei den neueren AVRs. Und selbst da
rudert Atmel ja inzwischen wieder zurück... Aber Controllertakt ist ja
nicht Alles. Mit schlanker Programmierung erreicht man meist mehr.
...
Hallo Leute,
mir ist ja selbst schon klar geworden das es über diesen Weg nicht
möglich ist. Der Taschenrechner (Ja, ein wenig Mathe kann ich schon) hat
meine Ergebnisse auch immer Bestätigt. Die Hoffnung war das es sich über
einen anderen Weg realisieren lässt. DDS halte für diese Anwendung für
übertrieben. So 100% exakt muss das nicht laufen.
Das ganze läuft nun ohne Vorteiler. Da ich eh nur bis ~30kHz gehen
möchte bin ich schon in einer Region wo sich die Frequenz halbwegs gut
einstellen lässt. Gut genug für das was er tun soll.
Danke für Eure Antworten und auch für diese die vielleicht einen etwas
härteren Ton bevorzugt :)
Grüße
Flo