mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR Hardware PWM - ich raffs nicht


Autor: Björn R. (sushi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!
Ja, das Thema gabs schon öfter ;-)
Ich hab diverse Threads durch und auch das LED-Dimmen laut Artikel läuft 
auf dem dort auch verwendeten Mega8.

Ich habe mittlerweile aus dem Vorhaben, einen RGB-LED Controller zu 
bauen, eins gemacht, erstmal nur eine LED irgendwie zu faden und die PWM 
zum laufen zu bringen. Quasi ein Minimal-Programm:
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
  PORTB=(1<<PB0);
  TCCR0A=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted OC0A
  TCCR0B=(1<<CS02)|(1<<CS00); //Prescaler 1/1024
  OCR0A=0;
  //Hauptschleife
  while(1)
  {
    OCR0A=OCR0A+1;
    if(OCR0A==255)OCR0A=0;
    _delay_ms(100);
    
  }
}

Das programm soll auf einem ATTiny25 laufen, die Fuses stehen auf 
Standard (8Mhz interner Oszillator, CKDIV/8 programmiert, also 1Mhz 
Takt).

Keine logarithmische Kurve/Tabelle, nichts, die LED sollte einfach nur 
irgendwie heller werden und dann von vorne anfangen.

Was habe ich vergessen??? Das Ding macht mich seit wochen bescheuert...

EDIT: Mit diesem Programm leuchtet die LED ganz schwach mit einer 
Helligkeit durch. Kein Flackern, nichts. Oszilloskop habe ich leider 
nicht, um zu gucken, was wirklich rauskommt.

Danke für die hilfe im Voraus!
LG, Björn

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Was habe ich vergessen???

Vielleicht das Datadirection-Register?

Autor: Marius Wensing (mw1987)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiß grad nicht auswendig wie das war. Aber eventuell musst du noch 
das Data Direction Bit für den Pin setzen. Das schwache Glimmen könnte 
vom Pull-Up kommen.

MfG
Marius

Autor: Björn R. (sushi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Scheisse wie peinlich...hab PORTB anstatt DDRB geschrieben...wird sofort 
getestet...
In den Programmen vorher war dann viellciht was anderes falsch, also 
nicht dass einer denkt ich verzweifel seit wochen an den 3 zeilen wegen 
dem ddr...

Danke schonmal!
LG, Björn

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Was habe ich vergessen??? Das Ding macht mich seit wochen bescheuert...

Timer0 des ATMega8 hat keine Hardware-PWM! Wenn schon 8-Bit, dann 
musst du Timer2 nehmen.

>Vielleicht das Datadirection-Register?

Quatsch. Die Funktion des OCR-Pins wird mit den COM-Bits

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Dummerweise auf Absenden gedrückt.

>Quatsch. Die Funktion des OCR-Pins wird mit den COM-Bits

im TCC-Register eingestellt. Wenn das PIN mit der Compareeinhet 
verbunden ist kannst du in DDR einstellen, was du willst.

MfG Spess

Autor: Björn R. (sushi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ging um den Tiny25, nicht um den Mega8!
Und, Zitat aus dem Datenblatt:

>>The COM0A1:0 and COM0B1:0 bits control the behaviour of Output Compare >>pins 
OC0A and
>>OC0B, respectively. If any of the COM0A1:0 bits are set, the OC0A output 
>>overrides the normal
>>port functionality of the I/O pin it is connected to. Similarly, if any of >>the 
COM0B1:0 bits are set,
>>the OC0B output overrides the normal port functionality of the I/O pin it >>is 
connected to. How-
>>ever, note that the Data Direction Register (DDR) bit corresponding to the 
>>OC0A and OC0B pins
>>must be set in order to enable the output driver.

Das DDR war der Fehler. Außerdem war die PWM-Frequenz wesentlich zu 
niedrig.
So funktioniert es jetzt:
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
  DDRB=(1<<PB0);
  TCCR0A=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted OC0A
  TCCR0B=(1<<CS01)|(1<<CS00); //Prescaler 1/64
  OCR0A=0;
  //Hauptschleife
  while(1)
  {
    OCR0A=OCR0A+1;
    if(OCR0A==255)OCR0A=0;
    _delay_ms(20);
    
  }
}
nur für die, die es interessiert.

Jetzt kann ich die logarithmische Tabelle einbauen und dann das ganze 
verdreifachen....

Danke nochmals für die Hilfe!
LG, Björn

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Kommando zurück. Soll ja ATTiny25 sein.

Trotzdem musst du in TCCR0A mit COM0A1 und COM0A0 dem Timer sagen, was 
er mit dem Pin machen soll. Wie gesagt, DDR ist egal.

MfG Spess

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Timer0 des ATMega8 hat keine Hardware-PWM! Wenn schon 8-Bit, dann
>musst du Timer2 nehmen.

Den Mega8 habe ich überlesen. Der Tiny25 hat allerdings die gewünschte 
Funktion.

>Wenn das PIN mit der Compareeinhet
>verbunden ist kannst du in DDR einstellen, was du willst.

Ist beim Tiny45 nicht der Fall. (Figure 11-6; Text nicht gelesen, nur 
Bild beguckt...).

Autor: Björn R. (sushi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Trotzdem musst du in TCCR0A mit COM0A1 und COM0A0 dem Timer sagen, was
> er mit dem Pin machen soll.
Hatte ich bereits von Anfang an..
>Wie gesagt, DDR ist egal.
Eben nicht...siehe mein Zitat aus dem Datenblatt oben.

Trotzdem danke für die Hilfe!
LG, Björn

Autor: Björn R. (sushi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mach mal hier weiter ;-)

Das nächste absolut unerklärliche Problem für mich:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>


uint8_t pwmtable[32] PROGMEM= {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11,
                                    13, 16, 19, 23, 27, 32, 38, 45, 54, 64, 76,
                                    91, 108, 128, 152, 181, 215, 255};


int main(void)
{
  DDRB=(1<<PB0);
  TCCR0A=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted OC0A
  TCCR0B=(1<<CS01)|(1<<CS00); //Prescaler 1/64
  OCR0A=0;
  uint8_t i =0;
  //Hauptschleife
  while(1)
  {
    
    for(i=0;i<32;i++)
    {
      OCR0A=pgm_read_byte(&pwmtable[i]);
      _delay_ms(100);
    }
    for(i=31;i>=0;i--)
    {
      OCR0A=pgm_read_byte(&pwmtable[i]);
      _delay_ms(100);
    }
    
    
  }
}

Die LED fadet jetzt einmal hoch und einmal runter wie sie soll, was dank 
der Wertetabelle echt gut aussieht. Danach scheint das Programm aber den 
Programmspeicher zu lesen anstelle der Tabelle. Die LED blinkt wild 
herum, irgendwann fadet sie wieder von ganz hell nach dunkel, dann 
wiederholt sich das Spiel. Irgendwas scheint also mit i nicht zu stimmen 
bzw. mit meinen for-Schleifen...

LG, Björn

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Björn R. (sushi)

>wiederholt sich das Spiel. Irgendwas scheint also mit i nicht zu stimmen

Stimmt genau! ;-)
Mach mal aus deinem i mal ein int8_t ohne u und staune ;-)

