Hallo zusammen, ich habe folgendes Problem. Ich will in meine Hofeinfahrt 4-5 LED-Bodenstrahler einbauen. Nun kam mir die Idee einer verzögerten Einschaltung der einzelnen Strahler. Sprich ähnlich wie bei einem Lauflicht, soll beim Auslösen eines Bewegungsmelders zu erst der 1. Strahler, dann zeitlich versetzt der 2. Strahler und so weiter, eingeschalten werden. Bei erreichen des 4 bzw 5. Strahler sollen alle in einer Art Selbsthaltung bleiben, bis die "Einschaltzeit" des Bewegungsmelders alle Strahler gleichtzeitig abschält. vielleicht noch zu Ergänzung: habe die Bodenstrahler noch nicht gekauft um etwas flexibel zu bleiben. Solche Bodenstrahler gibt es meines Wissens mit 230 V und 12 V. Nun habe ich grobe Kenntnisse im Bereich Elektronik aber komme nicht selber auf eine Lösung und bitte um Hilfe. Zeit-Relais sind mir eigentlich generell zu teuer, da ich ja mehrere bräuchte. Hat mir jemand eine gut umsetzbare und kostengünstige Lösung? Vielen Dank schon im Voraus Grüße s-buali
Ganz ohne Elektronik (-Kenntnisse) wirds nicht gehen. Das Projekt besteht aus vier Teilen, das macht die Sache sehr übersichtlich. Es geht sicher auch viel kompakter ("einfacher" - entsprechende Beiträge werden nicht lange auf sich warten lassen), aber dann ist es nicht gut für Anfänger geeignet. a) die Leistungsschalter für die Lampen, optisch potentialgetrennt b) die Steuerung für das Zeitverhalten c) dem Empfänger/Auslöser d) Netzteil für b u. c Die kann man alle einzeln aufbauen, testen und wenn sie funktionieren zusammen in ein Gehäuse Setzen und in Betrieb nehmen. zu a) da würde ich Solid-State-Relais nehmen. Einfach aunzusteuern, ohne Verschleiß zu b) ICH würde da einen MC nehmen, es geht aber auch mit einem Zähler oder Schieberegister nebst Taktgenerator aus Logikbausteinen - je nach Vorliebe. Oder so einen LED-Bar-Controller für Audioanzeigen an einem sich ladenden Kondensator. zu c) ist im einfachsten Fall ein Schalter. Oder ein IR- bzw. Funkempfäger. Kann auch ein Relais sein, was z.B. vom Gartentorantrieb nebenbei mit ausgelöst wird zu d) ohne große Erklärung
Ich habe sowas für mein Stiegenlicht umgesetzt. Aber um einen µC wirst du nicht rumkommen. Mein System läuft auf 12V. Wenn die 12V vom Netzteil kommen fährt der µC an. Je nach Input Pin PINB0 wird das Lauflicht von unten oder oben gestartet. Zusätzlich habe ich die SoftPWM übernommen, damit ich die Leitungslängen zu den einzelnen Lichter kompensiert werden kann. PINB1 dient dazu, da eine Stiege nur 9 Lichter hat und die andere 11. Über DelayBetweenPINs kann die Verzögerung der einzelnen Lichter eingestellt werden. Funktioniert einwandfrei!
1 | /*
|
2 | Eine 8-kanalige PWM mit intelligentem Lösungsansatz
|
3 |
|
4 | ATmega32 @ 8 MHz
|
5 |
|
6 | */
|
7 | |
8 | // Defines an den Controller und die Anwendung anpassen
|
9 | |
10 | #define F_CPU 12000000L // Systemtakt in Hz
|
11 | #define F_PWM 100L // PWM-Frequenz in Hz
|
12 | #define PWM_PRESCALER 8 // Vorteiler für den Timer
|
13 | #define PWM_STEPS 256 // PWM-Schritte pro Zyklus(1..256)
|
14 | #define PWM_PORT_1 PORTD // Port für PWM
|
15 | #define PWM_DDR_1 DDRD // Datenrichtungsregister für PWM
|
16 | #define PWM_PORT_2 PORTC // Port für PWM
|
17 | #define PWM_DDR_2 DDRC // Datenrichtungsregister für PWM
|
18 | #define PWM_CHANNELS 11 // Anzahl der PWM-Kanäle
|
19 | |
20 | // ab hier nichts ändern, wird alles berechnet
|
21 | |
22 | #define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
|
23 | //#define T_PWM 1 //TEST
|
24 | |
25 | #if ((T_PWM*PWM_PRESCALER)<(111+5))
|
26 | #error T_PWM zu klein, F_CPU muss vergrössert werden oder F_PWM oder PWM_STEPS verkleinert werden
|
27 | #endif
|
28 | |
29 | #if ((T_PWM*PWM_STEPS)>65535)
|
30 | #error Periodendauer der PWM zu gross! F_PWM oder PWM_PRESCALER erhöhen.
|
31 | #endif
|
32 | // includes
|
33 | |
34 | #include <stdint.h> |
35 | #include <string.h> |
36 | #include <avr/io.h> |
37 | #include <avr/interrupt.h> |
38 | #include <util/delay.h> |
39 | |
40 | // globale Variablen
|
41 | |
42 | uint16_t PINFreigabe = 0; |
43 | uint8_t DelayBetweenPINs = 50; // verzögerung zwischen den ausgängen |
44 | |
45 | uint16_t pwm_timing[PWM_CHANNELS+1]; // Zeitdifferenzen der PWM Werte |
46 | uint16_t pwm_timing_tmp[PWM_CHANNELS+1]; |
47 | |
48 | uint16_t pwm_mask[PWM_CHANNELS+1]; // Bitmaske für PWM Bits, welche gelöscht werden sollen |
49 | uint16_t pwm_mask_tmp[PWM_CHANNELS+1]; // ändern uint16_t oder uint32_t für mehr Kanäle |
50 | |
51 | uint8_t pwm_setting[PWM_CHANNELS]; // Einstellungen für die einzelnen PWM-Kanäle |
52 | uint8_t pwm_setting_tmp[PWM_CHANNELS+1]; // Einstellungen der PWM Werte, sortiert |
53 | // ändern auf uint16_t für mehr als 8 Bit Auflösung
|
54 | |
55 | volatile uint8_t pwm_cnt_max=1; // Zählergrenze, Initialisierung mit 1 ist wichtig! |
56 | volatile uint8_t pwm_sync; // Update jetzt möglich |
57 | |
58 | // Pointer für wechselseitigen Datenzugriff
|
59 | |
60 | uint16_t *isr_ptr_time = pwm_timing; |
61 | uint16_t *main_ptr_time = pwm_timing_tmp; |
62 | |
63 | uint16_t *isr_ptr_mask = pwm_mask; // Bitmasken fuer PWM-Kanäle |
64 | uint16_t *main_ptr_mask = pwm_mask_tmp; // ändern uint16_t oder uint32_t für mehr Kanäle |
65 | |
66 | // Zeiger austauschen
|
67 | // das muss in einem Unterprogramm erfolgen,
|
68 | // um eine Zwischenspeicherung durch den Compiler zu verhindern
|
69 | |
70 | void tausche_zeiger(void) { |
71 | uint16_t *tmp_ptr16; |
72 | uint16_t *tmp_ptr8; // ändern uint16_t oder uint32_t für mehr Kanäle |
73 | |
74 | tmp_ptr16 = isr_ptr_time; |
75 | isr_ptr_time = main_ptr_time; |
76 | main_ptr_time = tmp_ptr16; |
77 | tmp_ptr8 = isr_ptr_mask; |
78 | isr_ptr_mask = main_ptr_mask; |
79 | main_ptr_mask = tmp_ptr8; |
80 | }
|
81 | |
82 | // PWM Update, berechnet aus den PWM Einstellungen
|
83 | // die neuen Werte für die Interruptroutine
|
84 | |
85 | void pwm_update(void) { |
86 | |
87 | uint8_t i, j, k; |
88 | uint16_t m1, m2, tmp_mask; // ändern uint16_t oder uint32_t für mehr Kanäle |
89 | uint8_t min, tmp_set; // ändern auf uint16_t für mehr als 8 Bit Auflösung |
90 | |
91 | // PWM Maske für Start berechnen
|
92 | // gleichzeitig die Bitmasken generieren und PWM Werte kopieren
|
93 | |
94 | m1 = 1; |
95 | m2 = 0; |
96 | for(i=1; i<=(PWM_CHANNELS); i++) { |
97 | main_ptr_mask[i]=~m1; // Maske zum Löschen der PWM Ausgänge |
98 | pwm_setting_tmp[i] = pwm_setting[i-1]; |
99 | if (pwm_setting_tmp[i]!=0) m2 |= m1; // Maske zum setzen der IOs am PWM Start |
100 | m1 <<= 1; |
101 | }
|
102 | main_ptr_mask[0]=m2; // PWM Start Daten |
103 | |
104 | // PWM settings sortieren; Einfügesortieren
|
105 | |
106 | for(i=1; i<=PWM_CHANNELS; i++) { |
107 | min=PWM_STEPS-1; |
108 | k=i; |
109 | for(j=i; j<=PWM_CHANNELS; j++) { |
110 | if (pwm_setting_tmp[j]<min) { |
111 | k=j; // Index und PWM-setting merken |
112 | min = pwm_setting_tmp[j]; |
113 | }
|
114 | }
|
115 | if (k!=i) { |
116 | // ermitteltes Minimum mit aktueller Sortiertstelle tauschen
|
117 | tmp_set = pwm_setting_tmp[k]; |
118 | pwm_setting_tmp[k] = pwm_setting_tmp[i]; |
119 | pwm_setting_tmp[i] = tmp_set; |
120 | tmp_mask = main_ptr_mask[k]; |
121 | main_ptr_mask[k] = main_ptr_mask[i]; |
122 | main_ptr_mask[i] = tmp_mask; |
123 | }
|
124 | }
|
125 | |
126 | // Gleiche PWM-Werte vereinigen, ebenso den PWM-Wert 0 löschen falls vorhanden
|
127 | |
128 | k=PWM_CHANNELS; // PWM_CHANNELS Datensätze |
129 | i=1; // Startindex |
130 | |
131 | while(k>i) { |
132 | while ( ((pwm_setting_tmp[i]==pwm_setting_tmp[i+1]) || (pwm_setting_tmp[i]==0)) && (k>i) ) { |
133 | |
134 | // aufeinanderfolgende Werte sind gleich und können vereinigt werden
|
135 | // oder PWM Wert ist Null
|
136 | if (pwm_setting_tmp[i]!=0) |
137 | main_ptr_mask[i+1] &= main_ptr_mask[i]; // Masken vereinigen |
138 | |
139 | // Datensatz entfernen,
|
140 | // Nachfolger alle eine Stufe hochschieben
|
141 | for(j=i; j<k; j++) { |
142 | pwm_setting_tmp[j] = pwm_setting_tmp[j+1]; |
143 | main_ptr_mask[j] = main_ptr_mask[j+1]; |
144 | }
|
145 | k--; |
146 | }
|
147 | i++; |
148 | }
|
149 | |
150 | // letzten Datensatz extra behandeln
|
151 | // Vergleich mit dem Nachfolger nicht möglich, nur löschen
|
152 | // gilt nur im Sonderfall, wenn alle Kanäle 0 sind
|
153 | if (pwm_setting_tmp[i]==0) k--; |
154 | |
155 | // Zeitdifferenzen berechnen
|
156 | |
157 | if (k==0) { // Sonderfall, wenn alle Kanäle 0 sind |
158 | main_ptr_time[0]=(uint16_t)T_PWM*PWM_STEPS/2; |
159 | main_ptr_time[1]=(uint16_t)T_PWM*PWM_STEPS/2; |
160 | k=1; |
161 | }
|
162 | else { |
163 | i=k; |
164 | main_ptr_time[i]=(uint16_t)T_PWM*(PWM_STEPS-pwm_setting_tmp[i]); |
165 | tmp_set=pwm_setting_tmp[i]; |
166 | i--; |
167 | for (; i>0; i--) { |
168 | main_ptr_time[i]=(uint16_t)T_PWM*(tmp_set-pwm_setting_tmp[i]); |
169 | tmp_set=pwm_setting_tmp[i]; |
170 | }
|
171 | main_ptr_time[0]=(uint16_t)T_PWM*tmp_set; |
172 | }
|
173 | |
174 | // auf Sync warten
|
175 | |
176 | pwm_sync=0; // Sync wird im Interrupt gesetzt |
177 | while(pwm_sync==0); |
178 | |
179 | // Zeiger tauschen
|
180 | cli(); |
181 | tausche_zeiger(); |
182 | pwm_cnt_max = k; |
183 | sei(); |
184 | }
|
185 | |
186 | // Timer 1 Output COMPARE A Interrupt
|
187 | |
188 | ISR(TIMER1_COMPA_vect) { |
189 | static uint8_t pwm_cnt; // ändern auf uint16_t für mehr als 8 Bit Auflösung |
190 | uint16_t tmp; // ändern uint16_t oder uint32_t für mehr Kanäle |
191 | |
192 | OCR1A += isr_ptr_time[pwm_cnt]; |
193 | tmp = isr_ptr_mask[pwm_cnt]; |
194 | |
195 | if (pwm_cnt == 0) { |
196 | tmp &= PINFreigabe; |
197 | PWM_PORT_1 = tmp; // Ports setzen zu Begin der PWM |
198 | PWM_PORT_2 = tmp >> 8; // zusätzliche PWM-Ports hier setzen |
199 | |
200 | pwm_cnt++; |
201 | }
|
202 | else { |
203 | tmp &= PINFreigabe; |
204 | PWM_PORT_1 &= tmp; // Ports löschen |
205 | PWM_PORT_2 &= tmp >> 8; // zusätzliche PWM-Ports hier setzen |
206 | |
207 | if (pwm_cnt == pwm_cnt_max) { |
208 | pwm_sync = 1; // Update jetzt möglich |
209 | pwm_cnt = 0; |
210 | }
|
211 | else pwm_cnt++; |
212 | }
|
213 | }
|
214 | |
215 | int main(void) { |
216 | |
217 | // Helligkeit für jeden PIN einstellen
|
218 | // CN14 CN12 CN11 CN10 CN9 CN8 CN7 CN6 CN5 CN3 CN1
|
219 | uint8_t timing[PWM_CHANNELS]={243, 243, 244, 245, 246, 249, 249, 250, 253, 254, 255}; |
220 | uint8_t Anzahl = 9; |
221 | uint8_t cnt; |
222 | int i; |
223 | |
224 | |
225 | // PWM Port einstellen
|
226 | |
227 | PWM_DDR_1 = 0xFF; // Port als Ausgang |
228 | PWM_DDR_2 = 0x07; // zusätzliche PWM-Ports hier setzen |
229 | DDRB = 0x00; // Port B als Input |
230 | PORTB = 0x03; // Pull Up auf PB0 und PB1 aktivieren |
231 | |
232 | // Timer 1 OCRA1, als variablen Timer nutzen
|
233 | |
234 | TCCR1B = 2; // Timer läuft mit Prescaler 8 |
235 | TIMSK1 |= (1<<OCIE1A); // Interrupt freischalten |
236 | |
237 | sei(); // Interrupts global einschalten |
238 | |
239 | // Abfrage ob 9 oder 11 Pins benutzt werden sollen
|
240 | if ((PINB & (1<<PINB1)) == 0) |
241 | Anzahl = 11; |
242 | |
243 | |
244 | memcpy(pwm_setting, timing, PWM_CHANNELS); |
245 | pwm_update(); |
246 | |
247 | // Abfrage in welche Richtung gezählt werden soll
|
248 | if ((PINB & (1<<PINB0)) == 0) |
249 | {
|
250 | for (i=0; i<Anzahl; i++) |
251 | {
|
252 | PINFreigabe |= (1 << i); |
253 | |
254 | for (cnt=0;cnt<DelayBetweenPINs;cnt++) |
255 | {
|
256 | _delay_ms(1); |
257 | }
|
258 | }
|
259 | }
|
260 | else
|
261 | {
|
262 | for (i=Anzahl-1; i>=0; i--) |
263 | {
|
264 | PINFreigabe |= (1 << i); |
265 | |
266 | for (cnt=0;cnt<DelayBetweenPINs;cnt++) |
267 | {
|
268 | _delay_ms(1); |
269 | }
|
270 | }
|
271 | }
|
272 | |
273 | while(1); |
274 | }
|
Funktioniert einwandfrei! /* Eine 8-kanalige PWM mit intelligentem Lösungsansatz ATmega32 @ 8 MHz */ im Anhang...
Beitrag "Re: Anzugsverzögerung Relais mit RC-Glied" Beitrag "Re: Einschaltverzögerung bzw. Auschaltverzögerung für Relais" Beitrag "Re: Nochmal Einschaltverzögerung: RC-Glied berechnen+Schaltplan"
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.