LEDs langsam auf- und wieder abdimmen

OP #2575662
Lesenswert?

Hallo,
ich bin Anfänger im Programmieren in C. Ich möchte  LEDs langsam auf- 
und wieder abdimmen. Die Idee dabei ist, eine pwm zu erzeugen deren 
Pulsbreite langsam zunimmt. Dazu soll der timer alle 5 ms den Wert einer 
Variablen verändern der dann in das Register OCR1A eingelesen wird. 
Leider funktioniert es nicht. Wer kann mir helfen?
sunmoon
Angehängte Dateien:
Gast #2575766
Lesenswert?

Zwei Anmerkungen:

C-Quellen lassen sich als solche einbinden.

und

Du änderst zwar die Variable "lauf" sehr schön, schreibst sie aber nur 
einmal, nämlich im "init" nach OCR1A, danach nicht mehr. Ich würde also 
erwarten, das PWM immer auf Maximum oder Minimum bleibt.
Richtig?

Ahoi, Martin
Gast #2576646
Lesenswert?

Klaus Dieter schrieb:
> Und bevor du dich wunderst, dass das Ganze nicht schön langsam auf und
> ab geht, guck dir folgenden Artikel mal an:
> http://www.mikrocontroller.net/articles/LED-Fading

danke! das ist kompliziert aber könnte helfen. Allerdings meckert meine 
Programmierumgebung daran herum.
Aber nochmal zu meiner eigenen Programmierung: Die ISR sollte die 
Variable "lauf" Schritt für Schritt verringern, tut sie aber nicht. 
Warum?
Wenn ich "lauf" per hand ändere geht die LED je nachdem an oder aus oder 
ist nur halb hell, das funktioniert also.-
Ich habe damit nochmal herumbrobiert, siehe txt- Datei, leider 
funktioniert es immernoch nicht.
Grüße
A
Angehängte Dateien:
Gast #2576700
Lesenswert?

>   if (lauf==0); lauf=10200;

Was meinst du, was das erste Semikolon bewirkt? Der Compiler übersetzt 
leider immer was da steht und nicht, was der Programmierer gemeint hat.

Hast du im Simulator mal geguckt, ob alles so abläuft, wie du dir das 
gedacht hast?
#2576885
Lesenswert?

1
#ifndef F_CPU
2
#define   F_CPU   4000000
3
#endif
4
#include <avr\io.h>
5
#include <avr\interrupt.h>
6
volatile uint16_t lauf=10200;
7
volatile uint8_t isrlauf=0;
8
uint8_t laufup, laufdown;
9
//--------------------------------------------------------------------
10
// TIMER2_COMP_vect - Timer2 Interrupt bei Vergleichswert
11
// aktuelle Einstellung:  200.321 Hz  4.992 ms
12
//--------------------------------------------------------------------
13
ISR(TIMER2_COMP_vect)  //(vorher:   timer2_comp_vect)
14
{
15
//   lauf--;
16
//  if (lauf==0){
17
//     lauf=10200;
18
//  }
19
  isrlauf=1;
20
}
21
//------------------------------------------------------------------------
22
// Initialisierungen
23
//------------------------------------------------------------------------
24
void init()
25
{
26
   // Ports initialisieren
27
   DDRB |= _BV(1);   // PORTB1 auf Ausgang
28
   DDRB |= _BV(2);   // PORTB2 auf Ausgang
29
   DDRD &= ~_BV(2);   // PORTD2 auf Eingang mit PullUp
30
   PORTD |= _BV(2);
31
   //--- Timer 2 initialisieren ---
32
   TCCR2= (1<<CS20)|(1<<CS21);   // Teiler 1/32
33
   TCCR2|=0x08;   // Modus: Zählen bis Vergleichswert (WGM21=1)
34
   OCR2=56;   // Vergleichswert speichern
35
   TIMSK|=0x80;   // Interrupt bei Vergleichswert
36
   
37
   TCCR1A = (1<<COM1A0)|(1<<COM1A1)|(1<<COM1B0)|(1<<COM1B1)|(1<<WGM11);  //
38
  
39
  TCCR1B = (1<<CS10)|(1<<WGM13);
40

41
  ICR1 = 10200;  
42
  OCR1A=lauf;
43
  
44
  laufup=1;
45
  laufdown=0;
46

47
   //--- Interrupts erlauben ---
48
   sei();
49
}
50

51
/////////////////////////////////////////////////////////////////////////////
52
// Main-Funktion
53
/////////////////////////////////////////////////////////////////////////////
54
int main(void)
55
{
56
   init();   // Initialisierungen
57
   for (;;)    // Mainloop-Begin
58
   {
59
    if(isrlauf){
60

61

62
      if(lauf==0){
63
        laufup=1;
64
        laufdown=0;
65
      }
66

67
      if(lauf==10200){
68
        laufdown=1;
69
        laufup=0;
70
      }
71

72
      if(laufup){
73
        lauf++;
74
      }
75

76
      if(laufdown){
77
        lauf--;
78
      }
79

80
        
81
       OCR1A=lauf;
82
      isrlauf=0;
83
    }
84
   } // Mainloop-Ende
85
}
Ist auch nicht schön, aber funktioniert.
Ist mit dem AVR-studio compiliert, sollte daher keine großen Probleme 
machen.
Gast #2577454
Lesenswert?

