Forum: Mikrocontroller und Digitale Elektronik PWM über 2 Potis


von Joachim B. (jojo84)


Lesenswert?

Hallo zusammen,

für ein Projekt zu Hause brauche ich eine "PWM", bei der ich die Ein- 
und Auszeit über zwei Potis separat vorgeben kann. Das ganze soll auf 
einem Atmega88 Unterschlupf finden. CPU-Takt ist 8MHz (intern).

Das Problem hierbei:
Einschaltzeit: 1-1024 µs (10-bit ADC-Wert von Poti 1 + 1)
Ausschaltzeit: 1-1024 ms (10-bit ADC-Wert von Poti 2 + 1)

Im Hauptprogramm finden noch einige Dinge statt (ADC-Werte einlesen, 
LCD-Ausgabe), die aber nicht wirklich zeitkritisch sind.

Über "normale" PWM ist das ja schonmal so einfach nicht zu machen 
(Timer-Auflösung zu gering). Im schlimmsten Fall beträgt meine 
Periodendauer ja ca. 1 Sekunde, bei einer Auflösung von 1 µs :/ ...

Mein Ansatz bisher war, den 16-bit Timer mit Prescaler 8 laufen zu 
lassen (1 MHz) und den TOP-Wert direkt von Poti 1 zu übernehmen. In der 
OVF-ISR wird dann der Prescaler auf 64 und der TOP-Wert auf 125 gesetzt 
(ca. 1 kHz) und bei jeder weiteren ISR eine Variable hochgezählt, die 
dann mit meinem Potiwert 2 verglichen wird. Sind die beiden Werte 
gleich, Prescaler wieder auf 8 stellen, usw... Ein entsprechendes 
"Flag", was ich zur Unterscheidung innerhalb der ISR nutze, hab ich 
natürlich (schneller Betrieb oder langsamer "Vergleich-Betrieb").
Mit diesem Ansatz klappt es aber überhaupt nicht und ich glaub da bin 
ich irgendwie auf dem Holzweg.

Ich will jetzt nicht, daß ihr meinen Kram debuggt. Aber es wäre toll, 
wenn ich von euch ein paar Denkanstöße kriegen könnte, wie ihr das 
lösen würdet!

Danke schonmal!

Grüße
Joachim

von MaWin (Gast)


Lesenswert?

Der ATmega88 hat 2 8 bit PWM Kanäle, und ich würde als erstes überlegen, 
ob mir nicht 256 PWM Stufen mit 4us Auflösung reichen, dann ist die 
Implementierung nämlich eingfach.
Aber man kann die Hardware-PWM auch durch umprogrammieren der 
Vergleichswerte durch Software auf 10 bit erweitern, es gibt ja einen 
Interrupt (der allerindings wenig hilft wenn man Counter-Werte von 0-10 
programmieren muss, da braucht man einen Interrupt der deutlich früher 
kommt, also vom zweiten Timer).

Also:

Setze PWM-Timer und Interrupt-Timer auf 1us Aufkösung.
Programmiere Interupts alle 128us (PWM läuft ja 256us).
In diesem Interrupt wird der Output Compare Wert der beiden PWM Kanäle 
umprogrammiert, und zwar genau dann, wenn der nächste Compare Wert weit 
genug weg ist (zumindest 10us) damit es zu keinen Störungen kommt.


Neben dieser Methode, ständigem umprogrammieren der Vergleichswerte, ist 
1us bei 8MHz Takt auch komplett in Software machbar, ohne Interrupts 
kann man vergleichen und ein bit auf den Port ausgeben. Da man bei 2 PWM 
Kanälen a 10 bit nur 4 mal in 1ms was machen muss, hat man zwischen den 
Momenten auch Zeit für längere Operationen auf LCD und ADC. Man muss 
sich nach Rückkehr von diesen Operationen bloss wider sysnchronisieren, 
in dem man auf den durczlaufenden Timer1 per polling guckt

