Forum: Mikrocontroller und Digitale Elektronik SOFT PWM Pinversatz


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Christian (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
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
von Axel S. (a-za-z0-9)


Bewertung
0 lesenswert
nicht lesenswert
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"?

von Christian (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.