Forum: Gesperrte Threads Problem mit Soft-PWM ATtiny2313


von bubi (Gast)


Lesenswert?

Hallo,

ich versuchem mit einem attiny 2313 4 Konstantstromquellen zu steuern.
Die Konstantstromquellen haben einen PWM Eingang der von 0 bis 2.5V
steuerba ist. Dazu werwende ich das Beispiel aus der Wiki
Titelhttp://www.mikrocontroller.net/articles/Soft-PWM#I...

aber ich bekomme an den entschprechenden Pins nich die gewinschte
Spannung um die Konstantstromquellen zu steuern. Bitte um Hilfe.
1
/*
2
    Eine 8-kanalige PWM mit intelligentem Lösungsansatz
3
   aus dem Artikel Soft-PWM auf www.Mikrocontroller.net
4
 
5
*/
6
 
7
// Defines an den Controller und die Anwendung anpassen
8
 
9
#define F_CPU         8000000L           // Systemtakt in Hz
10
#define F_PWM         100L               // PWM-Frequenz in Hz
11
#define PWM_PRESCALER 8                  // Vorteiler für den Timer
12
#define PWM_STEPS     256                // PWM-Schritte pro Zyklus(1..256)
13
#define PWM_PORT      PORTB              // Port für PWM
14
#define PWM_DDR       DDRB               // Datenrichtungsregister für PWM
15
#define PWM_CHANNELS  8                 // Anzahl der PWM-Kanäle
16
 
17
// ab hier nichts ändern, wird alles berechnet
18
 
19
#define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
20
//#define T_PWM 1   //TEST
21
 
22
#if ((T_PWM*PWM_PRESCALER)<(111+5))
23
    #error T_PWM zu klein, F_CPU muss vergrössert werden oder F_PWM oder PWM_STEPS verkleinert werden
24
#endif
25
 
26
#if ((T_PWM*PWM_STEPS)>65535)
27
    #error Periodendauer der PWM zu gross! F_PWM oder PWM_PRESCALER erhöhen.   
28
#endif
29
// includes
30
 
31
#include <stdint.h>
32
#include <string.h>
33
#include <avr/io.h>
34
#include <avr/interrupt.h>
35
#include <math.h> 
36
// globale Variablen
37
 
38
uint16_t pwm_timing[PWM_CHANNELS+1];          // Zeitdifferenzen der PWM Werte
39
uint16_t pwm_timing_tmp[PWM_CHANNELS+1];      
40
 
41
uint8_t  pwm_mask[PWM_CHANNELS+1];            // Bitmaske für PWM Bits, welche gelöscht werden sollen
42
uint8_t  pwm_mask_tmp[PWM_CHANNELS+1];        // ändern uint16_t oder uint32_t für mehr Kanäle
43
 
44
uint8_t  pwm_setting[PWM_CHANNELS];           // Einstellungen für die einzelnen PWM-Kanäle
45
uint8_t  pwm_setting_tmp[PWM_CHANNELS+1];     // Einstellungen der PWM Werte, sortiert
46
                                              // ändern auf uint16_t für mehr als 8 Bit Auflösung  
47
 
48
volatile uint8_t pwm_cnt_max=1;               // Zählergrenze, Initialisierung mit 1 ist wichtig!
49
volatile uint8_t pwm_sync;                    // Update jetzt möglich
50
 
51
// Pointer für wechselseitigen Datenzugriff
52
 
53
uint16_t *isr_ptr_time  = pwm_timing;
54
uint16_t *main_ptr_time = pwm_timing_tmp;
55
 
56
uint8_t *isr_ptr_mask  = pwm_mask;              // Bitmasken fuer PWM-Kanäle
57
uint8_t *main_ptr_mask = pwm_mask_tmp;          // ändern uint16_t oder uint32_t für mehr Kanäle
58
 
59
// Zeiger austauschen
60
// das muss in einem Unterprogramm erfolgen,
61
// um eine Zwischenspeicherung durch den Compiler zu verhindern
62
 