Damit diese reine Software ohne Interrupts sauber läuft, musst du deine 
LCD und ADC Routinen so schreiben, daß sie weniger als 250us benötigen. 
Das sollte ja kein Problem sein.
Die eigentliche in 1us durchlaufende Programmschleife macht nun 
folgendes:
Vergleiche Timer1 mit nächsten Event, wenn der Event gekommen ist, Event 
ausführen (nein, das ist KEINE Subroutine, der Call-Overhead wäre zu 
hoch) und zum nächsten Event weiterschalten (das kann man gut machen, in 
dem man die Schleife aufrollt und 7 mal hintereinander schreibt und nur 
ein mal zurückspringt)
  Es gibt die Events:
    PWM Ausgänge ändern
      PWM0 und PWM1 auf 0
      PWM1 auf 0 und PWM1 auf 1
      PWM1 auf 1 und PWM1 auf 0
      PWM0 und PWM1 auf 1
  und
    eine Routine aufrufen
      LCD Routine aufrufen
      ADC Routine aufrufen
      Events neu berechnen

Das Einordnen, welche Events kommen, macht man ausserhalb der engen 
Schleife. Die platziert die 7 oben aufgeführten Events zu passenden 
Zeiten, d.h. die LCD Routine wird in die Event-Liste eingefügt, wenn der 
nächst Timer-Event mindestens 256us weg ist (uns so einen Timeslot gibt 
es immer, weil deine 4 Operationen während der 1us nicht schlechter 
verteilt sein können).

Klingt schwierig ? Es ist nicht schwieriger, als das umprogrammieren der 
PWM on the fly. Und es hat den Vorteil, daß man auch 8 PWM Kanäle nutzen 
könnte, weil keine PWM Hardwware nötig ist. Es läuft also auf jedem noch 
so einfach gestrickten Prozessor.

von Thomas (kosmos)


Lesenswert?

Es gibt doch 2 Compare Register die du verwenden kannst. So kannst du 
bei jeder Übereinstimmung einen Interrupt auslösen im ersten schaltest 
du den Portpin High im 2ten Interrupt auf Low. Deine Adc Werte musst du 
halt entsprechend hochmultiplizieren.

von Joachim B. (jojo84)


Lesenswert?

MaWin schrieb:
> Klingt schwierig ? Es ist nicht schwieriger, als das umprogrammieren der
> PWM on the fly. Und es hat den Vorteil, daß man auch 8 PWM Kanäle nutzen
> könnte, weil keine PWM Hardwware nötig ist. Es läuft also auf jedem noch
> so einfach gestrickten Prozessor.

Danke für deine Idee und deine Mühe! Klingt dennnoch im ersten Moment 
nach hartem Tobak ;) . Ich werde aber mal gucken, ob ich das irgendwie 
umsetzen kann. Es klingt auf jeden Fall recht souverän und robust.

@Thomas:
wie meinst du das? Quasi als normale schnelle PWM? Kannst du das kurz 
näher beschreiben?

DANKE!
Gruß

von Harald W. (wilhelms)


Lesenswert?

Joachim B. schrieb:

> für ein Projekt zu Hause brauche ich eine "PWM", bei der ich die Ein-
> und Auszeit über zwei Potis separat vorgeben kann.
> Einschaltzeit: 1-1024 *µs*
> Ausschaltzeit: 1-1024 *ms*

In Hardware würde ich da einfach zwei Monoflops nehmen, die sich
gegenseitig triggern. Z.B. in Form eines 4538-ICs.
Gruss
Harald

von Thomas (kosmos)


Lesenswert?

Ich versuche es mal einfach zu erklären und gehe mal von 255 Bit aus. 
Wobei man hier nicht viel Zeit für die Interrupts hat wenn man keinen 
Taktteiler verwendet

ADC Werte der beiden Potis einlesen z.b. 10 und 245 eigentlich würde man 
dafür nur 1 Poti benötigen, da man sich die 245 auch ausrechnen kann.

Diese gibt man an die beiden Compareregister, initialisier die 
Interrupts...
Setzt den Ausgangspin auf high wenn der Wert1 nicht 0 ist, danach Timer 
starten, sobald nun der Timer den Wert des ersten Compareregisters 
erreicht hat wird ein Interrupt ausgelöst, dein Programm verzweigt als 
an die vorgegebene stelle wo z.B. steht der Ausgangspin wieder auf low 
zu setzen ist, der Timer zählt weiter und wenn Comparewert 255 erreicht 
hat ist wird wieder auf high zu setzen.

Wenn eine Wandlung fertig ist kann man wiederum per Interrupt die 
Comparewerte neu schreiben und dann läuft das ganze z.B. mit 30 und 255 
ab.


|---|                  |---|                |---|
|   |------------------|   |----------------|   |
   10       245       255 10       245     255 10

