PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM mit ATMega8 und Timer2



Eroli
19.04.2011, 09:24
Hallo zusammen,

ich bin ein blutiger Anfänger in diesem Bereich, deshalb entschuldigt bitte, falls ich doof frage und seid geduldig mit euren Erklärungen ;-)
Nachdem ich in einem anderem Forum keine Hilfe mehr bekam (Die letzte Antwort war "Nimm dir das Datenblatt und werd flügge"), habe ich mir zwar das Datenblatt angeguckt (hatte ich auch schon davor :-D), doch so richtig schlau werde ich da leider immer noch nicht draus....

Nach einigen Googlen habe ich dann dieses Forum hier gefunden und einige Beiträge durchgelesen und ich denke, hier sind viele nette und kompetente Köpfe :-)

So, nun zu meinem Problem, bei dem ihr mir hoffentlich helfen könnt :-)

Ich habe eine kleine Schaltung mit einem ATMega8 entworfen, mit der ich die Gartenbeleuchtung meiner Mutter etwas "Pepp" verleihen will (also nicht nur doof leuchten, sondern bisschen dimmen, lauflicht, etc...).
Dazu benutze ich derzeit 2 Timer. Timer1 wechselt durch die verschiedenen Programme durch (Timer1, weil 16bit-Timer und jedes Beleuchtungs-Programm ja schon etwas andauern sollte...) und Timer0 z.B. für einige Beleuchtungsprogramme selber: Aufsteigende oder Absteigende Reihenfolge des Anschaltens der LEDs.

Diese 2 Timer sind also schonmal weg und nun wollte ich die LEDs mittels PWM dimmen und im zweiten Schritt die Helligkeit mittels Timer0 variieren lassen.
Die LEDs benutzen übrigens komplett PORTB und D.

Ich denke ich muss hier erstmal keinen Code posten, da ich ja die Hardware-PWM benutzen will, falls ich mich irre, sagt Bescheid.

So, ich hab mir also das Datenblatt durchgelesen und da steht drin, dass Timer2 über eine phasenkorrekte PWM verfügt und die wollte ich dann also benutzen. Ist das allgemeine Vorgehen dafür so?

Im TIMSK die entsprechenden Interrupts "erlauben". Ich denke ich werde die brauchen, siehe (*)
LSB von WGM21 auf 1 setzen, um die phasenkorrekte PWM zu benutzen
Im OC2 die Helligkeit einstellen oder eben wie hoch der Timer zählen soll
(Über eine COM21 kann man eine (nicht)invertierte PWM benutzen)
Nun wird hoffentlich die entsprechende Waveform am OC2-Pin (muss auf output geschaltet sein) erzeugt. Da hier ja nur eine Waveform am OC2-Pin erzeugt wird und ich jedoch PORTB und D brauche, werde ich wohl um die Interrupts nicht herum kommen, oder? (siehe (*))


Nun einige Fragen, die mir auf der Seele brennen ;-)

Ist das Vorgehen oben überhaupt korrekt?
Wird die Waveform am OC2-Pin ohnen irgendwelchen Code im InterruptHandler erzeugt (Vermutung Ja, da ja Hardware PWM)?
Wie kann ich damit meine Ports pulsweitenmodellieren, was ja mein eigentlich Ziel ist. Eine Waveform nur an einem Pin bringt mir nicht sooo viel...


Ihr würdet mir einen riesigen Gefallen tun, wenn ich ihr euch mal einige Momente Zeit für mich nehmen könntet :-)

Vielen Dank im Voraus,
Eroli

Bernd_Stein
19.04.2011, 13:53
[QUOTE=Eroli;509131]Hallo zusammen,
...
So, ich hab mir also das Datenblatt durchgelesen und da steht drin, dass Timer2 über eine phasenkorrekte PWM verfügt und die wollte ich dann also benutzen. Ist das allgemeine Vorgehen dafür so?

