PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM mit Timer1 Atmega8 in Assembler



hegewald
06.11.2013, 10:04
Hallo Atmelfreaks,
beschäftige mich mit der Wahnsinnsmaterie PWM mit Timer1
Zu Beginn hatte ich mich mit CTC-Betrieb beschäftigt und es läuft auch.
Jetzt bin ich beim PWM-fast Betrieb und PWM Phasenkorrekt Betrieb angekommen,
und es ist ein Wahnsinn, was sich dahinter verbirgt.
Fakt ist, dieser Code zeigt nichts an den LEDs die an PB1 und PB2 gegen GND hängen.
Bei CTC lief alles.
Wo ist nur mein Gedankenfehler?

; Projekt: Mega8-PWM Datum: 03.11.2013

; Datei: mega8-FASTPWM01.asm

; ATmega8 Timer1 FastPWM-Betrieb Kanäle A und B

; Port B: Ausgang Kanal A:OC1A (PB1-Pin15) Kanal B:OC1B (PB2-Pin16)

; Konfiguration: interner Oszillator 1 MHz, externes RESET-Signal
.INCLUDE "m8def.inc" ; Deklarationen für Mega8
.EQU takt = 1000000 ; Systemtakt 1 MHz intern

.DEF akku = r16
.DEF temp17 = r17
.CSEG ; Programm-Flash
rjmp start ; Reset-Einsprung
.ORG $13 ; Interrupt-Einsprünge übergehen

start:
ldi akku,LOW(RAMEND); Stapel anlegen
out SPL,akku ;
ldi akku,HIGH(RAMEND)
out SPH,akku

ldi akku,(1<<PB1) | (1<<PB2)
out DDRB,akku

.equ WertH = 100 ; Konstante für OCR1AH u. OCR1BH (r16)
.equ WertL = 70 ; Konstante für OCR1AL u. OCR1BL (r17)


; Timer1 programmieren: WGM10=1<<<PWM8Bit phasenrichtig (TOPP=00FF)

; KanalA (COM1Ax) zu PB1 und KanalB (COM1Bx) zu PB2 nicht invertiert
ldi akku,(0<<COM1A1) |(1<<COM1A0)| (0<<COM1B1) | (0<<COM1B0)| (0<<WGM11) | (1<<WGM10)
out TCCR1A,akku ; Steuerregister A Timer1

clr akku
ldi akku,(0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10)
out TCCR1B,akku ; Steuerregister B Timer1 Prescale = 1 (1MHz)


loop: ldi akku,WertH ; r16 auf 100
ldi temp17,WertL ; r17 auf 70

out OCR1AH,akku ; Kanal A = 100 (WertH)
out OCR1AL,temp17 ; Kanal A = 70 (WertL)