es gibt aber sehr viele Möglichkeiten wie man das macht, man kann den 
Timer automatisch zurücksetzen lassen, ihn einfach weiterlaufen lassen, 
alles per Hand machen, also Timerwert selber löschen...es gibt sehr 
viele Möglichkeiten deswegen musst du mal schauen was für deine 
Anwendung brauchst.

Schau dir die verschiedenen Möglichkeiten im Datenblatt an.

Und wenn du 10Bit ADC Werte hast dein Timer aber mit 16Bit läuft kannst 
du die ADC Werte einfach um 6 Stellen nach links schieben oder du 
addierst 64 Messungen zu einem 16Bit Wert zusammen und hast da gleich 
eine Mittelung deines Ergebnisses drin und deine Werte schwanken auch 
nicht mehr so stark.

von m.n. (Gast)


Lesenswert?

Du mußt Dir die Zeiten ein wenig anpassen; dann sollte das Programm 
Deine Wünsche erfüllen.
http://www.mino-elektronik.de/Generator/takte_impulse.htm#bsp1

Im Anschluß ist ein Programm, wo die Daten per RS232 eingegeben und im 
EEPROM fürs nächste Einschalten hinterlegt werden.
http://www.mino-elektronik.de/Generator/takte_impulse.htm#bsp2

von Joachim B. (jojo84)


Lesenswert?

Harald Wilhelms schrieb:
> In Hardware würde ich da einfach zwei Monoflops nehmen, die sich
> gegenseitig triggern. Z.B. in Form eines 4538-ICs.
> Gruss
> Harald

Ui, das klingt auch gut. Da hab ich doch glatt wieder den NE555 im Kopf 
;) ...

@Thomas:
super, vielen Dank für die Ausführung!

Ich werd mich heut abend mal daran machen eure Ideen um zu setzen.

Gruß und danke!

von RomanK (Gast)


Lesenswert?

Hallo JoJo,

da du die Einheiten µs und ms extra hervorgehoben hast gehe ich davon 
aus das du eine PWM im Verhältnis von max. ca. 1 zu 1 Million 
realisieren willst. Bist Du dir da sicher? Die 10bit Auflösung der ADC 
ist auch nur graue Theorie. Vielleicht beschreibst Du mal was du damit 
regeln willst. Bestimmt finden wir dann eine realistische Lösung.

Gruß

Roman

von m.n. (Gast)


Lesenswert?

RomanK schrieb:
> da du die Einheiten µs und ms extra hervorgehoben hast gehe ich davon
> aus das du eine PWM im Verhältnis von max. ca. 1 zu 1 Million
> realisieren willst.

Ich lese dies gerade. Die beiden genannten Zeiten sind jeweils 1:1024, 
einmal in 'µs' und einmal in 'ms'. Es gibt keinen Grund diese 
miteinander zu multiplizieren.
Der ATmega88-interne ADC reicht für diese Auflösung aus und es gibt auch 
keinen Grund, die Auflösung auf 1:256 zu reduzieren oder auf Monoflops 
auszuweichen.

von Mike (Gast)


Lesenswert?

m.n. schrieb:
> Ich lese dies gerade. Die beiden genannten Zeiten sind jeweils 1:1024,
> einmal in 'µs' und einmal in 'ms'. Es gibt keinen Grund diese
> miteinander zu multiplizieren.

Wie willst du das denn sonst nennen, wenn als Extremwerte Pulslänge von 
1024µs mit 1ms Pause (i.e. Tastverhältnis 50%) und im anderen Grenzfall 
1µs mit 1024ms Pause (i.e. Tastverhältnis 0.00009765625%) genannt 
werden.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Mike schrieb:
> Wie willst du das denn sonst nennen, wenn als Extremwerte Pulslänge von
> 1024µs mit 1ms Pause (i.e. Tastverhältnis 50%) und im anderen Grenzfall
> 1µs mit 1024ms Pause (i.e. Tastverhältnis 0.00009765625%) genannt
> werden.

 Ja.
 Und von PWM kann dann mit Sicherheit nicht mehr die Rede sein.
 Zumindest kenne ich nichts mit solch einem Tastverhaltnis, dass sich
 PWM nennt.

von m.n. (Gast)


Lesenswert?

Mike schrieb:
> Wie willst du das denn sonst nennen,