Im TIMSK die entsprechenden Interrupts "erlauben". Ich denke ich werde die brauchen, siehe (*)
LSB von WGM21 auf 1 setzen, um die phasenkorrekte PWM zu benutzen
Im OC2 die Helligkeit einstellen oder eben wie hoch der Timer zählen soll
(Über eine COM21 kann man eine (nicht)invertierte PWM benutzen)
Nun wird hoffentlich die entsprechende Waveform am OC2-Pin (muss auf output geschaltet sein) erzeugt. Da hier ja nur eine Waveform am OC2-Pin erzeugt wird und ich jedoch PORTB und D brauche, werde ich wohl um die Interrupts nicht herum kommen, oder? (siehe (*))


Nun einige Fragen, die mir auf der Seele brennen ;-)

Ist das Vorgehen oben überhaupt korrekt?
Wird die Waveform am OC2-Pin ohnen irgendwelchen Code im InterruptHandler erzeugt (Vermutung Ja, da ja Hardware PWM)?
Wie kann ich damit meine Ports pulsweitenmodellieren, was ja mein eigentlich Ziel ist. Eine Waveform nur an einem Pin bringt mir nicht sooo viel...


> Ihr würdet mir einen riesigen Gefallen tun, wenn ich ihr euch mal einige Momente Zeit
> für mich nehmen könntet :-)
>
Hallo,

ich befasse mich gerade mit dem Timer0 des ATtiny13. Bin also auch nicht so Sattelfest, aber hoffe trotzdem Dir helfen zu können. Meistens gesellen sich dann auch andere dazu, so das doch etwas vernünftiges dabei herauskommt.
Für mich reichen leider einige Momente Zeit nicht aus um Dir komplett helfen zu können.
Aber egal ich will mal anfangen.

Zu 1 bei deinem allgemeinem Vorgehen.

Um ein Phase Correct PWM-Signal zu erzeugen bedarf es keines Interrupts. Es wird bei einem Match zwischen TCTN2 und OCR2 der Pin
OC2 ( Pin 17 => PortB3 ) je nach Konfiguration durch die Bits COM21 und COM20 ( Tabelle 17.5 Seite 122 ) gesteuert.

Zu 2. korrekt.

Zu 3. OCR2 enthält den Wert für den MATCH. OC2 ist der Pin. Der Zähler zählt dann trotzem weiter bis MAX und danach bis BOTTOM usw.

Zu 4. Ja mit den Bits COM21 und COM20 siehe Tabelle 17.5 Seite 122 wird dies eingestellt.

Zu 5. Ist mir nicht ganz klar wie Du das meinst. Dein PWM-Signal wird ja an PortB3 ausgegeben. Um dies zu vervielfachen, muß extern noch ein Baustein angefügt werden.

Ich denke hiermit auch die Fragen die Dir auf der Seele brennen wenigstens Teilweise beantwortet zu haben.

Bernd_Stein

Eroli
19.04.2011, 16:02
Hallo Bernd,

Danke für deinen Beitrag, damit ist jetzt schon einiges klarer. Vorallem das mit den Registern und Pins und Ports, aber ich muss schon sagen, dass ich gar nicht sooo weit daneben war :-D


Dein PWM-Signal wird ja an PortB3 ausgegeben. Um dies zu vervielfachen, muß extern noch ein Baustein angefügt werden.
Hmm, das scheint ein größeres Problem für mich zu werden, als zuerst gedacht.
Doch verfolgen wir mal einen anderen Denkansatz, quasi eine Software-Hardware-PWM-Mischung.
Der Timer zählt ja immer hoch und runter und schaltet bei einem MATCH den PORTB3 um. Jedoch wird bei einem MATCH doch auch ein Interrupt geworfen und an dieser Stelle könnte ich doch manuell auch den kompletten PORTB und D - so wie ich es brauche - umschalten, oder nicht?

