Forum: Mikrocontroller und Digitale Elektronik LED Lauflicht aber mit 8 Kanal PWM


von Dennis Brücke (Gast)


Lesenswert?

Hi @all,

irgendwie hänge ich grad und weis nicht wie man den Ablauf machen
sollte... Habe hier einen ATMega8 (wie immer) mit 8 Kanal PWM mit 100
Schritten je LED.

Jeder Kanal hat sein eigenes Register (brauch ich auch nicht umstricken
ist ok so) Wie könnte ich vom Ablauf her jetzt z.B. ein Lauflicht
machen... damit meine ich natürlich eine Sinnvollere Variante als in
meiner Main Routine LED1 auf 100 setzen kurz warten abschalten und
nächste LED auf 100 setzen. Wenn ich dann noch nen 2. Lichteffekt
einbauen will ist es schon nicht mehr elegant. Irgendeiner eine Idee
wie ich das z.b. mit Tabellen realisieren könnte ? So müsste es doch
möglich sein die verschiedensten effekte einzubauen.

Gruß Dennis

von TobyTetzi (Gast)


Lesenswert?

Hallo,

warum dinnst du nicht die erste LED ab, und zeitgleich beginnst du die
zweite hoch zu dimmen.
Bei wert 100 der zweiten wieder abdimmen, und die dritte aufdimmen,
usw.

Hast Du vergessen, deinen ode anzuhängen?
Womit Programmierst Du denn, in ASM oder in C oder Bascom ?

Gruß Toby

von Dennis Brücke (Gast)


Lesenswert?

Ach Mensch,

ja patsch Also Programmieren in ASM. Code brauch ich derzeitig keinen
Anzuhängen weil es eigendlich eine von vielen Artem ist Software PWM
über Timer0 in Overflowmodus. (auch in nem anderen Thread schon
besprochen) Mir geht es jetzt eher einfach darum eine sinnvolle methode
zu finden die einzelnen PWM´s jetzt so zu steuern das ich verschiedene
Effekte machen kann, wie du z.b. geschrieben hast. Es geht mehr um die
Methode als um irgendwelchen Code von euch zu erhalten. Will ja
weiterhin was lernen dabei ;)

Sicher könnte ich jetzt einfach das ganze in einer mainloop laufen
lassen:
PWM1 setzen
5ms Warten
PWM1 Löschen
5ms Warten
PWM2 setzen....

usw.

Das möcht ich allerdings so nicht handhaben, da ich sonst in der
effektauswahl eingeschränkt bin. Also müsste was universelleres her...

vieleicht hat ja einer eine Idee

Gruß Dennis

von Hannes L. (hannes)


Lesenswert?

Hallo Dennis... - Was macht der Müllberg? Ist er nun endlich gelöscht?

Denkanstöße:

- Im Prinzip könntest du jeden PWM-Kanal mit einem zusätzlichen Flag
  ausstatten.
- In der PWM-Routine prüfst du diese Flags und erhöhst die
  Helligkeiten der Kanäle, deren Flags gesetzt sind und verringerst
  die Helligkeit der Kanäle, deren Flags gelöscht sind (falls sie
  noch nicht auf 0 sind).
- Wird der Maxwert erreicht, so kann ein weiteres Betriebsartenflag
  entscheiden, ob der Maxwert beibehalten wird, oder ob das Flag
  gelöscht wird (und dadurch wieder abgedimmt wird).
- In eine Tabelle legst du Bitmuster, die du zyklisch (anderer Timer
  oder weitere Zählvariable, vom PWM-Int erhöht/vermindert) ausliest
  und damit deine Flags fütterst.
- Wird dabei ein Flag gesetzt, so dimmt der Kanal langsam hoch, wird
  ein Flag gelöscht, so dimmt er wieder runter. Bzw. in der anderen
  Betriebsart (Betriebsartenflag) dimmt er hoch und gleich wieder
  runter.
- Wenn du die Tabelle schneller ausliest, als ein Hoch-Runterdimmen
  dauert, dann kannst du weitere Effekte erreichen (mehrfaches Auf-
  Abschwellen).
- Sollte das Aufdimmen/Abdimmen zu schnell gehen, dann hilft
  vielleicht ein weiteres Register (RAM-Zelle) als Vorteiler.