Es geht hier nicht um PWM-Tastverhältnisse, sondern um zwei separate 
Zeiten, für die jeweils einzeln ein Verhältnis von max. 1:1024 
einstellbar sein soll. Wo ist das Problem?

Wenn hieraus eine "PWM im Verhältnis von max. ca. 1 zu 1 Million" 
konstruiert wird, dann vermutlich mit dem Gedanken, die Anforderungen 
dramatisch ins Unlösbare zu treiben.
Die Aufgabe ist aber durchaus uneingeschränkt mit wenig Aufwand lösbar, 
selbst wenn man 'wackelige' Monoflops nehmen möchte!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

m.n. schrieb:
> Es geht hier nicht um PWM-Tastverhältnisse, sondern um zwei separate
> Zeiten, für die jeweils einzeln ein Verhältnis von max. 1:1024
> einstellbar sein soll. Wo ist das Problem?

 Thread name: PWM über 2 Potis
 Du magst Recht haben, aber TO nicht.
 Eine Uhr, bei der 2 LEDs im Sekundentakt blinken, ist mit Sicherheit
 nicht PWM gesteuert, egal ob 100ms an oder 600ms an.
 Auch Blaulicht ist mit etwa 10Hz nicht PWM gesteuert.
 Gelblicht an einer Ampel...

 Blinken und PWM haben genau nichts miteinander zu tun.

von Jörg E. (jackfritt)


Lesenswert?

Ich glaube deswegen hat der TO im Text dann auch PWM in 
Anführungszeichen gesetzt ;)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Jörg Esser schrieb:
> Ich glaube deswegen hat der TO im Text dann auch PWM in
> Anführungszeichen gesetzt ;)

 Kann sein.
 Irgendetwas mit PWM steuern, hört sich irgendwie besser an, als:
 Irgendetwas periodisch für eine bestimmte Zeit ein- und ausschalten.

 Klingt irgendwie komplizierter, zeugt von Kenntnis der Materie.
 Auch wenn es nicht annähernd stimmt.

von Ralph (Gast)


Lesenswert?

Joachim B. schrieb:
> Einschaltzeit: 1-1024 µs (10-bit ADC-Wert von Poti 1 + 1)
> Ausschaltzeit: 1-1024 ms (10-bit ADC-Wert von Poti 2 + 1)

Also ergibt sich daraus eine Frequenz von 1 Hz bis 1 KHz mit einem 
Dutycycle von 0,0000001 % bis 50 %.  ( falls ich mich jetzt bei den 
Nullen nicht verzählt hab)
Also der Timer muss mit einer Schrittweite von 1µs auflösen. Sollte im 
AVR machbar sein.
Aber der Timer muss bei dieser Auflösung bis auf eine Sekunde kommen.
==> Anzahl Schritt 1.000.000 ==> 2^20.
Das heißt es wird ein Timer mit eine Bitbreite von mindesten 20 Bit 
benötigt.

==> vergiss den AVR , das kann der nicht.

Bei den Rahmenbedingungen bleiben dir jetzt 3 Möglichkeiten.

1. eine Softwarelösung mit Interuptgetriebenen Umkonfigurierungen des 
Timers.
Hier musst du sehr darauf achten das du mit den anderen 
Programmfunktionen nicht in die Quere kommst. ==> Verschiebungen der 
Timereinstellungen, Aussetzer auf der PWM, Verzögerte 
Displayausgaben,.....
Diese Umschlatung des Timers muss ja auch bei einer Frequenz von 1 KHz 
noch funktionieren. sportlich

2. Such einen µC der entsprechend breite Timerregister hat. Ich kenne da 
jetzt nur eine µC Familie, es gibt bestimmt mehrere. (TI ARM µC mit 
HighEndTimer Device HET , bis zu 27 Bit Registerbreite im Timer)

3. Überdenke die Rahmenbedingungen ob diese extreme Bandbreite wirklich 
benötigt wird und reduziere diese auf ein praktikables Maß.


10 Bit ADC.
Bei der üblichen Beschaltung der ADC's wirst du mit viel Glück 8 
nutzbare Bits aus dem ADC erhalten.
Die beiden Lowbits werden soviel springen das du diese glatt vergessen 
kannst.

==> nutzbar 8 Bit ==> 256 Bits Auflösung für beide Potis.
Erhöht die Schrittweite auf 4 µs, dann brauchst du einen 18 Bit Timer. 
reicht im AVR immer noch nicht.

