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


von Björn R. (sushi)


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:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
int main(void)
5
{
6
  PORTB=(1<<PB0);
7
  TCCR0A=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted OC0A
8
  TCCR0B=(1<<CS02)|(1<<CS00); //Prescaler 1/1024
9
  OCR0A=0;
10
  //Hauptschleife
11
  while(1)
12
  {
13
    OCR0A=OCR0A+1;
14
    if(OCR0A==255)OCR0A=0;
15
    _delay_ms(100);
16
    
17
  }
18
}

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

von STK500-Besitzer (Gast)


Lesenswert?

>Was habe ich vergessen???

Vielleicht das Datadirection-Register?

von Marius W. (mw1987)


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

von Björn R. (sushi)


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

von spess53 (Gast)


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

von spess53 (Gast)


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

von Björn R. (sushi)


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:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
int main(void)
5
{
6
  DDRB=(1<<PB0);
7
  TCCR0A=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted OC0A
8
  TCCR0B=(1<<CS01)|(1<<CS00); //Prescaler 1/64
9
  OCR0A=0;
10
  //Hauptschleife
11
  while(1)
12
  {
13
    OCR0A=OCR0A+1;
14
    if(OCR0A==255)OCR0A=0;
15
    _delay_ms(20);
16
    
17
  }
18
}
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

von spess53 (Gast)


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

von STK500-Besitzer (Gast)


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...).

von Björn R. (sushi)


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

von Björn R. (sushi)


Lesenswert?

Ich mach mal hier weiter ;-)

Das nächste absolut unerklärliche Problem für mich:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/pgmspace.h>
4
5
6
uint8_t pwmtable[32] PROGMEM= {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11,
7
                                    13, 16, 19, 23, 27, 32, 38, 45, 54, 64, 76,
8
                                    91, 108, 128, 152, 181, 215, 255};
9
10
11
int main(void)
12
{
13
  DDRB=(1<<PB0);
14
  TCCR0A=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted OC0A
15
  TCCR0B=(1<<CS01)|(1<<CS00); //Prescaler 1/64
16
  OCR0A=0;
17
  uint8_t i =0;
18
  //Hauptschleife
19
  while(1)
20
  {
21
    
22
    for(i=0;i<32;i++)
23
    {
24
      OCR0A=pgm_read_byte(&pwmtable[i]);
25
      _delay_ms(100);
26
    }
27
    for(i=31;i>=0;i--)
28
    {
29
      OCR0A=pgm_read_byte(&pwmtable[i]);
30
      _delay_ms(100);
31
    }
32
    
33
    
34
  }
35
}

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

von Falk B. (falk)


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

von Björn R. (sushi)


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

von Björn R. (sushi)


Angehängte Dateien:

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:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
int main(void)
5
{
6
  DDRB=(1<<PB0)|(1<<PB1)|(1<<PB4);
7
  //Timer 0(R,G)
8
  TCCR0A=(1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00); //fast-pwm, non inverted, OC0A, OC0B
9
  TCCR0B=(1<<CS01)|(1<<CS00); //Prescaler 1/64
10
  //Timer 1(B)
11
  TCCR1=(1<<CS10)|(1<<CS11)|(1<<CS12);//Prescaler 1/64
12
  GTCCR=(1<<PWM1B)|(1<<COM1B1);//PWM, non-inverted, OC1B
13
  //Timer 1 TOP
14
  OCR1C=255;
15
  
16
  OCR0A=0;
17
  OCR0B=0;
18
  OCR1B=0;
19
  uint8_t r =0;
20
  uint8_t g =31;
21
  uint8_t b =31;
22
  uint8_t phase = 0;
23
  //Hauptschleife
24
  while(1)
25
  {
26
    
27
    OCR0A=r;
28
    OCR0B=g;
29
    OCR1B=b;
30
    
31
    switch(phase)
32
    {
33
      case 0:
34
        b--;
35
        if(b==0) phase++;
36
        break;
37
      case 1:
38
        r++;
39
        if(r==255) phase++;
40
        break;
41
      case 2:
42
        g--;
43
        if(g==0) phase++;
44
        break;
45
      case 3:
46
        b++;
47
        if(b==255) phase++;
48
        break;
49
      case 4:
50
        r--;
51
        if(r==0) phase++;
52
        break;
53
      case 5:
54
        g++;
55
        if(g==255) phase++;
56
        break;
57
        
58
      case 6: phase=0;
59
        
60
    }
61
      
62
    _delay_ms(10);
63
    
64
  }
65
}

LG, Björn

von poly (Gast)


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.

von Läubi .. (laeubi) Benutzerseite


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.

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.