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
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
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
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)
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
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
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
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...
@Andy, natürlich auch in diesem Thread nochmal ein Dankeschön funkt. wirklich wunderbar und spart zeit und code. Gruß Dennis
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.