Hallo allerseits, Ich hab mich in letzter Zeit mal wieder ein bisschen mit Software PWM beschäftigt und möchte nun eine 3-Kanal PWM zum Dimmen einer (oder mehrerer ;-) ) RGB-LED(s) realisieren. Ich nutze einen Atmel Atmega8. Mein bisheriger Code dimmt eine LED logarithmisch in einer festgelegten Geschwindigkeit zwischen einem MIN und einem MAX Wert rauf und runter, ist aber schon gut auf die 3 LEDs erweiterbar.
1 | .include "m8def.inc" |
2 | |
3 | .def counter = r16 ;PWM-Counter |
4 | .def temp = r17 ;temp-Register |
5 | .def port = r18 ;Port-Byte |
6 | |
7 | .def led1 = r19 ;Helligkeitswert 1 mit Gammakorrektur |
8 | .def led2 = r20 ;Helligkeitswert 2 mit Gammakorrektur |
9 | .def led3 = r21 ;Helligkeitswert 3 mit Gammakorrektur |
10 | |
11 | .def ledpointer1 = r22 ;Helligkeitswert 1 ohne Gammakorrektur |
12 | .def ledpointer2 = r23 ;Helligkeitswert 2 ohne Gammakorrektur |
13 | .def ledpointer3 = r24 ;Helligkeitswert 3 ohne Gammakorrektur |
14 | |
15 | .def dir = r25 ;Richtungs-Flagregister |
16 | .def speed1 = r26 ;Counter 1 für Geschwindiggkeit |
17 | |
18 | .equ CMAX = 255 ;PWM-Counter Maximalwert |
19 | |
20 | .equ MIN1 = 50 ;Minimalwert 1 |
21 | .equ MAX1 = 255 ;Maximalwert 1 |
22 | |
23 | .cseg |
24 | .org $0000 |
25 | rjmp reset ; Reset Handler |
26 | reti ; IRQ0 |
27 | reti ; IRQ1 |
28 | reti ; Timer/Counter2 Compare Match |
29 | reti ; Timer/Counter2 Overflow |
30 | reti ; Timer/Counter1 Capture Event |
31 | reti ; Timer/Counter1 Compare Match A |
32 | reti ; Timer/Counter1 Compare Match B |
33 | reti ; Timer/Counter1 Overflow |
34 | rjmp calc_leds ; Timer/Counter0 Overflow |
35 | reti ; Serial Transfer Complete |
36 | reti ; USART, Rx Complete |
37 | reti ; USART, Data Register Empty |
38 | reti ; USART, Tx Complete |
39 | reti ; ADC Conversion Complete |
40 | reti ; EEPROM Ready |
41 | reti ; Analog Comparator |
42 | reti ; Two-Wire Serial Interface |
43 | reti ; Store Program Memory Ready |
44 | |
45 | reset: |
46 | ldi temp, LOW(RAMEND) ;Init Stackpointer |
47 | out SPL, temp |
48 | ldi temp, HIGH(RAMEND) |
49 | out SPH, temp |
50 | |
51 | ldi ZL, LOW(pwm_seq*2) ;Init Z-Pointer |
52 | ldi ZH, HIGH(pwm_seq*2) |
53 | |
54 | ldi temp, 0xFF ;Config Port D |
55 | out DDRD, temp |
56 | out PORTD, temp ;LEDs aus |
57 | |
58 | ldi led2, 0 |
59 | ldi led3, 0 |
60 | |
61 | ldi temp, 1<<TOIE0 ;Config Timer/Counter0 |
62 | out TIMSK, temp |
63 | ldi temp, 0x00 |
64 | out TCNT0, temp |
65 | ldi temp, 0b00000001 ;ohne Prescaler |
66 | out TCCR0, temp |
67 | |
68 | sei |
69 | |
70 | clr speed1 |
71 | clr ledpointer1 |
72 | clr dir |
73 | |
74 | main: |
75 | brtc main ;Idle-Schleife, solange PWM-Zyklus noch nicht fertig |
76 | |
77 | inc speed1 |
78 | cpi speed1,3 |
79 | brne fade_end |
80 | |
81 | cpi dir,255 |
82 | breq backward |
83 | |
84 | forward: |
85 | inc ledpointer1 |
86 | |
87 | cpi ledpointer1,MAX1 |
88 | brne next1 |
89 | |
90 | com dir |
91 | |
92 | next1: |
93 | clr speed1 |
94 | |
95 | rjmp fade_end |
96 | |
97 | backward: |
98 | dec ledpointer1 |
99 | |
100 | cpi ledpointer1,MIN1 |
101 | brne next2 |
102 | |
103 | com dir |
104 | |
105 | next2: |
106 | clr speed1 |
107 | |
108 | fade_end: |
109 | clt |
110 | |
111 | rjmp main |
112 | |
113 | calc_leds: |
114 | ldi ZL, LOW(pwm_seq*2) ;Gammakorrektur |
115 | ldi ZH, HIGH(pwm_seq*2) |
116 | ldi temp,0 |
117 | |
118 | add ZL,ledpointer1 |
119 | adc ZH,temp |
120 | |
121 | lpm led1,Z |
122 | |
123 | |
124 | check_led1: |
125 | ldi port, 0b11111000 ;Alle LEDs an |
126 | |
127 | cp counter, led1 ;LED1 vergleichen |
128 | brlo check_led2 |
129 | |
130 | ori port, 0b00000001 ;wenn led1>=counter: LED1 aus |
131 | |
132 | check_led2: |
133 | cp counter, led2 ;LED2 vergleichen |
134 | brlo check_led3 |
135 | |
136 | ori port, 0b00000010 ;wenn led2>=counter: LED2 aus |
137 | |
138 | check_led3: |
139 | cp counter, led3 ;LED3 vergleichen |
140 | brlo check_end |
141 | |
142 | ori port, 0b00000100 ;wenn led3>=counter: LED3 aus |
143 | |
144 | check_end: |
145 | out PORTD, port ;Portausgabe |
146 | |
147 | cpi counter, CMAX ;Maximalwert erreicht? |
148 | breq cycleReset ;ja: PWM-Zyklus zu Ende |
149 | inc counter ;nein: counter+1 |
150 | |
151 | reti |
152 | |
153 | cycleReset: |
154 | clr counter ;counter = 0 |
155 | |
156 | set ;T-Flag im SREG setzen, PWM-Zyklus fertig |
157 | |
158 | reti |
159 | |
160 | pwm_seq: ;logarithmische Helligkeitswerte für Gammakorrektur |
161 | .db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,9,9,9,9,10,10,10,10,10,11,11,11,11,12,12,12,13,13,13,13,14,14,14,15,15,15,15,16,16,16,17,17,17,18,18,18,19,19,20,20,20,21,21,22,22,22,23,23,24,24,25,25,26,26,26,27,27,28,28,29,30,30,31,31,32,32,33,33,34,35,35,36,37,37,38,38,39,40,41,41,42,43,43,44,45,46,46,47,48,49,50,51,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,71,72,73,74,75,77,78,79,80,82,83,84,86,87,89,90,92,93,95,96,98,99,101,102,104,106,107,109,111,113,115,116,118,120,122,124,126,128,130,132,134,137,139,141,143,145,148,150,153,155,157,160,162,165,168,170,173,176,179,181,184,187,190,193,196,199,202,206,209,212,216,219,222,226,229,233,237,241,244,248,252,255 |
Jetzt würde ich gern eine Art Programmablauf im Programmspeicher speichern, wo die nächsten Helligkeitswerte der einzelnen LEDs (noch ohne logarithmischen Verlauf, sprich "ledpointerX" im Code), sprich die nächste Farbe und die Fade-Geschwindigkeiten gespeichert sind. Dieser Programmablauf soll dann zyklisch durchlaufen werden. Also z.B. R1,G1,B1,Zeit1,R2,G2,B2,Zeit2,... Das Problem besteht jetzt darin, alle 3 Helligkeitswerte in der vorgegebenen Zeit von drei unterschiedlichen Anfangswerten zu drei unterschiedlichen Endwerten zu dimmen, also die Farbe zu wechseln. Vielleicht hat sowas schonmal jemand gemacht (bestimmt) und kann mir weiterhelfen. Vielen Dank! Grüße, Christoph