Forum: Compiler & IDEs LED Dimmen ohne PMW am Atmega8


von Michael (Gast)


Lesenswert?

Hallo Mikrocontroller Leute, :)

und zwar hab ich folgendes Problem ich möchte gerne LED´s ohne hilfe des 
PWM dimmen. Dies gelingt mir auch aber ich möcht, das sie automatisch 
bzw je nach programmierung heller bzw dunkler werden. Nur geht es nicht 
so wie ich mir das dachte. Habt ihr vllt ein Lösungsansatz?

Danke im Vorraus :D

Hier mein Code

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <inttypes.h>
 int i;
int main( void )
{
  uint8_t pwm_soll = 0; // gewünschter Dimmerwert 0..100
  uint8_t pwm_phase = 0; // Laufwert der Schleife 0..100


  DDRD |= (1<<PB5); // Pin PB0 an Port B als Ausgang


  while( 1 )
  {

  for (i=0;i<=255;i++)
  {

    if( pwm_soll == pwm_phase )
    {
      PORTD |=(1<<PB5); // active low LED aus
    }
    pwm_phase++;
    if( pwm_phase == i )
    {
      pwm_phase = 0;
      PORTD &=~ (1<<PB5); // active low LED an
    }
  }
  }
  return 0;
}

von Maik M. (myco)


Lesenswert?

vergleiche pwm_phase nicht mit i sondern einer anderen 8Bit Variablen, 
die außerhalb der FOR-Schleife definiert ist, und sich innerhalb derer 
nicht ändert. Das müsste gehen, aber wäre dann auch komplizierter als 
nötig.

von MaWin (Gast)


Lesenswert?

> Habt ihr vllt ein Lösungsansatz?

Programmieren lernen.



Funktionierender Code sähe so aus:

  uint8_t pwm_soll = 0; // gewünschter Dimmerwert 0..100
  while(1)
  {
    for(i=0;i<=100;i++) // dann klappt's sogar mit den 100
    {
      if(i<pwm_soll)
      |
        PORTD &=~ (1<<PB5); // active low LED an
      }
      else
      {
        PORTD |=(1<<PB5); // active low LED aus
      }
    }
  }

von Michael (Gast)


Lesenswert?

Also den Code den du mir gegeben hast funktioniert nicht. Trotzdem 
danke. Ich weiß nicht ob du genau weißt was ich meine ich möchte das die 
LED langsam heller bzw dunkler wird und nicht nur die Dimmstufe annimmt.

von Maik M. (myco)


Lesenswert?

muss mich korrigieren, sollte nicht mit einer anderen Variable 
verglichen werden, sondern mit 0, wobei pwm_soll dann größer 0 sein 
sollte.

MaWins code müsste gehen, obwohl da ein Schreibfehler drin ist, den du 
aber leicht finden könntest, wenn du die Compiler-Meldungen lesen 
würdest. "Fading" würde dann funktionieren wenn pwm_soll außerhalb der 
FOR-Schleife geändert werden würde

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Also den Code den du mir gegeben hast funktioniert nicht. Trotzdem
> danke. Ich weiß nicht ob du genau weißt was ich meine ich möchte das die
> LED langsam heller bzw dunkler wird und nicht nur die Dimmstufe annimmt.

Dann solltest du die PWM Erzeugung von der Einstellung des aktuellen 
Dimmgrades unabhängig machen.

Deine PWM Erzeugung basiert auf einem aktuellen Dimmwert.
Dein Benutzer gibt dir einen Dimmwert vor => Sollwert

und deinen aktuellenb Dimmwert (der dann die Helligkeit definiert) 
führst du langsam dem Sollwert nach: Ist er kleiner als der Sollwert, 
dann erhöhst du ihn um 1. Ist er größer als der Sollwert, dann 
erniedrigst du ihn um 1.

Dein Benutzer kann am Rädchen drehen soviel er will, die Helligkeit geht 
langsam seinen Änderungen nach.


Warum willst du eigentlich keine Hardware-Pwm nehmen? Würde alles enorm 
vereinfachen.

> LED Dimmen ohne PMW am Atmega8
Du machst eine PWM! Nur machst du die in Software statt in Hardware 
obwohl letzter viel einfacher wäre.
Angst vor Timern? Das langsame Nachführen der Helligkeit macht man 
ebenfalls am besten mit einem Timer. Da ist das dann ganz easy.

von Michael (Gast)


Lesenswert?

Naja ich hab nen LED Cube 3x3x3 gemacht. :)
Und läuft eigentlich soweit ganz gut nun wollte ich halt noch das ich 
die LED´s dimmen kann und naja da hab ich dann bemerkt das ich die PWM 
schon verheizt habe :S ... deswegen das.
Und war will ich ja das hier keiner am Rad dreht sondern das ich 
einstellen kann das die LED jetzt von AUS auf AN geht aber das halt 
langsam. Nun weiß ich zwar wie man die LED dimmen kann aber nicht das es 
Automatisch geht. Die lösungsvorschläge bis jetzt haben mir bis jetzt 
nicht weitergeholfen. Trotzdem danke :)

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Naja ich hab nen LED Cube 3x3x3 gemacht. :)