63
void tausche_zeiger(void) {
64
    uint16_t *tmp_ptr16;
65
    uint8_t *tmp_ptr8;                          // ändern uint16_t oder uint32_t für mehr Kanäle
66
 
67
    tmp_ptr16 = isr_ptr_time;
68
    isr_ptr_time = main_ptr_time;
69
    main_ptr_time = tmp_ptr16;
70
    tmp_ptr8 = isr_ptr_mask;
71
    isr_ptr_mask = main_ptr_mask;
72
    main_ptr_mask = tmp_ptr8;
73
}
74
 
75
// PWM Update, berechnet aus den PWM Einstellungen
76
// die neuen Werte für die Interruptroutine
77
 
78
void pwm_update(void) {
79
 
80
    uint8_t i, j, k;
81
    uint8_t m1, m2, tmp_mask;                   // ändern uint16_t oder uint32_t für mehr Kanäle    
82
    uint8_t min, tmp_set;                       // ändern auf uint16_t für mehr als 8 Bit Auflösung
83
 
84
    // PWM Maske für Start berechnen
85
    // gleichzeitig die Bitmasken generieren und PWM Werte kopieren
86
 
87
    m1 = 1;
88
    m2 = 0;
89
    for(i=1; i<=(PWM_CHANNELS); i++) {
90
        main_ptr_mask[i]=~m1;                       // Maske zum Löschen der PWM Ausgänge
91
        pwm_setting_tmp[i] = pwm_setting[i-1];
92
        if (pwm_setting_tmp[i]!=0) m2 |= m1;        // Maske zum setzen der IOs am PWM Start
93
        m1 <<= 1;
94
    }
95
    main_ptr_mask[0]=m2;                            // PWM Start Daten 
96
 
97
    // PWM settings sortieren; Einfügesortieren
98
 
99
    for(i=1; i<=PWM_CHANNELS; i++) {
100
        min=PWM_STEPS-1;
101
        k=i;
102
        for(j=i; j<=PWM_CHANNELS; j++) {
103
            if (pwm_setting_tmp[j]<min) {
104
                k=j;                                // Index und PWM-setting merken
105
                min = pwm_setting_tmp[j];
106
            }
107
        }
108
        if (k!=i) {
109
            // ermitteltes Minimum mit aktueller Sortiertstelle tauschen
110
            tmp_set = pwm_setting_tmp[k];
111
            pwm_setting_tmp[k] = pwm_setting_tmp[i];
112
            pwm_setting_tmp[i] = tmp_set;
113
            tmp_mask = main_ptr_mask[k];
114
            main_ptr_mask[k] = main_ptr_mask[i];
115
            main_ptr_mask[i] = tmp_mask;
116
        }
117
    }
118
 
119
    // Gleiche PWM-Werte vereinigen, ebenso den PWM-Wert 0 löschen falls vorhanden
120
 
121
    k=PWM_CHANNELS;             // PWM_CHANNELS Datensätze
122
    i=1;                        // Startindex
123
 
124
    while(k>i) {
125
        while ( ((pwm_setting_tmp[i]==pwm_setting_tmp[i+1]) || (pwm_setting_tmp[i]==0))  && (k>i) ) {
126
 
127
            // aufeinanderfolgende Werte sind gleich und können vereinigt werden
128
            // oder PWM Wert ist Null
129
            if (pwm_setting_tmp[i]!=0)
130
                main_ptr_mask[i+1] &= main_ptr_mask[i];        // Masken vereinigen
131
 
132
            // Datensatz entfernen,
133
            // Nachfolger alle eine Stufe hochschieben
134
            for(j=i; j<k; j++) {
135
                pwm_setting_tmp[j] = pwm_setting_tmp[j+1];
136
                main_ptr_mask[j] = main_ptr_mask[j+1];
137
            }
138
            k--;
139
        }
140
        i++;
141
    }
142
 
143
    // letzten Datensatz extra behandeln
144
    // Vergleich mit dem Nachfolger nicht möglich, nur löschen
145
    // gilt nur im Sonderfall, wenn alle Kanäle 0 sind
146
    if (pwm_setting_tmp[i]==0) k--;
147
 
148
    // Zeitdifferenzen berechnen
149
 
150
    if (k==0) { // Sonderfall, wenn alle Kanäle 0 sind
151
        main_ptr_time[0]=(uint16_t)T_PWM*PWM_STEPS/2;
152
        main_ptr_time[1]=(uint16_t)T_PWM*PWM_STEPS/2;
153
        k=1;
154
    }
155
    else {
156
        i=k;
157
        main_ptr_time[i]=(uint16_t)T_PWM*(PWM_STEPS-pwm_setting_tmp[i]);
158
        tmp_set=pwm_setting_tmp[i];
159
        i--;
160
        for (; i>0; i--) {
161
            main_ptr_time[i]=(uint16_t)T_PWM*(tmp_set-pwm_setting_tmp[i]);
162
            tmp_set=pwm_setting_tmp[i];
163
        }
164
        main_ptr_time[0]=(uint16_t)T_PWM*tmp_set;
165
    }
166
 
167
    // auf Sync warten
168
 
169
    pwm_sync=0;             // Sync wird im Interrupt gesetzt
170
    while(pwm_sync==0);
171
 
172
    // Zeiger tauschen
173
    cli();
174
    tausche_zeiger();
175
    pwm_cnt_max = k;
176
    sei();
177
}
178
 