Bernd_Stein
19.04.2011, 16:21
Hallo Bernd,
...
Hmm, das scheint ein größeres Problem für mich zu werden, als zuerst gedacht.
Doch verfolgen wir mal einen anderen Denkansatz, quasi eine Software-Hardware-PWM-Mischung.
Der Timer zählt ja immer hoch und runter und schaltet bei einem MATCH den PORTB3 um. Jedoch wird bei einem MATCH doch auch ein Interrupt geworfen und an dieser Stelle könnte ich doch manuell auch den kompletten PORTB und D - so wie ich es brauche - umschalten, oder nicht?

Nein das heißt Ja. Es ist gar kein Problem, so wie Du es schreibst, hast Du es schon gelöst. Habe Dich da wohl etwas auf den Holzweg geschickt mit dem zusätzlichen Baustein.

Bernd_Stein

Eroli
19.04.2011, 17:00
Hallo Bernd,


Es ist gar kein Problem, so wie Du es schreibst, hast Du es schon gelöst. Habe Dich da wohl etwas auf den Holzweg geschickt mit dem zusätzlichen Baustein.
Gut, schonmal beruhigend.

Ich bin gerade dabei alles auszutesten und hier mal ein Snippet:


ldi temp, 0x01 ; Zur Kontrolle die ersten beiden LEDs einschalten
out PORTB, temp
out PORTD, temp

ldi temp, 1<<OCIE2 | 1<<TOIE1 | 1 <<TOIE0 ; Timer0-Overflow und Timer1-Overflow und Timer2-Compare "erlauben"
out TIMSK, temp
ldi temp, 1 << WGM21 | 1 << CS22 | 1 << CS21 | 1 << CS20 ; Phasenkorrekte PWM und Prescaler setzen
out TCCR2, temp
ldi temp, 0xFF ; Irgendein Startwert fuer OCR2 (Unsere Helligkeit: 0xFF entspricht volle Helligkeit)
out OCR2, temp


Leider bleibt die LED an PortB3 die ganze Zeit aus (auch wenn ich OCR2 mit 0x00 lade)...

Irgendeine Idee?


EDIT: Ich musste COM20 noch auf 1 setzen, damit beim CompareMatch auch getoggled wird....Ein Erfolgserlebnis :-)

Eroli
19.04.2011, 19:25
Hallo nochmal,

ich weiß nun, dass es eigentlich klappen müsste, denn wenn ich den Prescaler entsprechend hochsetze, z.B. 1024, dann sehe ich die LED flackern. Wenn ich den Prescaler soweit runtersetze, dass ich kein flackern mehr sehe (derzeit Prescaler 64), dann kann ich leider keine Helligkeitsunterschiede feststellen, egal ob ich OCR2 mit 0xFF oder 0x00 lade...
Das wird wohl an der logarithmischen Helligkeitswahrnemung unseres Auges liegen, was ich auf Mikrocontroller.net gelesen habe, damit unser Auge einen möglichst großen Helligkeitsbereich wahrnehmen kann.

Gibt es da vielleicht noch einen Trick um doch irgendwie deutlichere Ergebnisse zu erzielen?

Mein Code sieht derzeit so aus:


ldi temp, 0x01 ; Zur Kontrolle die ersten beiden LEDs einschalten
out PORTB, temp
out PORTD, temp

ldi temp, 1<<OCIE2 | 1<<TOIE1 | 1 <<TOIE0 ; Timer0-Overflow und Timer1-Overflow und Timer2-Compare "erlauben"
out TIMSK, temp
ldi temp, 1 << COM20 | 1 << WGM21 | 0 << CS22 | 1 << CS21 | 0 << CS20 ; Phasenkorrekte PWM und Prescaler setzen
out TCCR2, temp
ldi temp, 0x00 ; Irgendein Startwert fuer OCR2 (Unsere Helligkeit)
out OCR2, temp


Vielen Dank im Voraus :-)

Bernd_Stein
20.04.2011, 06:04
Hallo,