Dann sag das das nächste mal bitte auch. Dann denken nicht alle in die 
falsche Richtung.

> Und läuft eigentlich soweit ganz gut nun wollte ich halt noch das ich
> die LED´s dimmen kann

alle gemeinsam oder jede Led einzeln?

Wie sieht deine Cube Ansteuerung jetzt aus?

(jede LED einzeln)
Grundsätzlich brauchst du für jede LED nicht nur 1 Bit, welches aussagt 
ob die LED ein oder aus ist, sondern einen Helligkeitswert (zb uint8_t). 
Dein Array, in dem die Helligkeitswerte abgelegt sind, muss es 2-mal 
geben. Aus dem einen holt sich die Cubeansteuerung den Helligkeitswert, 
den sie für diese LED realisieren soll und im anderen Array stehen die 
Helligkeitswerte, die du in deinem Programm vorgibst. Nach x 
Zeiteinheiten (zb nach einem Komplett-PWM Zyklus des Cubes) führst du 
die realisierten Helligkeitswerte den Vorgabewerten wie oben beschrieben 
nach.

Wenn du nur Ein/Aus hast, welche Framerate schaffst du mit deinem Cube? 
Die kannst du gleich mal durch die Anzahl der gewünschten PWM STufen 
dividieren um abzuschätzen, ab wann das alles flackern wird.

von Volkmar D. (volkmar)


Lesenswert?

Wie oben geschrieben mußt Du den Wert pwm_soll außerhalb der 
PWM-Schleife anpassen. Wenn ich Marvins PWM-Code nehme, könnte man es 
wie folgt ergänzen:
1
  uint8_t pwm_soll = 0; // gewünschter Dimmerwert 0..100
2
  while(1)
3
  {
4
    for(i=0;i<=100;i++) // dann klappt's sogar mit den 100
5
    {
6
      if(i<pwm_soll)
7
      {
8
        PORTD &=~ (1<<PB5); // active low LED an
9
      }
10
      else
11
      {
12
        PORTD |=(1<<PB5); // active low LED aus
13
      }
14
    }
15
    pwm_soll++;
16
    if(pwm_soll > 100)
17
      pwm_soll = 0;
18
  }

Damit sollte die LED langsam aufdimmen und wenn sie hell ist wieder bei 
dunkel anfangen. Es kann sein dass es zu schnell geht, dann mußt Du 
pwm_soll seltener inkrementieren.

Vielleicht wird Dir damit das notwendige Prinzip klar, das Karl Heinz 
auch schon erwähnt hat.

von Michael (Gast)


Lesenswert?

Ok sorry ^^

Naja wäre schon schön wenn ich alle ansteuern könnte ... könnte man halt 
manche Effekte besser sehen  :)

Ansteuerung läuft über ein atmega8 mit multiplexing ... also 3 ebenen 
mit jewahls 9 leds.

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:

> Ansteuerung läuft über ein atmega8 mit multiplexing ... also 3 ebenen
> mit jewahls 9 leds.

In einer Interrupt-Routine?
(Hoffe ich mal ganz stark)

von Michael (Gast)


Lesenswert?

jo klar :)

von Karl H. (kbuchegg)


Lesenswert?

Dann baust du die erst mal um auf Soft-PWM, so dass du für jede LED 
einzeln
die Helligkeit einstellen kannst. Das langsame Dimmen kommt später. Erst
mal muss jede LED unabhängig von allen anderen einen eigenen
Helligkeitswert annehmen können.

> jo klar :)
Sag das nicht. Alles schon gehabt: Cube-Asteuerung in der mainloop per 
'nur die einzuschaltenden LED werden auch eingeschaltet' und dann war 
das Geschrei gross, dass man mit dem Timing nicht hinkommt und je 
nachdem wieviele LED einzuschalten sind die Helligkeit abnimmt.

von Michael (Gast)


Lesenswert?

Hmm dumme frage SOFT PWM ? ... was soll ich denn da umstellen? und wie ? 
...

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Hmm dumme frage SOFT PWM ?


Na genauso wie du das oben gamcht hast.

Wenn du 16 Helligkeitswerte hast, dann brauchst du auch 16 Zeitticks 
dafür. Eine Helligkeit 1 bedeutet, dass die LED nur 1 Zeittick lang 
brennt und 15 Ticks lang nicht.

> ... was soll ich denn da umstellen? und wie ?
> ...

genau darum hab ich dich nach deiner Cubeansteuerung gefragt. Dann 
könnte man das ein wenig konkreter anhand von konkretem Code zeigen. Ich 
weiß ja nicht, wie du deinen Multiplex in die Timer-IST eingepasst hast.

Dem Prinzip nach wird es ungefähr so aussehen

ISR( Timer... )
{
  aktuelle Ebene abschalten

  Ebene++;
  if Ebene == 3
    Ebene = 0

  Leds der Ebene "Ebene" einschalten

}