- Wenn die Tabelle 2 Bytes pro Eintrag erhält, kann das erste die
  Flags enthalten, das zweite den Timer-Reload für den Tabellentimer.
  Ein vereinbarter Wert (0?) kennzeichnet das Ende der Tabelle, worauf
  wieder mit dem Anfang begonnen wird.

Ich hoffe, ich habe deine Ideenquelle wieder freigespült... ;-)

Bit- & Bytebruch...
...HanneS... (vom westlichen Ende der B246)

von Dennis Brücke (Gast)


Angehängte Dateien:

Lesenswert?

Hi ...HanneS...,

Müllberg ist gelöscht ;) Täter habe Sie auch noch und der Besitzer hat
viel ärger an hals...

Ok Deiner Idee konnte ich leider nicht ganz folgen habe jetzt fast 1
Jahr mit AVR & ASM nichts mehr gemacht und musste einfach auch
feststellen, das man verdammt schnell raus kommt aus der Materie wenn
man es wirklich nur als Hobby macht.

Hab im Anhang mal die ASM Datei von mir angehängt
alle Kommentare stimmen nicht mehr, da ich nicht jedesmal wenn ich
spiele alles neu schreibe.

Gruß Dennis

von Andreas K. (andi_k)


Lesenswert?

Na ja, eigentlich immer noch etwas Müll ;-)

Das geht wesentlich einfacher.
Z. B. das mit der Null-Prüfung war in dem alten Thread völliger
Quatsch.
Desweiteren brauchst Du die Bits im PWM-Ausgabe-Register nicht einzeln
zu löschen, da tut es vorab ein einziges clr PWMAusgabe1 auch.
Ansonsten würde ich noch SREG nicht in ein anderes Register (Save_SREG)
einlesen sondern auf den Stack schieben.
Da Du ja mehrere Interrupts nutzen möchtest und es irgenwann mal sein
kann, das ein nicht so zeitkritischer Interrupt Interrupts erlauben muß
(SEI in der "lahmen" ISR) käme es dann zu einem Konflikt.

Timer0_Overflow:
  push temp1  ;Sicherung von Registern im Interrupt
  in Temp1, SREG  ;StatusRegister
  push temp1  ;auf den Stack sichern.
  push temp2
  push temp3
  push xl
  push xh

; SoftPWM Anfang
  dec PWMZ  ;PWM-Counter minus 1.
  brne label1     ;Ist PWM-Counter bei 0?
  ldi PWMZ, PWM_Max   ;Wenn, dann auf Höchstwert setzen.

label1:
  clr PWMAusgabe1  ;Alle PWM-Kanäle aus.

  cp PWM_1, PWMZ   ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label2     ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm1_p
label2:
  cp PWM_2, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label3  ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm2_p
label3:
  cp PWM_3, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label4  ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm3_p
label4:
  cp PWM_4, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label5  ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm4_p
label5:
  cp PWM_5, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label6  ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm5_p
label6:
  cp PWM_6, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label7  ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm6_p
label7:
  cp PWM_7, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label8  ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm7_p
label8:
  cp PWM_7, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  brcs label17  ;Wenn nicht, dann Pin B0 setzen.
  sbr PWMAusgabe1, pwm8_p
label17:
  out pwm_port, PWMAusgabe1

; SoftPWM Ende

  ldi temp1, T0PRESET
  out TCNT0, temp1

  pop xh
  pop xl
  pop temp3
  pop temp2
  pop temp1  ;SREG vom Stack zurückholen
  out SREG, Temp1  ;und wiederherstellen.
  pop temp1
  reti

Wenn Deine LED´s low-Akive sein sollten benutzt Du statt "clr
PWMAusgabe1" "ser PWMAusgabe1" und machst statt "sbr" ein "cbr"
bei den PWM-Vergleichen.

Aber es geht noch kürzer:

Timer0_Overflow:
  push temp1  ;Sicherung von Registern im Interrupt
  in Temp1, SREG  ;StatusRegister
  push temp1  ;auf den Stack sichern.
  push temp2
  push temp3
  push xl
  push xh

; SoftPWM Anfang
  dec PWMZ  ;PWM-Counter minus 1.
  brne label1     ;Ist PWM-Counter bei 0?
  ldi PWMZ, PWM_Max   ;Wenn, dann auf Höchstwert setzen.