in deinem Programm wo das OCR2-Register mit dem Wert Null lädst, wird dadurch ein Dauer-Low-Signal oder je nachdem ob invertiert oder nicht ein Dauer-High-Signal erzeugt.
Im Datenblatt auf Seite 116 nach einer Formel steht dazu folgendes.

The extreme values for the OCR2 Register represent special cases when generating a PWM
waveform output in the phase correct PWM mode. If the OCR2 is set equal to BOTTOM, the output
will be continuously low and if set equal to MAX the output will be continuously high for noninverted
PWM mode. For inverted PWM the output will have the opposite logic values.

Bernd_Stein

Eroli
20.04.2011, 09:53
Das ist allerdings seltsam, dann müsste bei 0x00 die LED immer aus sein und bei 0xFF immer an, aber genau das ist nicht der Fall. Die LED leuchtet immer mit derselben Helligkeit.
Stimmt vielleicht doch etwas mit meiner PWM nicht?
Warum konnte ich denn ganz klar ein blinken/flackern mit größerem Prescaler feststellen?

Bernd_Stein
20.04.2011, 10:35
Zeig uns doch mal dein ganzes Programm.
Ein Oszilloskop scheinst Du ja leider nicht zu besitzen, da könnte man schön sehen was Überhaupt passiert.
Versuche mit Prescaler auf 1024 brachten doch Erfolg. Es gibt ja noch die Möglichkeit den Systemtakt zu verringern.
Entweder durch einen anderen Quarz oder durch einen Vorteiler. Dazu muß man glaube ich an den FUSE-Bits etwas ändern.
Da sollte man jedoch gur aufpassen, sonst kann es passieren das der µC nicht mehr Ansprechbar ist.

Bernd_Stein

Eroli
20.04.2011, 10:43
Gerne, das ist allerdings schon etwas umfangreicher. Bitte entschuldigt auch, wenn es nicht aufgeräumt ist, bin ja noch mitten im Testen und baue deswegen oft um...
Das prog-Register wird am Anfang übrigens mit 4 geladen, damit ich direkt im Fading-Programm bin und testen kann. Normalerweise wird das Register mit 0 geladen...

Hier der Code


;************************************************* *********************************
;Beschreibung:
;Dieses Programm lässt verschiedene "Licht-Programme" an PortB und Port D des
;des Mikrocontrollers ablaufen. Timer1 ist der "Programm-Timer" und
;Timer0 der BlinkTimer für die Programme. Timer2 dient zum LED-Fading als PWM.
;************************************************* *********************************

.include "m8def.inc" ;Die Definitionsdatei des ATmega8 einfügen.

.def temp = R16 ;Es werden in diesem Programm 2 Arbeitsregister benötigt.
.def temp2 = R17 ;benötigt: R16 und R17 (ginge auch mit nur einem).
.def prog = R18 ;Aktuelles Programm
.def runs = R19 ;Erster Timerdurchlauf

rjmp RESET ; Reset Handler
reti ; IRQ0 Handler
reti ; IRQ1 Handler
rjmp Timer2_CompareHandler ; Timer2 Compare Handler => Zur LED-Dimmung
reti ; Timer2 Overflow Handler
reti ; Timer1 Capture Handler
reti ; Timer1 CompareA Handler
reti ; Timer1 CompareB Handler
rjmp Timer1_Overflow ; Timer1 Overflow Handler => Programmwechsel
rjmp Timer0_Overflow ; Timer0 Overflow Handler => zyklischer Programmablauf (blinken, aufsteigend, absteigend, ...)
reti ; SPI Transfer Complete Handler
reti ; USART RX Complete Handler
reti ; UDR Empty Handler
reti ; USART TX Complete Handler
reti ; ADC Conversion Complete Handler
reti ; EEPROM Ready Handler
reti ; Analog Comparator Handler
reti ; Two-wire Serial Interface Handler
reti ; Store Program Memory Ready Handler

reset:
ldi temp, LOW(RAMEND) ;Initialisieren des StackPointers:
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp

;============================ Int. Oszillator kalibrieren ============================
ldi temp, $C2 ;Diesen Wert im STK500-Steuerpanel ablesen unter "Advanced" (dort wird
out OSCCAL, temp ;auch die gewünschte Frequenz des int. Oszillators eingestellt).

;============================ Timer0 ============================ (Erstmal auskommentiert, denn Timer0 soll in Timer1 gestartet werden)
;ldi temp, 0b101 ;Timer0 starten mit Vorteiler 1:1024 (Teilt die Blinkfrequenz durch 1024)
;out TCCR0, temp ;TCCR0 ist das Kontrollregister des Timers 0

;============================ Timer ============================
ldi temp, 1<<TOIE1 | 1 <<TOIE0 ; Timer0-Overflow und Timer1-Overflow "erlauben"
out TIMSK, temp

ldi temp, 0xFF ; Timer1 "vorspulen"
out TCNT1H, temp
ldi temp, 0xFE
out TCNT1L, temp
ldi temp, 1<<CS12|1<<CS10 ;Timer1 starten mit Vorteiler 1:1024 (Teilt die Frequenz durch 1024)
;ldi temp, 1<<CS11 ; nur zu Debug-Zwecken
out TCCR1B, temp


ser temp ;Arbeitsregister "temp" mit Einsern füllen.
out DDRB, temp ;Datenrichtungsregister des Ports B mit Einsern aus "temp" füllen (= alle Pins des Ports als AUSGANG)
out PORTB, temp ;Alle Pins des Ports auf's High-Level bringen

out DDRD, temp ; Alle Pins von PortD als Ausgang festlegen
out PORTD, temp ; Alle Pins auf HIGH setzen

ldi prog, 4 ; Bei Programm 0 beginnen


sei ;Interrupts freigeben
;------------------------------

; ============================ Hauptprogramm ============================
loop:
;Warten auf Timer0/1-Überlauf in einer Endlosschleife.
rjmp loop

; ============================ Hauptprogramm Ende ============================



; ============================ Programmwechsel-Timer ============================
Timer1_Overflow:
push temp ; Sichern von "TEMP" im Stack
in temp, SREG ; Einlesen des SREG
push temp ; Schreiben von SREG im Stack (KOPIE)

cpi prog, 5 ; Programmüberlauf?
BRGE resetProg
rjmp continue
resetProg:
CLR prog
continue:
ldi temp, 0b000 ; Timer0 beenden (Kein Blinken)
out TCCR0, temp

ldi temp, 0xFF ; LEDs jetzt an
out PORTB, temp
out PORTD, temp
ldi runs, 0

cpi prog, 0
brne Prog1
;Prog0 ausfuehren: LEDs an (schon geschehen)
rjmp ende
Prog1:
cpi prog, 1
brne Prog2
;Prog1 ausfuehren: LEDs blinken
ldi temp, 0xFE
out TCNT0, temp
ldi temp, 0b101 ;Timer0 starten
out TCCR0, temp
rjmp ende
Prog2:
cpi prog, 2
brne Prog3
;Prog2 ausfuehren: LEDs absteigend
ldi temp, 0xFF
out TCNT0, temp
ldi temp, 0b101 ;Timer0 starten mit Vorteiler 1:1024 (Teilt die Blinkfrequenz durch 1024)
out TCCR0, temp
rjmp ende
Prog3:
cpi prog, 3
brne Prog4
;Prog3 ausfuehren: LEDs aufsteigend
ldi temp, 0xFF
out TCNT0, temp
ldi temp, 0b101
out TCCR0, temp
ldi temp, 0
out PORTB, temp
out PORTD, temp
rjmp ende
Prog4:
cpi prog, 4
brne ende
; Prog4 ausfuehren: Test-Fading
ldi temp, 0x01 ; Zur Kontrolle die ersten beiden LEDs einschalten
out PORTB, temp
out PORTD, temp

ldi temp, 1<<OCIE2 | 1<<TOIE1 | 1 <<TOIE0 ; Timer0-Overflow und Timer1-Overflow und Timer2-Compare "erlauben"
out TIMSK, temp
ldi temp, 1 << COM20 | 1 << WGM21 | 0 << CS22 | 1 << CS21 | 0 << CS20 ; Phasenkorrekte PWM und Prescaler setzen
out TCCR2, temp
ldi temp, 0x00 ; Irgendein Startwert fuer OCR2 (Unsere Helligkeit)
out OCR2, temp


rjmp ende
ende:
inc prog
pop temp ; LESEN von SREG vom STACK (KOPIE)
out SREG, temp ; Wiederherstellen von SREG
pop temp ; Wiederherstellen von "TEMP"
reti

; ============================ Programmwechsel-Timer Ende ============================



; ============================ Timer0 Overflow (Blinken) ============================
Timer0_Overflow: ;Die Blink-ISR lässt die LED am Pin 0 am PORTB (=PB0) blinken.
push temp ; Sichern von "TEMP" im Stack
in temp, SREG ; Einlesen des SREG
push temp ; Schreiben von SREG im Stack (KOPIE)

; ==== Programmreihenfolge ====
cpi prog, 2
breq blinken
cpi prog, 3
breq absteigend
cpi prog, 4
breq aufsteigend
cpi prog, 5
breq fading
rjmp end

blinken:
sbic PORTB, 0 ;Nächsten Befehl überspringen, falls Bit0 abm PortB ist AUS (= LED ist EIN)
rjmp led_ein ;Ansonsten LED einschalten (s. unten).
sbis PORTB,0 ;Überspringen, falls Bit0 abm PortB ist EIN (= LED ist AUS)
rjmp led_aus ;Ansonsten LED ausschalten (s. unten).

led_ein: ;Zum Einschalten:
ldi temp, 0x00
out PORTB, temp
out PORTD, temp
rjmp end ;und beenden.
led_aus: ;Zum Ausschalten:
ldi temp, 0xFF
out PORTB, temp
out PORTD, temp
rjmp end

absteigend:
in temp, PORTB ; Aktuellen Zustand holen
LSL temp ; Linksshift
out PORTB, temp ; Ausgeben
out PORTD, temp
cpi temp, 0
breq absteigend2
rjmp end
absteigend2:
LDI temp, 0xFF
out PORTB, temp
out PORTD, temp
rjmp end

aufsteigend:
in temp, PORTB ; Aktuellen Zustand holen
COM temp
LSL temp ; 0 rein
COM temp ; Aus reingekommener 0 eine 1 machen
out PORTB, temp ; Ausgeben
out PORTD, temp
cpi temp, 0xFF
breq aufsteigend2
rjmp end
aufsteigend2:
LDI temp, 0
out PORTB, temp
out PORTD, temp
rjmp end

fading: ; ==== TODO ====
; Hier später Helligkeit variieren

end:
inc runs
rjmp exit

exit:
pop temp ; LESEN von SREG vom STACK (KOPIE)
out SREG, temp ; Wiederherstellen von SREG
pop temp ; Wiederherstellen von "TEMP"
reti ; ISR beenden.
; ============================ Timer0 Overflow (Blinken) Ende ============================

Timer2_CompareHandler:
; Hier später LEDs an PORTB und D togglen
reti


(Am interessantesten sollte wohl die Prog4-Headline oder Prog4-Marke oder Prog4-Label oder wie das heißt sein)

Was das Programm machen soll, habe ich ja schon im ersten Post geschrieben...
Gibt es hier eigentlich auch spezielle Assembler-Tags anstatt der generischen Code-Tags?

Bernd_Stein
20.04.2011, 14:57
Hallo,

ich werde einfach nicht aus deinem Code schlau.
Du erzeugst ja verschiedene Lichtspiele die nacheinander ablaufen.
Prog2 => blinken, Prog3 => absteigend, Prog4 => aufsteigend.
Fading wäre ja Prog5 und dort ist ja erstmal nichts.

