Kann man während einer PWM noch nebenbei was auf dem Display anzeigen!?

Gast #2248768
Lesenswert?

Hallo Leute,

ich bin gerade an einem Projekt, bei dem ich mit einem Atmega16 eine 
Steuerung für ein LED-Board aufbaue.
Dabei ist es schon möglich über ein Menu eine entsprechende anzahl von 
LED Feldern anzusteuern, diese werden bisher für eine entsprechende 
Zeit, welche der Benutzer vorher über das Menu einstellt, eingeschalten. 
Die entsprechende Zeit läuft als Countdown ab und wird auf dem Display 
angezeigt.

Das ist der IST-Stand.

Ich möchte das Projekt gerne insofern erweitern, das die entsprechenden 
Felder in der Helligkeit durch eine PWM gedimmt werden können. So das 
man im Menu einen Helligkeitswert zwischen 0 und 100 auswählt und dann 
die entsprechende LED mit z.B 50% leuchtet und aber trotzdem der 
Countdown auf dem Display abläuft.

Nun meine Frage an euch.

Hat jemand in der Richtung schon einmal sowas gemacht oder kann mir 
einen Tipp geben, wie die parallele Abarbeitung (PWM und Display) 
handeln könnte!?

Ich freue mich über euer Know How.

Gruß Mik-X
Gast #2248784
Lesenswert?

>Optimal wäre natürlich Assembler für den Interrupt.

Lächerlich. Ein schlechtes Assemblerprogramm
ist auch nicht schneller als das was der C Compiler
mit Optimierung rausholt. Wenn man ein bisschen
was drauf hat ist der Unterschied vieleicht 5%.
Gast #2248790
Lesenswert?

> Hat jemand in der Richtung schon einmal sowas gemacht oder kann mir
> einen Tipp geben, wie die parallele Abarbeitung (PWM und Display)
> handeln könnte!?

Sicher.

Ob per Interrupt oder beide nacheinander in der Hauptschleife ist 
letztlich egal, so oder so muß der Prozessor die nötigen Instruktionen 
abarbeiten, aber mehere Ereignisse quasi gleichzeitg zu beachten und zu 
bearbeiten ist Standard bei der Microcontrollerprogrammierung, man macht 
es eben schnell zeitverschachtelt.

Wenn jemand auf die Idee kommt, in solchen Jobs längere 
warte-Zeitschleifen durchzuziehen oder auf Ereignisse zu warten, schon 
verloren, längere Tätigkeiten müssen eben in kürzere Einzelaktionen 
unterteilt werden.
#2248793
Lesenswert?

holger schrieb:
> Lächerlich. Ein schlechtes Assemblerprogramm
> ist auch nicht schneller als das was der C Compiler
> mit Optimierung rausholt.

Naja, normalerweise sind C-Compiler schon sehr gut, nur im Falle einer 
ISR muss der Compiler, will er denn standardkonform sein, beispielsweise 
alle Register sichern, da er nicht wissen kann, welche denn in der ISR 
benötigt werden, etc.

Aber ich glaube nicht, dass es dem Vorposter um die Geschwindigkeit 
ging, denn die ist bei der Anwendung egal, es geht ja nur um eine LED. 
Der weitere Vorteil von Assembler ist natürlich dass es deutlich 
einfacher geht.
Gast #2248808
Lesenswert?

>holger schrieb:
>> Ein schlechtes Assemblerprogramm
>> ist auch nicht schneller als das was der C Compiler
>> mit Optimierung rausholt. Wenn man ein bisschen
>> was drauf hat ist der Unterschied vieleicht 5%.
>
>Träum weiter.

Naja, wenn du meinst. Ich hab da so meine Erfahrungen.

>Naja, normalerweise sind C-Compiler schon sehr gut, nur im Falle einer
>ISR muss der Compiler, will er denn standardkonform sein, beispielsweise
>alle Register sichern, da er nicht wissen kann, welche denn in der ISR
>benötigt werden, etc.

Nö, muss er nicht. Der weiss durchaus welche Register benutzt
werden. Wenn man so dumm ist eine Funktion in einem Interrupt
aufzurufen dann muss er natürlich alle Register sichern.
Das ist aber nicht immer so. Bei den schlappen ATMega vieleicht;)

