mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Soft-PWM nie völlig High


Autor: JayDee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Tag,

ich habe ein kleines Problem mit der Sofware PWM, die hier in den 
Artikeln beschrieben wird. Ich habe den Quellcode zur intelligenten 
Lösung 1 zu 1 von hier übernommen.
http://www.mikrocontroller.net/articles/Soft-PWM

Klappt auch ansich ganz wunderbar. 0 ist wirklich Null und das Oszi 
zeigt eine saubere Linie. Das andere extrem funktioniert leider nicht 
richtig. Die PWM hat 8 Bit (256 Schritte), macht für mich als höchsten 
einstellbaren Wert 255. Hier sollte das Oszi ja eigentlich eine glatte 
Linie bei 5V zeigen. Jedoch hat man alle 10ms einen sehr kurzen Peak 
Richtung Masse drin. An der Hardware liegt es nicht. Das manuelle Setzen 
auf High- oder Low-Pegel klappt und auch eine einfachere Software PWM 
funktioniert ohne diesen Fehler. Da ich zum einen diese Software auf 16 
Kanäle und 10 Bit erweitern wollte, bin ich schon auf eine performante 
Software PWM angewiesen. Zum anderen ist das anzusteuernde Element 
Low-Aktiv, weshalb dieser Fehler nun wirklich störend ist. Wirklich 
abschalten kann man so nicht. Auch verstehe ich die funktionsweise 
dieser PWM noch nicht so ganz und bin somit auf euere Hilfe angewiesen.

MfG
Jürgen

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die PWM funktioniert absolut korrekt. Wenn du mal ins Atmel Datenblatt 
schaust, wirst du sehen, dass die normalen PWM Ausgänge auch dieses 
Phänomen haben (solang du die nicht im Glitch free Modus laufen lässt).

Du kannst ja einfach abfangen ob der Wert 255 ist und dann die Software 
PWM "ausschalten". Sprich den Pin dauerhaft auf 1 setzen.
Eventuell reicht es aber auch den PWM Zähler nur von 0-254 zählen zu 
lassen, Je nach Software (Hab oben in den Artikel nicht reingeguckt).

Autor: ftf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich denke da verstehst du was falsch:

>> Das andere extrem funktioniert leider nicht richtig. Die PWM hat 8 Bit (256 
Schritte), macht für mich als höchsten einstellbaren Wert 255. Hier sollte das 
Oszi ja eigentlich eine glatte Linie bei 5V zeigen.


Ein PWM-Kanal ist kein "echter" DAC!

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das sagt ja niemand, er hat das osci halt als logic-analyzer benutzt um 
sich das PWM-Signal anzuschauen.

Das Problem ist halt, das man bei pwmwert==curStep abschaltet

das funtktioniert bei 0, bei 255 gibts da halt die lücke,
wenn man erst bei pwm-wert>curStep abschaltet gehts bei 0 nicht, dafür 
schaltet er bei 255 nicht ab.

man kann das nur mit einer Speziallösung für den Wert 255 umgehen, indem 
man bei 255 einfach gar nicht den Pin abschaltet.

Das brauch dann aber natürlich ein µ mehr rechenzeit

Autor: JayDee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok,

das mit dem exkludieren von 255 als Wert aus der PWM ist sicherlich eine 
Lösung. Ich kann mir aber immer noch nicht erklären, warum diese 
Software dieses Verhalten aufweist. Einen Zusammenhang zwischen der 
Hardware PWM und diesem Programm kann ich jedenfalls nicht erkennen.

Grüße Jürgen

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du erreichen willst, dass eine PWM bei 0..255 zwischen "ganz aus" 
und "ganz an" schwankt, dann muss die Periode 255 Takte betragen, nicht 
256, sonst fehlt immer an einem Ende etwas. 255 von 256 Takten sind halt 
einer zuwenig, wenn 0 für 0 Takte steht.

Merke: 0..256 sind 257 mögliche Werte.

Hardware-PWMs sind da auch nicht besser.

