Forum: Mikrocontroller und Digitale Elektronik Fragen zu PWM


von Joachim G. (big_daddi)


Lesenswert?

Hi,

erstmal danke für des tut mit PWM-software!

Dazu hab ich jetzt ein paar verständnisprobleme!
 Hier erstmal den code:
timer0_overflow:                      ; Timer 0 Overflow Handler
        inc     PWMCount              ; den PWM Zähler von 0 bis
        cpi     PWMCount, 128         ; 127 zählen lassen
        brne    WorkPWM
        clr     PWMCount

WorkPWM:
        ldi     temp, 0b11000000      ; 0 .. Led an, 1 .. Led aus

        cp      PWMCount, ocr_1       ; Ist der Grenzwert für Led 1 
erreicht
        brlt    OneOn
        ori     temp, $01

OneOn:  cp      PWMCount, ocr_2       ; Ist der Grenzwert für Led 2 
erreicht
        brlt    TwoOn
        ori     temp, $02

TwoOn:  cp      PWMCount, ocr_3       ; Ist der Grenzwert für Led 3 
erreicht
        brlt    ThreeOn
        ori     temp, $04

ThreeOn:cp      PWMCount, ocr_4       ; Ist der Grenzwert für Led 4 
erreicht
        brlt    FourOn
        ori     temp, $08

FourOn: cp      PWMCount, ocr_5       ; Ist der Grenzwert für Led 5 
erreicht
        brlt    FiveOn
        ori     temp, $10

FiveOn: cp      PWMCount, ocr_6       ; Ist der Grenzwert für Led 6 
erreicht
        brlt    SetBits
        ori     temp, $20

SetBits:                              ; Die neue Bitbelegung am Port 
ausgeben
        out     PORTB, temp

        reti

Was bedeutet ori temp, $10 oder so??? also jetzt nicht bezogen auf die 
zahl sondern auf die ganze zeile!

Die LEDs leuchten erst wenn das Programm SetBits oder versteh ich des 
falsch??

von johnny.m (Gast)


Lesenswert?

> Was bedeutet ori temp, $10
Das bedeutet, dass der Inhalt des Registers temp mit der (Hexadezimal-) 
Zahl 10h (bitweise) ODER-verknüpft wird. Mit anderen Worten: Das Bit 
Nummer 4 in temp wird gesetzt (egal welchen Wert es vorher hatte), 
während alle anderen Bits im Register unverändert bleiben.

von Karl H. (kbuchegg)


Lesenswert?

ori verknüpft ein register mit einer Zahl (daher das i in ori -
immediate - direkt angegeben) mittels einer ODER Verknüpfung.
Und zwar macht ori das Bit für Bit

Die Wahrheitstabelle für ODER

  A     B     Ergebnis
 ----------------------
  0     0       0
  1     0       1
  0     1       1
  1     1       1

(Das Ergebnis ist dann 1, wenn entweder A oder B oder beide 1 sind)
Man erkennt aber auch: Das Ergebnis ist nur dann 0, wenn weder
A noch B eine 1 aufweisen.

Und das benutzt man hier:
Sei A irgendein Bit im Register und B das korrespondierende Bit
in der Zahl, dann taucht im Ergebnis auf jeden Fall eine 1 auf,
wenn B den Wert 1 hat, unabhängig davon welchen Wert A hatte
(in der Wahrheitstabelle kontrollieren!). Wenn A sowieso
schon den Wert 1 hat, dann ist auch das Ergebnis 1, diesmal
unabhängig von B.

Bsp:
Im Register steht zb. die Bitkombination  01000100
Und die Zahl habe die Bitkombination      00010001

dan ergibt die ODER Verknüpfung
(einfach untereinanderstehende Bits laut
 Wahrheitstabelle miteinander verknüpfen) 01010101

man erkennt: Dort wo ursprünglich im Register bereits eine 1 war,
ist auch im Ergebnis eine 1. Dort wo in der Zahl eine 1 ist
kommen im Ergebnis 1-en dazu.

In Summe kann man also mit einer ODER Verknüpfung gezielt
Bits in einem Register setzen.

(Ich seh schon, da wird im Tutorial mal eine Seite über
logische Verknüpfungen fällig)

von Erik (Gast)


Lesenswert?

Hallo  Joachim Geiger, zu Frage 2:
1
SetBits:                              ; Die neue Bitbelegung am Port
2
ausgeben
3
        out     PORTB, temp
