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
> Leider funktioniert es nicht
Wenn ich mir dein Programm ansehen, wundert das nicht,
da steht keinerlei Code zum auf/ab dimmen drin.
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
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
Richtig, es bleibt immer entweder auf Minimum oder Maximum! Die Änderungen der Variable "lauf" werden nicht sichtbar.
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
> 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?
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.
Hubert G. schrieb: > Ist auch nicht schön Stimmt! Besonders bemerkenswert ist die Speicherung der Bool Information für Up/Down, denn bei Dir gilt immer laufup == !laufdown.
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
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.
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.
Es ist kein Problem den PWM-Ausgang mit einem anderen Pin zu verbinden. Z.B. Taste X gedrückt, PWM-Signal auch an PORTC0. Wenn du nicht genügend I/O hast, kannst du auf Portexpander wie PCF8574 zurückgreifen oder einen Mega16 mit 32 I/O verwenden.
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
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
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
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.
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.
Damit OC1B auch als PWM-Ausgang funktioniert musst du das schon programmieren. PB0 in meinem Programm ist nur parallel zu OC1A geschaltet.
wie schaltest du 2 Ausgänge parallel? Hubert G. schrieb: > Damit OC1B auch als PWM-Ausgang funktioniert musst du das schon > programmieren. > PB0 in meinem Programm ist nur parallel zu OC1A geschaltet.
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.
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
Das funktioniert recht brauchbar, Verbesserungsmöglichkeiten gibt es sicher noch.
Super! das funktioniert bestens. Vielen Dank, Grüße Anando
Boooor, formatiere den Code gescheit! Der sieht aus wie Kraut und Rüben.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.