Hallo zusammen, ich habe den Beispielcode (Version 3 - Intelligenter Ansatz) zur Software PWM hier aus dem Forum verwendet. Die PWM läuft auch gut, jedoch besteht das Problem wenn ich die verschiedenen Pins ansteuern will, das die Pins immer um 1 versetzt sind. Folgende Pins werden angesteuert wenn ich natürlich anstatt den PINx einen Wert angebe: uint16_t t1[8]={PIN1, PIN3, PIN5, PIN7, ?,?,?,?}; Ich habe den Code durchforstet kann jedoch keinen Fehler feststellen. Hoffe es kann mir jemand helfen. Vielen Dank vorab! Gruß Christian
:
Verschoben durch Moderator
Stell dir einfach mal vor, du wärest wir. Du wüßtest nichts über dein Projekt als das, was da in deinem Post steht. Wüßtest du dann überhaupt, worum es geht? Was ist "Software PWM hier aus dem Forum"? Und was zum Geier bedeutet "die Pins immer um 1 versetzt"?
Guten Morgen, danke für den Hinweis. Bitte um Entschulidgung das ich nicht ausreichend Info Material geliefert habe. Ich meine dieses Tutorial "Soft-PWM": http://www.mikrocontroller.net/articles/Soft-PWM Hier direkt mal der 1:1 Code aus dem Beitrag den ich verwendet habe:
1 | /*
|
2 | Eine 8-kanalige PWM mit intelligentem Lösungsansatz
|
3 | |
4 | ATmega32 @ 8 MHz
|
5 | |
6 | */
|
7 | |
8 | // Defines an den Controller und die Anwendung anpassen
|
9 | |
10 | #define F_CPU 8000000L // Systemtakt in Hz
|
11 | #define F_PWM 100L // PWM-Frequenz in Hz
|
12 | #define PWM_PRESCALER 8 // Vorteiler für den Timer
|
13 | #define PWM_STEPS 256 // PWM-Schritte pro Zyklus(1..256)
|
14 | #define PWM_PORT PORTB // Port für PWM
|
15 | #define PWM_DDR DDRB // Datenrichtungsregister für PWM
|
16 | #define PWM_CHANNELS 8 // Anzahl der PWM-Kanäle
|
17 | |
18 | // ab hier nichts ändern, wird alles berechnet
|
19 | |
20 | #define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
|
21 | //#define T_PWM 1 //TEST
|
22 | |
23 | #if ((T_PWM*PWM_PRESCALER)<(111+5))
|
24 | #error T_PWM zu klein, F_CPU muss vergrössert werden oder F_PWM oder PWM_STEPS verkleinert werden
|
25 | #endif
|
26 | |
27 | #if ((T_PWM*PWM_STEPS)>65535)
|
28 | #error Periodendauer der PWM zu gross! F_PWM oder PWM_PRESCALER erhöhen.
|
29 | #endif
|
30 | // includes
|
31 | |
32 | #include <stdint.h> |
33 | #include <string.h> |
34 | #include <avr/io.h> |
35 | #include <avr/interrupt.h> |
36 | |
37 | // globale Variablen
|
38 | |
39 | uint16_t pwm_timing[PWM_CHANNELS+1]; // Zeitdifferenzen der PWM Werte |
40 | uint16_t pwm_timing_tmp[PWM_CHANNELS+1]; |
41 | |
42 | uint8_t pwm_mask[PWM_CHANNELS+1]; // Bitmaske für PWM Bits, welche gelöscht werden sollen |
43 | uint8_t pwm_mask_tmp[PWM_CHANNELS+1]; // ändern uint16_t oder uint32_t für mehr Kanäle |
44 | |
45 | uint8_t pwm_setting[PWM_CHANNELS]; // Einstellungen für die einzelnen PWM-Kanäle |
46 | uint8_t pwm_setting_tmp[PWM_CHANNELS+1]; // Einstellungen der PWM Werte, sortiert |
47 | // ändern auf uint16_t für mehr als 8 Bit Auflösung
|
48 | |
49 | volatile uint8_t pwm_cnt_max=1; // Zählergrenze, Initialisierung mit 1 ist wichtig! |
50 | volatile uint8_t pwm_sync; // Update jetzt möglich |
51 | |
52 | // Pointer für wechselseitigen Datenzugriff
|
53 | |
54 | uint16_t *isr_ptr_time = pwm_timing; |
55 | uint16_t *main_ptr_time = pwm_timing_tmp; |
56 | |
57 | uint8_t *isr_ptr_mask = pwm_mask; // Bitmasken fuer PWM-Kanäle |
58 | uint8_t *main_ptr_mask = pwm_mask_tmp; // ändern uint16_t oder uint32_t für mehr Kanäle |
59 | |
60 | // Zeiger austauschen
|
61 | // das muss in einem Unterprogramm erfolgen,
|
62 | // um eine Zwischenspeicherung durch den Compiler zu verhindern
|
63 | |
64 | void tausche_zeiger(void) { |
65 | uint16_t *tmp_ptr16; |
66 | uint8_t *tmp_ptr8; // ändern uint16_t oder uint32_t für mehr Kanäle |
67 | |
68 | tmp_ptr16 = isr_ptr_time; |
69 | isr_ptr_time = main_ptr_time; |
70 | main_ptr_time = tmp_ptr16; |
71 | tmp_ptr8 = isr_ptr_mask; |
72 | isr_ptr_mask = main_ptr_mask; |
73 | main_ptr_mask = tmp_ptr8; |
74 | }
|
75 | |
76 | // PWM Update, berechnet aus den PWM Einstellungen
|
77 | // die neuen Werte für die Interruptroutine
|
78 | |
79 | void pwm_update(void) { |
80 | |
81 | uint8_t i, j, k; |
82 | uint8_t m1, m2, tmp_mask; // ändern uint16_t oder uint32_t für mehr Kanäle |
83 | uint8_t min, tmp_set; // ändern auf uint16_t für mehr als 8 Bit Auflösung |
84 | |
85 | // PWM Maske für Start berechnen
|
86 | // gleichzeitig die Bitmasken generieren und PWM Werte kopieren
|
87 | |
88 | m1 = 1; |
89 | m2 = 0; |
90 | for(i=1; i<=(PWM_CHANNELS); i++) { |
91 | main_ptr_mask[i]=~m1; // Maske zum Löschen der PWM Ausgänge |
92 | pwm_setting_tmp[i] = pwm_setting[i-1]; |
93 | if (pwm_setting_tmp[i]!=0) m2 |= m1; // Maske zum setzen der IOs am PWM Start |
94 | m1 <<= 1; |
95 | }
|
96 | main_ptr_mask[0]=m2; // PWM Start Daten |
97 | |
98 | // PWM settings sortieren; Einfügesortieren
|
99 | |
100 | for(i=1; i<=PWM_CHANNELS; i++) { |
101 | min=PWM_STEPS-1; |
102 | k=i; |
103 | for(j=i; j<=PWM_CHANNELS; j++) { |
104 | if (pwm_setting_tmp[j]<min) { |
105 | k=j; // Index und PWM-setting merken |
106 | min = pwm_setting_tmp[j]; |
107 | }
|
108 | }
|
109 | if (k!=i) { |
110 | // ermitteltes Minimum mit aktueller Sortiertstelle tauschen
|
111 | tmp_set = pwm_setting_tmp[k]; |
112 | pwm_setting_tmp[k] = pwm_setting_tmp[i]; |
113 | pwm_setting_tmp[i] = tmp_set; |
114 | tmp_mask = main_ptr_mask[k]; |
115 | main_ptr_mask[k] = main_ptr_mask[i]; |
116 | main_ptr_mask[i] = tmp_mask; |
117 | }
|
118 | }
|
119 | |
120 | // Gleiche PWM-Werte vereinigen, ebenso den PWM-Wert 0 löschen falls vorhanden
|
121 | |
122 | k=PWM_CHANNELS; // PWM_CHANNELS Datensätze |
123 | i=1; // Startindex |
124 | |
125 | while(k>i) { |
126 | while ( ((pwm_setting_tmp[i]==pwm_setting_tmp[i+1]) || (pwm_setting_tmp[i]==0)) && (k>i) ) { |
127 | |
128 | // aufeinanderfolgende Werte sind gleich und können vereinigt werden
|
129 | // oder PWM Wert ist Null
|
130 | if (pwm_setting_tmp[i]!=0) |
131 | main_ptr_mask[i+1] &= main_ptr_mask[i]; // Masken vereinigen |
132 | |
133 | // Datensatz entfernen,
|
134 | // Nachfolger alle eine Stufe hochschieben
|
135 | for(j=i; j<k; j++) { |
136 | pwm_setting_tmp[j] = pwm_setting_tmp[j+1]; |
137 | main_ptr_mask[j] = main_ptr_mask[j+1]; |
138 | }
|
139 | k--; |
140 | }
|
141 | i++; |
142 | }
|
143 | |
144 | // letzten Datensatz extra behandeln
|
145 | // Vergleich mit dem Nachfolger nicht möglich, nur löschen
|
146 | // gilt nur im Sonderfall, wenn alle Kanäle 0 sind
|
147 | if (pwm_setting_tmp[i]==0) k--; |
148 | |
149 | // Zeitdifferenzen berechnen
|
150 | |
151 | if (k==0) { // Sonderfall, wenn alle Kanäle 0 sind |
152 | main_ptr_time[0]=(uint16_t)T_PWM*PWM_STEPS/2; |
153 | main_ptr_time[1]=(uint16_t)T_PWM*PWM_STEPS/2; |
154 | k=1; |
155 | }
|
156 | else { |
157 | i=k; |
158 | main_ptr_time[i]=(uint16_t)T_PWM*(PWM_STEPS-pwm_setting_tmp[i]); |
159 | tmp_set=pwm_setting_tmp[i]; |
160 | i--; |
161 | for (; i>0; i--) { |
162 | main_ptr_time[i]=(uint16_t)T_PWM*(tmp_set-pwm_setting_tmp[i]); |
163 | tmp_set=pwm_setting_tmp[i]; |
164 | }
|
165 | main_ptr_time[0]=(uint16_t)T_PWM*tmp_set; |
166 | }
|
167 | |
168 | // auf Sync warten
|
169 | |
170 | pwm_sync=0; // Sync wird im Interrupt gesetzt |
171 | while(pwm_sync==0); |
172 | |
173 | // Zeiger tauschen
|
174 | cli(); |
175 | tausche_zeiger(); |
176 | pwm_cnt_max = k; |
177 | sei(); |
178 | }
|
179 | |
180 | // Timer 1 Output COMPARE A Interrupt
|
181 | |
182 | ISR(TIMER1_COMPA_vect) { |
183 | static uint8_t pwm_cnt; // ändern auf uint16_t für mehr als 8 Bit Auflösung |
184 | uint8_t tmp; // ändern uint16_t oder uint32_t für mehr Kanäle |
185 | |
186 | OCR1A += isr_ptr_time[pwm_cnt]; |
187 | tmp = isr_ptr_mask[pwm_cnt]; |
188 | |
189 | if (pwm_cnt == 0) { |
190 | PWM_PORT = tmp; // Ports setzen zu Begin der PWM |
191 | // zusätzliche PWM-Ports hier setzen
|
192 | pwm_cnt++; |
193 | }
|
194 | else { |
195 | PWM_PORT &= tmp; // Ports löschen |
196 | // zusätzliche PWM-Ports hier setzen
|
197 | if (pwm_cnt == pwm_cnt_max) { |
198 | pwm_sync = 1; // Update jetzt möglich |
199 | pwm_cnt = 0; |
200 | }
|
201 | else pwm_cnt++; |
202 | }
|
203 | }
|
204 | |
205 | int main(void) { |
206 | |
207 | // PWM Port einstellen
|
208 | |
209 | PWM_DDR = 0xFF; // Port als Ausgang |
210 | // zusätzliche PWM-Ports hier setzen
|
211 | |
212 | // Timer 1 OCRA1, als variablen Timer nutzen
|
213 | |
214 | TCCR1B = 2; // Timer läuft mit Prescaler 8 |
215 | TIMSK |= (1<<OCIE1A); // Interrupt freischalten |
216 | |
217 | sei(); // Interrupts global einschalten |
218 | |
219 | |
220 | /******************************************************************/
|
221 | // nur zum testen, in der Anwendung entfernen
|
222 | /*
|
223 | // Test values
|
224 | volatile uint8_t tmp;
|
225 | const uint8_t t1[8]={255, 40, 3, 17, 150, 99, 5, 9};
|
226 | const uint8_t t2[8]={27, 40, 3, 0, 150, 99, 5, 9};
|
227 | const uint8_t t3[8]={27, 40, 3, 17, 3, 99, 3, 0};
|
228 | const uint8_t t4[8]={0, 0, 0, 0, 0, 0, 0, 0};
|
229 | const uint8_t t5[8]={9, 1, 1, 1, 1, 1, 1, 1};
|
230 | const uint8_t t6[8]={33, 33, 33, 33, 33, 33, 33, 33};
|
231 | const uint8_t t7[8]={0, 0, 0, 0, 0, 0, 0, 88};
|
232 | |
233 | |
234 | // Messung der Interruptdauer
|
235 | tmp =1;
|
236 | tmp =2;
|
237 | tmp =3;
|
238 | |
239 | // Debug
|
240 | |
241 | memcpy(pwm_setting, t1, 8);
|
242 | pwm_update();
|
243 | |
244 | memcpy(pwm_setting, t2, 8);
|
245 | pwm_update();
|
246 | |
247 | memcpy(pwm_setting, t3, 8);
|
248 | pwm_update();
|
249 | |
250 | memcpy(pwm_setting, t4, 8);
|
251 | pwm_update();
|
252 | |
253 | memcpy(pwm_setting, t5, 8);
|
254 | pwm_update();
|
255 |
|
256 | memcpy(pwm_setting, t6, 8);
|
257 | pwm_update();
|
258 |
|
259 | memcpy(pwm_setting, t7, 8);
|
260 | pwm_update();
|
261 | */
|
262 | /******************************************************************/
|
263 | |
264 | while(1); |
265 | return 0; |
266 | }
|
Ich verwende bei mir 8Kanäle PortB. Das Problem das auftritt ist das mit dem Aufruf:
1 | uint8_t t1[8]={255, 40, 3, 17, 150, 99, 5, 9}; |
nicht PB0 - PB7 angesprochen wird sondern nur PB0,PB2,PB4,PB6 und zwar mit diesen Werten:
1 | uint8_t t1[8]={255, 40, 3, 17, |
der Rest:
1 | 150, 99, 5, 9}; |
wirkt sich auf keinen Pin aus. Mit Versatz von einem Pin meine ich, das PB1, PB3, PB5 und PB7 nicht angesprochen werden. Vielen Dank vorab! Gruß Christian
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.