179
// Timer 1 Output COMPARE A Interrupt
180
 
181
ISR(TIMER0_COMPA_vect) {
182
    static uint8_t pwm_cnt;                     // ändern auf uint16_t für mehr als 8 Bit Auflösung
183
    uint8_t tmp;                                // ändern uint16_t oder uint32_t für mehr Kanäle
184
 
185
    OCR0A += isr_ptr_time[pwm_cnt];
186
    tmp    = isr_ptr_mask[pwm_cnt];
187
 
188
    if (pwm_cnt == 0) {
189
        PWM_PORT = tmp;                         // Ports setzen zu Begin der PWM
190
                                                // zusätzliche PWM-Ports hier setzen
191
        pwm_cnt++;
192
    }
193
    else {
194
        PWM_PORT &= tmp;                        // Ports löschen
195
                                                // zusätzliche PWM-Ports hier setzen
196
        if (pwm_cnt == pwm_cnt_max) {
197
            pwm_sync = 1;                       // Update jetzt möglich
198
            pwm_cnt  = 0;
199
        }
200
        else pwm_cnt++;
201
    }
202
}
203
 
204
int main(void) {
205
 
206
    // PWM Port einstellen
207
 
208
    PWM_DDR = 0xFF;         // Port als Ausgang
209
    // zusätzliche PWM-Ports hier setzen
210
 
211
    // Timer 1 OCRA1, als variablen Timer nutzen
212
 
213
    TCCR0A = (1<<WGM01); // CTC Modus
214
    TCCR0B |= (1<<CS01); // Prescaler 8            
215
    TIMSK |= (1<<OCIE0A);   // Interrupt freischalten
216
 
217
    sei();                  // Interrupts global einschalten
218
 
219
220
 uint8_t port [8];
221
222
     port[0] = 50;    //PWM wert für PB0 einstellen
223
    port[1] = 100;    //PWM wert für PB1 einstellen
224
    port[2] = 50;    //PWM wert für PB2 einstellen
225
    port[3] = 100;    //PWM wert für PB3 einstellen
226
    port[4] = 0;    //PWM wert für PB4 einstellen
227
    port[5] = 0;    //PWM wert für PB5 einstellen
228
    port[6] = 0;    //PWM wert für PB6 einstellen
229
    port[7] = 0;    //PWM wert für PB7 einstellen
230
  
231
      memcpy(pwm_setting, port, 8);
232
      pwm_update();
233
234
235
  while (1) 
236
    {
237
    
238
    }
239
    return 0;
240
}

: Verschoben durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?


Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.