Forum: Mikrocontroller und Digitale Elektronik AVR PWM mit beliebigem Output-Pin


von Wowa (Gast)



Lesenswert?

Hallo,
ich versuche schon seit einiger Zeit eine bestimmte Art von PWM zu 
generieren.

Es ist ein Overflow/Compare-Interrupt in dem ich den Timer jedes mal neu 
aufziehe und damit das gewünschte Tastverhältnis einstelle. Eine feste 
Periode ergibt sich ja aus ton+toff, wenn das Verhältnis stimmt. Damit 
soll möglich sein auf beliebigem Output eine PWM auszugeben.

Es funktioniert mit mehreren Timer-Modi gut, solange das Tastverhältnis 
zwischen 10%...90% bleibt.

Meine Frage: Ist es möglich die 10% nach oben und unten zu realisieren?

Es handelt sich um eine BLDC Ansteuerung, d.h. die Hardware steht, 
funktioniert auch - bin halt bei dem Tastverhältnis eingeschränkt. Es 
muss aber unbedingt das Schema beibehalten werden, da der Interrupt den 
Takt vorgibt.

Hier zwei Beispiel mit zwei Modi -> FastPWM, CTC - 20kHz

PS. läuft auf einem ATMEGA328P / Arduino UNO

CTC-Modus:
1
#include <Arduino.h> 
2
3
int flag = 0; 
4
5
unsigned int ton,toff;
6
7
void setup() 
8
{ 
9
    // LED output
10
    DDRD |= (1<<2);
11
    PORTD &= ~(1<<2);
12
    
13
    // Mode 4 - CTC, prescaler 1
14
    TCCR1A = 0x00;
15
    TCCR1B = (1<<WGM12)|(1<<CS10);
16
    
17
    // Capture-Compare - Interrupt
18
    TIMSK1 = (1<<OCIE1A);
19
    sei();
20
    
21
} 
22
23
// 20 kHz PWM
24
ISR (TIMER1_COMPA_vect)
25
{
26
  // ton - Time
27
  if(flag==0) 
28
    { 
29
        // LED on
30
        PORTD |= (1<<2); 
31
32
        // duty-cycle = 25%
33
        ton = 200;
34
        OCR1A = ton;
35
        
36
        flag=1; 
37
    } 
38
    else  // toff - Time
39
    { 
40
        // LED off
41
        PORTD &= ~(1<<2); 
42
        
43
        toff = 799 - ton; 
44
        OCR1A = toff; 
45
        
46
        flag=0; 
47
    } 
48
}
49
 
50
void loop() 
51
{ 
52
53
}

FastPWM
1
#include <Arduino.h> 
2
3
int flag = 0; 
4
5
unsigned int ton, toff;
6
7
void setup() 
8
{ 
9
    // LED output
10
    DDRD |= (1<<2);
11
    PORTD &= ~(1<<2);
12
13
    // Mode 15 - FastPWM, Prescaler 1
14
    TCCR1A = (1<<WGM11)|(1<<WGM10);
15
    TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS10);
16
    
17
    // Overflow Interrupt
18
    TIMSK1 = (1<<TOIE1);
19
    sei();
20
    
21
} 
22
23
// 20 kHz PWM
24
ISR(TIMER1_OVF_vect) 
25
{ 
26
    // ton - Time
27
    if(flag==0) 
28
    { 
29
        // LED on
30
        PORTD |= (1<<2); 
31
        
32
        // duty-cycle = 50%
33
        ton= 400;        
34
        OCR1A = ton;
35
36
        flag=1; 
37
    } 
38
    else // toff - Time
39
    { 
40
        // LED off
41
        PORTD &= ~(1<<2); 
42
 
43
        toff = 799-ton;        
44
        OCR1A = toff;
45
46
        flag=0; 
47
    } 
48
} 
49
void loop() 
50
{ 
51
52
}

von Norbert S. (norberts)


Lesenswert?

Hi,

der Timer läuft mit Systemtakt, da kann eine Soft-PWM nicht wirklich gut 
funktionieren. Auch mit bestem Assembler nicht.
Die Periode ist doch nur 800 Takte lang.
Mit Soft-PWM kann man vielleicht nebenbei eine LED dimmen oder sowas 
aber doch keine PWM mit 20kHz.
ton immer wieder in der ISR zu setzen ist jetzt auch nicht sonderlich 
effizient aber das macht den Kohl nicht fett.
Überhaupt ginge das etwas besser (ICR1 als Overflow vorher festlegen) 
aber das löst Dein Problem nicht, da das auch nur minimal besser wird.

Einzige Chance wäre Timer mit 8Bit, Teiler 8, PWM-Frequenz 
dementsprechend runter auf ca. 7,8kHz. Darüber wird das Schalten der 
Endstufe auch langsam ein ernsteres Thema.
Damit wird es aber auch noch nicht wirklich gut sondern nur etwas 
weniger schlecht.
Spätestens wenn es noch andere Interrupts gibt kannst Du das komplett 
vergessen.

Das wird nur mit Hardware PWM was werden.

Gruß,
Norbert

von Peter D. (peda)


Lesenswert?

Programmausführung kostet nunmal Zeit. Deshalb wurde ja die HW-PWM 
eingebaut.

Ein Interrupthandler braucht schnell mal 50 Zyklen.
Und wenn noch andere Interruptquellen oder atomare Zugriffe im Programm 
vorkomen, wirds noch kritischer.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wenn du schon einen Mega328 da hast, ist mir nicht klar, warum du zur 
BLDC Ansteuerung unbedingt Soft PWM nehmen willst. Die 3 Timer mit ihren 
komplementären Ausgängen sind ideal für direkte BLDC Ansteuerung und 
können sogar FOC, wenn du das mal möchtest.
Siehe die Applikation Notes AVR447 und AVR444 bei Atmel. Auch mein 
Frequnezumrichter macht von den Timern regen Gebrauch:
http://www.mikrocontroller.net/articles/3-Phasen_Frequenzumrichter_mit_AVR

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Wowa schrieb:
> Meine Frage: Ist es möglich die 10% nach oben und unten zu realisieren?

Mein uralter WinAVR generiert aus deiner ISR-Roútine (ohne die 
konstanten Zuweisungen, due willst ja sicherlich on/of während der 
Laufzeit verändern) ein Programm, das ca. 75 Zyklen benötigt. Dazu kommt 
noch die Einsprungzeit in die ISR  von minimal 4 Zyklen.

That's it - beantworte deine Frage selber...

Mit handoptimierten Assembler liesse sich noch vier Zyklen für ein 
push/Pop sparen, wenn man zwei Register für die ISR reserviert, nochmals 
8, das bringt dich dann auf ca. 8%. Mehr ist halt nicht drin.

Oliver

von Wowa (Gast)


Lesenswert?

Hallo,
vielen Dank für die aufschlussreichen Antworten. Bei der nächsten 
Version werde ich es anders machen.

Again what learned, würde der Lothar sagen

Danke

von Peter D. (peda)


Lesenswert?

Entwas schneller gehts, wenn man 2 Interrupts (COMPA/B) nimmt zum 
Ein-/Ausschalten und die dann als nacked nur mit SBI/CBI+RETI drin. Dann 
sinds 12 Zyklen.

von Wowa (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Entwas schneller gehts, wenn man 2 Interrupts (COMPA/B) nimmt zum
> Ein-/Ausschalten und die dann als nacked nur mit SBI/CBI+RETI drin. Dann
> sinds 12 Zyklen.

Danke für den Tipp, habs eben probiert...

bei 20kHz komme ich auf 6% ... 93%
bei 10kHz 3% ... 97%
.
.
.

je größer der Zählerwert (kleinere Frequenz) desto genauer/besser wird 
es.

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.