Das gilt dann aber nicht konsequent für alle C Compiler.
Es kommt auf den Prozessor an den du benutzt. Ein Cortex M3
sichert seine Register in Hardware wenn ein Interrupt
aufgerufen wird. Der Compiler hat da überhaupt nichts mit zu tun.

Alles Ansichtssache.
#2248876
Lesenswert?

holger schrieb:

> Nö, muss er nicht. Der weiss durchaus welche Register benutzt
> werden. Wenn man so dumm ist eine Funktion in einem Interrupt
> aufzurufen dann muss er natürlich alle Register sichern.
> Das ist aber nicht immer so. Bei den schlappen ATMega vieleicht;)

Naja, es ist in C sehr schwierig festzustellen, ob Du eine Funktion 
aufrufst oder nicht. Da es sehr viele Möglichkeiten gibt, das zu tun. 
Eine der populären Möglichkeiten ist beispielsweise den Rücksprungzeiger 
auf dem Stack zu überschreiben. Das ist für den Compiler sehr schwierig 
zu detektieren.
#2248936
Lesenswert?

ein schrieb:
> holger schrieb:
>> Ein schlechtes Assemblerprogramm
>> ist auch nicht schneller als das was der C Compiler
>> mit Optimierung rausholt. Wenn man ein bisschen
>> was drauf hat ist der Unterschied vieleicht 5%.
>
> Träum weiter.#

Dann muss ich dir leider mitteilen, dass du erst mal C lernen solltest, 
ehe du einem Anfänger nahelegst, dass er doch seine ISR aus 
Geschwindigkeitsgründen lieber in Assembler schreiben soll.

Es gibt diese Fälle, wo es auf jeden Taktzyklus ankommt. Natürlich gibt 
es sie. Wenn man ein PAL Signal erzeugen muss, dann ist jeder Takt 
wichtig. Aber ansonsten spielt es keine Rolle, ob der Compiler mal da 
und dort den einen oder anderen Takt liegen lässt. Mehr als 5 bis 10% 
sind es so gut wie nie. Eher weniger als 5%.

Wenn es dann doch mal exzessiv mehr ist, dann liegt es meistens daran 
(Erfahrung hier aus dem Forum), dass der Programmierer weniger drauf 
hatte, als er ursprünglich dachte.
Gast #2249120
Lesenswert?

Hy Leute,

danke erstmal für die mehr oder wenig hilfreichen Kommentare.

Die angehängten Dateien sind nett gemeint, aber ich schreibe in C.

Trotzdem Respekt, das du da nen überblick drinne behältst, da hätte man 
ja auch unterprogramme in die Main einbinden können.

Nochmal zu meinem Problem:

Nachdem alle Parameter:
   - Anzahl der Anzusteuernden Ports (LEDs)
   - Zeit, z.B. 10sek.
eingegeben sind, wird derzeit der/die entsprechenden PIN/s high und es 
wird danach in die Routine "Countdown" gesprungen, welche dann die Zeit 
runter zählt und auf dem Display ausgibt. Hier ein kleiner Auszug davon:

if (LED_Wert_1 == 1)
{
PORTD = 0x01;
fertig_1=Countdown(Zeit_Wert_1);          break;
}
else if (LED_Wert_1 == 2)
{
PORTD = 0x03;
fertig_1=Countdown(Zeit_Wert_1);          break;

Nachdem die Zeit abgelaufen ist und die Countdown beendet ist, wird 
diese verlassen und der/die PIN/s zurückgesetzt.

Meine Frage nun wie kann ich die PWM eventuell in die nachfolgende 
Countdown integrieren!? Kann man das in die Countdown mit rein machen?

char Countdown(int Zeit_Wert_2)
{
char str_8[1];
char str_9[2];
char Ende =0;
char Minuten_1 = Zeit_Wert_2/60;
char Minuten = Minuten_1;
char Sekunden_1 = Zeit_Wert_2-(Minuten*60);
char Sekunden = Sekunden_1;

char Tastenspeicher_8 = PINB;

  while((Tastenspeicher_8 != 0x6F) && (Ende == 0))
  {
  Tastenspeicher_8 = PINB;
  Sekunden = Sekunden-1;
  if((Sekunden == 255) && (Minuten==0))
  {
  Sekunden=0;
  Minuten =0;
  Ende = 1;
  PORTD=0x00;
sprintf(str_8,"%01d",Minuten); lcd_set_cursor (2, 0); lcd_write (str_8);
sprintf(str_9,"%02d",Sekunden); lcd_set_cursor (2, 5); lcd_write 
(str_9);
_delay_ms(1000);
  }
  else if((Sekunden == 255) && (Minuten >=0))
  {
  Sekunden = 59;
  Minuten = Minuten-1;
sprintf(str_8,"%01d",Minuten); lcd_set_cursor (2, 0); lcd_write (str_8);
sprintf(str_9,"%02d",Sekunden); lcd_set_cursor (2, 5); lcd_write 
(str_9);
_delay_ms(1000);
  }
  else
  {
  Sekunden = Sekunden;
  Minuten = Minuten;
sprintf(str_8,"%01d",Minuten); lcd_set_cursor (2, 0); lcd_write (str_8);
sprintf(str_9,"%02d",Sekunden); lcd_set_cursor (2, 5); lcd_write 
(str_9);
  _delay_ms(1000);
  }
}
PORTD=0x00;
return Ende;
}

Ich freue mich auf eure Meinungen.
Gast #2249145
Lesenswert?

Mik-X schrieb:
> _delay_ms(1000);

Wenn du deinen Prozessor im Hauptprogramm so blockierst, bleibt für PWM 
eine Interruptsteuerung (was sowieso sinnvoll wäre) oder, falls die 
Anzahl der Hardware-PWM-Kanäle vom ATmega16 reicht noch einfacher, die 
direkt Steuerung durch die Hardware.
Wieviel LEDs mußt du denn ggf. steuern?
Gast #2249162
Lesenswert?

>  _delay_ms(1000);
> Ich freue mich auf eure Meinungen.

Es wurde bereits gesagt, daß Delay-Schleifen der vollkommen falsche 
Ansatz sind, wenn man mehrere Jobs quasi gleichzeitg nebeneinander 
erledigen will.

Der vollkommen falsche Ansatz.
Persönliche Seite #2249239
Lesenswert?

Mik-X

_delay_ms(1000)

ist eine reine Softwareschleife in der der Prozessor verharrt.
ala for(int t=0;t<.....;t++){nop;.....}

Es gibt dann mehrere Möglichkeiten PWM auf die Art und Weise dann doch 
noch nebenläufig zu betreiben:

1. man benutzt die 2 bis 6 PWM-Kanäle die per Hardware realisiert sind
oder
2. man unterbricht den Prozessor zyklisch und macht es mit ein paar 
if-Befehlen (oder anders) auf SoftPWM-Basis.
Als Kommunikation zwischen ISR und Hauptprogramm bietet sich dann ein 
Satz volatile-Variablen an.

SoftPWM heißt, ein paar (>1000 je nach Auflösung) mal pro Sekunde in 
eine, durch einen Timer-Vergleich/Überlauf ausgelöste, 
Unterbrechungsroutine anspringen,
einen globalen Zähler in der ISR (vornehmlich static) hochzählen,
mit den vorgegebenen LED-Einschalt-Zähler-Vergleichsvariablen 
(volatile/zugreifbar durch Main) vergleichen und An- oder Ausschalten.
oder
Ein Bitfeld (16 bit und mehr) pro LED im Speicher halten, welches genau 
bestimmt, wann eine LED anzusein hat und eine ISR die diese Bitfelder 
Bit für Bit durch einen Zähler bestimmt absucht und das Bit an den Port 
weiterleitet.
#2249259
Lesenswert?

Mik-X schrieb:
> danke erstmal für die mehr oder wenig hilfreichen Kommentare.
>
> Die angehängten Dateien sind nett gemeint, aber ich schreibe in C.

Hmmm, Du versuchst es...
Mit Warteschleifen (Delay) kommst Du da nicht weit.
Aber tröste Dich, mit C komme ich da auch nicht weit. ;-)

>
> Trotzdem Respekt, das du da nen überblick drinne behältst,

Warum sollte ich da die Übersicht verlieren? Ist doch alles gut lesbar 
und verständlich kommentiert. Und halbwegs strukturiert ist es auch. 
Allerdings denke ich nicht in Schleifen, sondern in Zuständen. Anders 
ist Multitasking nicht möglich. Das geht aber auch in C, ich kann es 
allerdings nur in ASM. Ist aber nicht weiter schlimm, der AVR kann auch 
kein C, somit gibt es weniger Missverständnisse zwischen mir und dem 
AVR. ;-)

> da hätte man
> ja auch unterprogramme in die Main einbinden können.

Muss ich das jetzt verstehen?
Die Mainloop enthält bedingte Sprünge, also Verzweigungen. Diese sind 
ganz bewusst nicht als Unterprogramm (Rcall, Call) geschrieben sondern 
als direkter Sprung (Rjmp, Jmp), damit nach der Rückkehr zur Mainloop 
immer die obersten Jobs bevorzugt werden. Dies bewirkt eine Art 
Priorität beim Abarbeiten der Jobs. Erst wenn keine unerledigten Jobs 
mehr da sind, fällt die CPU in den Sleep, wo sie der nächste Interrupt 
wieder weckt.


Willi schrieb:
> Mik-X schrieb:
>> Die angehängten Dateien sind nett gemeint, aber ich schreibe in C.
> Die Hoffnung dabei war wohl, dass du beim Lesen, quasi als passiven
> Wortschatz, über multilinguale Kompetenz verfügst ;-)

So in etwa. Und dabei muss man nichtmal ASM perfekt beherrschen, denn 
die Kommentare ersetzen einen PAP. Man erfährt also schon anhand der 
Kommentare die Struktur des Programms.

...
(Firma: Nisch-Aufzüge) Persönliche Seite #2249310
Lesenswert?

auch in C ist delay das blödeste was man anstellen kann wenn mann mehere 
Prozesse quasiparallel bearbeiten will.

Alles was zeitbasiert ist gehört in eine Timer ISR welche mit dem 
Timertakt des Grösten gemeinsamen Teilers aller benötigten Zeitbasen 
läuft.

Diese werden dort je Kanal in static-integer(char)-sw-zählern 
incrementiert, verglichen, zurückgesetzt und die ports entsprechend 
gesetzt.

Bei PWM bietet sich an beim Schwellwert in% auszuschalten bei 100 
zurückzusetzen auf 0 und wiedereinzuschalten.

Hat man mehere PWM Kanäle braucht man nur einen Zähler welchen man 
durchlaufen lässt und kann für jeden Kanal einen Einschaltwert und einen 
Ausschaltwert verwenden. So lassen sich in den Lastkreisen die 
Schaltspikes klein halten.

Ob man das in C oder Assembler macht spielt eine untergeordnete Rolle.

Wichtig ist als ersters wird alles erledigt was 100% syncron sein muss
und immer zu erledigen ist. Bedingte Ausführungen erfolgen zum Schluß.

Beim 8Bit ATARI gab es eine VideoISR. An diese konnte eine Verlängerunng 
angelinkt werden in der der User seine regelmäßigen Sachen 
miterledigenlassen konnte. Normal zeigt der Vector auf ein Reti verbiegt 
man ihn erfolgt der reti aus der Verlängerung.

Namaste
(Firma: Nisch-Aufzüge) Persönliche Seite #2249531
Lesenswert?

Was mir geade noch einfällt die VideoISR nach jedem Vblank hat gleich 
noch sämmtliche Schattenregister verwaltet.

Diese stellten ein Userinterinterface dar um Hardwarregister 
anzusprechen welche im Bereich des Rom's addressiert sind oder in das 
Speichermanagment oder Videomanagment eingriffen.

So sichert man das die Hardware und SW nicht wegen fehlerhaften Timings 
abschmierte. Gleichzeitig konnte der User in aller Ruhe die schreibenden 
Schattenregister bearbeiten und die lesenden auslesen. Während das BS 
(die VideoISR) sich um die richtige Abfolge und das korrekte Timing beim 
schreiben und lesen der HW register und der Speicherverwaltung kümmerte.

Sie stellte auch die Systemzeit welche in der Zeropage an der Adresse 
0x12-0x14 jederzeit auslesbar war.

Namaste
Gast #2249727
Lesenswert?

Diese Funktionen wie "_delay_ms(1000)" gehören verboten.

Nur Ärger damit und keinerlei sinnvollen Nutzen.

1. stimmt die angegebene Zeit nie.
   Schließlich werden ja Interrupts nicht rausgerechnet.
2. Ist der µC für andere sinnvolle Funktionen blockiert


Alternative :
HW Timer nutzen.
1. Macro erstellen das die 1000msec in die systembedingten Timertakte 
umrechnet.  (Abhängik der Timer configuration und SystemTakt)
2. Timer mit diesem Wert starten und Interrupt einschalten.
3. In der Interruptroutine die nächste Anweisung antriggern aber NICHT 
im Interrupt ausführen. zb über ein Flag
Gast #2249745
Lesenswert?

Keine Ahnung, welche µC ihr hier für PWM so benutzt. Ich hätte ja 
geglaubt, ein integriertes PWM-Peripheral sei heute Standard.

Selbst in meinen 15 Jahre alten 8051-Derivaten SAB80C517A habe ich eine 
16-bit-PWM-Unit. Sie arbeitet, einmal initialisiert, völlig losgelöst 
von der CPU. Nur bei Änderungen muß man noch mal z.B. ein 
Compare-Register beschreiben. Damit kann man also dann alles andere 
bedienen, ohne die PWM-Unit weiter zu berücksichtigen.
Gast #2249756
Lesenswert?

> Keine Ahnung, welche µC ihr hier für PWM so benutzt. Ich hätte ja
> geglaubt, ein integriertes PWM-Peripheral sei heute Standard.

Joo ich wüsste auf Anhieb keinen µC ohne , bis auf minimalste Version 
wie vielleciht die kleinen Tiny's.

ABER diese PWM zu nutzen bedeutet ja Datenblätter zu lesen. Timer zu 
programmieren.
Und auf einmal vielleicht sogar zu denken.

Für viele ist das eindeutig zu viel Anspruch.
Gast #2249765
Lesenswert?

Guten Abend,

mir genügen die bei Atmega16 vorhandenn 4 PWM Ausgänge nicht, ich 
benötige 8 PWM Kanäle.

Die Wartezeiten mit der Delayfunktion sind unkritisch. Jedoch 
hinderlich. Werde Sie daher gegen eine Timerfunktion ersetzen.

Werde die Hinweise und Ratschläge beherzigen und ein wenig 
experimentieren.
Gast #2249954
Lesenswert?

>Diese Funktionen wie "_delay_ms(1000)" gehören verboten.
Genau. Es sei denn 'delay' wird in einem RTOS so verwendet, dass es 
nicht den Prozessor (mit bekloppten Schleifenbefehlen) blockiert.

> Ein Cortex M3 sichert seine Register in Hardware wenn ein Interrupt
> aufgerufen wird.
Auch CM3 muss die Register auf den Stack legen, was Takte kostet.
Register-File wäre da viel schneller, aber das hat der CM3 nicht.
Gast #2250147
Lesenswert?

MCUA schrieb:
> Auch CM3 muss die Register auf den Stack legen, was Takte kostet.
> Register-File wäre da viel schneller, aber das hat der CM3 nicht.

Wenn eine Anwendung diese paar Takte benötigt ist sowieso was 
Grundlegendes falsch gelaufen.

Entweder ist das Software Design sowas von Müll,...

Oder der µC ist vollkommen falsch ausgewählt worden.

Einen Wohnungsumzug macht man ja auch nicht mit einem Smart weil der 
gerade da ist, sondern mit was größerem.
(Firma: Nisch-Aufzüge) Persönliche Seite #2250196
Lesenswert?

Eigentlich böte sich an die Register allesamt mit einem 
Schattenregisterstapel zu versehen.

Jede INT schiebt dann den Registersatz komplett um eine Position nach 
hinten und stellt einen neuen leeren Registersatzbereit um dann zur 
Int_adresse zu springen.

Bei reti sollte dann alle aktuellen register mit den letzen Eintrag der 
Schattenregiser beschrieben werden.

Das ist sicher in einem Takt zu erledigen.

Alternativ ließen sich alle Register durch einen Interuptcounter aus 
einem Registerarray wählen.

Damit wären gar kein Registerkopieren mehr nötig.