out OCR1BH,akku ; Kanal B = 100 (WertH)
out OCR1BL,temp17 ; Kanal B = 70 (WertL


rjmp loop
.EXIT


Grüße

Rolf

oberallgeier
06.11.2013, 10:33
Hallo Rolf,

bitte nimm mal das Codefenster für Code: einfach im Editor auf das Lattenzahnsymbol (Hash) klicken. Ich habs mal etwas lesbarer gemacht - aber mittlerweile kneift meine Zeit, später vielleicht mehr.

... dieser Code zeigt nichts an den LEDs ... Bei CTC lief alles ...

; Projekt: Mega8-PWM Datum: 03.11.2013; Datei: mega8-FASTPWM01.asm
; ATmega8 Timer1 FastPWM-Betrieb Kanäle A und B
; Port B: Ausgang Kanal A:OC1A (PB1-Pin15) Kanal B:OC1B (PB2-Pin16)
; Konfiguration: interner Oszillator 1 MHz, externes RESET-Signal
.INCLUDE "m8def.inc" ; Deklarationen für Mega8
.EQU takt = 1000000 ; Systemtakt 1 MHz intern
.DEF akku = r16
.DEF temp17 = r17
.CSEG ; Programm-Flash
rjmp start ; Reset-Einsprung
.ORG $13 ; Interrupt-Einsprünge übergehen
start:
ldi akku, LOW(RAMEND) ; Stapel anlegen
out SPL, akku ;
ldi akku, HIGH(RAMEND)
out SPH, akku
ldi akku, (1<<PB1) | (1<<PB2)
out DDRB, akku
.equ WertH = 100 ; Konstante für OCR1AH u. OCR1BH (r16)
.equ WertL = 70 ; Konstante für OCR1AL u. OCR1BL (r17)

; Timer1 programmieren: WGM10=1<<<PWM8Bit phasenrichtig (TOPP=00FF)
; KanalA (COM1Ax) zu PB1 und KanalB (COM1Bx) zu PB2 nicht invertiert
ldi akku, (0<<COM1A1) |(1<<COM1A0)| (0<<COM1B1) | (0<<COM1B0)| (0<<WGM11) | (1<<WGM10)
out TCCR1A, akku ; Steuerregister A Timer1
clr akku
ldi akku, (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10)
out TCCR1B, akku ; Steuerregister B Timer1 Prescale = 1 (1MHz)

loop: ldi akku, WertH ; r16 auf 20
ldi temp17, WertL ; r17 auf 70
out OCR1AH, akku ; Kanal A = 100 (WertH)
out OCR1AL, temp17 ; Kanal A = 70 (WertL)
out OCR1BH, akku ; Kanal B = 100 (WertH)
out OCR1BL, temp17 ; Kanal B = 70 (WertL

rjmp loop
.EXIT

Searcher
06.11.2013, 14:08
ldi akku,(0<<COM1A1) |(1<<COM1A0)| (0<<COM1B1) | (0<<COM1B0)| (0<<WGM11) | (1<<WGM10)
out TCCR1A,akku ; Steuerregister A Timer1


Hallo Rolf,
die COM1Ax und COM1Bx Bit Kombinationen schalten die OC1A und OC1B Pins im Phase Correct Modus 1 nicht auf die Compare Unit durch. Schau mal im Datenblatt (doc2486 zum Mega8 ) in die Tabelle 38.

Der Ausdruck zB (0<<COM1A1) ist in einer ODER Verknüpung effektlos und verwirrt (mich) beim Lesen des Codes.

Mir ist nicht klar, warum Du in der Loop das OCRA Register immer neu mit den gleichen Werten beschreibst. Einmal reicht. (OCR1AH braucht in dem 8 Bit Modus des Timers keinen höheren Wert als 0)

Gruß
Searcher

hegewald
06.11.2013, 15:14
Hallo Searcher,
nun hab ich hier das Datenblatt vom Atmega8(L) von der Fa. Reichelt vor mir und bin auf Seite88
oh weia...mein englisch!
mit meinen Code hab ich doch "Figure 38. Fast PWM Mode, Timing Diagram" gewählt, oder?
Nun hab ich auch mein schlaues Buch in Deutsch vor mir und sehe aus einer Tabelle,
dass ich mit (1<<WGM10) Mist gebaut habe.
Um den Zähler bis 00FF laufen zu lassen, hätte ich WGM12 und WGM10 auf 1 setzen müssen,
wobei hier COM1A1 auf 1 steht und COM1A0 auf * mh, was ist das nun wieder.
Sicher könnte ich das OCRA Register nur einmal beschreiben und die (0<<COM1A1) weglassen.

Grüsse

Rolf
Vielleicht sollte ich mich erst mal auf Kanal A konzentrieren.

Searcher
06.11.2013, 16:00
Hi,


nun hab ich hier das Datenblatt vom Atmega8(L) von der Fa. Reichelt vor mir und bin auf Seite88
oh weia...mein englisch!

ich nehme immer die Datenblätter original von Atmel:
http://www.atmel.com/images/atmel-2486-8-bit-avr-microcontroller-atmega8_l_datasheet.pdf

Falls das nicht Dein µC ist, bitte verlinke das Datenblatt, das Du benutzt - ich nehme aber an, daß es das gleiche ist.


mit meinen Code hab ich doch "Figure 38. Fast PWM Mode, Timing Diagram" gewählt, oder?
Nun hab ich auch mein schlaues Buch in Deutsch vor mir und sehe aus einer Tabelle,
dass ich mit (1<<WGM10) Mist gebaut habe.

Na ja, die "Table 38", die ich meine ist auf Seite 97 im Datenblatt. Mit dem WGM10 hast Du Mode 1 gewählt (Phase Correct,8 Bit Modus des Timers). Dazu müssen die COM1Ax und COM1Bx Bits entsprechend der Table 38 gesetzt werden.


Um den Zähler bis 00FF laufen zu lassen, hätte ich WGM12 und WGM10 auf 1 setzen müssen,

Das wäre dann nicht mehr "Phase Correct", sondern "Fast PWM"



wobei hier COM1A1 auf 1 steht und COM1A0 auf * mh, was ist das nun wieder. ...

Ob "Normal" "Fast PWM" "CTC" Modus - dazu gehören jeweils eigene Tabellen für die COM1Ax und COM1B Bits, die Du unter der TCCR1A Register Beschreibung im Datenblatt ab Seite 96 findest. Hab schon einige deutsche Beschreibungen gesehen und muß sagen, es geht nichts über das Original. Da kommt man um Englisch kaum herum :(

:-) Ich such mir immer zuerst den Modus aus, den ich für meine Anwendung brauche. Danach geht die Bitsucherei los. :-)

Die ganzen Möglichkeiten sind nicht ohne und es gibt auch noch gewisse Feinheiten, die man erst bei mehrmaligen Durchlesen der kompletten Doc im Datenblatt mitkriegt.

Dein obiges Programm mit Timer im Modus 1 könntest Du schon zur Ausgabe an den OC1A und OC1B Pins bewegen, wenn Du die COM1Ax und COM1Bx Bits nach der ominösen Table 38 setzt.

Gruß
Searcher

hegewald
06.11.2013, 17:10
Hallo Searcher,
habe gleich Deine Mitteilung ausgedruckt um es später zu verarbeiten...Danke Dir!

Zwischenzeitlich habe ich aus meinen Buch etwas entdeckt, was ich umgebaut habe.
Sieht so aus:

sbi DDRB,PB1 ; PB1 ist Ausgang OC1A
sbi DDRB,PB2 ; PB2 ist Ausgang OC1B

.equ WertH = 100 ; Konstante für OCR1AH u. OCR1BH (r16)
.equ WertL = 120 ; Konstante für ICR1H (r16)
.equ Wert = 70 ; Konstante für OCR1AL u. OCR1BL u.ICR1L (r17)


; Timer1 PWM programmieren
clr akku ; Steuerbits einsetzen
ori akku,(1 << COM1A1) | (0 << COM1A0) ; nicht inv.
ori akku,(1 << COM1B1) | (1 << COM1B0) ; inv.
ori akku,(1 << WGM11) | (0 << WGM10) ; PWM 9Bit phasenrichtig
out TCCR1A,akku ; Steuerregister A Timer1

ldi akku,0b001 ; Taktteiler :1
ori akku,(1 << WGM13) ; variable Frequenz durch ICR1 ;
out TCCR1B,akku ; Steuerregister B Timer1 start


ldi akku,WertH ; r16 auf 100
ldi r17,Wert ; r17 auf 70

out OCR1AH,akku ; Kanal A = 100
out OCR1AL,r17 ;

out OCR1BH,akku ; Kanal B = 100
out OCR1BL,r17 ;

ldi akku,WertL ; r16 auf 120
out ICR1H,akku
out ICR1L,r17


loop:
rjmp loop ;
.EXIT ; Ende des Quelltextes

die Konstanten habe ich vorgegeben und das Ganze aus der Loop Schleife
herausgenommen.
Die beiden LEDs blinken an PB1+PB2 unterschiedlich, da ja in den beiden Registern eine
Invertierung vorliegt.
Entferne ich die Vorgabe in ICR1H und L ist tote Hose, d.h die LEDs lassen sich mit den OCR1xx Registern
nur noch auf HIGH / LOW schalten.
Wiegesagt, das ist ein Wahnsinn, was sich hier abspielt, ob ich das in meinen Alter noch begreife?
Aber so schnell geb ich nicht auf.

Grüße

Rolf

hegewald
07.11.2013, 08:28
Hallo Searcher,
sorry, das ich Dich schon wieder nerve!
Jetzt stehe ich richtig auf dem Schlauch. Hab mich erst mal nur mit Kanal A beschäftigt und die LED
an OC1A rührt sich zum verrecken nicht, d.h. dunkel.
Hab nach Deinen Vorschlag WGM12+10 auf 1 gesetzt.
Hab die Bits COM1A1+A0 in allen Möglichkeiten auf HIGH/LOW gesetzt.
(ich glaube COM1A1=1 / COM1A0=0 leuchtet die LED konstant.
Die Konstante WertH=100 habe ich versuchsweise in OCR1AL bzw. AH gesetzt
Fazit<<<<es rührt sich nichts!
Die Seite 97 habe ich mir angesehen
.equ WertH = 100

; Timer1 PWM programmieren (WGM12 und WGM10=1<<PWM 8Bit fast,Top=0x00FF)
clr akku ; Steuerbits einsetzen
ori akku,(0 << COM1A1) | (1 << COM1A0) ; nicht inv.
ori akku,(0 << COM1B1) | (0 << COM1B0) ; inv.
ori akku,(0 << WGM11) | (1 << WGM10)
out TCCR1A,akku ; Steuerregister A Timer1

ldi akku,0b001 ; Taktteiler :1
ori akku,(0 << WGM13) | (1<<WGM12)
out TCCR1B,akku ; Steuerregister B Timer1 start


ldi akku,WertH ; r16 auf 100

out OCR1AL,akku ; Kanal A = 100

loop:
rjmp loop ;
Was mach ich nur falsch, hab nun alle Möglichkeiten geprüft.

Searcher
07.11.2013, 16:45
Hallo Atmelfreaks,
beschäftige mich mit der Wahnsinnsmaterie PWM mit Timer1
Zu Beginn hatte ich mich mit CTC-Betrieb beschäftigt und es läuft auch.
Jetzt bin ich beim PWM-fast Betrieb und PWM Phasenkorrekt Betrieb angekommen,
und es ist ein Wahnsinn, was sich dahinter verbirgt.


Hallo Rolf,
ich bin nochmal von Deinem ersten Post ausgegangen und habe Dein Programm meinen Gedankengängen angepaßt. Nicht getestet aber nach bestem Wissen und Gewissen gearbeitet :-)


; Projekt: Mega8-PWM Datum: 03.11.2013

; Datei: mega8-FASTPWM01.asm

; ATmega8 Timer1 FastPWM-Betrieb Kanäle A und B

; Projekt: Mega8-PWM Datum: 03.11.2013; Datei: mega8-FASTPWM01.asm
; ATmega8 Timer1 FastPWM-Betrieb Kanäle A und B
; Port B: Ausgang Kanal A:OC1A (PB1-Pin15) Kanal B:OC1B (PB2-Pin16)
; Konfiguration: interner Oszillator 1 MHz, externes RESET-Signal
.INCLUDE "m8def.inc" ; Deklarationen für Mega8
.EQU takt = 1000000 ; Systemtakt 1 MHz intern
.DEF akku = r16
.DEF temp17 = r17
.CSEG ; Programm-Flash
rjmp start ; Reset-Einsprung
.ORG $13 ; Interrupt-Einsprünge übergehen
start:
ldi akku, LOW(RAMEND) ; Stapel anlegen
out SPL, akku ;
ldi akku, HIGH(RAMEND)
out SPH, akku
ldi akku, (1<<PB1) | (1<<PB2)
out DDRB, akku
;.equ WertH = 100 ; Konstante für OCR1AH u. OCR1BH (r16)
.equ WertL = 127 ; Konstante für OCR1AL u. OCR1BL (r17)

; Timer1 programmieren: WGM10=1<<<PWM8Bit phasenrichtig (TOPP=00FF)
; KanalA (COM1Ax) zu PB1 und KanalB (COM1Bx) zu PB2
; Set OC1A and OC1B when upcounting, clear when downcounting. COM1 bits according table 38.
ldi akku, (1<<COM1A1) |(1<<COM1A0)| (1<<COM1B1) | (1<<COM1B0)| (1<<WGM10)
out TCCR1A, akku ; Steuerregister A Timer1
clr akku
ldi akku, (1<<CS10)| (1<<CS12) ;Prescale = 1024 (PWM frequency ~ 2Hz)
out TCCR1B, akku ; Timer1 Steuerregister B

; setting of high byte register not needed in 8 bit Timer1 operation
ldi temp17, WertL ; r17 auf 127
out OCR1AL, temp17 ; Kanal A = 127 (WertL)
out OCR1BL, temp17 ; Kanal B = 127 (WertL)

loop:
rjmp loop
.EXIT

1. Die Ausdrücke, die eine 0 nach links verschieben rausgenommen - hatten sowieso keinen Effekt, löschten auch kein Bit, wenn eins vorhanden gewesen wäre!
2. 8Bit Phase Correct Modus des Timer1 belassen. (Mode 1 laut Table 39 im Datenblatt)
3. Die COMA und COMB Bits nach der Table 38 gesetzt.
4. Prescaler auf 1024 gesetzt, damit man die LEDs auch blinken sehen kann. Mit Prescaler 1 wäre die Frequenz so hoch, daß man nur ein Leuchten sehen würde.
5. Setzten der OCR1xL Register mit einem Wert (127), der etwa 50% Duty Cycle der PWM erzeugt. OCR1xH sind durch Einschaltreset des µC auf 0 und brauchen für den 8 Bit Mode des Timers auch nicht gesetzt werden.
6. Setzen der OCRx nicht mehr in der Loop.

Hoffe hab mich nirgends verrechnet oder vertan.



Zu Deinem letzten Post: Ich hatte doch nirgends vorgeschlagen WGM12 und WGM10 auf eins zu setzten?

Würde vorschlagen bei Deinem ursprünglichen Programm zu bleiben und das zum Laufen bringen. Danach kann man Veränderungen mit SBI etc einbringen oder die beiden LEDs unterschiedlich blinken lassen oder auf 16 Bit Timer Modus umschalten. Erst sollte aber, wie gesagt, Dein erstes Programm laufen.

Frag ruhig nach, warum ich was im Programm geändert habe. Ich kann es nicht Testen und es könnten Fehler drin sein.

Gruß
Searcher

hegewald
07.11.2013, 18:13
Danke....morgen geht es weiter....will noch einen Hubi für morgen zum laufen bekommen.
Goblin500...wenn Dir das was sagt!

Grüße aus Hmb.

Rolf

hegewald
08.11.2013, 07:32
Hallo Searcher,
ich sitze schon seit 6 Uhr.....und ES LÄUFT
Bevor ich es rüber schiebe hätte ich gern gewußt wie Ihr das mit den Codefenster macht.
Im AVR-Studio 4 schwärze ich den Code an...gehe auf Kopieren....wechsel nach Roboternetz und sage Einfügen...und dann!
wie soll ich das nur verstehen??
bitte nimm mal das Codefenster für Code: einfach im Editor auf das Lattenzahnsymbol (Hash) klicken. Ich habs mal etwas lesbarer gemacht - aber mittlerweile kneift meine Zeit, später vielleicht mehr.

- - - Aktualisiert - - -


sbi DDRB,PB1 ; PB1 ist Ausgang OC1A
sbi DDRB,PB2 ; PB2 ist Ausgang OC1B

.equ WertH = 100 ; Konstante für OCR1AH u. OCR1BH (r16)
.equ WertL = 120 ; Konstante für ICR1H (r16)
.equ Wert = 70 ; Konstante für OCR1AL u. OCR1BL u.ICR1L (r17)

ich glaub ich habs gefunden, mal sehen

- - - Aktualisiert - - -

ja es funzt!

folgendes ist heute Morgen hier abgelaufen:
1. Die ganzen 0<<COMxx raus damit.
2. Eintragungen in OCR1AH und BH gelöscht bzw. entfernt.
3. Unter einen neuen Namen "8BitPhase-Correct.asm abgespeichert.
4. Mit Prescale 1024 über ISP Schnittstelle gestartet. Beide LEDs blinkten gut sichtbar.
5. Prescale auf 1 geändert (1<<CS10)
Da ich hier einen Skop stehen habe ergaben sich messbar eine Periode von 0,5ms (Tastverh.=1:1)

So, und das ists Ergebnis: (mh..muß es leider so lassen ein Icon Code ist im Editor nicht zu sehen)


; Projekt: Mega8-PWM Datum: 08.11.2013

; Datei: 8BitPhase-Correct.asm

; Mode1 PWM 8 Bit phasenrichtig (Zähler läuft hoch bis 00FF
; und zurück bis 0000)

; Port B: Ausgang Kanal A:OC1A (PB1-Pin15) Kanal B:OC1B (PB2-Pin16)

; Konfiguration: interner Oszillator 1 MHz, externes RESET-Signal
.INCLUDE "m8def.inc" ; Deklarationen für Mega8
.EQU takt = 1000000 ; Systemtakt 1 MHz intern

.DEF akku = r16
.DEF temp17 = r17
.CSEG ; Programm-Flash
rjmp start ; Reset-Einsprung
.ORG $13 ; Interrupt-Einsprünge übergehen

start:
ldi akku,LOW(RAMEND); Stapel anlegen
out SPL,akku ;
ldi akku,HIGH(RAMEND)
out SPH,akku

ldi akku,(1<<PB1) | (1<<PB2)
out DDRB,akku

.equ WertL = 127 ; Konstante für OCR1AL u. OCR1BL (r17)


; Timer1 programmieren: WGM10=1<<<PWM8Bit phasenrichtig (TOPP=00FF)
; KanalA (COM1Ax) zu PB1 und KanalB (COM1Bx) zu PB2

; Set OC1A and OC1B when upcounting, clear when downcounting. COM1 bits according table 38.
ldi akku,(1<<COM1A1) |(1<<COM1A0)| (1<<COM1B1) | (1<<COM1B0)| (1<<WGM10)
out TCCR1A,akku ; Steuerregister A Timer1

clr akku
ldi akku, (1<<CS10) ;Prescale = 1 (Periode=0,5ms Imp./Pause ca.1:1)
out TCCR1B,akku ; Timer1 Steuerregister B

; setting of high byte register not needed in 8 bit Timer1 operation
ldi temp17, WertL ; r17 auf 127
out OCR1AL, temp17 ; Kanal A = 127 (WertL)
out OCR1BL, temp17 ; Kanal B = 127 (WertL)

loop:
rjmp loop
.EXIT

XCircle
10.11.2013, 18:19
Zu deinem Problem mit der richtigen Code-Anzeige..

Das Zeichen(Screenshot) siehst du wahrscheinlich nicht, weil du im Direkt-Antworten bist.
Dazu musst du einmal auf den Erweitert-Button unter deinem Textfeld klicken.
Danach erscheint ein erweiterter Antwort-Editor, wo du auch das richtige Zeichen findest.



testcode blablubb

hegewald
11.11.2013, 18:33
mh...komisch, habe keine Info über Deinen Hinweis bekommen!
Danke Dir.

Grüße

Rolf