Forum: Compiler & IDEs LED Helligkeit festlegen mit Soft-PWM ( ATMEGA8 )


von Firebird (Gast)


Lesenswert?

Hallo zusammen

Aus freude an der Sache habe ich mir ein Entwicklungsboard MySmartUSB 
(mit ATMEGA8 Prozessor) zugelegt und wage die ersten Schritte im 
Programmieren. Dazu habe ich mir eine LED-Platine zusammengelötet um zu 
experimentieren.

Die Idee sieht wie folgt aus: Wenn PINC0 aktiv ist sollen die LEDS an 
PINB1 und PINB2 mit reduzierter Helligkeit leuchten (case 0xc1). Wenn 
PINC1 zugeschaltet wird soll die LED an PINB1 mit voller Helligkeit 
leuchten, d.h. ohne Soft-PWM und PINB2 weiterhin mit reduzierter 
Helligkeit (case 0xc3).

Hier ist mein bestehender C-Code:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
  int main(void)
5
  {
6
  
7
  DDRC = 0x00;     // Port C ist Eingang
8
  PORTC = 0xff;    // Port C ist auf "high" gelegt
9
  
10
  DDRB = 0xff;     // Port B ist Ausgang
11
  PORTB = 0x00;    // Port B ist auf "low" gelegt
12
  
13
  DDRD = 0xff;     // Port D ist Ausgang
14
  PORTD = 0x00;    // Port D ist auf "low" gelegt
15
  
16
  volatile unsigned char input;
17
  
18
  while(1)
19
  {
20
  
21
  input =~ PINC;  // LEDs an Anode (+5V) und Kathode an GRD; also invertiert
22
 
23
  switch (input)
24
   
25
  {
26
    case 0xc1:                          // Schalter 1 zu, Schalter 2 offen
27
    PORTB = ((1<<PINB1) | (1<<PINB2));  // LED1 & LED2 Helligkeit reduziert
28
    break;
29
    
30
    case 0xc3:                          // Schalter 1 & 2 zu
31
    PORTB = ((1<<PINB1) | (1<<PINB2));  // LED1 volle Helligkeit und LED2 reduziert 
32
    break;
33
    
34
    default:                 // Zeigt das keine Inputs aktiv sind
35
    PORTB = (1<<PINB3);      // LED3 an PINB3 
36
  }
37
  _delay_ms(1000);           // Verzögerung um CPU Last zu reduzieren
38
  }
39
  }

Ich habe mir die Soft-PWM im Tutorial zu gemüte geführt. Leider fehlt 
mir das Verständnis um meine Idee zu realisieren. Das Beispiel für 
PWM-Modi unter 
http://www.rn-wissen.de/index.php/Timer/Counter_(Avr)#Die_verschiedenen_PWM-Modi 
scheint mir im Prinzip naheliegend (?). Hier kann man den PWM-Wert 
festlegen, wobei ich die Output-Pins selber bestimmen möchte.

Vielleicht kann mir jemand helfen die Lösung zu erarbeiten.

von Firebird (Gast)


Lesenswert?

In der Zwischenzeit bin ich ein paar Schritte vorwärts gekommen. Ich 
habe under "case 0xc1" eine Bibliotek pwmLed1() eingefügt. Das sieht so 
aus:
1
#include <avr/io.h>
2
3
int pwmLed1 (void)
4
  {  
5
  int pwm_phase=0, pwm_soll=90;    // Dimmerwert definieren
6
  
7
  while(1)
8
  {
9
    if(pwm_soll==pwm_phase)
10
    {
11
      PORTB = ((1<<PINB1) | (1<<PINB2));    //  LED1 & LED2 Helligkeit reduziert
12
    }
13
    pwm_phase++;
14
    if(pwm_phase==100)
15
    {
16
      pwm_phase=0;
17
      PORTB = 0x00;
18
    }
19
    }
20
  return(0);
21
  }

Die LEDs werden gedimmt, wie gewünscht. Aber, wenn das Programm einmal 
in pwmLed1() ist bleibt es dort hängen.

Was habe ich übersehen?

von Oliver (Gast)


Lesenswert?

>while(1)

bildet nun mal eine Endlosschleife. Da gibt es kein Entrinnen. Und 
pwmLed1() ist eine Funktion, keine Bibliothek.

Oliver

von Stefan E. (sternst)


Lesenswert?

Oliver schrieb:
>>while(1)
>
> bildet nun mal eine Endlosschleife. Da gibt es kein Entrinnen

Gibt es schon, nennt sich "break" und "return" (und noch ein paar 
weniger gebräuchliche, wie "goto" oder "longjump()").

Sind im Code aber nicht vorhanden, also Endlosschleife = Endstation.

von Firebird (Gast)


Lesenswert?

Danke euch beiden für die Hinweise. Jetzt werde ich wohl einen anderen 
Lösungsansatz suchen müssen. Habt ihr eventuell einen Tipp?

von Firebird (Gast)


Lesenswert?

Ok, ich habe mir mal die 8-kanalige PWM mit intelligenter Lösungsansatz 
probiert. Es funktioniert mit den angegebenen Test Values.

