SOFT PWM Pinversatz

Gast #4760261
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
Gast #4760445
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren