Hallo Leute,
ich würde mir gerne eine Funktion für einen Mikrocontroller schreiben,
der ich eine beliebige Frequenz (zwischen 1Hz und 10kHz) übergebe und
die mir dann daraus ein PWM Signal mit eben dieser Frequenz generiert.
Nun stehe ich vor dem Problem, dass die Frequenz möglichst genau (auf 1%
genau wäre super) sein sollte. Ich glaub es ist am besten, wenn ich das
mit ein, zwei Beispielen konkretisiere:
Zur Information:
Der Mikrocontroller wird mit einem 8MHz Quarz betrieben. Weiters besitzt
dieser die Möglichkeit über ein internes Prescale-Register (16bit breit)
die Frequenz entsprechend vorzuteilen. Der Wert des Auto-Reload
Registers wird nach folgender Formel berechnet:
CPU_FREQ/PRESCALER/gewünschte_Frequenz
Angenommen ich verwende einen Prescale Wert von 800 und hätte gerne eine
gewünschte Frequenz von 200Hz.
Dann würde ich rechnen: 8MHz/800/200 = 50
Hier ist noch alles in Butter.
Würde ich den gleichen Prescale Wert verwenden um eine gewünschte
Frequenz von 7000Hz erzeugen zu wollen, dann würde ich aber folgendes
bekommen:
8MHz/800/7000 = 1,428
Der Wert ist aber in zweierlei Hinsicht schlecht. Erstens habe ich, wenn
ich den Wert auf 1 abrunde einen Fehler von gut 40% und zweitens sollte
der Auto-Reload Wert zumindest zweistellig sein, damit man über ein
Capture/Compare Register das Pulsbreitenverhältnis (75%, 50%, 25%...etc)
verändern kann.
Ich hoffe man sieht bereits auf was ich hinaus möchte. Meine Idee wäre
nun folgende: Ich berechne mir möglichst 'gute' Prescale Werte und lege
diese in einer Tabelle im Mikrocontroller ab. Wenn ich nun eine Frequenz
erzeugen möchte, dann durchsuche ich die Tabelle und vergleiche die
Fehler, die durch die einzelnen Prescale Werte entstehen. Derjenige, der
am besten abschneidet, den nehm ich dann.
Die Frage ist nur, wie berechne ich mir die 'guten' Prescale-Werte? Zu
beachten ist, dass das Prescale Register und das Auto-Reload Register
jeweils nur 16bit breit sind und das der Auto-Reload Wert zumindest
zweistellig sein sollte (wobei man letzteres ziemlich einfach
softwaretechnisch lösen könnte). Welche Genauigkeit kann man damit
erzielen? Ist 1% Genauigkeit aus der Luft gegriffen oder realistisch?
Hat jemand einen besseren Vorschlag?
Weiter rechnen
8MHz/800/7000 = 1,428
-> du wählst einen Prescaler von 1
Wie groß muss dann der Auto-Reload sein
1
8Mhz / 1 / 7000 = 1142
Also Vorteiler: 1, Auto-Reload 1142
Das ergibt dann nach deiner Formel eine Frequenz von
1
8Mhz / 1 / 1142 = 7005 Hz
Aus dem Bauch heraus würde ich schätzen, dass du einen möglichst kleinen
Prescaler benutzen willst. 1 wird als Wert immer gut sein, es sei denn
dass dadurch der Reload Wert die zulässige Grenze verlässt, dann musst
du mit dem Prescaler höher gehen.
Worum gehts denn:
du suchst ein x, sodas
8Mhz / x = gesuchte Frequenz
dieses x setzt sich wiederrum zusammen aus
x = prescaler * reload
da sowohl prescaler als auch reload ganze Zahlen sein müssen, kann dein
kompletter Teilerfaktor x sowieso auch nur eine ganze Zahl sein.
Bei deinem Beispiel mit den 7Khz bräuchtest du einen kompletten
Teilerfaktor von 80000000 / 7000 = 1142.85
Die 0.85 wirst du nie erreichen können. Du suchst also 2 Zahlen p und r
(prescaler und reload), sodass
p * r = 1142 (oder 1143 wenn du rundest)
Jetzt kannst du zb probieren: prescaler 1, 2, 3, 4, 5
(oder aber einfach mal einen reload Wert in der Mitte des angepeilten
Bereichs annehmen, daraus den prescaler berechnen und mit dem jetzt
festgelegten prescaler den reload Wert korrigieren
Du kannst natürlich auch mit "Bruth Force" an die Sache rangehen.
Aus
p * r = 1142
lässt du deinen Rechner einfach alle Kombinationen durchspielen und
lässt ihn die Kombination von p und r finden (du weisst ja, dass weder p
noch r größer als der Zielwert sein können, d.h. du hast eine Obergrenze
für beide Werte), die am nähesten beim Zielwert liegt. Wenn Computer
etwas wirklich gut können, dann ist das Rechnen.
Hallo Karl Heinz,
ich hab deine Idee mit den möglichst niedrigen Prescale Werten mal
aufgegriffen und ein paar Testberechnungen durchgeführt. Ich hab das
Gefühl, dass dadurch die Genauigkeit zunimmt. Ich bin mir noch nicht
ganz sicher ob das Zufall ist, oder nicht. Das werd ich mir morgen noch
genauer ansehen.
Karl Heinz Buchegger schrieb:> Du kannst natürlich auch mit "Bruth Force" an die Sache rangehen.> Aus> p * r = 1142> lässt du deinen Rechner einfach alle Kombinationen durchspielen und> lässt ihn die Kombination von p und r finden (du weisst ja, dass weder p> noch r größer als der Zielwert sein können, d.h. du hast eine Obergrenze> für beide Werte), die am nähesten beim Zielwert liegt. Wenn Computer> etwas wirklich gut können, dann ist das Rechnen.
Das hab ich mir auch schon überlegt. Nur die Frage ist: Wie verfahre ich
dann weiter? Ich hab dann einen optimalen Wert für p und r der für eben
diese Frequenz optimal ist. Wenn sich die Frequenz ändert, dann geht die
Rechnerei wieder von Neuem los. Prinzipiell stellt das für den PC
natürlich kein Problem dar, für den sind solche Berechnungen ja Pipifax.
Nur wär es halt schön, wenn man ohne diesen Zwischenschritt, dem PC
Programm/Excel-Sheet..etc auskommen könnte. Also das man einfach eine
Funktion aufruft, dieser einen Frequenzwert übergibt und die dann die
alles weitere vornimmt. Also mal wieder eine eierlegende Wollmilchsau,
ich weiß ;)
Bernhard B. schrieb:> diese Frequenz optimal ist. Wenn sich die Frequenz ändert, dann geht die> Rechnerei wieder von Neuem los.
So viele sinds ja auch wieder nicht.
aus
p * r = Zielwert
folgt
p = Zielwert / q
du lässt für q eine Schleife von 1 bis Zielwert-1 laufen und siehst nach
ob die Division einen Rest von 0 ergibt. Theoretisch würde es sogar
reichen, wenn man für q nur alle Primzahlen im Bereich 1 bis Zielwert
untersucht. Wenn da nicht die Forderung wäre, dass man (falls es keinen
Rest 0 gibt), dasjenige q sucht, für das abs(Zielwert - p*q) minimal
ist. Da bin ich mir jetzt nicht sicher, ob man das dann auch finden
würde, wenn man sich nur auf Primzahlen beschränkt. Ich denke: ja. Aber
dann gibt es ja auch noch die Nebenbedingung, dass p kleiner als eine
obere Schranken sein muss.
Aber eine 'Optimierung' gibt es. Es reicht, aus Symetriegründen, die
Schleife von 1 bis sqrt(Zielwert-1) laufen zu lassen, denn eine der
beiden Zahlen muss kleiner/gleich sqrt(Z-1) sein. sqrt kann jetzt eine
teure Operation sein, eventuell durch (zielwert-1)/2 ersetzen.
Ist nun mal so:
Du hast 1 Gleichung in 2 Unbekannten und zwei Nebenbedingungen. So der
Mathecrack bin ich nun auch wieder nicht, dass ich wüsste wie man sowas
löst bzw. ob das überhaupt geschlossen lösbar ist.
Bernhard B. schrieb:> Hallo Karl Heinz,>> ich hab deine Idee mit den möglichst niedrigen Prescale Werten mal> aufgegriffen und ein paar Testberechnungen durchgeführt. Ich hab das> Gefühl, dass dadurch die Genauigkeit zunimmt.
Logisch.
Wenn der Prescaler 1 ist, dann kannst du deinen Gesamtteiler rein durch
den Reload Wert in 1-er Schritten variieren.
Ist dein Presscaler 2, dann kannst du den Gesamtteiler auch nur noch in
2-er Schritten variieren. Erhöhst du den Reload-Wert um 1, dann wird der
komplette Teilerfaktor um 2 größer.
Machst du einen Prescaler von 3, dann kann dein kompletter Teilerfaktor
auch nur noch in 3-er Schritten variieren.
etc. etc.
Mit einem Prescaler von 1 hast du daher die Möglichkeit, den kompletten
Teiler am feinsten einzustellen.
Als Ausgleich dafür kriegst du aber mit einem höheren Prescaler Wert
auch höhere Gesamtteiler-Werte. Das ist jetzt insofern wichtig, als du
dir zb ausgerechnet hast, dass du einen Gesamtteiler von 70000 brauchen
würdest. Mit einem Prescaler von 1 würde das einen Reload Wert von 70000
ausmachen. Das geht aber nicht, weil Reload nicht größer als 65535 sein
kann.
Aber mit einem Prescaler von 2 geht es. Denn dann ist der Preload Wert
35000, und das geht dann wieder mit 16 Bit. Allerdings ist der nächste
Gesamtteiler nach 70000 dann erst wieder 70002. Ein Teiler von 70001 ist
so mit diesem Prescaler nicht erreichbar.
Karl Heinz Buchegger schrieb:> Logisch.> Wenn der Prescaler 1 ist, dann kannst du deinen Gesamtteiler rein durch> den Reload Wert in 1-er Schritten variieren.
Jetzt wo ich (im ausgeschlafenen Zustand) drüber nachdenke ist das
natürlich logisch.
Durch deinen letzten Beitrag angespornt hab ich mir jetzt folgende
Vorgehensweise überlegt:
Ich werd ein mir ein C-Programm für den PC schreiben, welches mir für
jede Frequenz zwischen 1Hz und 10kHz die Abweichung vom Sollwert
berechnet. Den Prescale-Wert lass ich dabei von 1 bis 50 laufen. Ein
höherer Prescale-Wert wird denke ich nicht so viel Sinn haben. So kann
ich mal überprüfen welche Genauigkeiten überhaupt erreicht werden
können.
Sollte sich die Abweichung in Grenzen halten, dann gehts daran das im
Mikrocontroller zu realisieren. Wenn ich nun, so wie oben beschrieben,
den Prescaler von 1 bis 50 laufen lasse, dann würde das 50 Divisionen
bedeuten. Ich hab ehrlich gesagt nicht wirklich ein Gespür wie lang ein
32bit-Mikrocontroller, getaktet mit 8MHz ohne FPU für 50 Divisionen
braucht.
Aber ich denke ich werd das einfach mal ausprobieren.
Danke!
@Peter: Könntest du kurz erklären was PWM_max und f_out ist?
f_out = gewünschte Frequenz?