label1:
  clr PWMAusgabe1  ;Alle PWM-Kanäle aus.

  cp PWM_1, PWMZ   ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label2:
  cp PWM_2, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label3:
  cp PWM_3, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label4:
  cp PWM_4, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label5:
  cp PWM_5, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label6:
  cp PWM_6, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label7:
  cp PWM_7, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label8:
  cp PWM_7, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
label17:
  out pwm_port, PWMAusgabe1

; SoftPWM Ende

  ldi temp1, T0PRESET
  out TCNT0, temp1

  pop xh
  pop xl
  pop temp3
  pop temp2
  pop temp1  ;SREG vom Stack zurückholen
  out SREG, Temp1  ;und wiederherstellen.
  pop temp1
  reti

Da wird das Ergabnis-Bit (Carry-Bit) nach einem CP einfach nur in das
Register PWMAusgabe1 für jeden Kanal hineingaschoben (ror
PWMAusgabe1).
Sollte es auch wieder low-Aktiv sein genügt vor dem Output ein
einfaches "com PWMAusgabe1".

MfG
Andi

von Andreas K. (andi_k)


Lesenswert?

Ach ja, die ganzen Labels kann man sich in der "Kurzversion" natürlich
sparen:

Timer0_Overflow:
  push temp1  ;Sicherung von Registern im Interrupt
  in Temp1, SREG  ;StatusRegister
  push temp1  ;auf den Stack sichern.
  push temp2
  push temp3
  push xl
  push xh

; SoftPWM Anfang
  dec PWMZ  ;PWM-Counter minus 1.
  brne label1     ;Ist PWM-Counter bei 0?
  ldi PWMZ, PWM_Max   ;Wenn, dann auf Höchstwert setzen.

label1:
  clr PWMAusgabe1  ;Alle PWM-Kanäle aus.

  cp PWM_1, PWMZ   ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
  cp PWM_2, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
  cp PWM_3, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
  cp PWM_4, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
  cp PWM_5, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
  cp PWM_6, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
  cp PWM_7, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.
  cp PWM_7, PWMZ  ;Ist PWM-Kanal 1 >= PWM-Max?
  ror PWMAusgabe1  ;Wenn nicht, dann Pin B0 setzen.

  out pwm_port, PWMAusgabe1

; SoftPWM Ende

  ldi temp1, T0PRESET
  out TCNT0, temp1

  pop xh
  pop xl
  pop temp3
  pop temp2
  pop temp1  ;SREG vom Stack zurückholen
  out SREG, Temp1  ;und wiederherstellen.
  pop temp1
  reti

MfG
Andi

von Ulrich (Gast)


Lesenswert?

auf die idee bin ich noch gar nicht gekommen mit dem cp vewrgleich das
carry-bit zu setzen und dann zu schieebn. Cool wird mir sicherlich ein
paar Zeilen Code sparen. Das ist ein Guter anlass um meine Software-PWM
Rotine umzuwerfen...

von Dennis Brücke (Gast)


Lesenswert?

@Andy,

natürlich auch in diesem Thread nochmal ein Dankeschön funkt. wirklich
wunderbar und spart zeit und code.

Gruß Dennis

von Uwe (Gast)


Lesenswert?

Hi!
Mal so am Rande, die Vergleiche zb.
"cp PWM_1, PWMZ   ;Ist PWM-Kanal 1 >= PWM-Max?"
sind nicht ganz sauber, weil 100% PWM nicht erreichbar sind.
Bsp.:
PWM_1=255 ;sollen 100% sein
PWMZ =255 ;=PWM_Max
Der Vergleich bringt jetzt kein C-Flag und der Kanal wird für 1 Count
abgeschaltet. Das ist zwar nicht sehr störend, aber wer es nachprüft
wündert sich eventuell über einen Impuls wo keiner sein soll.

Viel Erfolg, Uwe

von Andreas K. (andi_k)


Lesenswert?

Dann setz den Vergleich andersrum:

 cp PWMZ, PWM_1

und hinterher einfach mit dem Befhehl

 com PWMAusgabe1       oder so

das Output-Register invertieren bzw. richtig stellen.

MfG
Andi

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.