Problem mit Soft-PWM ATtiny2313

Gast #3953721
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#Intelligenter_L.C3.B6sungsansatz

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
}
Moderator Persönliche Seite #3954237
Lesenswert?

bubi schrieb:
> ich habe nur 100nF Kondensatoren und 10kOhm Widerstände reicht das

10 kΩ · 100 nF = 1 ms Zeitkonstante.  Deine PWM sollte also wenigstens
einige Kilohertz als Taktfrequenz haben.  Im Code da oben stehen
jedoch 100 Hz drin.

> oder
> lieg ich da voll daneben ich verstehe das nicht do ganz

Naja, ein paar Grundlagen solltest du dir schon mal anlesen.
Pulsweitenmodulation: DA-Wandlung mit PWM wurde dir ja bereits
genannt.  Lesen musst du es schon selbst, vorlesen können wir es dir
schlecht.

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