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.
1 | Prescaler = (uint16_t)(f_Quarz / PWM_max / f_out + 1.0); |
Peter
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.