Hubert G. schrieb:
> st auch nicht schön, aber funktioniert.
> Ist mit dem AVR-studio compiliert, sollte daher keine großen Probleme
> machen.

Hallo Hubert,
danke, das funktioniert auf Anhieb!
Ob schön oder nicht ist mir weniger wichtig.
jetzt noch eine Frage: ist es irgendwie möglich das auf- und abfaden 
auch auf andere Ausgänge des Microcontrollers zu übertragen, oder geht 
das jetzt nur auf dem Ausgang OC1A ??
Grüße
Anando
Gast #2577598
Lesenswert?

A.Z. schrieb:
> jetzt noch eine Frage: ist es irgendwie möglich das auf- und abfaden
> auch auf andere Ausgänge des Microcontrollers zu übertragen, oder geht
> das jetzt nur auf dem Ausgang OC1A ??

Dann mal raus mit der Sprache, was soll das werden?
Möchtest du das Signal auf einem anderen Pin habe? Dazu sagt das 
Datenblatt, dass der ATmega8 auch den OC1B bedienen kann.
Wenn du zwei verschiedene PWM Signale auf OC1A und B erzeugen willst, 
überleg' dir, was du gegenüber dem jetzigen Programmablauf ändern mußt.
Falls du mehr als die beiden PWM Signale brauchst, siehst du aus dem 
Datenblatt, dass dafür keine Hardwareunterstützung im µC vorhanden ist. 
Dann heißt es also: Software-PWM, anderer Prozessor oder externes Dimmer 
IC, wie z.B. die PCA953x Serie, die du dann über I2C/TWI mit dem µC 
steuern kannst.
Gast #2577646
Lesenswert?

Hallo Wolfgang,
was ich will ist folgendes: ich bin Künstler und steuere meine Objekte 
mit Microcontrollern. Zur Zeit baue ich an einem Objekt, daß interaktiv 
sein soll, also die Betrachter können über Taster und evtl anderes (z.B. 
lichtempfindliche Widerstände) in die Steuerung eingreifen. In dem 
Objekt gibt es mehrere Gruppen von LEDs, die langsam auf- und abgedimmt 
werden sollen. Das soll durch ein Programm einerseits automatisch 
ablaufen, andererseits sollen die unterschiedlichen Funktionen durch die 
Betrachter ausgelöst werden können.
Dazu wäre es praktisch, wenn ich das pwm-Signal zu jedem beliebigen 
Zeitpunkt auf jeden beliebigen Port legen könnte.
Das Ganze muss jedoch nicht auf einem Microcontroller programmiert sein, 
sondern ich könnte mir vorstellen, daß mehrere Microcontroller dafür 
zusammenarbeiten.Auch, weil auf dem AT Mega 8, den ich immer benutze, 
nicht genügend PORTs zur Verfügung stehen.
Grüße
Anando

Wolfgang schrieb:
> Dann mal raus mit der Sprache, was soll das werden?
> Möchtest du das Signal auf einem anderen Pin habe? Dazu sagt das
> Datenblatt, dass der ATmega8 auch den OC1B bedienen kann.
> Wenn du zwei verschiedene PWM Signale auf OC1A und B erzeugen willst,
> überleg' dir, was du gegenüber dem jetzigen Programmablauf ändern mußt.
> Falls du mehr als die beiden PWM Signale brauchst, siehst du aus dem
> Datenblatt, dass dafür keine Hardwareunterstützung im µC vorhanden ist.
> Dann heißt es also: Software-PWM, anderer Prozessor oder externes Dimmer
> IC, wie z.B. die PCA953x Serie, die du dann über I2C/TWI mit dem µC
> steuern kannst.
Gast #2577750
Lesenswert?

A.Z. schrieb:
> Dazu wäre es praktisch, wenn ich das pwm-Signal zu jedem beliebigen
> Zeitpunkt auf jeden beliebigen Port legen könnte.

Dann ist für deinen Zweck vielleicht die PCA963x Serie von NCA noch 
besser geeignet. Mit dem PCA9633 kannst du 4, mit dem PCA9634 8 und mit 
dem PCA9635 sogar 16 LEDs unabhängig in der Helligkeit einstellen. Dem 
Baustein schickst du über I2C jeweils einen Helligkeitswert. Um die 
Erzeugung des PWM Signals kümmert sich dann der Baustein ohne weiteres 
Zutun. Am Prozessor brauchst du dann für die LED-Steuerung nur zwei Pins 
und kannst mit dem Konzept im Extremfall 2048 LEDs unabhängig steuern. 
Ob du das voll ausschöpfst, hängt von deinem Objekt ab.