Eine Beschaltung der ADC die eine Nutzung der 10 Bit erlaubt, ist mit 
praktikablen Aufwand im Hobbybereich nicht umsetzbar.

von Genervter (Gast)


Lesenswert?

Pappnasen. Eine PWM kann man auch periodisch An- und Ausschalten, bzw. 
für viele Perioden auf PWM-Wert "0" setzen, und dann für eine Periode 
auf einen entsprechenden Wert für den us-Impuls.

von Paul Baumann (Gast)


Lesenswert?

Genervter schrieb:
> Pappnasen.

Köln? Karneval?

Sportler haben festgestellt,
daß Marmelade Fett enthält!

Tätä, Tätä, Tätä...

von m.n. (Gast)


Lesenswert?

Ralph schrieb:
> Aber der Timer muss bei dieser Auflösung bis auf eine Sekunde kommen.
> ==> Anzahl Schritt 1.000.000 ==> 2^20.
> Das heißt es wird ein Timer mit eine Bitbreite von mindesten 20 Bit
> benötigt.
>
> ==> vergiss den AVR , das kann der nicht.

Weiter oben habe ich doch ein Programm gezeigt, was einen 32-Bit Timer 
zur Verfügung stellt: Auflösung 50ns @20MHz.

Ralph schrieb:
> 10 Bit ADC.
> Bei der üblichen Beschaltung der ADC's wirst du mit viel Glück 8
> nutzbare Bits aus dem ADC erhalten.
> Die beiden Lowbits werden soviel springen das du diese glatt vergessen
> kannst.

Das ist absoluter Blödsinn! Der ADC wandelt deutlich besser als die 
Potis eine lineare Kennlinie vorgeben könnten.
Zudem empfiehlt es sich, dem µC einen Abblockkondensator zu spendieren.
Probiere es doch mal aus!

Genervter schrieb:
> Pappnasen. Eine PWM kann man auch periodisch An- und Ausschalten,

Dann geht PWM bestimmt auch rückwärts?

Paul Baumann schrieb:
> Tätä, Tätä, Tätä...

Das ist der beste Kommentar dazu ;-)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Genervter schrieb:
> Pappnasen. Eine PWM kann man auch periodisch An- und Ausschalten, bzw.
> für viele Perioden auf PWM-Wert "0" setzen, und dann für eine Periode
> auf einen entsprechenden Wert für den us-Impuls.

 Troll.
 Hier existiert keine PWM, die ein- und ausgeschaltet wird, hier soll
 irgendetwas in veränderlichen Zeitabständen für eine variable Zeit
 eingeschaltet werden.

 Oder kennst du eine PWM mit eins zu eine Million ?

 Es ist in etwa so, als ob ich eine Glühbirne alle 2 Wochen für eine
 Sekunde einschalte, nach 9 Tagen dann für 2 Sekunden einschalte und
 dann behaupte, meine Küchenbeleuchtung wird PWM gesteuert.

: Bearbeitet durch User
von Joachim B. (jojo84)


Lesenswert?

Nun streitet euch doch mal bitte nicht. Ok, die Titel war vielleicht 
nicht ganz glücklich gewählt. Wobei man dennnoch auch in diesem Fall 
noch eingeschränkt von "PWM" sprechen kann... sei es drum...

Also es geht wirklich nur um ein ganz kurzes Anschalten und dann eine 
längere Pause. Konkret um den Unterbrecher ("Interrupter") für eine 
DRSSTC. Den könnte man natürlich auch analog/dirkret aufbauen, aber ich 
möchte die aktuell eingestellten Zeiten gern auf einem LCD ablesen 
können, um den optimalen Arbeitspunkt leichter ermitteln zu können. Das 
geht einfach leichter, wenn man "was sieht" -> LCD.
Und wenn ich eh schon nen µC einsetze, wollte ich auch gleich die Pulse 
vom Controller kommen lassen.

Darum sind auch die Zeiten so sehr unterschiedlich, weil ich zum einen 
1-1000 BPS erzeugen möchte und zum anderen die maximal zulässige An-Zeit 
stark variieren kann. Meist liegt die aber im Bereich von einigen zig 
bis wenigen 100 µs.

Aber wie gesagt, streitet euch nicht um Begrifflichkeiten. Bringt doch 
nichts!
Ich hab einige tolle Vorschläge erhalten -> vielen Dank für diese 
Anregungen!

Peace ;)

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.