Als Anfänger komme ich jetzt leider nicht mehr weiter und bitte um 
Starthilfe. Wie kann ich jetzt z.B. 8 LEDs mit unterschiedlicher 
Helligkeit unten einbinden?
1
int main(void)
2
{
3
    // PWM Port einstellen
4
    
5
    PWM_DDR = 0xFF;         // Port als Ausgang
6
    
7
    // Timer 1 OCRA1, als variablem Timer nutzen
8
 
9
    TCCR1B = 2;             // Timer läuft mit Prescaler 8
10
    TIMSK |= (1<<OCIE1A);   // Interrupt freischalten
11
 
12
   sei();                   // Interrupts gloabl einschalten
13
 
14
volatile unsigned char input;
15
16
????????????
17
  
18
  while(1)
19
    {
20
    input = ~PINC;         // LEDs an Anode (+5V) und Kathode an GRD; also invertiert
21
   
22
    switch (input)
23
    {
24
      case 0xc1:           // Schalter 1 zu, Schalter 2 offen
25
        ????;
26
      break;
27
   
28
      case 0xc3:           // Schalter 1 & 2 zu
29
        ????;
30
      break;
31
   
32
      default:             // Zeigt das keine Inputs aktiv sind
33
        PORTB |= 0x10;     // LED5 an PINB4
34
    }  
35
    }
36
  return 0;
37
}

Besten Dank

von Firebird (Gast)


Lesenswert?

Jetzt hab ich's fast. Die LED Helligkeiten kann ich problemlos 
bestimmen, aber sie blinken unregelmässig, als ob sie unter 
"Wackelkontakt" leiden. Waran könnte das liegen?
1
volatile unsigned char input;
2
3
const uint8_t t1[8] = {150, 150, 150, 150, 0, 150, 0, 0};
4
const uint8_t t2[8] = {0, 200, 200, 200, 0, 50, 0, 0};
5
const uint8_t d[8] = {0, 0, 0, 0, 0, 0, 0, 0};
6
7
  while(1)
8
    {
9
    input = ~PINC;    // LEDs an Anode (+5V) und Kathode an GRD; also invertiert
10
    
11
   
12
    switch (input)
13
    {
14
      case 0xc1:        // Schalter 1 zu, Schalter 2 offen
15
        memcpy(pwm_setting, t1, 8);
16
        pwm_update();  
17
      break;
18
19
      case 0xc3:               // Schalter 1 & 2 zu
20
        memcpy(pwm_setting, t2, 8);
21
        pwm_update();
22
      break;
23
24
      default:       // Zeigt das keine Inputs aktiv sind
25
        memcpy(pwm_setting, d, 8);  // LEDs off
26
        pwm_update();  
27
    }
28
    }
29
  return 0;
30
}

von Falk B. (falk)


Lesenswert?

@ Firebird (Gast)

>Jetzt hab ich's fast. Die LED Helligkeiten kann ich problemlos
>bestimmen, aber sie blinken unregelmässig, als ob sie unter
>"Wackelkontakt" leiden. Waran könnte das liegen?

Deine Tastenabfrage ist komisch. Mach es lieber einfach per

1
  if(input & (1<<PC0)) {}    /// Taste an PC0 gedrückt

MFG
Falk

von Firebird (Gast)


Lesenswert?

@ Falk

Danke für den Hinweis. Ich habe es wie folgt ausprobiert:
1
  while(1)
2
  {
3
    input = ~PINC;    // LEDs an Anode (+5V) und Kathode an GRD; also invertiert
4
    if (input & (1<<PINC0))         // Schalter 1 zu, Schalter 2 offen
5
    {
6
      memcpy(pwm_setting, t1, 8);
7
      pwm_update();
8
    }
9
    if (input & (1<<PINC1))         // Schalter 1 offen, Schalter 2 zu
10
    {
11
      memcpy(pwm_setting, t2, 8);
12
      pwm_update();
13
    }
14
    if (input & ((1<<PINC0)|(1<<PINC1)))  // Schalter 1 und 2 zu
15
    {
16
      memcpy(pwm_setting, t3, 8);
17
      pwm_update();
18
    }
19
    else
20
    {
21
      memcpy(pwm_setting, d, 8);    // LEDs off
22
      pwm_update();
23
    }
24
  }
25
  return 0;

Es funktioniert besser wobei dazu kommt, dass die einzelnen Fälle nicht 
sauber erfasst werden:
Für (1<<PINC0) flackern die LEDs
Für (1<<PINC1) flackern sie ein bischen weniger
Für ((1<<PINC0)|(1<<PINC1)) leuchten die LEDs analog wie für (1<<PINC0)
Die else Anweisung wird nicht erkannt ausser wenn INPUT =~PINC

In meiner Switch Anweisung habe ich "0xc1" und "0xc3" verwendet um alle 
PINC Zustände zu erfassen. Sobald ich dort mit einzelnen PINC Zustände 
(analog oben) gearbeitet habe gab es die gleichen Probleme.

An meinem ATMEGA8 wird PINC6 für Reset verwendet und PINC7 ist gar nicht 
vorhanden, deswegen die "c" in "0xC1".

Mit freundlichem Gruss
Firebird

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.