>bzw. mit meinen for-Schleifen...

Schau dir mal die zweite Schleife an.

MFG
Falk

Autor: Björn R. (sushi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, Falk! Da wäre ich so schnell nicht drauf gekommen. Auch nachdem 
ich es ausprobiert hatte und es auf einmal funktionierte, hat es die 
Zahnräder im Hirn etwas drehen müssen, bis der Groschen gefallen ist...

Spitze!
LG, Björn

Autor: Björn R. (sushi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, das RGB-faden funktioniert jetzt auch. Allerdings hat es mit der 
exponentiellen Kennlinie nicht so gut funktioniert, da waren dann 
hauptsächlich die grundfarben zu sehen und die Mischfarben nur sehr 
kurz. Ich habe dann mit mehreren anderen Kennlinien experimentiert, 
wobei sich herausstellte, dass es mit einer linearen doch am Besten 
klappt. Ich vermute, die Kennlinie meiner RGB-LED ist dahingehend 
angepasst, dass man mit einer linearen PWM da schön faden kann. Leider 
habe ich dafür keine Beweise, da ich kein Datenblatt dazu habe. 
Überhaupt habe ich da wohl am falschen Ende gespart, die 3 Chips 
strahlen nicht in die gleiche Richtung. man hat also immer Ränder in den 
beteiligten Grundfarben mit dabei. Im Anhang die kennlinien, die ich 
ausprobiert habe(naja die braune nicht mehr, da war es schon klar), 
bevor ich das feature rausgenommen und einfach von 0 bis 255 
durchgelaufen bin. Das Programm sieht jetzt so aus:
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
  DDRB=(1<<PB0)|(1<<PB1)|(1<<PB4);
  //Timer 0(R,G)
  TCCR0A=(1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted, OC0A, OC0B
  TCCR0B=(1<<CS01)|(1<<CS00); //Prescaler 1/64
  //Timer 1(B)
  TCCR1=(1<<CS10)|(1<<CS11)|(1<<CS12);//Prescaler 1/64
  GTCCR=(1<<PWM1B)|(1<<COM1B1);//PWM, non-inverted, OC1B
  //Timer 1 TOP
  OCR1C=255;
  
  OCR0A=0;
  OCR0B=0;
  OCR1B=0;
  uint8_t r =0;
  uint8_t g =31;
  uint8_t b =31;
  uint8_t phase = 0;
  //Hauptschleife
  while(1)
  {
    
    OCR0A=r;
    OCR0B=g;
    OCR1B=b;
    
    switch(phase)
    {
      case 0:
        b--;
        if(b==0) phase++;
        break;
      case 1:
        r++;
        if(r==255) phase++;
        break;
      case 2:
        g--;
        if(g==0) phase++;
        break;
      case 3:
        b++;
        if(b==255) phase++;
        break;
      case 4:
        r--;
        if(r==0) phase++;
        break;
      case 5:
        g++;
        if(g==255) phase++;
        break;
        
      case 6: phase=0;
        
    }
      
    _delay_ms(10);
    
  }
}

LG, Björn

Autor: poly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sind nicht zufällig die Flux-LEDs ausm Ebay-Shop "shop4leds" oder? 
Da ist mir das mit den Farbrändern auch schon unangenehm aufgefallen. 
Wenn du besseren Ersatz findest (schön hell sind sie a schon), oder 
jemand bessere helle RGB-LEDs kennt, teilt das mal bitte mit.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest lieber HSB statt RGB Codierung nutzen wenn du die Farben 
durchgehen möchtest.
In der Codesammlung hat mal jemand einen entsprechenden Konverter 
vorgestellt.

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.