LED Helligkeit festlegen mit Soft-PWM ( ATMEGA8 )

Gast #1290009
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.
Gast #1294505
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?
Gast #1308589
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
Gast #1309868
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
}
Gast #1311117
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren