0-5 V in PWM mit ATmega

  • Guten Tag,
    Also ich hab bei mir einige LED-Leisten die dimme ich zu zeit mit einem ATMega8
    der meine 0-5v in PWM umwandelt.
    Mein Problem ist jetzt das die Dimmstufen ziemlich ruckelig sind besonders im unteren Bereich.
    Ich selber kenn mich fast gar nicht mit der Programmierung von µC aus.
    Den jetzigen Code hat mir ein freundliches Mitglied von http://www.mikrocontroller.net geschrieben
    ist aber schon über ein Jahr her.
    Hab natürlich wieder nachgefragt, ob jemand mein Code editieren kann, hat sich aber keiner gemeldet.
    Nur wurde mir geraten mich paar Monate damit zu beschäftigen, bis ich es selber kann. Leider habe ich nich die Zeit dafür.


    Deswegen wollte ich hier mal nachfragen, ob jemand hier so freundlich ist und mein Code editieren kann.


    Die LED,s sollen jetzt logarithmisch gedimmt werden. Wie hier beschrieben http://www.mikrocontroller.net/articles/LED-Fading.
    Sollte mein Problem beheben oder ?


    Hier der aktuelle code:


    Vielen Dank im Voraus

  • Grundsätzlich willst du mit 8 Bit dimmen. 8 Bit können max. 256 Stufen liefern (2^8 = 256). Selbst wenn du fast alle Werte auf den unteren Bereich verteilst, wirst du vermutlich immer Stufen sehen. Im unteren Bereich ist das Auge sehr empfindlich, was Helligkeitsunterschiede angeht. Daher wären mehr als 8 Bit besser.


    Ansosnten müsstest du den Code zw. Zeile 31 und 32 auf logarithmisch ändern, also nicht x = 255 - adc_read() (linear), sondern irgendwas mit Wertezuordnung, wobei die Werte schon logarithmisch abgelegt sind. So'n AVR wird sich mit der Berechnung vom Logarithmen schwer tun. In dem Link zum LED-Fading stehen die Werte schon drin const uint16_t pwmtable_16[256] PROGMEM =


    Also könnte man es vllt. so machen:
    OCR1A = pwmtable_16[adc_read8(PC0)];


    Das mal eben auf die schnelle aus der Hüfte geschossen. Habe leider ein wenig Zeitdruck..... [Blockierte Grafik: http://home.arcor.de/kgenius/pix/icon_nerved.gif]

  • Ich habe mit diesen Werten hier sehr gute Erfahrungen gemacht mit meiner 8bit PWM-Dimmung:
    0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 19, 24, 29, 35, 43, 52, 64, 78, 95, 116, 141, 172, 209, 255


    Daraus folgt dieser Code:

    Code
    const uint8_t pwmtable[26]  PROGMEM = { 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 19, 24, 29, 35, 43, 52, 64, 78, 95, 116, 141, 172, 209, 255 }; Muss in Zeile 7


    aus

    Code
    return ADCH; (Zeile 44) wird
    return ADCH/10;


    und aus

    Code
    OCR1A = 255-adc_read8(PC0);
    OCR1B = 255-adc_read8(PC1);


    wird

    Code
    OCR1A = 255-pwmtable[adc_read8(PC0)];
    OCR1B = 255-pwmtable[adc_read8(PC1)];





    Das ist jetzt mal ein sehr einfacher Ansatz - aber vielleicht gefällt er dir ja schon.

  • Also erst mal vielen dank für eure Hilfe.


    Hab grad den Code von Fakrae aufgespielt.
    Aber irgendwie stimmt was nicht damit scheint noch ein Fehler drin zu sein.
    Die LEDs Blinken in unsymmetrischen abständen und gehen dann aus.
    Was muss ich noch ändern?


    Hier ist der Code, den ich eingespielt habe:

  • Der Fehler ist (u. a.) der, dass die Funktion adc_read8() einen Rückgabewert vom Typ 'char' hat und der Typ ist 8-Bit groß, kann also Werte von 0 bis 255 annehmen. Das sind 256 Werte. Der ADC wird auch real in dem Bereich Werte zurückliefern, kann auch sein, dass es nur 250 Werte sind (steht genauer im Datenblatt). Mit diesen 256 verschiedenen Werten greift das Programm auf eine Tabelle zu, die nur aus 26 Werten besteht (unsigned char pwmtable[26]). Was, wenn der ADC den Wert 83 zurück gibt? Dann wird auf das 83. Element der pwmtable[] zugegriffen und das gibt es nicht, bei 25 bzw. pwmtable[25] ist nämlich Schluss (0...25 = 26 Werte). Also musst du die Tabelle auf 250/256 Werte erweitern oder aber den Rückgabewert auf den Bereich 0 bis 25 runterskalieren. Ersteres wäre sinnvoller, weil hier die Abstufung feiner ist und du am meisten dabei rausholst. Mit runterskalieren geht die Genauigkeit phlöten. Sähe ungefähr so aus:


    ADC-Wert im Bereich 0 bis 4 => Rückgabewert := 0
    ADC-Wert im Bereich 5 bis 9 => Rückgabewert := 1
    ADC-Wert im Bereich 10 bis 14 => Rückgabewert := 2
    ADC-Wert im Bereich 15 bis 19 => Rückgabewert := 3
    usw.


    Das ist suboptimal. Wenn das Programm aber auf das 83. Element der Tabelle zugreifen will, wird irgendein Wert aus dem Speicher gelesen, der nicht zur Tabelle gehört (Speicherzugriffsfehler oder segmentation fault/access violation, endet schonmal im Programmabsturz). Dass können andere Konstanten sein oder wenn da nichts drin steht, 0xFF = 255. Und aus der Anweisung OCR1A = 255-pwmtable[adc_read8(PC0)] wird dann z. B. OCR1A = 255-pwmtable[83] => OCR1A = 255-255 => OCR1A = 0 => LED aus (vermutlich, oder an).


    EDITH: Habe da wohl Mist geschrieben... [Blockierte Grafik: http://home.arcor.de/kgenius/pix/icon_yawn.gif] schon speeeeht! Kukk mah auffe Uhr!


    In der Funktion adc_read8()wird ja der Rüickgabewert auf den Bereich 0 bis 25 runterskaliert (Zeile 47), runden fällte wohl aus, weil 255 ÷ 10 = 25 sein wird. Wie auch immer, ich würde die PWM-Tabelle mit 256 Werten füllen und die gesamte Auflösung des ADC für die Dimmwerte benutzen. So wird nix verschenkt.

  • Du kannst auch



    versuchen - bleiben wir mit dem Array mal komplett im RAM und lassen mal die Charakters außen vor.

  • Für 256 Stufen musst du hier { 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 19, 24, 29, 35, 43, 52, 64, 78, 95, 116, 141, 172, 209, 255 }
    eben 256 Werte rein schreiben (aber bitte nicht 0,1,2,...,254,255 - das ist nicht logarithmisch ^^) und bei Zeile 43 das "/10" weglassen


    Die werte kannst du bspw über die angehängte Exceltabelle berechnen lassen (Bei Steps 255 eintragen und dann eben am Ende so anpassen, dass kein Wert >255 vorkommt)



    EDIT: und natürlich pwmtable[26] in pwmtable[256] ändern

  • Danke Fakrae
    Also habe jetzt die Tabelle wie du gesagt hast berechnet und eingefügt.
    Dimmt aber immer noch in sehr sehr groben Stufen. Habt ihr noch mehr Ideen, was man machen kann??


    Hier der aktuelle Code:


    EDIT:
    Der Sprung in der Tabelle von 1 zu 2 ist zu stark. Da fehlen die Zwischenschritte.
    Hab ich die Tabelle so richtig gemacht?

  • Mit 8bit hast du keine Möglichkeit, den Sprung 1-> 2 weniger stark zu machen.


    Ich hab jetzt nicht gezählt, aber wenn die Tabelle 256 Werte umfasst ist sie richtig ^^


    Es könnte auch sein, dass die ADC generell etwas grob auflöst, aber das kann ich von hier aus nicht sagen oder ändern.

  • Dimmt aber immer noch in sehr sehr groben Stufen. Habt ihr noch mehr Ideen, was man machen kann??


    Ich zitiere mich mal selbst:

    Grundsätzlich willst du mit 8 Bit dimmen. 8 Bit können max. 256 Stufen liefern (2^8 = 256). Selbst wenn du fast alle Werte auf den unteren Bereich verteilst, wirst du vermutlich immer Stufen sehen. Im unteren Bereich ist das Auge sehr empfindlich, was Helligkeitsunterschiede angeht. Daher wären mehr als 8 Bit besser.


    Ergo, 8-Bit reichen nicht für eine nicht mehr sichtbare Abstufungn nicht aus. Soweit ich weiß sind dazu mindestens 10-Bit = 1024 Stufen notwendig. Es gibt eine Möglichkeit, mit einem 8-Bit AVR auch mehr als 8-Bit PWM zu erreichen. Schauste hier mal: http://www-user.tu-chemnitz.de…ikrocontroller/3PWM16.htm
    Ist zwar in Assembler aber vllt. passt alles schon so wiedes haben willst.


    EDITH: Schlage vor, dass du dir selber eine Lösung erarbeitest, so lernt man am meisten. Oder frag' mal Tante Guhgel.
    Bzgl. ADC: Der hat eine maximale Auflösung von 10-Bit, also sollten 10-Bit vom ADC auch zu 10-Bit PWM werden.

  • Die Umwege von Sabu brauchen wir nicht zu gehen, weil der ATMega8 schon über einen 16bit Timer verfügt - ich werd mal bei Gelegenheit da rein schauen was wir genau ändern müssen.
    (Der Timer1, der verwendet wird ist schon der 16bit Timer - aber hab grad keine Zeit mich da rein zu denken)

  • Code
    Der Code war falsch - für richtigen Code siehe Ende dieser Seite (10bit) oder auf Seite 2 (16bit)



    Wenn du jetzt noch 1024 Werte in dein Array schreibst müsste es eigentlich besser abstufen können (Auflösung vervierfacht) - ich hoffe ich habe nichts zu ändern vergessen. Ich hoffe deine Platine ist auch gut genug aufgebaut, damit du die 10bit ADC auch benutzen kannst - der ist da nämlich durchaus etwas empfindlich was Spannungssschwankungen angeht.




    EDIT:Fehlerhaft, siehe nächster Beitrag.

  • Wird Zeit, dass ich mich mal wieder mit den kleineren uC beschäftige - wenn ich immer mit den großen arbeite denke ich an solch "unwichtige" Sachen wie Speicherbeschränkungen gar nicht mehr ^^


    Okay, dann müssen wir wohl doch nach dem PROGMEM / pgm_read_byte schauen. Mit welchem Programm kompilierst du denn? Vielleicht wird da die Makrofunktion nicht unterstützt.

  • Eigentlich schon, der benutzt mittlerweile auch den normalen GCC.
    Okay, vielleicht hat er sich auch an dem "uint_8t" verschluckt. Versuchen wir mal das hier - natürlich wieder das Array entsprechend aufblasen (auf 1024 Werte).