Macht genau was da steht: Der Inhalt von "temp" wird auf PORTB 
ausgegeben.

von Karl H. (kbuchegg)


Lesenswert?

Joachim Geiger wrote:

> Die LEDs leuchten erst wenn das Programm SetBits oder versteh ich des
> falsch??

Das verstehst du schon richtig.

Die Idee ist folgende:
Mittels PWMCount wird ein Zeitraster erzeugt.
Es gibt also den Zeitpunkt 1, Zeitpunkt 2, Zeitpunkt 3 etc.

Die OCR Werte geben an, zu welchem Zeitpunkt eine LED ausgeschaltet
werden soll. Enthält OCR den Wert 3, dann bedeutet das, das
die LED nur während der Zeitpunkte 0, 1, 2 leuchten soll.
Zu allen anderen Zeitpunkten (3 bis 127) soll sie dunkel
sein. Enthält OCR den Wert 7, dann soll die LED während der
Zeitpunkte 0, 1, 2, 3, 4, 5, 6 leuchten. Im zweiten Fall
leuchtet sie daher länger als im ersten Fall. Und genau das
wollen wir ja: Wir wollen das Verhältnis von Einschaltzeit
zu Auszeit einstzellen können.

Bei der Verschaltung im Tutorial leuchtet eine LED genau dann,
wenn der zugehörige Port Pin eine 0 aufweist.
Also beginnt die PWM Abfrage damit, dass in einem Register
einfach mal alle Bits (bis auf die obersten 2, die sind
nicht benutzt) auf 0 gesetzt werden. Würde man diesen
Registerinhalt so auf den Port ausgeben, dann würden alle
Leds leuchten.
Aber jetzt kommt ja noch die Abfragekaskade. Sie vergleicht
den OCR Wert mit dem PWMCount (stellt also fest, ob der
vorgegebene Zeitpunkt bereits erreicht oder überschritten
wurde). Ist der Zeitpunkt noch nicht erreicht, dann passiert
nichts mit dem Bit. Ist der Zeitpunkt erreicht oder überschritten,
so wird in diesem Register mittels ori das zugehörige Bit auf 1
gesetzt.

Nachdem die Abfragekaskade durchgelaufen ist, enthält also
dieses Register für alle Led deren Zeitpunk noch nicht erreicht
ist eine 0 und für alle Led deren Zeitpunkt bereits erreicht
oder abgelaufen ist eine 1. (Nochmal: bei 0 leuchtet die
zugehörige Led, bei 1 ist sie dunkel)

Und das wird in einem Rutsch auf den Port ausgegeben.

Man hätte das Ganze auch gezielt direkt mit Einzelbit
Port-Setz- und Rücksetzbefehlen machen können (für Ports gibt
es die), aber wenn du das mal probierst stellst du fest,
dass dadurch das Program auch nicht kürzer wird sondern,
ganz im Gegenteil, eine Menge Sprünge mehr hinzugekommen
wären.


von Joachim G. (big_daddi)


Lesenswert?

Danke für eure antworten jetzt versuch ich mal mein glück!

ja die logischen verknüpfungen sind schon klar aber ich stand auf dem 
schlauch was zb die 10 bedeutet aber des is ja 1010. Des war einfach nur 
des was mich verwirrt hat. ich könnt doch anstatt dem $10 auch 
0b00001010 schreiben oder??

mir ging es darin eigentlich nur um die Zahl da hinten dran weil ich den 
zusammenhang zwischen der zahl und dem befehl nicht ganz verstanden hab. 
aber das "$" Zeichen gibt ja einfach eine dec. zahl binär oder hex an 
oder??

von johnny.m (Gast)


Lesenswert?

> ich könnt doch anstatt dem $10 auch 0b00001010 schreiben oder??
Nö, $10 ist 0b00010000.

von johnny.m (Gast)


Lesenswert?

"$10" ist eine alternative Schreibweise für "0x10" und das ist eine 
Hexadezimalzahl. Dezimalzahlen schreibt man ohne "$" oder "0x". 0x10 in 
Dezimal ist 16.

von Joachim G. (big_daddi)


Angehängte Dateien:

Lesenswert?

Also ich hab jetzt im Anhang mal mein erstes Prog rein gehängt. Sorry 
aber wie gesagt ich bin noch relativ neu. Ich komm irgendwie nicht mehr 
weiter. Wäre nett wenn einer nur mal kurz drüber schaut und ein kurzes 
statement bzw. vorschläge abgibt!!!!

