Hallo
Ich will einen langsamen Sinus erzeugen. Ich habe mir überlegt, das
ganze mit PWM zu realisieren. Die Frequenz soll bei max. 100Hz liegen.
Bei klassischem PWM, bei dem der Sinus mittels Filtern aus einem
Rechteck erzeugt wird, wäre das Signal nicht schön und es werden große
Filter benötigt.
Daher habe ich mir überlegt, den Sinus mit einem deutlich schnelleren
PWM Signal zu erzeugen, bei dem laufend das on/off Verhältnis verstellt
wird.
Die Ausgabe würde dann z.B. so aussehen:
high: X X X X
X X X X
X X X X
low:_____X____X__X_X[...]
In diesem Fall würde ein kleiner Tiefpass als Integrator ausreichen, um
ein schönes Signal zu erzeugen:
high: --
---
-----
low:------
Die PWM wollte ich mit einem kleinen AVR erzeugen, bin da allerdings
noch nicht so ganz fit. Als Controller verwende ich einen ATTiny462.
Gesteuert wird die PWM über Timer0 und seine beiden Compare Match
Register. In CompareMatchA ist dabei die Periode gespeichert. Zu beginn
einer Periode wird der Pin auf low gelegt. In CompareMatchB wird dann
der Schaltzeitpunkt geladen, zu dem der Pin auf high gelegt werden soll.
Nach Ablauf der Periode wird der Pin wieder zurück auf low gelegt.
Im AVR Studio Simulator funktioniert alles wie gewollt. Leider tut das
nicht in der Realität. Verwende ich in der Tabelle durchgehend den
selben Wert, z.B. 0x50, stimmt alles. Im nächsten Schritt wollte ich
jeden 2. Wert der Tabelle mit 0x10 ersetzen. Ich hätte erwartet, einen
Rechteck mit abwechselnd langer und kurzer off-Zeit zu erhalten. Statt
dessen erhalte ich das ERgebnis, dass ich erwartet hätte, wenn in der
Tabelle 16x 0x10 eingetragen wäre.
Ich bin jetzt ein wenig ratlos. Habe ich etwas nicht bedacht? Die
Periode für die IRQs sollte bei einem Prescaler von 8 ausreichen oder?
Wäre das etwas für die Codesammlung wenn es läuft?
Viele Grüße, Tilo
Deine Verwendung des Timers ist ....... unüblich.
Allerdings sollte es funktionieren ich seh aber im Code das Problem
nicht, warum es nicht geht. Kannst du eine Fehlinterpretation deiner
Messung bzw. überhaupt eine fehlerhafte Messung (flascher Trigger am
Oszi. etc) ausschliessen?
Zum Code selber:
Dir ist klar, dass du dir eine Menge Mühe für nichts machst, weil sich
90% deines Codes damit beschäftigen etwas nachzustellen, was die
Hardware ganz von alleine machen kann?
(Nimm wenigstens das Umschalten der Enable Bits für die beiden Compare
Matches raus. Solange der Wert den du ins B-Register schreibst kleiner
als der im A-Register ist, treten die schon schön im Wechsel auf)
> Wäre das etwas für die Codesammlung wenn es läuft?http://www.mikrocontroller.net/articles/Digitaler_Funktionsgenerator
Aber lass dich nicht aufhalten einen Artikel für die Codesammlung fertig
zu machen.
Hallo
:) Ich weiß. Ich denke gerne mit dem Finger von hinten ins Auge ;)
Ich habe mir überlegt, das ganze mit Hardware-PWM zu machen. Allerdings
habe ich das Handbuch so verstanden, dass damit das Tastverhältnis immer
fest ist.
DDS kenne ich, allerdings wird in dem Artikel ein DAC verwendet, den ich
weglassen wollte.
Viele Grüße, Tilo
Tilo schrieb:> Ich habe mir überlegt, das ganze mit Hardware-PWM zu machen. Allerdings> habe ich das Handbuch so verstanden, dass damit das Tastverhältnis immer> fest ist.
Das ist aber ein komisches Handbuch !
Der Sinn und Zweck von PWM ist, dass man das Tastverhältniss verändern
kann. Die Frequenz ist meist nur sekundär und wird nicht verändert
sondern je nach Einsatzgebiert einmal ausgesucht (damit wird das PWM
Modul initialisiert!)
Wenn man z.B. LEDs dimmen will initialisiert man beispielsweise mit 5kHz
und dimmen tut man dann mittels Tastverhältnis (meist 8Bit = 2^8 = 255
Schritte).
Als Beispiel vom PIC mit Microe Compiler:
[alles mögliche Initialisieren]
int i=0;
PWM1_Init(5000); // Initialisiere PWM mit 5kHz
PWM1_Start;
for(i=0;i<256;i++){
PWM1_Set_Duty(i);
Delay_ms(80);
}
for(i=255;i>0;i--){
PWM1_Set_Duty(i);
Delay_ms(80);
}
// Ende
Das Programm dimmt die LED von 0 bis maximum und wieder zurück.
(Nonlinearität der LED-Dimmung mal ausgenommen).
Siehst du was ich meine? Man arbeitet mit dem Duty-Cycle und nicht mit
der Frequenz!
Danke.
Ich hab das Handbuch nochmal genau gelesen. Ich war wohl beim ersten mal
nicht so ganz auf der Höhe. Diesmal habe ich einige Dinge die keinen
Sinn ergeben einfach ignoriert und etwas brauchbares hinbekommen.
OK.
Natürlich wirst du noch das Weiterschalten von einem Datenbyte zum
nächsten vom PWM Timer entkoppeln indem du zb dafür einen anderen Timer
benutzt. Denn erstens willst du ja deinen Sinus mit einer bestimmten
Frequenz erzeugen, die erst mal nichts mit der PWM Frequenz zu tun hat
und zum anderen möchtest du ja die PWM im Interesse einer möglichst
guten Ausgangsspannung nach der Filterung mit maximaler Frequenz (sprich
einem Vorteiler von 1) laufen lassen.
Noch ein Tip:
Wenn du dir an das Ende deines Datenfeldes noch ein label machst, dann
brauchst du in der Reloadroutine die Anzahl der Datenbytes nicht wissen,
weil du dann einfach dieses Label für die Erkennung der letzten gültigen
Adresse hernehmen kannst.
Das spart einen möglichen Fehler, wenn du in das Datenfeld welches deine
Schwingung beschreibt noch Bytes einfügst oder rausnimmst.
1
Timer1_Reload:
2
LPM R16, Z+ ; Load new value from PWM table
3
OUT OCR1D, R16
4
LDI R17, HIGH(2*sine_end) ; Copy end address of table
5
LDI R16, LOW(2*sine_end) ; Copy end address of table
6
7
....
8
9
; this table contais off values. period is 0xA3. the difference between 0xA3 and value is the on value
Guten morgen
Die Entkopplung ist eine gute Idee. Ich habe nur leider keinen freien
Timer mehr, Timer0 brauche ich für etwas anderes. Da fällt mir aber
vieleicht noch etwas ein, eventuell eine Zählvariable und gut. Der Timer
kann mit einem höhrem asynchronen Takt betrieben werden. Damit könnte
ich auch noch etwas raus holen, muss mir aber noch genau anschauen, wie
das tut.
Das Label am Ende der Tabelle ist eine gute Idee. Der Schwachpunkt ist
mir auch aufgefallen. Ich habe zu erst an sizeof() gedacht. Allerdings
kann der Assembler nicht wissen, wie groß die Tablle ist. Auf die Idee
ein Label zu verwenden bin ich nicht gekommen. Klingt aber logisch,
Labels sind auch nicht mehr dynamische Aliase für eine Adresse im
Programmspeicher.
Viele Grüße, Tilo