Funktionieren die Programmteile ( Prog2 usw. ) denn für sich alleine ?
Damit meine ich das z.B. nur immer Prog2 läuft.

Bernd_Stein

Eroli
20.04.2011, 15:37
Ja, die funktionieren an und für sich. Das Programm 5 (Fading) in Timer2 leer ist, liegt daran, dass ich erstmal die PWM testen wollte. Wenn die später funktioniert, wollte ich in Timer2 die Helligkeit variieren lassen.
Solange das da noch leer ist, wird Programm 5 ähnlich Programm 1 (Alle LEDs an => braucht kein Timer) nur im Programmwechseltimer (Timer 1) ausgeführt.
Ich hab von anderer Stelle einen Tipp bekommen, dass ich WGM21 auf 1 gesetzt habe, was dem CTC-Mode entspricht. Für eine Phasenkorrekte PWM müsste aber WGM21 auf 0 und WGM20 auf 1 gesetzt werden.

Ich werde das heute abend mal testen und mich dann wieder melden...

Schönen Nachmittag noch :-)

EDIT: Das verwirrt mich aber auch wieder. Laut Datenblatt kann Timer2 doch nur eine phasenkorrekte PWM. Warum steht im Datenblatt in Table42 dann, dass ich WGM21 und WGM20 auf 1 setzen muss, um eine FastPWM zu benutzen??

Bernd_Stein
20.04.2011, 16:13
...
> EDIT: Das verwirrt mich aber auch wieder. Laut Datenblatt kann Timer2 doch nur eine
> phasenkorrekte PWM. Warum steht im
> Datenblatt in Table42 dann, dass ich WGM21 und WGM20 auf 1 setzen muss, um eine
> FastPWM zu benutzen??

Also im dem Datenblatt das ich benutze ( ATmega8A ), fängt ab Seite 106 mit dem Kapitel 17
der " 8-Bit Timer/Counter2 with PWM and Asynchronous Operation " an.

Auf Seite 112 Kapitel 17.7 Modes of Operation tauchen die Modes die er kann auf.
Nämlich Normal, CTC, Fast PWM, Phase Correct PWM und das wo von ich sehr sehr wenig ahnung habe
" Asynchronous Operation of Timer/Counter2 ".

Die Table 42 konnte ich leider nicht finden.

Bernd_Stein

Eroli
20.04.2011, 19:25
So, habe das nunmal getestet mit dem CTC-Mode, aber es hat nichts gebracht:



ldi temp, 0x01 ; Zur Kontrolle die ersten beiden LEDs einschalten
out PORTB, temp
out PORTD, temp

ldi temp, 1<<OCIE2 | 1<<TOIE1 | 1 <<TOIE0 ; Timer0-Overflow und Timer1-Overflow und Timer2-Compare "erlauben"
out TIMSK, temp
ldi temp, 1 << COM20 | 0 << WGM21 | 1 << WGM20 | 0 << CS22 | 1 << CS21 | 0 << CS20 ; Phasenkorrekte PWM und Prescaler setzen
out TCCR2, temp
ldi temp, 0xFF ; Irgendein Startwert fuer OCR2 (Unsere Helligkeit)
out OCR2, temp


Egal, ob ich OCR2 mit 0x00, 0xFF oder 0x99 vorlade, es ist kein Helligkeitsunterschied feststellbar...

Habe auch nochmal das ganze Programm angehangen. Beachtet dabei bitte, dass es zu Testzwecken so manipuliert ist, dass immer nur das letzte Programm ausgeführt wird...
Irgendwo ist da der Wurm drin...sieht vielleicht jemand wo?

Searcher
20.04.2011, 20:21
Hallo,