Autor: JayDee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, aber 256 klappt mit der Software nicht als Wert. Das gibt nur ein 
wildes Geflacker. 255 ist der höchste einstellbare Wert. Stellt sich 
natürlich die Frage ob man da irdenwo dran drehen kann. Muss ich mir 
morgen mal in Ruhe anschauen.

Autor: JayDee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok,

ich verstehe immer noch nicht wirklich, wie dieses Programm arbeitet 
oder warum es zu diesen Spikes kommt. Hat sonst noch jemand eine Idee, 
wie man das fixen könnte?

Grüße Jürgen

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JayDee schrieb:
> Hat sonst noch jemand eine Idee,
> wie man das fixen könnte?

Warum sollte man das?

Das ist ja nur in Deinem Kopf ein Problem.
Keiner merkt, daß die LED mit max 99,6% Helligkeit leuchtet.


Peter

Autor: Bernhard Mayer (bernhard84)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi.

Änder mal die Interrupt routine:
ISR(TIMER1_COMPA_vect) {
    static uint8_t pwm_cnt;
    uint8_t tmp;
 
    OCR1A += isr_ptr_time[pwm_cnt];
    tmp    = isr_ptr_mask[pwm_cnt];
    
    if (pwm_cnt == 0) {
        PWM_PORT = tmp;                         // Ports setzen zu Begin der PWM
        pwm_cnt++;
    }
    else {
        PWM_PORT &= tmp;                        // Ports löschen
        if (pwm_cnt == pwm_cnt_max-1) { // <-- HIER ÄNDERN!!! -1
            pwm_sync = 1;                       // Update jetzt möglich
            pwm_cnt  = 0;
        }
        else pwm_cnt++;
    }
}

hAb den Code jetzt auch nicht 100 5ig durch, es könnte eber hier haken. 
Kann aber auch sein, dass es dann gar nicht mehr geht. habs nicht 
ausprobiert ;-)

Bernhard

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im Artikel stehen diverse Lösungen drin, welche du verwendet hast weiss 
ich also nicht. Zur Illustration nehme ich mal die erste Variante 
"Einfacher Lösungsansatz".

Da kommt raus:
für 0: 256x low, 0x high,
für 255: 1x low, 255x high.

Variante für
für 0: 255x low, 0x high,
für 255: 0x low, 255x high:
ISR(TIMER1_COMPA_vect) {
    static uint8_t pwm_cnt=0;
    uint8_t tmp=0, i=0, j=1;
 
    OCR1A += (uint16_t)T_PWM;
 
    for (; i<8; i++) {    
      if (pwm_setting[i] > pwm_cnt) tmp |= j;
        j<<=1;
    }
    PWM_PORT = tmp;                         // PWMs aktualisieren
    if (pwm_cnt==(uint8_t)(PWM_STEPS-2))    //<===== war: PWM_STEPS-1
        pwm_cnt=0;
    else
        pwm_cnt++;
}

Autor: Magnus Müller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard Mayer schrieb:
> hAb den Code jetzt auch nicht 100 5ig durch, es könnte eber hier haken.

Ich glaube, deine Shift Taste setzt aus ;)

Autor: Bernhard Mayer (bernhard84)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Magnus Müller schrieb:
> Bernhard Mayer schrieb:
>> hAb den Code jetzt auch nicht 100 5ig durch, es könnte eber hier haken.
>
> Ich glaube, deine Shift Taste setzt aus ;)

Hoffentlich wars die Taste und nicht der Finger ;-)

Autor: Magnus Müller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard Mayer schrieb:
> Hoffentlich wars die Taste und nicht der Finger ;-)

Kann man sich gegen solche Ausfälle (Gliedmaßen) nicht versichern? ;o)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Korrekter ist es natürlich, wenn PWM_STEPS nie grösser wird als 255. 
Dann steht der Bereich 0..PWM_STEPS für ganzaus..ganzan und die Periode 
passt auch wieder.

Der Kernfehler liegt darin, dass PWM_STEPS=256 zwar intuitiv nahe liegt, 
aber mit diesem 8bit basierten Code nicht vollständig funktionieren 
kann.

Autor: JayDee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, ich habe die Version mit dem intelligenten Lösungsansatz aus dem 
oben genannten Artikel verwendet. Mein Problem an der Sache ist, daß ich 
einen Low-Aktiven Treiber damit ansteuern will. Wenn die PWM also nicht 
permanent High-Pegel halten kann kriegt man den Treiber nie 
abgeschaltet. Klar jetzt könnte man noch einen inverter davor setzen, 
aber Softwarelösungen sind billiger.

Zurück zum Thema. Die Software bietet 256 Stufen für die PWM an. Das ist 
eine 8-Bit Zahl. 0 ist alles aus 255 sollte alles an sein. Sind genau 
256 Schritte. Gibt man 255 als Wert für die On-Time an, so hat man halt 
alle 10ms kurze Peaks im Signal, obwohl ja jetzt permanente On-Time sein 
sollte. 256 ist kein korrekter Wert für die PWM. Passt ja schon nicht 
mehr in die 8Bit Zahl und das merkt man auch. Bei 256 gibt es auf allen 
Ports nur noch wildes geflacker.

Mein Problem ist, daß ich die Funktionsweise dieser intelligenten Lösung 
nicht völlig durchblicke und halt nicht weiß, wo ich eingreifen muss um 
aus 255 als Wert für die On-Time ein permanentes High-Pegel Signal zu 
erzeugen.

Ich habe jetzt mal den Vorschlag die ISR abzuändern durchprobiert. 
Klappt aber bei der Version mit dem intelligenten Lösungsansatz alles 
nicht. Danach klappt die ganze PWM nicht mehr richtig.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JayDee schrieb:

> 256 ist kein korrekter Wert für die PWM. Passt ja schon nicht
> mehr in die 8Bit Zahl und das merkt man auch. Bei 256 gibt es auf allen
> Ports nur noch wildes geflacker.

Du musst die Periode der PWM (PWM_STEPS) auf 255 reduzieren.

Autor: JayDee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
255 ist sowieso der Maximalwert mit dem ich die Software anspreche. 256 
war nur ein Test der wie es zu erwarten ist auch nicht funktioniert, da 
daß ja keine 8 Bit Zahl mehr ist.

Autor: JayDee (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok,

ich konnte das Problem jetzt auf die ISR Routine eingrenzen. Selbst wenn 
ich den Port von Hand auf High-Pegel setze und nicht über die PWM setzen 
lasse, habe ich diese kurzen Peaks Richtung Low-Pegel drin. Der Effekt 
verschwindet, sobald ich die ISR auskommentiere. Jetzt muss ich mir mal 
klarmachen, wieso das Programm den Else Teil der ISR Aufruft und wie man 
es so umbauen kann, daß die Kanäle die permanente On-Time haben sollen 
davon nicht betroffen sind.

Die IST sieht übrigens so aus
ISR(TIMER1_COMPA_vect) {
    static uint16_t pwm_cnt;
    uint16_t tmp;
 
    OCR1A += isr_ptr_time[pwm_cnt];
    tmp    = isr_ptr_mask[pwm_cnt];
    
  if (pwm_cnt == 0) {
        PWM_PORT = tmp&0x07;                         // Ports setzen zu Begin der PWM
    PWM_PORT2 = (tmp>>3)&0x3F;
    PWM_PORT3 = (tmp>>4)&0xE0;
        pwm_cnt++;
    }
    else {
        PWM_PORT &= tmp&0x07;                        // Ports löschen
    PWM_PORT2 &= (tmp>>3)&0x3F;
    PWM_PORT3 &= (tmp>>4)&0xE0;
        if (pwm_cnt == pwm_cnt_max) 
    {
            pwm_sync = 1;                       // Update jetzt möglich
            pwm_cnt  = 0;
        }
        else pwm_cnt++;
    }
    
}

Die oben vorgeschlagenen Lösung mit
if (pwm_cnt == pwm_cnt_max)
in
if (pwm_cnt == pwm_cnt_max-1)
zu ändern stoppte das Programm ja leider völlig.

Grüße Jürgen

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.