Der Einstieg in die I2C-Steuerung ist sicher etwas aufwändiger, aber 
dann hättest du alle Möglichkeiten. Zu Soft-PWM als Alternative gibt es 
hier im Forum einen Artikel mit einem gan pfiffigen Ansatz:
http://www.mikrocontroller.net/articles/Soft-PWM
Gast #2578225
Lesenswert?

Hallo Wolfgang,
danke für die Tips! Das ist allerdings viel, das muss ich mir erst 
einmal in Ruhe ansehen.
Grüße und Dank
Anando

Wolfgang schrieb:
> Mit dem PCA9633 kannst du 4, mit dem PCA9634 8 und mit
> dem PCA9635 sogar 16 LEDs unabhängig in der Helligkeit einstellen.

Wolfgang schrieb:
> Zu Soft-PWM als Alternative gibt es
> hier im Forum einen Artikel mit einem gan pfiffigen Ansatz:
> http://www.mikrocontroller.net/articles/Soft-PWM
Gast #2578354
Lesenswert?

Hallo Wolfgang,
Eine einfache Lösungsidee: wäre folgendes möglich?
Der Microcontroller1 produziert die auf-und abdimmende pwm an OC1A. 
Diese pwm wird an Microcontroller2 in einen Eingang gegeben, sagen wir 
PORTC,2. Das Signal wir dann im Microcontroller 2 auf beliebige Pins an 
den Ports verteilt.
z.B. so:
loop_until_bit_is_set(<PINC><2>);sbi(<PORTX><x>);loop_until_bit_is_clear 
(<PINC><2>);cbi(<PORTX><x>)
Per Interrupt wird (<PORTX><x>) dann in (<PORTY><y>)etc verändert.
Damit die Phase der pwm stimmt, die leds also dunkel anfangen und 
langsam heller werden wird durch ein gesetztes Bit in einem Ausgang von 
Microcontroller 2 (oder evtl µC3) ein reset an µC1 ausgelöst.
Ich denke das könnte gehen!
Den Artikel über Soft pwm habe ich mir angesehen. Leider meckert meine 
Programmierumgebung heftig daran herum.
Grüße
A
Gast #2578960
Lesenswert?

Auf dem Mega 8, den ich jetzt benutze habe ich die  auf- und abdimmende 
pwm eigenartigerweise nur auf dem PB1, und nicht - wie ich denke, daß es 
sein sollte - auch auf PB2 (OC1B). Auf PB2 habe ich ein gleichmäßiges 
Signal, das die led gleichmäßig bei mittlerer Helligkeit leuchten lässt. 
Ich frage mich woran das liegt.

Hubert G. schrieb:
> Du musst gar nicht so kompliziert arbeiten.
> Auf PB0 hast du jetzt die gleiche PWM wie auf PB1.
> Das dann abhängig von irgendwelchen Taster oder sonstigen Eingaben
> machen ist kein Problem.
> Bei einem Mega16 hast du vier PWM und 32IO.
#2579714
Lesenswert?

Die sind nicht elektrisch parallel geschaltet, sonder mittels SW.
Auf diese Weise kannst du Leds faden lassen wenn du eine Taste drückst.
In meiner SW geschieht das hier:
1
    if (PINB &(1<<PINB1)){
2
      PORTB|=(1<<PB0);
3
    }
4
    else {
5
      PORTB &= ~(1<<PB0);
6
    }
Wenn du es mit Taste willst musst du vorher noch den Tasteneingang 
abfragen.
Gast #2582363
Lesenswert?

Hubert G. schrieb:
> Die sind nicht elektrisch parallel geschaltet, sonder mittels SW.


Danke, das hat mir sehr geholfen! damit kann ich das Signal auf 
beliebige Ports weiterleiten.
Jetzt versuche ich Folgendes, per Interrupt wird die Variable lauf bei 
Tastendruck auf 10200 gesetzt, und damit das Signal auf 0. Das 
funktioniert. Gleichzeitig soll die Variable schalt von 0 bis 5 und dann 
wieder nach 0 weitergeschaltet werden:

ISR (INT0_vect)
{
  waitMs(10); //entprellen

      if(schalt==5){
        schalt=0;
      }
      lauf=10200;
      schalt++;
}
schalt soll dann je nach Zustand das Signal auf verschiedene Ausgänge 
legen, das funktioniert leider noch nicht:

int main(void)
{
   init();   // Initialisierungen


if (schalt = 0)
   {
   if (PINB & 0x02)
  {
   PORTB |=(1<<PB0);
   PORTB |=(1<<PB7);
   }
   else{
   PORTB &= ~(1<<PB0);
   PORTB &= ~(1<<PB7);
  }
   }
//----------------
  else if (schalt==1)
   {
   if (PINB & 0x02)
  {
   PORTB |=(1<<PB0);

   }
   else{
   PORTB &= ~(1<<PB0);

  }
   }
 else if (etc)
}
Wenn du dazu eine Idee hättest, würde mir das sehr helfen.
Grüße

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