Aber ich wette das wird längst so gemacht.

Namaste
Gast #2250201
Lesenswert?

> Damit wären gar kein registerkopieren mehr nötig.

Doch.

Wen du nämlich 2 geschachtelte Interrupts zulässt,
zulassen musst weil die Anwendung das so erfordert.

Das mit den zweiten Registersatz hatte schon der
ehrwürdige Z80.

Und auf universelleren Maschinen mit genug Registern
hat man einfach in der Interrupt-Routine andere
Register verwendet als im normalen Programm, schon
muß man die nicht mehr retten.

> ABER diese PWM zu nutzen bedeutet ja Datenblätter zu lesen.
> Timer zu programmieren.

Oh Ralph, DIESE PWM zu verwenden bedeute vor allem,
alle <x> LED leider nur gleichhell leuchten lassen zu können,
weil man nämlich für <x> LED eigentlich <x> solcher
Hardware-PWMs bräuchte.
Gast #2250294
Lesenswert?

>Eigentlich böte sich an die Register allesamt mit einem
>Schattenregisterstapel zu versehen.
>Jede INT schiebt dann den Registersatz komplett um eine Position nach
>hinten und stellt einen neuen leeren Registersatzbereit um dann zur
>Int_adresse zu springen.
>Bei reti sollte dann alle aktuellen register mit den letzen Eintrag der
>Schattenregiser beschrieben werden.
>Das ist sicher in einem Takt zu erledigen.
Kein Mensch macht einen Schattenregisterstapel!
Entweder man benutzt Schattenregister oder einen Stack.
Schattenregister kommen einem RegisterFile gleich, wobei die Frage immer 
ist, wie viele Registersätze dort aufgenommen werden können. (1...?) 
(Sparc-Prozessoren hatten sehr viele davon) Ein Registersatz-wechsel 
geht sehr schnell, typ 1..2 Takte (im Vergleich zu zig Takten bei 
verschicken auf den Stack).
Reicht das RegisterFile (mit >=1 Registersätzen) nicht aus, muss man 
halt  auf den Stack sichern, aber das dauert.


>Aber ich wette das wird längst so gemacht.
wie gesagt, total falsch.
Gast #2250345
Lesenswert?

MCUA schrieb:
>>Wenn eine Anwendung diese paar Takte benötigt ist sowieso was
>>Grundlegendes falsch gelaufen.
> Von wegen.
> Einige uCs brauchen dafür (um in den INT zu schalten) 4 Takte andere
> 100...

Und wenn die IRQ's gerade gesperrt sind wegen..... dauert es noch 
länger.
Und genau deshalb ist ein Design das auf Takte rechnen muss damit es 
funktioniert grundsätzlcih Müll.

Soviel Luft muss bei der Auslegung der Hardware / Software mit 
einkalkuliert werden.

Sonst wird das NIE ein stabiles System.
Gast #2250352
Lesenswert?

>Und wenn die IRQ's gerade gesperrt sind wegen..... dauert es noch
>länger.
>Und genau deshalb ist ein Design das auf Takte rechnen muss damit es
>funktioniert grundsätzlcih Müll.
Schonmal was von Echtzeit-Anwendung gehört?
Gast #2250392
Lesenswert?

Aber 1. geht es hier nicht um ein Real Time OS
Doch. auch hier ist es Realtime. Denn die PWM ist Realtime-App (wen auch 
recht langsam).

Aber, es gibt HardRealTime-Anwendungen, wo's natürlich auf Takte 
ankommt, und da is nix mit IRQs sperren!
Manche uC's können das erfüllen, manche nicht.
(zB waren die ersten MIPS- u. PowerPC-uCs diesbezügl katastrophal)
#2250419
Lesenswert?

MCUA schrieb:
>>der klug µC würde sich schlafen legen und auf dn nächsten IRQ warten.
> wenn das mal nicht zu lange dauert

Das ist eine PWM für LEDs, wir sprechen von Frequenzen im Bereich von 
vielleicht 100 Hz. Das bedeutet, Du brachst vielleicht ein paar wenige 
ISR-Aufrufe pro Millisekunde. Das ist nicht zeitkritisch, der µC braucht 
nur (maximal) ein paar dutzend Taktzyklen um aufzuwachen.

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