und das erweiterst du noch um eine Software-PWM


ISR( Timer... )
{
  aktuelle Ebene abschalten

  Ebene++;
  if Ebene == 3 {
    Ebene = 0
    Pwm_counter++;
    if Pwm_counter == 16
      Pwm_counter = 0
  }

  Leds der Ebene "Ebene" einschalten, wenn
  der Pwm_Counter < Helligkeitswert dieser Led
}

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hier mal mein code

von Karl H. (kbuchegg)


Lesenswert?

Darf ich dich fragen, warum du mich verarscht und du mir sagst, du 
machst das Multiplexing des LED-Cube in einer Timer-ISR?

Das ist genau der besch.... Code, den ich weiter oben gemeint habe!
Tritt ihn in die Tonne und mach erst mal die Cube Ansteuerung richtig, 
ehe du da was dimmen willst. Solange das nicht richtig ist, hat es 
keinen Sinn sich weitere Gedanken darüber zu machen.

von Michael (Gast)


Lesenswert?

Sorry ... dann hab ich dich falsch verstanden. Also kann ich das 
garnicht machen oder wie ? oder was würdest du mir jetzt empfehlen zu 
machen ?

von Karl H. (kbuchegg)


Lesenswert?

Neues Programm

du hast ein globales
uint8_t Led[3][3]
welches 1 Ebene deines Cube repräsentiert. Jedes Array-Element steht für 
1 LED in dieser Ebene. Werte: 0 für LED aus, 1 für LED ein

wie muss der Code aussehen, der dieses 2D Array abklappert und alle LED 
einer Ebene entsprechend den Werten dieses Arrays ein bzw. ausschaltet. 
Und zwar so, dass alle LED gemeinsam und gleichzeitig(!), also nicht 
gemultiplext, leuchten können.

Damit gehts los.

von Michael (Gast)


Lesenswert?

Hmm .. wüsste ich jetzt nicht wie ich da anfangen soll ... sorry wollte 
dich net verarschen ... kannste vllt bisschen näher erklären .. steh da 
grad aufm schlauch .... danke schonmal das du so hilfsbereit bist ;)

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Hmm .. wüsste ich jetzt nicht wie ich da anfangen soll ... sorry wollte
> dich net verarschen ... kannste vllt bisschen näher erklären .. steh da
> grad aufm schlauch .... danke schonmal das du so hilfsbereit bist ;)


Du musst ALLE Leds einer Ebene auf einen Rutsch ein/ausschalten können!

In der ISR passiert dann nämlich folgendes:
1
ISR( Timer .... )
2
{
3
  alle momentan brennenden LED ausschalten
4
5
  Ebene++;
6
  if( Ebene == 3 )
7
    Ebene = 0;
8
9
  alle Leds der Ebene 'Ebene' einschalten, sofern sie eingeschaltet werden müssen
10
}

Das ist Multiplexing über die Ebenen. Und dazu musst du abhängig vom 
Array, welches den logischen Zustand des Cube darstellt, eben alle Led 
in einer Ebene ein bzw. ausschalten können. Je nachdem, wie es das Array 
vorschreibt.

In deiner Hauptschleife wird dann im Array eine 1 bzw. 0 eingetragen, 
wenn die LED leuchten soll. Tatsächlich eingeschaltet wird sie aber erst 
durch den Timerinterrupt, der regelmässig alle Ebenen nacheinander 
durchgeht und die jeweilige Ebene als ganzes anzeigt. Bis dann eben nach 
ein paar µs der Timerinterrupt erneut kommt und die nächste Ebene 
anzeigt. Immer reihum, eine Ebene nach der anderen.

Und dazu brauchst du Code, der eine Ebene als ganzes bearbeiten kann.
Im Endeffekt wird das Array dann ein
uint8_t Led[3][3][3];
werden. Aber ich dachte mir, ein 2D Array wird dich schon vor genügend 
Probleme stellen, also lass ich die 3.te Dimension erst mal weg.

Wie sieht dein Schaltplan aus?
Ich kann mich noch dunkel erinnern, dass du da gar nicht alle LED einer 
Ebene gleichzeitig brennen lassen kannst. Stimmt das?

Wenn das so ist, dann gehts nämlich überhaupt nicht nicht vernünftig 
bzw. wird horrend aufwendig bei miesen Ergebnissen. Dann muss das ganze 
komplett anders gemacht werden. Dann braucht man eine Liste von Leds die 
brennen sollen und der Interrupt muss diese Liste reihum abarbeiten. Ist 
besch..., geht aber nicht anders.

Aber sei es wie es sei: Eines deiner Muster darf auf keinen Fall so 
realisiert sein, dass das Muster selbst die Portpins ansteuert. Sobald 
du das machst, hast du schon verloren. Ein Muster trägt in eine 
Datenstruktur ein, welche LED zu brennen haben und ein allgemeiner 
Mechanismus, der ständig im Hintergrund mitläuft, schnappt sich diese 
Beschreibung und bringt die LED entsprechend zum leuchten.

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.