Forum: Mikrocontroller und Digitale Elektronik 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#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
}

: Verschoben durch Moderator
von bubi (Gast)


Lesenswert?

Oh ich glaube ich bin in faschem Forum sorry!!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hab's verschoben.

Vielleicht schreibst du ja erstmal, was du bekommst.  „PWM-Eingang,
der von 0 bis 2,5 V steuerbar ist“ ist ein Widerspruch in sich: eine
PWM ist ein digitales Signal, das man besser mit einem Oszilloskop
als einem Multimeter misst, 0 bis 2,5 V klingt nach
Steuergleichspannung.

von bubi (Gast)


Lesenswert?

Entschuldigung es ist kein PWM eingang an der Konstantstromquelle 
sondern ein DIM-Anschluss der von 0-2,5V steuerba ist. Leider besitze 
ich kein Osziloskop und kann deswegen nur mit einem Multimeter die 
Spannung an den Pins messen PB0 = 3,3V , PB1 = 3,5V , PB2 = 3,3V PB3 = 
3,5V.

von Frank (Gast)


Lesenswert?

Hast du Tiefpässe an den PWM Ausgängen um das Signal zu glätten?

von Frank (Gast)


Lesenswert?


von bubi (Gast)


Lesenswert?

Nein habe ich nicht, werde asprobieren . Aber was ich nicht verstehe ist 
wiso veränder sich die Spannung an allen Pins auch wenn ich nur den Wert 
von von PWM am Pin 0 verändere. Ist es so richtig wie ich das mache oder 
habe ich da ein Denkfehler.

von Frank (Gast)


Lesenswert?

Ohne Glättung kannst du an einem digitalen Pin garkeine analoge Spannung 
erzeugen.
Und erst recht nicht mit einem Multimeter messen!
--> Tiefpässe anschließen!

von bubi (Gast)


Lesenswert?

ich habe nur 100nF Kondensatoren und 10kOhm Widerstände reicht das oder 
lieg ich da voll daneben ich verstehe das nicht do ganz

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

: Bearbeitet durch Moderator
von bubi (Gast)


Lesenswert?

Ich habe jetzt ausgerechnet das bei einem Widerstand von 10kOhm einen 
Kondensator mit 5uF brauche:

Verstehe ich das richtig das jeder Werd in dem Array für den jeweiligen 
Pin zuständig ist.

von Frank (Gast)


Lesenswert?

Naja, ich würde mir mal überlegen ob ich nicht lieber versuche mit der 
PWM Frequenz hoch zu gehen.
Dann wird der Kondensator auch kleiner!

Ansonsten ist es neben dem Rippel auch immer eine Frage der Dynamik. 
Also wie schnell sich deine Gleichspannung ändern können soll.

von Frank (Gast)


Lesenswert?

Und ja, Wert im Array port ist für den jeweiligen Pin.

von bubi (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe die Tiefässe angeschlossen, aber jetzt wenn Werte im Array für 
die ersten 2 Pins übergebe kommt nur am Pin 1 ein Signal raus.

von bubi (Gast)


Angehängte Dateien:

Lesenswert?

Es funktioniert ich habe den Timer 1 genommen, dann bekomme ich an allen 
8 Pins PWM Signal.

Kann mir jemand erkleren wieso die PWM Frequenz steigt wenn ich den 
Timer0 nehme, oder wie ich die PWM Freqeunz ausrechnen kann (Bild2).

Vielen dank für die Antworten

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
Noch kein Account? Hier anmelden.