mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Fragen zu PWM


Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht 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??

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Erik (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.


Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht 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??

Autor: johnny.m (Gast)
Datum:

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

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Geiger (big_daddi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gad Zinkler (gad)
Datum:

Bewertung
0 lesenswert
nicht 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


Autor: Joachim Geiger (big_daddi)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
genau des is ja mein problem!!!!!!!!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.


Autor: Joachim Geiger (big_daddi)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
;interrupt vectors

  rjmp init     ;reset vector address
  reti      ;External Interrupt0 Vector Address
  reti      ;External Interrupt1 Vector Address
  reti      ;Input Capture1 Interrupt Vector Address
  reti      ;Output Compare1A Interrupt Vector Address
  reti      ;Output Compare1B Interrupt Vector Address
  reti      ;Overflow1 Interrupt Vector Address
  reti      ;Overflow0 Interrupt Vector Address
  reti      ;SPI Interrupt Vector Address
  rjmp get_byte    ;UART Receive Complete Interrupt Vector Address
  reti      ;UART Data Register Empty Interrupt Vector Address
  reti      ;UART Transmit Complete Interrupt Vector Address
  reti      ;Analog Comparator Interrupt Vector Address
  reti      ;External Interrupt2 Vector Address
  reti      ;Output Compare0 Interrupt Vector Address
  reti      ; EEPROM Interrupt Vector Address
  reti      ; SPM complete Interrupt Vector Address
  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)
      ldi      temp1, 0x01
      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).

Autor: Joachim Geiger (big_daddi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Geiger (big_daddi)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht 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??

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Joachim Geiger (big_daddi)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sieht dann so aus (ungetestet)
.include "m16def.inc"
 
.def temp  = r16
.def temp2 = r17

.def PWMCount = r18
 
.org 0x0000
        rjmp    main                  ; Reset Handler
.org OVF0addr
        rjmp    timer0_overflow       ; Timer Overflow Handler
 
main:
        ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp
  
        ldi     temp, 0xFF            ; Port B auf Ausgang
        out     DDRB, temp

        ldi     temp2, 0
        sts     OCR_1, temp2
        ldi     temp2, 1
        sts     OCR_2, temp2
        ldi     temp2, 10
        sts     OCR_3, temp2
        ldi     temp2, 20
        sts     OCR_4, temp2
        ldi     temp2, 80
        sts     OCR_5, temp2
        ldi     temp2, 127
        sts     OCR_6, temp2
 
        ldi     temp, 0b00000001      ; CS00 setzen: Teiler 1
        out     TCCR0, temp
 
        ldi     temp, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow
        out     TIMSK, temp
 
        sei
 
loop:   rjmp    loop
 
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

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

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

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

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

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

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

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

        reti

        .DSEG                          ; das Folgende kommt ins SRAM
OCR_1:  .BYTE   1                      ; 6 Bytes für die OCR Register
OCR_2:  .BYTE   1
OCR_3:  .BYTE   1
OCR_4:  .BYTE   1
OCR_5:  .BYTE   1
OCR_6:  .BYTE   1

Autor: harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://ww1.microchip.com/downloads/en/AppNotes/00654a.pdf

aber in C wäre das ganze mal angebracht

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.