Danke schon mal

von Joachim G. (big_daddi)


Lesenswert?

Ah jetzt ich versteh!! :-)

Oh des mit den #, (), $ ... Zeichen is voll verwirrend. wir 
Programmieren in der Schule mit nem Motorolla und da machen wir alles 
ganz anders aber so wie es mit dem Amtel geh versteh ich zumindest ein 
wenig.

von Gad Z. (gad)


Lesenswert?

> ja die logischen verknüpfungen sind schon klar aber ich stand auf dem
> schlauch was zb die 10 bedeutet aber des is ja 1010. Des war einfach nur
> des was mich verwirrt hat. ich könnt doch anstatt dem $10 auch
> 0b00001010 schreiben oder??

Nein nicht ganz, der Unterschied zwischen 10 und $10 ist das 
Zahlensystem.
10  = Dezimal      = 0b00001010
$10 = Hexadezimal  = 0b00010000


von Joachim G. (big_daddi)


Lesenswert?

kann mir keiner weiterhelfen mit der datei da ich absolut nicht mehr 
weiter komme!!!

von Karl H. (kbuchegg)


Lesenswert?

Ich seh nirgends den globalen PWM Counter.
Ich seh auch nirgends, dass du den Timer Interrupt
angeschlossen hättest.

Was du anscheinend überhaupt nicht begriffen hast ist,
dass die ganze PWM im Hintergrund von einem Timerinterrupt
erledigt wird.

Du musst nur dafür sorgen, dass ein Timer in regelmässigen
Abständen die PWM Funktion aufruft. Mehr nicht.

Warum spielst du nicht einfach mal ein bischen mit dem
im Tutorial angeführten Programm rum, bevor du versuchst
sie in dein bestehendes Programm einzubinden.

von Joachim G. (big_daddi)


Lesenswert?

genau des is ja mein problem!!!!!!!!

von Karl H. (kbuchegg)


Lesenswert?

Was ist dein Problem?

Alle Fragenkreise sind im Beispielprogramm im Tutorial
ausgeführt:

* Wie man den Timer aufsetzt
* Wie man den Interrupt in den Interrupt Vektor einbaut.
* Was die Interrupt funktion machen muss.

Du wirst diese 3 Themenkreise ja wohl noch alleine
in dein Programm übernehmen können.


von Joachim G. (big_daddi)


Lesenswert?

ok dann schau ich es mir nochmal genauer an ich hab des nur nicht so 
ganz kapiert mit den interrupts!!

von Karl H. (kbuchegg)


Lesenswert?

Ist ganz simpel:

Für einen Interrupt brauchst du

1) Einen Eintrag in der Interrupt Vektor Tabelle
2) Das Freigabebit für den entsprechenden Interrupt muss
   gesetzt sein
3) die globalen Interrupts müssen mittels sei freigegeben sein
4) Eine Funktion die den Interrupt bearbeitet

ad 1)

Das ist deine Interrupttabelle
1
;interrupt vectors
2
3
  rjmp init     ;reset vector address
4
  reti      ;External Interrupt0 Vector Address
5
  reti      ;External Interrupt1 Vector Address
6
  reti      ;Input Capture1 Interrupt Vector Address
7
  reti      ;Output Compare1A Interrupt Vector Address
8
  reti      ;Output Compare1B Interrupt Vector Address
9
  reti      ;Overflow1 Interrupt Vector Address
10
  reti      ;Overflow0 Interrupt Vector Address
11
  reti      ;SPI Interrupt Vector Address
12
  rjmp get_byte    ;UART Receive Complete Interrupt Vector Address
13
  reti      ;UART Data Register Empty Interrupt Vector Address
14
  reti      ;UART Transmit Complete Interrupt Vector Address
15
  reti      ;Analog Comparator Interrupt Vector Address
16
  reti      ;External Interrupt2 Vector Address
17
  reti      ;Output Compare0 Interrupt Vector Address
18
  reti      ; EEPROM Interrupt Vector Address
19
  reti      ; SPM complete Interrupt Vector Address
20
  reti      ; SPM complete Interrupt Vector Addres

Ich sehe in der Zeile für den Overflow 0 Interrupt lediglich einen
reti aber keine Weiterleitung zu einer Funktion

ad 2)
1
      ldi      temp1, 0x01
2
      out      TIMSK, temp1
Die Schreibweise ist zwar besch..... weil man wissen muss, das Bit 0
in TIMSK den Overflow Interrupt freigibt, aber was solls. Der Timer 0
darf bei einem Overflow einen Interrupt generieren.

ad 3)
den sei seh ich im Code

ad 4)
Ich sehe aber keine Interrupt Funktion, die dem Vorbild des
Tutorials folgt.
Ich sehe aber sehr wohl einen in sehr weit gefassten Grenzen
ähnlichen Programmteil, der über dubiose Pfade immer dann aufgerufen
wird, wenn ein Zeichen empfangen wird.
Das ist es aber nicht!
Die Timer 0 Overflow Interrupt Funktion wird in regelmässigen
Abständen vom Timer aufgerufen, unabhängig davon, ob über die
UART ein Zeichen eintrudelt oder nicht! Die beiden Funktions-
blöcke haben nichts miteinander zu tun (ausser dass die UART
Empfangsfunktion ein empfangenes Byte in einem Register
hinterlässt, welches von der Timer-PWM-Interrup Funktion
ausgewertet wird).

von Joachim G. (big_daddi)


Angehängte Dateien:

Lesenswert?

womit ich jetzt nur auf dem Schlauch steh ist, dass ich ja 16 einzelne 
Kanäle hab die über dmx signal gesteuert werden. Ist überhaupt die 
verarbeitung des eingangssignals richtig. Im Anhang nur mal ein kleiner 
Schaltplan wie ich vor hab das ganze zu schalten. die 3. Leitungen ins 
leere sind die DMX-Eingänge. So gut soweit.

Zurück zum Thema ich versteh nicht wie ich aus dem Interrupt in meine 
verschiedenen unterprogramme spring damit er mir z.b. kanal 7 anmacht 
und nicht alles!! oder legt man das mit dem register ocr fest?? wenn ocr 
als beispiel nur bei kanal 7 ungleich 0 ist so bleiben alle anderen 
kanäle aus aber durchlaufen wird trotzdem jeder kanal oder???

Sorry aber wie gesagt so richtig fit bin ich noch nicht aber durch 
dieses Projekt will ich mir ein wenig außerschulisches wissen aneignen! 
Deshalb ist mein Code auch ein wenig unübersichtlich bzw. lang oder 
umständlich. Ist mein erster Assemblercode den ich erstelle bzw. das 
erste vernünftige.

von Karl H. (kbuchegg)


Lesenswert?

Joachim Geiger wrote:
> Zurück zum Thema ich versteh nicht wie ich aus dem Interrupt in meine
> verschiedenen unterprogramme spring damit er mir z.b. kanal 7 anmacht
> und nicht alles!! oder legt man das mit dem register ocr fest?? wenn ocr
> als beispiel nur bei kanal 7 ungleich 0 ist so bleiben alle anderen
> kanäle aus aber durchlaufen wird trotzdem jeder kanal oder???

Ich kann dir nur raten:
Nimm dir das Programm aus dem Tutorial und brenne es mal
in deinen µC rein und spiele damit rum

Es hat wenig Sinn da jetzt gross was dazu zu sagen, wenn du
das Funktionsprinzip nicht verstehst.
Und ehrlich gesagt weiss ich nicht, wie ich dir das noch
einfacher erzählen kann. Von mir aus lade dir das Teil
auch mal in den Simulator und geh mit Einzelschritten
durch.

von Joachim G. (big_daddi)


Lesenswert?

dann werd ichs mal so probieren. Nur noch eine Frage und zwar ich 
benötige dann ja 16 freie Register für den Code! -> Problem: soviele hab 
ich nicht mehr frei.

von Karl H. (kbuchegg)


Lesenswert?

Lass die Interrupt Funktion zunächst mal so wie sie ist.
AUf mehr Kanäle erweitern kannst du sie immer noch.

PS: Die Einstellung der Helligkeiten der einzelnen
LEDS geschieht nicht in der ISR. Die ISR realisiert
lediglich die Helligkeitseinstellung. Aber gesetzt
werden die Helligkeiten hier:

        ldi     ocr_1, 0
        ldi     ocr_2, 1
        ldi     ocr_3, 10
        ldi     ocr_4, 20
        ldi     ocr_5, 80
        ldi     ocr_6, 127


