Hallo Commmunity, ich habe mal wieder eine Frage, udn da mir bisher immer gut geholfen werden konnte, hoffe ich auch diesmal auf eure Hilfe: Wie funktioniert das mit der PWM, damit ich eine LED Dimmen kann bei einem ATMEGA168. Ich habe mir schon Applicationsnotes und andere Quellen über Software PWM mit einem ATMEGA durchgelesen, konnte aber kein ansatzweise laufendes Programm erstellen. um das mal zu testen. Nun meine Frage, kann mir wer ein kleines Beispiel für eine Softwarepwm für den ATMEGA 168 zeigen und erklären? Es reicht völlig, wenn in diesem Beispiel nur 1 LED z.B. die led an PORTD PIN3 auf die hälfte gedimmt wird, wenn ich PORTB PIN0 auf 0V ziehe. Vielen Dank
Tobias xxx schrieb: > Nun meine Frage, kann mir wer ein kleines Beispiel für eine Softwarepwm > für den ATMEGA 168 Du kannst ein Programm für den ATmega8 hier aus dem Forum nehmen und mußt nur ein paar Registerbezeichnungen anpassen. Funktionieren tut der ATmega168 sonst sehr ähnlich.
wo finde ich den so einen beispiel-code? finde mich noch nicht so recht zurecht. das Programm sollte auch in c sein, da ich assembler noch fremder bin als c. Danke
Tobias xxx schrieb: > wo finde ich den so einen beispiel-code? Über die Suchfunktion des Forums. Zu PWM finden sich ungefähr 13744 Threads. Hast du da schon mal geguckt?
JA aber irgendwie finde ich nur forenbeiträge. und da ist kein definitiv funktionierender code für mich gerade zu finden aber ich versuche es weiter
Du mußt dir im Datenblatt nur den passenden PWM-Mode aus dem Datenblatt raussuchen und die Register entsprechend setzen. Der Rest läuft dann per Timer und PWM-Hardware des Prozessors selbständig. Zur Änderung des Tastverhältnis muß dann nur z.B. eines der Output Compare Register geändert werden. z.B. Beitrag "Ansteuerung einer RGB LED (PWM)" Es geht natürlich auch per Software: Beitrag "8-fach 12-Bit Soft-PWM LED-Dimmer für mega48"
Hallo, habe jetzt einen Code gefunden und umgeschrieben, womit ich alle meine LED'S Dimmen kann. Der Code war für einen ATMEGA 8 und ich habe ihn schon soweit umgeschrieben, das er auf einem MEGA168 läuft. Meine Frage ist jetzt, wo muss ich eingreifen, bzw. was ändern/löschen, damit die nicht wie es ja zu demo zwecken ist, die ganze zeit dimmen. sondern das ich die LEDS mit einem POTI am Analogeingang PC5 dimmen kann. Der Poti soll dann für Später einen Fototransiostor simulieren. Also die LEDS sollen dauerhaft an sein, udn durch den POTI gedimmt werden können. Wäre klasse, wenn mir wer da helfen könnte.
... schrieb: > Es geht natürlich auch per Software: > Beitrag "8-fach 12-Bit Soft-PWM LED-Dimmer für mega48" Hier geht es doch wenn ich das richtig sehe um eine HArdware PWM anstelle iner Software pwm.
Tobias xxx schrieb: > Hallo, > > habe jetzt einen Code gefunden und umgeschrieben, womit ich alle meine > LED'S Dimmen kann. > Der Code war für einen ATMEGA 8 und ich habe ihn schon soweit > umgeschrieben, das er auf einem MEGA168 läuft. > Meine Frage ist jetzt, wo muss ich eingreifen, bzw. was ändern/löschen, > damit die nicht wie es ja zu demo zwecken ist, die ganze zeit dimmen. > sondern das ich die LEDS mit einem POTI am Analogeingang PC5 dimmen > kann. Der Poti soll dann für Später einen Fototransiostor simulieren. > Also die LEDS sollen dauerhaft an sein, udn durch den POTI gedimmt > werden können. > > Wäre klasse, wenn mir wer da helfen könnte. Hatte leider vergessen, den CODE anzuhängen:
1 | // Software-PWM by PoWl - 25.10.08
|
2 | // webmaster@the-powl.de
|
3 | |
4 | // ATmega168 @ 8Mhz
|
5 | |
6 | #include <avr/io.h> |
7 | #include <avr/interrupt.h> |
8 | #include <util/delay.h> |
9 | #include <stdbool.h> |
10 | |
11 | |
12 | // Sinustabelle für Demo
|
13 | const uint8_t sinetable[] = { |
14 | 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, |
15 | 170, 173, 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, |
16 | 208, 211, 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, |
17 | 237, 238, 240, 241, 243, 244, 245, 246, 248, 249, 250, 250, 251, 252, |
18 | 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 254, 254, |
19 | 254, 253, 253, 252, 251, 250, 250, 249, 248, 246, 245, 244, 243, 241, |
20 | 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220, 218, 215, |
21 | 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, 182, 179, |
22 | 176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137, |
23 | 134, 131, 128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, 93, |
24 | 90, 88, 85, 82, 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, |
25 | 44, 42, 40, 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, |
26 | 12, 11, 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, |
27 | 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, 10, 11, 12, 14, 15, 17, 18, 20, |
28 | 21, 23, 25, 27, 29, 31, 33, 35, 37, 40, 42, 44, 47, 49, 52, 54, 57, |
29 | 59, 62, 65, 67, 70, 73, 76, 79, 82, 85, 88, 90, 93, 97, 100, 103, |
30 | 106, 109, 112, 115, 118, 121, 124 }; |
31 | |
32 | |
33 | |
34 | // -------------------------- 8-Bit PWM --------------------------- //
|
35 | // An - 254 Graustufen - Aus
|
36 | |
37 | #define CHANNELS 12
|
38 | |
39 | uint8_t pwm_mask_PORTC_A[CHANNELS + 1]; |
40 | uint8_t pwm_mask_PORTD_A[CHANNELS + 1]; |
41 | uint8_t pwm_timing_A[CHANNELS + 1]; |
42 | |
43 | uint8_t pwm_mask_PORTC_B[CHANNELS + 1]; |
44 | uint8_t pwm_mask_PORTD_B[CHANNELS + 1]; |
45 | uint8_t pwm_timing_B[CHANNELS + 1]; |
46 | |
47 | uint8_t *ptr_PORTC_main = &pwm_mask_PORTC_A; |
48 | uint8_t *ptr_PORTD_main = &pwm_mask_PORTD_A; |
49 | uint8_t *ptr_timing_main = &pwm_timing_A; |
50 | |
51 | uint8_t *ptr_PORTC_isr = &pwm_mask_PORTC_B; |
52 | uint8_t *ptr_PORTD_isr = &pwm_mask_PORTD_B; |
53 | uint8_t *ptr_timing_isr = &pwm_timing_B; |
54 | |
55 | uint8_t pwm_value[CHANNELS]; |
56 | uint8_t pwm_queue[CHANNELS]; |
57 | |
58 | volatile uint8_t pwm_cycle; |
59 | volatile bool pwm_change; |
60 | |
61 | uint8_t pwm_pin[CHANNELS] = { PC0, PC1, PC2, PC3, PC4, PD0, PD1, PD2, PD3, PD4, PD6, PD7 }; |
62 | |
63 | uint8_t **pwm_port[CHANNELS] = { |
64 | &ptr_PORTC_main, |
65 | &ptr_PORTC_main, |
66 | &ptr_PORTC_main, |
67 | &ptr_PORTC_main, |
68 | &ptr_PORTC_main, |
69 | &ptr_PORTD_main, |
70 | &ptr_PORTD_main, |
71 | &ptr_PORTD_main, |
72 | &ptr_PORTD_main, |
73 | &ptr_PORTD_main, |
74 | &ptr_PORTD_main, |
75 | &ptr_PORTD_main |
76 | };
|
77 | |
78 | |
79 | void pwm_update(void) |
80 | {
|
81 | pwm_change = 0; |
82 | |
83 | // Sortieren mit InsertSort
|
84 | |
85 | for(uint8_t i=1; i<CHANNELS; i++) |
86 | {
|
87 | uint8_t j = i; |
88 | |
89 | while(j && pwm_value[pwm_queue[j - 1]] > pwm_value[pwm_queue[j]]) |
90 | {
|
91 | uint8_t temp = pwm_queue[j - 1]; |
92 | pwm_queue[j - 1] = pwm_queue[j]; |
93 | pwm_queue[j] = temp; |
94 | |
95 | j--; |
96 | }
|
97 | }
|
98 | |
99 | // Maske generieren
|
100 | |
101 | for(uint8_t i=0; i<(CHANNELS + 1); i++) |
102 | {
|
103 | ptr_PORTC_main[i] = 0; |
104 | ptr_PORTD_main[i] = 0; |
105 | ptr_timing_main[i] = 0; |
106 | }
|
107 | |
108 | uint8_t j = 0; |
109 | |
110 | for(uint8_t i=0; i<CHANNELS; i++) |
111 | {
|
112 | // Sonderfall "ganz AUS" ausschließen:
|
113 | // - Pins garnicht erst anschalten
|
114 | // - Pins die vorher "ganz AN" waren müssen trotzdem noch deaktiviert werden, deshalb nur folgendes in der if
|
115 | if(pwm_value[pwm_queue[i]] != 0) |
116 | {
|
117 | (*pwm_port[pwm_queue[i]])[0] |= (1 << pwm_pin[pwm_queue[i]]); |
118 | }
|
119 | |
120 | // Sonderfall "ganz AN" ausschließen:
|
121 | // - Nicht in Timing-Tabelle übernehmen da sonst die Pointer niemals getauscht werden
|
122 | // - Pins die "ganz AN" sind müssen nicht abgeschaltet werden
|
123 | if(pwm_value[pwm_queue[i]] != 255) |
124 | {
|
125 | (*pwm_port[pwm_queue[i]])[j + 1] |= (1 << pwm_pin[pwm_queue[i]]); |
126 | |
127 | ptr_timing_main[j] = pwm_value[pwm_queue[i]]; |
128 | }
|
129 | |
130 | if(pwm_value[pwm_queue[i]] != pwm_value[pwm_queue[i + 1]]) |
131 | {
|
132 | j++; |
133 | }
|
134 | }
|
135 | |
136 | /*
|
137 | // Der ISR etwas Arbeit abnehmen
|
138 | for(uint8_t i=1; i<(CHANNELS + 1); i++)
|
139 | {
|
140 | ptr_PORTC_main[i] = ~ptr_PORTC_main[i];
|
141 | ptr_PORTD_main[i] = ~ptr_PORTD_main[i];
|
142 | }
|
143 | */
|
144 | |
145 | pwm_change = 1; |
146 | }
|
147 | |
148 | |
149 | int main(void) |
150 | {
|
151 | // PWM initialisieren
|
152 | for(uint8_t i=0; i<CHANNELS; i++) |
153 | {
|
154 | pwm_queue[i] = i; |
155 | }
|
156 | |
157 | DDRC = 0b00011111; |
158 | DDRD = 0b11011111; |
159 | DDRB = 0x00; |
160 | |
161 | |
162 | // Timer für PWM
|
163 | OCR1A = 255; |
164 | TIMSK1 = (1 << OCIE1A) | (1 << OCIE1B); |
165 | TCCR1B = (1 << WGM12) | 4; |
166 | |
167 | sei(); |
168 | |
169 | |
170 | uint8_t pos = 0; |
171 | |
172 | while(1) |
173 | {
|
174 | for(uint8_t i=0; i<CHANNELS; i++) |
175 | {
|
176 | pwm_value[i] = sinetable[(uint8_t) (pos + i * 20)]; |
177 | }
|
178 | |
179 | pwm_update(); |
180 | pos++; |
181 | |
182 | _delay_ms(5); |
183 | }
|
184 | }
|
185 | |
186 | |
187 | |
188 | ISR(TIMER1_COMPA_vect) |
189 | {
|
190 | pwm_cycle = 0; |
191 | |
192 | PORTC |= ptr_PORTC_isr[0]; |
193 | PORTD |= ptr_PORTD_isr[0]; |
194 | |
195 | OCR1B = ptr_timing_isr[0]; |
196 | }
|
197 | |
198 | |
199 | |
200 | ISR(TIMER1_COMPB_vect) |
201 | {
|
202 | pwm_cycle++; |
203 | |
204 | PORTC &= ~ptr_PORTC_isr[pwm_cycle]; |
205 | PORTD &= ~ptr_PORTD_isr[pwm_cycle]; |
206 | |
207 | if(ptr_timing_isr[pwm_cycle] != 0) |
208 | {
|
209 | OCR1B = ptr_timing_isr[pwm_cycle]; |
210 | }
|
211 | else if(pwm_change) |
212 | {
|
213 | pwm_change = 0; |
214 | |
215 | uint8_t *temp_ptr; |
216 | |
217 | temp_ptr = ptr_PORTC_main; |
218 | ptr_PORTC_main = ptr_PORTC_isr; |
219 | ptr_PORTC_isr = temp_ptr; |
220 | |
221 | temp_ptr = ptr_PORTD_main; |
222 | ptr_PORTD_main = ptr_PORTD_isr; |
223 | ptr_PORTD_isr = temp_ptr; |
224 | |
225 | temp_ptr = ptr_timing_main; |
226 | ptr_timing_main = ptr_timing_isr; |
227 | ptr_timing_isr = temp_ptr; |
228 | }
|
229 | }
|
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.