ldi temp, 1 << COM20 | 0 << WGM21 | 1 << WGM20 | 0 << CS22 | 1 << CS21 | 0 << CS20mit WGM20 und WGM21 hast Du "pwm, phase correct" eingestellt.
In dem Mode ist COM20 aber nach Table 45, Seite 118 reserved! (Datenblatt ATmega8 doc2486)

Gruß
Searcher

Eroli
20.04.2011, 23:06
Stimmt, das ist wirklich nicht erlaubt? Was macht der Microcontroller in so einem Fall? Stürzt der ab? Macht der irgendetwas unkontrollierbares?

Ich hatte COM20 doch extra auf 1 gesetzt, damit PortB3 bei CompareMatch getoggled wird. Wie soll ich das denn sonst machen?

Searcher
21.04.2011, 06:09
Wie soll ich das denn sonst machen?Vorausgesetzt Du bleibst bei dem Phase Correct Mode und bei der Signalausgabe an OC2, dann bleiben nach der o.g. Tabelle 45 noch zwei Möglichkeiten. Da müßtest Du Dich für eine entscheiden und die beiden Bits COM21 und COM20 entsprechend auf 0 oder 1 setzten.

Zu dem übrigen Programm kann ich nichts sagen, da nicht Assembler erfahren.

Gruß
Searcher

Eroli
21.04.2011, 08:11
Gut, ich werde das mal am Dienstag testen. Früher komme ich leider nicht an meine Hardware dran...

Bis dahin frohe Ostern und ich verspreche auch bis Dienstag nicht mehr zu nerven ;-)

Vitis
21.04.2011, 08:50
Habe jetzt das Programm nicht eingehend studiert, aber auf Seite 1 hab ich nur Anmerkung zu einem interrupt für die PWM gefunden.
Der reicht aber nicht, Du brauchst zwei Ints, einmal den Compare Match und den Overun. Compare Match -> ports an, Overrun -> Ports aus.

mit nur einem Interrupt gibts immer Tastverhältnis 50:50

Eroli
21.04.2011, 09:53
Hi Vitis,

Danke für den Hinweis, aber ich finde auf der ersten Seite keinen Kommentar zu so einem Overun Compare Match. Meinst du den Overflow?

Vielleicht noch eine allgemeine Sache zu den Interrupts: Die Reihenfolge in welcher die Labels stehen am Anfang des Codes ist doch relevant, oder?

Bernd_Stein
21.04.2011, 10:38
Hi Vitis,
...
Vielleicht noch eine allgemeine Sache zu den Interrupts: Die Reihenfolge in welcher die Labels stehen am Anfang des Codes ist doch relevant, oder?

Mit deinen Versprechen nimmst Du es wohl nicht so ernst ;-).

https://www.roboternetz.de/community/showthread.php?52855-PWM-mit-ATMega8-und-Timer2&p=509499&viewfull=1#post509499

Ja, die Interrupts haben Prioritäten. Das heißt der Reset-Interrupt hat die höchste und dieser hier
" Store Program Memory Ready Handler " die niedrigste Priorität.

Damit jedoch ein Interrupt mit einer höheren Priorität einen gerade laufenden Interrupt unterbrechen kann,
muß in dem laufenden Interrupt das Globale-Interrupt-Flag ( I-Flag im Statusregister ( SREG ))
mit dem Befehl CLI gelöscht werden, da es durch einen Interuppt automatisch gesetzt wird,
um andere Interrupts so lange zu sperren bis der laufende beendet ist.

Bernd_Stein

Vitis
21.04.2011, 16:19
ja, sorry, Du brauchst den Overflow- und den Compare- Interrupt

Eroli
28.04.2011, 18:32
Hallo zusammen,

wollte mich nur kurz nochmal zurückmelden: Es klappt nun alles hervorragend :-)
Alle LEDs an PORTB und PORTD pulsieren jetzt durch eine Hardware-PWM am 8-Bit-Timer. Der löst schon fein genug auf, so gefällt mir das :-)

Vielen Dank für eure geduldige Hilfe :-)