Das setzt LED 1 auf aus (weil im Register ocr_1 eine 0
steht), LED 2 auf minimale Helligkeit (ocr_2 auf 1),
LED 3 auf 'ein bischen heller' usw. bis zur LED 6
die auf volle Helligkeit gesetzt wird.

Und wenn später irgendwann mal die LED 6 auf 'aus'
gesetzt werden soll, dann lautet das

         ldi  ocr_6, 0

und wenn du eine Zahl von der UART für die LED 3 hast,
die deren Helligkeit darstellt, und diese Zahl möge
sich in Register 25 befinden, so lautet das dann

         mov  ocr_3, r25

Ansonsten brauchst du dich um nichts kümmern. Du schreibst
einfach die gewünschten Zahlenwerte in die zugeordneten
Register und die Interrupt Routine kümmert sich darum, dass
die Led auch mit dieser Helligkeit leuchtet.



Vielleicht ist es jetzt ein bischen klarer geworden.

von Karl H. (kbuchegg)


Lesenswert?

Joachim Geiger wrote:
> dann werd ichs mal so probieren. Nur noch eine Frage und zwar ich
> benötige dann ja 16 freie Register für den Code! -> Problem: soviele hab
> ich nicht mehr frei.

Dann wirst du nicht umhin kommen ein paar SRAM Speicherzellen
dafür abzustellen.

von Joachim G. (big_daddi)


Lesenswert?

sorry wenn ich mich vielleicht falsch ausgedrückt hab oder so aber des 
hab ich soweit alles schon verstanden aber wie gesagt du hast da 6 
register definiert und dann werte reingeladen. Sozusagen steht jedes 
register für die Helligkeit eines LEDs aber dann benötige ich ja 16 
register. Des is halt mein Problem was ich hab. Deshalb komm ich nicht 
weiter. Die Register 1-15 kann ich nicht dazu nehmen oder?? Den Rest hab 
ich eigentlich soweit schon verstanden aber wie gesagt ich tu mich 
schwer mit der ausdrucksweise! Das Problem ist einfach auch dass ich ein 
grundgerüst des programms schon hatte und es "nur" erweitert hab und 
nicht von vorn herein komplett selbst durchdacht. Also wie gesagt ich 
versteh des schon aber mit den registern komm ich halt nicht klar weil 
ich nicht mehr so viele frei hab.

von Joachim G. (big_daddi)


Lesenswert?

würde des funktionieren wenn ich anstatt den registern 16 speicherbytes 
dafür her nehm?????

von Karl H. (kbuchegg)


Lesenswert?

Joachim Geiger wrote:
> sorry wenn ich mich vielleicht falsch ausgedrückt hab oder so aber des
> hab ich soweit alles schon verstanden aber wie gesagt du hast da 6
> register definiert und dann werte reingeladen. Sozusagen steht jedes
> register für die Helligkeit eines LEDs aber dann benötige ich ja 16
> register.

Exakt.
Oder aber die Werte liegen nicht in Registern vor, sondern
werden im SRAM gespeichert. Die Interrupt Funktion muss
dann halt die Werte aus dem Speicher lesen anstatt sie schon
in den jeweiligen Registern vorzufinden.
Dafür können dann aber auch alle 16 Werte über ein einziges
Register nacheinander abgewickelt werden.

> Des is halt mein Problem was ich hab. Deshalb komm ich nicht
> weiter. Die Register 1-15 kann ich nicht dazu nehmen oder??

Warum nicht?

> Den Rest hab
> ich eigentlich soweit schon verstanden aber wie gesagt ich tu mich
> schwer mit der ausdrucksweise! Das Problem ist einfach auch dass ich ein
> grundgerüst des programms schon hatte und es "nur" erweitert hab und
> nicht von vorn herein komplett selbst durchdacht. Also wie gesagt ich
> versteh des schon aber mit den registern komm ich halt nicht klar weil
> ich nicht mehr so viele frei hab.

Ganz ehrlich.
Ich bin nicht Hannes. Solche Dinge programmiere ich in C.
Dann brauch ich mich nicht darum zu kümmern wann welches
Register welchen Inhalt hat. Ich lege einfach meine Variablen
an, und der Compiler verteilt das dann im Speicher :-)

von Joachim G. (big_daddi)


Lesenswert?

ich hab im tut wo gelesen dass die register 1-15 irgendwie schon belget 
sind bzw. wenn ich mein avr studio laufen lass dann schreibt er mir 
warnungen für die register aus wo kleiner wie 16 sind dass die schon 
verwendet worden sind.

Müssen beim Arbeiten mit speicher die Pins PB... frei sein, also darf da 
nix dran hängen?? ich will doch nix raus geben sondern nur was intern 
speichern und bei bedarf wieder laden.

Ich glaub ich steig jetzt auch mal wieder auf c um weil des mit den 
speichern und registern und was sonst noch alles is ziehmlich .....! 
Also find ich zumindest.

Greif ich auf den RAM mit dem gleichen Prinzip wie wenn ich auf einen 
Flash rom oder eeprom zugreife??

von Karl H. (kbuchegg)


Lesenswert?

Joachim Geiger wrote:
> ich hab im tut wo gelesen dass die register 1-15 irgendwie schon belget
> sind bzw. wenn ich mein avr studio laufen lass dann schreibt er mir
> warnungen für die register aus wo kleiner wie 16 sind dass die schon
> verwendet worden sind.

Es gibt ein paar Einschränkungen für diese Register. Mann
kann einige Operationen damit nicht machen.
Aber ansonsten: In Assembler hast du die volle Kontrolle
über die Register. Wenn du in r11 was hineinschreibst, dann
hindert dich keiner daran.

>
> Müssen beim Arbeiten mit speicher die Pins PB... frei sein, also darf da
> nix dran hängen?? ich will doch nix raus geben sondern nur was intern
> speichern und bei bedarf wieder laden.
>
> Ich glaub ich steig jetzt auch mal wieder auf c um weil des mit den
> speichern und registern und was sonst noch alles is ziehmlich .....!
> Also find ich zumindest.
>
> Greif ich auf den RAM mit dem gleichen Prinzip wie wenn ich auf einen
> Flash rom oder eeprom zugreife??

Du brauchst dazu die Befehle LDS, STS. Eventuell ist auch
LDD bzw STD zusammen mit dem Z Register ein guter Weg.

(Ich seh grade: dafür gibt es im Tutorial noch nicht mal
ein Beispiel. Ts, ts. Nachlässig)

von Joachim G. (big_daddi)


Lesenswert?

ok dann versuch ich mal weiter aber ich glaub ich nehm trotzdem die 
Speichermethode.

Deshalb hab ich mir ja gedacht ich frag mal nach weil ich nix gefunden 
hab!!! Aber trotzdem ein mega Dankeschön!

von Karl H. (kbuchegg)


Lesenswert?

Das sieht dann so aus (ungetestet)
1
.include "m16def.inc"
2
 
3
.def temp  = r16
4
.def temp2 = r17
5
6
.def PWMCount = r18
7
 
8
.org 0x0000
9
        rjmp    main                  ; Reset Handler
10
.org OVF0addr
11
        rjmp    timer0_overflow       ; Timer Overflow Handler
12
 
13
main:
14
        ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
15
        out     SPL, temp
16
        ldi     temp, HIGH(RAMEND)
17
        out     SPH, temp
18
  
19
        ldi     temp, 0xFF            ; Port B auf Ausgang
20
        out     DDRB, temp
21
22
        ldi     temp2, 0
23
        sts     OCR_1, temp2
24
        ldi     temp2, 1
25
        sts     OCR_2, temp2
26
        ldi     temp2, 10
27
        sts     OCR_3, temp2
28
        ldi     temp2, 20
29
        sts     OCR_4, temp2
30
        ldi     temp2, 80
31
        sts     OCR_5, temp2
32
        ldi     temp2, 127
33
        sts     OCR_6, temp2
34
 
35
        ldi     temp, 0b00000001      ; CS00 setzen: Teiler 1
36
        out     TCCR0, temp
37
 
38
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow
39
        out     TIMSK, temp
40
 
41
        sei
42
 
43
loop:   rjmp    loop
44
 
45
timer0_overflow:                      ; Timer 0 Overflow Handler
46
        inc     PWMCount              ; den PWM Zähler von 0 bis
47
        cpi     PWMCount, 128         ; 127 zählen lassen
48
        brne    WorkPWM
49
        clr     PWMCount
50
51
WorkPWM:
52
        ldi     temp, 0b11000000      ; 0 .. Led an, 1 .. Led aus
53
54
        lds     temp2, OCR_1
55
        cp      PWMCount, temp2       ; Ist der Grenzwert für Led 1 erreicht
56
        brlt    OneOn
57
        ori     temp, $01
58
59
OneOn:  lds     temp2, OCR_2
60
        cp      PWMCount, temp2       ; Ist der Grenzwert für Led 2 erreicht
61
        brlt    TwoOn
62
        ori     temp, $02
63
64
TwoOn:  lds     temp2, OCR_3
65
        cp      PWMCount, temp2       ; Ist der Grenzwert für Led 3 erreicht
66
        brlt    ThreeOn
67
        ori     temp, $04
68
69
ThreeOn:lds     temp2, OCR_4
70
        cp      PWMCount, temp2       ; Ist der Grenzwert für Led 4 erreicht
71
        brlt    FourOn
72
        ori     temp, $08
73
74
FourOn: lds     temp2, OCR_5
75
        cp      PWMCount, temp2       ; Ist der Grenzwert für Led 5 erreicht
76
        brlt    FiveOn
77
        ori     temp, $10
78
79
FiveOn: lds     temp2, OCR_6
80
        cp      PWMCount, temp2       ; Ist der Grenzwert für Led 6 erreicht
81
        brlt    SetBits
82
        ori     temp, $20
83
84
SetBits:                              ; Die neue Bitbelegung am Port ausgeben
85
        out     PORTB, temp
86
87
        reti
88
89
        .DSEG                          ; das Folgende kommt ins SRAM
90
OCR_1:  .BYTE   1                      ; 6 Bytes für die OCR Register
91
OCR_2:  .BYTE   1
92
OCR_3:  .BYTE   1
93
OCR_4:  .BYTE   1
94
OCR_5:  .BYTE   1
95
OCR_6:  .BYTE   1

von harry (Gast)


Lesenswert?

http://ww1.microchip.com/downloads/en/AppNotes/00654a.pdf

aber in C wäre das ganze mal angebracht

von eProfi (Gast)


Lesenswert?

Hallo Karl Heinz,
    cpi     PWMCount, 128    ; 127 zählen lassen
    brne    WorkPWM
    clr     PWMCount

geht das nicht eleganter?
    brcc    WorkPWM
    clr     PWMCount

oder noch kürzer:
    andi    PWMCount, 127    ; 127 zählen lassen



Die Abfragereihe läßt sich auch als Schleife schreiben:
    ldi     r30,byte0(OCR_6) ;Z zeigt auf Wert für LED6
    ldi     r31,byte1(OCR_6) ;weiß die genaue Syntax nicht
    ldi     bitmuster,$20    ;mit LED6 (bit5) anfangen
    ldi     temp, 0b11000000 ;0 .. Led an, 1 .. Led aus

pwmloop:
    ld      temp2,Z-         ;Wert holen, Z für nächste LED vorbereiten
    cp      PWMCount, temp2  ;ist der Grenzwert für Led erreicht?
    brne    nichtsetzen
    or      temp,bitmuster
nichtsetzen:
    lsr     bitmuster        ;wirkt gleichzeitig als "Zähler"
    brne    pwmloop          ;wenn das Bit noch nicht "herausgefallen" 
ist

    out     PORTB, temp      ;Die neue Bitbelegung am Port ausgeben
    reti

Nicht getestet....
Was hältst Du davon?

von Karl H. (kbuchegg)


Lesenswert?

eProfi wrote:

> Was hältst Du davon?

Viele Wege führen nach Rom.


>    cpi     PWMCount, 128    ; 127 zählen lassen
>    brne    WorkPWM
>    clr     PWMCount
>
> geht das nicht eleganter?
>
> oder noch kürzer:
>    andi    PWMCount, 127    ; 127 zählen lassen

In dem konkreten Fall würde das selbstverständlich gehen.
Und jetzt mach mal 100 Stufen :-)

> Die Abfragereihe läßt sich auch als Schleife schreiben:

Yep.
Ich hab trotzdem Loop Unrolling gemacht, weil:
* Im Tutorial der Zugriff aufs SRAM überhaupt noch nicht
  ghezeigt wurde
* Und daher klarerweise der Zugriff über den Z-Pointer
  plus Offset auch noch unbekannt sind. Wäre aber eine gute
  Gelegenheit, dieses Thema zum Anlass zu nehmen, diese Dinge
  in das Tutorial mit einzubauen.

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
Noch kein Account? Hier anmelden.