KerstLicht
Datum: Thu 20 December 2018
Samenvatting: Een 4-kanaals Looplicht voor Kerstverlichting, met 2-staps Timer.
Al een paar jaar heb ik een dennestruik in de tuin staan en doe ik daar lichtjes in. Dit zijn van die standaard lichtsnoeren die op batterijen werken en die een timer in zich hebben. De lichtjes worden aangestuurd vanuit een kastje, waar de electronica in zit en waar de batterijen in gaan (bij mijn snoeren zijn dat 3 AA batterijen per snoer). En ik heb twee van die lichtsnoeren in de struik hangen.
Ondertussen zijn de nadelen, die ik in die lichtsnoeren zie, groter dan het gemak die ik erin zag, zoals:
- De manier waarop de batterijen erin gedaan moeten worden. Dit gaat met schroefjes en na enkele jaren raak je ze kwijt (ze vallen en je vind ze niet meer terug in de tuin-aarde).
- Het timer-systeem op zich werkt wel leuk, het kent maar 1 periode (van 6 uren lang) van activiteit. Daarna gaat het lichtsnoer uit en 18 uur later wordt het weer aktief. Dit wordt elke 24-uur herhaald.
- De timer-cyclus wordt pas gestart wanneer je op de startknop duwt.
- Het minst wegend nadeel is dat ik ze altijd in plastic zakjes doe, om weersinvloeden (regen, sneeuw) zo weinig mogelijk invloed erop te hebben. Maar ... het weer slaat wel toe in de besturingen (o.a. de schroefjes worden roestig).
- PLUS als de batterijen leeg zijn, moeten de kastjes weer worden opengeschroefd, om de batterijen te verversen. Daarna moeten de timers weer opnieuw worden geactiveerd.
Batterijen eruit, Netvoeding "erin".
Tegenwoordig zijn er van die adapters (3V en 4.5V) te koop, met opvulstukjes, die in de plaats van de batterijen gaan. Maar de praktijk leert dat de tussenliggende kabel tussen de adapter en de opvulstukken te kort is voor naar de tuin. De oplossing die ik zag, was het verlengen van de kabel.
En dan kom je erachter dat de kabel zelf te dun is om de twee lichtsnoeren van voldoende energie te voldoen. Ik kan 1 lichtsnoer aan laten gaan, maar zodra ik het tweede lichtsnoer activeer, gaat er zoveel stroom door de kabel heen, dat de spanningsval over de kabel te groot wordt om beide lichtsnoeren voldoende spanning te kunnen geven. Resultaat: de beide lichtsnoeren gaan uit - of te wel, dit werkt niet.
Volgende oplossing was een losse tuin-transformator (12V) en deze via een lange kabel naar een losse 5V-stabilisator te laten gaan. De trafo gaat binnenshuis in het stopkontakt, de 5V stabilisator komt bij de lichtsnoeren in de buurt te hangen.
Op zich voldoet deze oplossing wel, MAAR er zit iets niet lekker in het geheel. Een paar dagen doen de timers het goed en opeens worden ze niet meer geactiveerd. En dan moet je weer naar buiten om op het knopje van de aanstuurkastjes te drukken.
Of te wel, ook dit idee werkt niet.
Een eigen aansturing maken.
Dan komt de volgende oplossing. Zelf een aansturing bouwen - bijvoorbeeld met een Arduino. Hiermee kan ik dan meteen enkele andere nadelen van de eerder gekochte lichtsnoeren oplossen.
Zodra de Arduino van stroom wordt voorzien, wordt deze meteen geaktiveerd. Als er dan een timer-storing zou zijn, is het voldoende om de stroom er even af te halen en weer op te zetten ... En de boel knippert weer.
De aktiviteits-periode.
Hebben de gekochte lichtsnoeren maar 1 aktiviteitsperiode, nu bouw ik er twee in. Want wanneer zijn de lichtjes aan? Bij de gekochte snoeren is dat op het moment dat je op het knopje duwt, meestal rond 16:30hr wanneer de duisternis eind van de middag invalt. 6 uur later, rond 22:30hr zijn ze weer donker. Ga je de volgende ochtend weg, dan is de boel ook donker. Dus worden er 2 periodes van aktiviteit mee programmeren.
Het aantal kanalen aan lichtjes.
Mijn lichtsnoeren hebben maar 2 kanalen aan lichtjes, terwijl er vroeger systemen waren met 4 kanalen. Met tegenwoordig de miniarisatie in allerlei micro besturingen, zijn er te weinig pinnen om meer dan 2 kanalen aan te sluiten. Ik programmeer er 4 kanalen op. In de toekomst moet dit uit te breiden zijn naar 8 kanalen. Er zitten pinnen zat op, op de Arduino.
En dan de lichtjes zelf. Een idee is om zelf alle Leds in snoeren te solderen. Een klus dat veel werk is en waarbij alle Led-solderingen spatwater-dicht moeten worden gemaakt.
Echter vooral vlak voor (en na) de kerstdagen wordt kerstverlichting met grote kortingen verkocht (tot 35%). De winkeliers willen toch van de handel af. Wat is er dan makkelijker om in die periode 4 lichtsnoeren te kopen (gevoed door batterijen (plus eventueel een timer)) en dan het batterij gedeelte af te knippen. Via een transistor (of een MosFet) moeten de nieuwe lichtsnoeren aan te sturen zijn met een Arduino. En TaRaaa, een eigen lichtsnoer is gemaakt.
Weersinvloeden.
Alleen met een goede behuizing en (siliconen)kit moet de boel aardig (spat)water dicht te maken zijn. Dan zijn er vast nog plastic zakjes nodig, maar dan moet het ook werken vanuit een adapter (of tuin-trafo).
Het programma - De Eisen.
In het kort zijn de eisen dus:
- 4 lichtkanalen - dus 4 losse LedSnoeren.
- Timer-funktie met 2 periodes van activiteit.
- Een Patronen-deel die gemakkelijk is uit te breiden.
Er is begonnen met een eenvoudig looplicht. 4 keer 2 Leds in serie, die keurig in een rijtje staan van [12341234]. Dit rijtje werd eerst als binaire teller aangestuurd. Je moet ergens mee beginnen.
Het Programma - De Timer.
Daarna werd de timer geprogrammeerd. De Arduino heeft een (zogenoemde) timer in zich, die op vaste tijdstippen een interrupt kan geven. Om het eenvoudig te houden, is gekozen om elke seconde een interrupt te laten geven. Via de interrupt-routine wordt software-matig een teller opgehoogd - er worden dus secondes geteld.
De Arduino werkt zelf op een frequentie van 16MHz. Door de voor-deler (pre-scaler) op 1024 te zetten (%101 in het register TCCR1B, op de bitjes CS12, CS11 en CS10)) en de teller-startwaarde op "15625" (OCR1A) (met de functie InitIrq()), worden de interrupts keurig met 1 Hz opgewekt.
In de loop van dit project heeft de Seconde-Teller enkele constantes gekregen om de boel te initialiseren en te regelen. De Teller houdt secondes bij, dus alle constantes moeten ook in secondes worden opgegeven. In plaats van constantes om te rekenen naar secondes, wordt in het programma het aantal uren opgegeven vermenigvuldigd met 3600 (het aantal secondes in een uur). Deze vermenigvuldigingen zijn boven in het programma duidelijk te zien. De constante-benamingen zijn:
- TimerSecondes: Dit is de eigenlijke seconde-teller.
- TimerInit: Deze waarde wordt in de Teller geladen op het moment van aanzetten. In het programma staat deze op 16*3600, of te wel we doen net alsof hij om 16:00hr begint.
- TimerStart: Deze heeft de waarde 0 (hoe kan dat ook anders) en deze waarde wordt in de Teller geladen op het moment dat hij het maximum bereikt.
- TimerReset: Zodra de Teller deze waarde bereikt, wordt hij terug gezet naar de Start-waarde van 0. De Reset-waarde is 24*3600, of te wel 24-uren aan secondes.
- TimerTrig1 .. TimerTrig4: Dit betreft 4 afzonderlijke Trigger waardes, die elk op een "tijdstip" staan. In het eerste programma zijn dit de waardes (1) 5*3600 = Aan, (2) 9*3600 = Uit, (3) 16*3600 = Aan en (4) 23*3600 = Uit. De uur-waardes zijn er nu eenvoudig uit te halen.
Als voorlopige extra laat ik de Teller gaan naar de 16-Leds die ik op de voorkant van mijn Arduino experimenteer-kastje heb zitten. Eerst in Binair-formaat, maar nu als Bcd laat ik hier de inhoud van de Teller zien in Uren en Minuten (met de functies Timer2Bcd() en ShiftLeds()) (zie schema, linker helft).
Voor test-doeleindes kan ik de interrupt-frequentie verhogen door een extra deling op de teller-startwaarde (OCR1A) te verrichten. Dit verklaart de deling in de regel "15625 / 1".
Het Programma - Aktiviteit-periode.
Door de Teller-waarde te vergelijken met de 4 Trigger-waardes, is vast te stellen of het Looplicht aktief moet zijn, of niet. Een meervoudige If-Then-Else Statement gaat deze toestand af in de functie CheckActive(). Hierbij is het wel zaak dat de laagste Trigger variabele ook echt de laagste waarde heeft.
Als extra wordt de ingebouwde Led op Pin 13 gebruikt om de toestand van de activiteit aan te geven. Aktief is Aan, Niet-Aktief is Uit. Op mijn experimenteer-kastje heb ik ook de grote blauwe Led op deze Pin 13 gezet.
Het Programma - De Lampen, c.q. LedSnoeren.
De pinnen die de Lampen/ LedSnoeren moeten aansturen, worden door de functie LampOutput() bediend. 4 losse If-Then statements testen de afzonderlijne bits en sturen hiermee de 4 losse pinnen aan.
Deze functie is uit te breiden dat er 8 pinnen aangestuurd kunnen worden - en dus 8 kanalen kunnen worden bediend.
Wanneer dan hele LedSnoeren aan elkaar bevestigd zijn, met de Leds keurig achter elkaar, dan ontstaat er echt een heel snoer met de volgorde [12341234123412341234123412341234].
Het Programma - De Patronen in een eigen Library.
Om het programma zelf overzichtelijk te houden, zijn de LoopLicht patronen in een grote Array gezet en in een eigen Library geplaatst, genaamd "Patterns.cpp" en "Pattern.h".
Het array zelf verandert niet qua inhoud, daarom is hier gekozen om het array in het programma geheugen te zetten. Dit is te herkennen aan de term "PROGMEM" in de Library. Een tweede reden hiervoor is ook, dat het programma-geheugen meer plaats heeft (32kB) dan het variabele geheugen (2kB). Een gevolg hiervan is het gebruik van de funktie "pgm_read_byte_near()" in het "loop()" gedeelte van het hoofdprogramma.
Ook is het array een recht-toe recht-aan 2-dimensionaal Array. De patronen hebben allemaal het zelfde aantal stappen en elke regel (in de Library) bevat 1 patroon. Hiermee is al een behoorlijk aantal patronen aan te brengen, zoals:
- Een Lamp aanzetten en deze echt alle 4 de kanalen af laten gaan. Het echt schuif-register looplicht, binair: [---x] [--x-] [-x--] [x---].
- De lampen wisselend aan en uit laten gaan, binair: [-x-x] [x-x-] of [xx--] [--xx].
- Diverse variaties hierop, al of niet met extra pauzes dat alles uit is (binair [----]).
Het Programma - De Init() en de Loop().
De initialisatie zet diverse indexen (Idx) op nul, zet de diverse pinnen op output en initialiseert de interrupt funktie InitIrq().
Na het testen met binaire waardes op de Looplicht-Leds wordt het tijd om de patronen uit een tabel te halen en aar de Leds te sturen. De Loop() zorgt hiervoor, inclusief het controleren of het LoopLicht aktief moet wezen en de vertraging tussen de LoopLicht stappen.
De patronen worden een aantal keren herhaal, voordat er een ander patroon wordt gekozen. Dit kiezen gaat via een Random()-functie ... hoewel het afwachten is hoe Random het Random is. Maar een voorbijganger buiten zal hier vast geen enkele aandacht aan besteden.
Patroon-uitbreiding.
Ondertussen is ook het aantal patronen uitgebreidt tot 24 stuks, inclusief binair tellen en gray-codes - bij elkaar zijn dit (maar) 384 bits. Wat wel prettig is om te weten, is dat er nog zo'n 29-duizend stappen bij kunnen (75 keer zoveel als nu gebruikt wordt). Er is dus ruimte genoeg voor creativiteit.
Toekomst idee 1) zou kunnen zijn om patronen van een wisselende lengte te kunnen gebruiken, waarbij een tweede array de indexen kan bevatten waar elk patroon begint (en dus het vorige patroon eindigt). Er zou dan zelfs de woorden "Vrolijk Kerst" in morse geknipperd kunnen worden.
Toekomst idee 2) zou kunnen zijn om de patronen in een 16-bits array te zetten, waarbij een tijdsduur ingegeven kan worden. Het aantal patroon-stappen wordt dan ongeveer maximaal 14.000 stuks.
Toekomst idee 3) zou kunnen zijn om de patronen in een 32-bits array te zetten, waarbij de bits (per kanaal) een helderheid aangeven om dan de LedSnoeren (bijvoorbeeld) via Binaire Modulatie aan sturen. Dit laatste vereist wel een uitbreiding van de interrupt routine. Het aantal patroon-stappen wordt dan ongeveer maximaal 7.000 stuks.
De LedSnoer aansturing.
Om een LedSnoer aan te kunnen sturen, is er eerst onderzoek nodig op het LedSnoer om te weten hoeveel stroom een LedSnoer verbruikt en wat voor spanning er over staat. Op de doos stond niets over knipperen, dus werd het een questie van batterijen erin doen en de multimeter erbij pakken. Het stroomverbruik is (bij 100Leds) 45mA, terwijl er een spanningsval van 2.8V is. Tevens blijkt dat alle Leds in het Snoer parallel staan. Er waren geen derde-draden in het snoer te zien, wat er zou moeten zijn bij serie-schakeling van de Leds.
Als aansturing is er eerst gedacht om een MosFet te gebruiken om een snoer aan en uit te schakelen. Maar met een stroom van maar 50mA (iets minder) is een standaard TUN (BC547) ook te gebruiken. Weerstanden erom (bij T1 is dat R1 en R2) en testen maar. En het voldoet. Nog iets aanpassen van een weerstand (R2) en dit deel is klaar. Er is zelfs nog een handige controle-Led erbij gekomen (D1).
En toen bedacht ik me dat er alleen maar een AC-voedingslijn aanwezig was (want het is de tuin-trafo). Dus moet er nog een (brug)gelijkrichter met een afvlak elko op de print komen. Deze moet de Arduino dan rechtstreeks voeden op de adapter konnector.
Daarna was het zoeken naar een behuizing ... tot ik mij bedacht dat het wellicht in een (buiten-)lasdoos zou passen. Met twee-componenten lijm werden twee schroeven vastgelijmd en (na het uitharden) de Arduino werd er in geschroefd.
De LedSnoeren Tie-wrappen en aansluiten.
Dan komt het saaiste gedeelte van dit project. Dat is niet het losknippen van een snoer met de oorspronkelijke besturing geweest, maar het samen binden van de 4 LedSnoeren. Elk snoer is 7.5meter lang en heeft 100 Leds. Na 3 uren is ook deze klus geklaard en zijn er zo'n 200 Tie-wraps gebruikt.
Er werd uitgezocht welke draden van dit nieuwe LedSnoer voor welke Leds zijn, of te wel het bepalen van Lamp 1 t/m Lamp 4. De draden van het nieuwe LedSnoer werden aangesloten op de besturingsprint en de Arduino werd opgestart. Et voila ... wat een mooi effect, 400 vrolijk knipperende Leds.
De laatste afwerking.
Als laatste moet het doorvoergat van de lasdoos, waar de draden door naar buiten gaan, worden dichtgekit. Ophangen in de dennestruik en activeren, net op tijd om de kerstdagen knipperend door te komen.
Van een afstand is aan de lijn-van-licht echt de vorm van het snoer te zien. Ook zijn de knipper-effecten spectaculairder dan van de oude twee losse snoertjes. 4 kanalen geeft immers meer mogelijkheden dan 2 x 2 kanalen (die vlak na elkaar hetzelfde patroon afspelen)..
Op de foto's is te zien dat de oude verlichting nog in de struik hangt. Deze zijn als eerste in de struik geplaatst en de rest "ligt" er bovenop.
En na ruim 2 weken werkt het nog steeds zoals gepland, ook de ochtend cyclus.
Programma werking.
De afgelopen jaren is de volgorde nu als volgt. Eerst slinger ik de lichtjes door de bomen in de tuin. Vervolgens sluit ik, via een lang stuk 220V tweeling-snoer de tuin-trafo binnens huis aan. Met een standaard kroonsteen sluit ik de kerstverlichting aan op het tweeling-snoer. Rond 16:00 uur trek ik de tuin-trafo even uit het stopkontakt en doe hem er weer in. Op dat moment start de Arduino besturing de tijd-telling, te beginnen bij 1600 uur (constante TimerInit).
Bij de telling van 2300 uur (constante TimerTrig4) dooft de verlichting, maar de tijd-telling gaat verder. Zodra deze het tijdstip 2400 uur (constante TimerReset) heeft bereikt, gaat de tijd-telling naar 0000 uur (middernacht) (constante TimerStart). Om 0500 uur (constante TimerTrig1) beginnen de lichtjes weer te knipperen, leuk als je met ochtend-dienst de deur uitgaat. Heeft de tijd-telling de stand van 0900 uur (constante TimerTrig2) bereikt, dan stopt het knipperen weer. Er is dan meestal alweer daglicht. En om 1600 uur (constante TimerTrig3) begint dit weer van voren af aan.
Wanneer de Arduino pas om 16:30hr spanning krijgt, ook dan denkt de Arduino dat het 16:00hr is. De bovengenoemde tijdstippen zullen dan ook een half uur later (in echte tijd) plaats vinden.
De werking na enkele jaren.
In het najaar is de dennenstruik uit de tuin gegaan en is er op die plaats een (langzaam groeiende) kerstboomje gepland. Met kerst 2019, 2020 heeft deze kerstverlichting ook gewerkt.
En met kerst 2021 werkt het nog steeds. Zonder enige verandering aan de verlichting en besturing ... en zonder herprogrammering.
Broncode:
[1: KerstLicht]
[2: De Patroon Library (.CPP)]
[3: De Patroon Library (.H)]
1: De broncode van KerstLicht
(Thu 20 December 2018)
Het Hoofdprogramma "KerstLicht.Ino"
Deze broncode heeft 242 regels met programma-code.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
// -----------------------------------------------------------------------------
// KerstLicht
//
// A Christmas Light Controller for 4 Lamps with 2 Periods of Activity
//
// -----------------------------------------------------------------------------
//--------[ Needed Include Files ] -------------------------------------------
// Include the Lamp Patterns
#include "e:\arduino\KerstLicht\Patterns.h"
// Next line is needed for PROGMEM and pgm_read_byte_near-function
#include <avr/pgmspace.h>
//==============================================================================
// Some Seconde Timing Values
const long TimerInit = 16L * 3600L; // Initialize Value for the TimerSecondes
const long TimerTrig1 = 5L * 3600L; // Trigger 3 Value for the TimerSecondes
const long TimerTrig2 = 9L * 3600L; // Trigger 4 Value for the TimerSecondes
const long TimerTrig3 = 16L * 3600L; // Trigger 1 Value for the TimerSecondes
const long TimerTrig4 = 23L * 3600L; // Trigger 2 Value for the TimerSecondes
const long TimerStart = 0L; // Start Value for the TimerSecondes
const long TimerReset = 24L * 3600L; // Reset Value for the TimerSecondes ( 86'400sec/day)
long volatile TimerSecondes = 0L; // Seconde Teller, which increases by Interupt (per seconde).
// Idxxes to the patterns
word IdxPattern = 0; // Idx for the Pattern to show
word IdxTimes = 0; // Number of Times to repeat the Pattern
word IdxStep = 0; // Step Number in the Pattern
// Some Lamp Output vars
byte LampValue = 0; // Temp Var for the Lamp Value
const byte Lamp1 = 9; // Lamp 1
const byte Lamp2 = 10; // Lamp 2
const byte Lamp3 = 11; // Lamp 3
const byte Lamp4 = 12; // Lamp 4
// Some Led-Shift
byte DataPin = 2; // Data (74HC595)
byte ClockPin = 3; // Clock (74HC595)
byte LatchPin = 4; // Latch (74HC595)
//==============================================================================
//== Setup and Loop ==
//==============================================================================
void setup()
{ // Serial.begin(115200); //////////////////////////////////////////
// Set the Pattern Index to the begin
IdxPattern = 0;
IdxStep = 0;
// Set A1 to Input, because the signal will be used
// to seed the Random(), for selecting a new Pattern.
pinMode(A1, INPUT);
randomSeed(analogRead(0));
IdxPattern = random(0, MaxPattern);
// Set Lamp-Pins to Output
pinMode(Lamp1, OUTPUT);
pinMode(Lamp2, OUTPUT);
pinMode(Lamp3, OUTPUT);
pinMode(Lamp4, OUTPUT);
// Set Led-Shift to Output
pinMode(DataPin , OUTPUT);
pinMode(ClockPin, OUTPUT);
pinMode(LatchPin, OUTPUT);
// Set Activity Led to Output
pinMode(13, OUTPUT);
TimerSecondes = TimerInit;
InitIrq();
}
void loop()
{ // Output the value of TimerSecondes
ShiftLeds( Timer2Bcd(TimerSecondes) );
// Check if the Lights must be active.
if (CheckActive() != 0)
{ // Active => Do Some Lamp Stuff
LampValue = pgm_read_byte_near( &LampPatterns[IdxPattern][IdxStep] );
LampOutput(LampValue);
// Increase IdxStep
IdxStep = IdxStep + 1;
if (IdxStep == MaxStep )
{ // If Max, Then Reset
IdxStep = 0;
// Do it One more time
IdxTimes = IdxTimes + 1;
if ( IdxTimes == MaxTimes)
{ // Reset Number of Times
IdxTimes = 0;
// Select the next IdxPattern
IdxPattern = random(0, MaxPattern);
}
}
}
else
{ // Not Active => No Lamps, No Patterns
LampOutput(0x00);
}
delay(213);
}
//==============================================================================
// Some Functions to handle stuff
//==============================================================================
void LampOutput (byte LampOut)
{ // Do Lamp 1
if ((LampOut & 0x01) == 0)
{ digitalWrite(Lamp1, LOW);
}
else
{ digitalWrite(Lamp1, HIGH);
}
// Do Lamp 2
if ((LampOut & 0x02) == 0)
{ digitalWrite(Lamp2, LOW);
}
else
{ digitalWrite(Lamp2, HIGH);
}
// Do Lamp 3
if ((LampOut & 0x04) == 0)
{ digitalWrite(Lamp3, LOW);
}
else
{ digitalWrite(Lamp3, HIGH);
}
// Do Lamp 4
if ((LampOut & 0x08) == 0)
{ digitalWrite(Lamp4, LOW);
}
else
{ digitalWrite(Lamp4, HIGH);
}
}
//==============================================================================
void ShiftLeds (word value)
{ // Show Value of a word
digitalWrite(LatchPin, LOW ); // Latch = Low, to Freeze the Value
shiftOut (DataPin, ClockPin, MSBFIRST, value >> 8); // Sent the Value
shiftOut (DataPin, ClockPin, MSBFIRST, value & 0x00FF); // Sent the Value
digitalWrite(LatchPin, HIGH); // Latch = High, to Send the Value thru
}
//==============================================================================
byte CheckActive ()
{ // Show if Active, or not (on pin 13)
byte BeActive = 0;
if (TimerSecondes < TimerTrig1)
{ // Periode 1 = Not Active
BeActive = 0;
}
else if (TimerSecondes < TimerTrig2)
{ // Periode 2 = Active
BeActive = 1;
}
else if (TimerSecondes < TimerTrig3)
{ // Periode 3 = Not Active
BeActive = 0;
}
else if (TimerSecondes < TimerTrig4)
{ // Periode 4 = Active
BeActive = 1;
}
else
{ // Periode 5 = Not Active
BeActive = 0;
}
if (BeActive == 0)
{ digitalWrite(13, LOW);
}
else
{ digitalWrite(13, HIGH);
}
return BeActive;
}
//==============================================================================
word Timer2Bcd (long daytime)
{ word hrs = 0;
word mins = 0;
word b0 = 0;
word b1 = 0;
word b2 = 0;
word b3 = 0;
// Split Daytime into Hours and Minutes
hrs = daytime / 3600;
mins = daytime % 3600;
mins = mins / 60;
// Convert Hours into BCD
b0 = hrs / 10;
b1 = hrs % 10;
// Convert Minutes into BCD
b2 = mins / 10;
b3 = mins % 10;
return (((( (b0 << 4) + b1) << 4) + b2) << 4) + b3;
}
//==============================================================================
//== Interupt Init ==
//==============================================================================
void InitIrq()
{ // Initialize Timer1 in the Arduino
cli(); // Disable Interrupts
// Timer Counter Control Registers 1A & 1B
TCCR1A = 0; // Make all bits of this register to 0
TCCR1B = 0; // Make all bits of this register to 0
OCR1A = 15625 / 1; // set Output Compare Register 1 to the desired timer count
TCCR1B = TCCR1B | B00001000; // turn on CTC mode (WGM12 = bit 3 - Waveform Generation Mode)
TCCR1B = TCCR1B | B00000101; // Set the Prescaler (CS12 CS11 CS10 = bit 2..0 - Clock Select)
TIMSK1 = TIMSK1 | B00000010; // set Timer Interupt MaSK 1 to compare interrupt
// (OCIE1A = bit 1 - Output Compare match Interrupt Enable 1A)
sei(); // Enable Interrupts
}
//==============================================================================
//== [ The Interupt Function ] ==
//==============================================================================
ISR(TIMER1_COMPA_vect)
// De Interrupt Service Routine
// The main interupt-routine. Do one count ...
{ TimerSecondes = (TimerSecondes + 1L);
if (TimerSecondes == TimerReset)
{ TimerSecondes = TimerStart;
}
}
|
Broncode:
[1: KerstLicht]
[2: De Patroon Library (.CPP)]
[3: De Patroon Library (.H)]
2: De broncode van De Patroon Library (.CPP)
(Thu 20 December 2018)
De bijbehorende "Pattern.Cpp"-file is leeg, de library bevat geen eigen functies.
Deze broncode heeft 19 regels met programma-code.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//------------------------------------------------------------------------------
// KerstLicht
//
// The Lamp Patterns
//------------------------------------------------------------------------------
#ifndef PATTERNS_CPP
#define PATTERNS_CPP
// Include some Libraries
//#include "Arduino.h"
#include "Patterns.h"
// #include "e:\arduino\KerstLicht\Patterns.h"
//==============================================================================
// This Library contains only array's.
// All array's are in the Header-file.
//==============================================================================
|
Broncode:
[1: KerstLicht]
[2: De Patroon Library (.CPP)]
[3: De Patroon Library (.H)]
3: De broncode van De Patroon Library (.H)
(Thu 20 December 2018)
De Patroon Library "Pattern.H" bevat alle patronen van het Kerstlicht. Geen ingewikkelde berekeningen, maar een uitgebredie verzameling van eenvoudige Bit"map" patronen van 4-bits breed.
Deze broncode heeft 51 regels met programma-code.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
//------------------------------------------------------------------------------
// KerstLicht
//
// The Lamp Patterns
//------------------------------------------------------------------------------
#ifndef PATTERNS_H
#define PATTERNS_H
#include "Arduino.h"
// Next 2 lines are needed for PROGMEM and pgm_read_byte_near-function
#include <avr/io.h>
#include <avr/pgmspace.h>
//==============================================================================
// Lamp Patterns
//==============================================================================
const word MaxTimes = 8 ; // Max number of Times to repeat a Pattern
const word MaxPattern = 24 ; // Max Number of Patterns in the Array
const word MaxStep = 16 ; // Max Number of Steps in a Pattern (in the Array)
static const byte LampPatterns [MaxPattern][MaxStep] PROGMEM = // = [000..max][00..max]
{ // 0 1 2 3 4 5 6 7 8 9 A B C D E F Pattern
{ 0x01,0x02,0x04,0x08 , 0x01,0x02,0x04,0x08 , 0x01,0x02,0x04,0x08 , 0x01,0x02,0x04,0x08 } , // 01
{ 0x05,0x00,0x0A,0x00 , 0x05,0x00,0x0A,0x00 , 0x05,0x00,0x0A,0x00 , 0x05,0x00,0x0A,0x00 } , // 02
{ 0x03,0x00,0x0C,0x00 , 0x03,0x00,0x0C,0x00 , 0x03,0x00,0x0C,0x00 , 0x03,0x00,0x0C,0x00 } , // 03
{ 0x01,0x03,0x07,0x0F , 0x0E,0x0C,0x08,0x00 , 0x01,0x03,0x07,0x0F , 0x0E,0x0C,0x08,0x00 } , // 04
{ 0x00,0x01,0x02,0x04 , 0x08,0x09,0x0A,0x0C , 0x09,0x03,0x05,0x09 , 0x01,0x02,0x04,0x08 } , // 05
{ 0x09,0x03,0x06,0x0C , 0x09,0x03,0x06,0x0C , 0x09,0x03,0x06,0x0C , 0x09,0x03,0x06,0x0C } , // 06
{ 0x0F,0x00,0x0F,0x00 , 0x0F,0x00,0x0F,0x00 , 0x0F,0x00,0x0F,0x00 , 0x0F,0x00,0x0F,0x00 } , // 07
{ 0x05,0x0A,0x05,0x0A , 0x05,0x0A,0x05,0x0A , 0x05,0x0A,0x05,0x0A , 0x05,0x0A,0x05,0x0A } , // 08
{ 0x03,0x0C,0x03,0x0C , 0x03,0x0C,0x03,0x0C , 0x03,0x0C,0x03,0x0C , 0x03,0x0C,0x03,0x0C } , // 09
{ 0x0E,0x0D,0x0B,0x07 , 0x0E,0x0D,0x0B,0x07 , 0x0E,0x0D,0x0B,0x07 , 0x0E,0x0D,0x0B,0x07 } , // 10
{ 0x00,0x0F,0x00,0x0F , 0x00,0x0F,0x00,0x0F , 0x00,0x0F,0x00,0x0F , 0x00,0x0F,0x00,0x0F } , // 11
{ 0x00,0x0F,0x00,0x0F , 0x00,0x00,0x0F,0x0F , 0x0F,0x0F,0x0F,0x0F , 0x00,0x00,0x00,0x00 } , // 12
{ 0x03,0x0C,0x00,0x00 , 0x0C,0x03,0x00,0x00 , 0x03,0x0C,0x00,0x00 , 0x0C,0x03,0x00,0x00 } , // 13
{ 0x09,0x00,0x06,0x00 , 0x09,0x00,0x06,0x00 , 0x09,0x00,0x06,0x00 , 0x09,0x00,0x06,0x00 } , // 14
{ 0x09,0x06,0x09,0x06 , 0x09,0x06,0x09,0x06 , 0x09,0x06,0x09,0x06 , 0x09,0x06,0x09,0x06 } , // 15
{ 0x08,0x04,0x02,0x01 , 0x08,0x04,0x02,0x01 , 0x08,0x04,0x02,0x01 , 0x08,0x04,0x02,0x01 } , // 16
{ 0x00,0x01,0x03,0x05 , 0x06,0x0A,0x0C,0x08 , 0x00,0x01,0x03,0x05 , 0x06,0x0A,0x0C,0x08 } , // 17
{ 0x01,0x02,0x04,0x08 , 0x08,0x04,0x02,0x01 , 0x01,0x02,0x04,0x08 , 0x08,0x04,0x02,0x01 } , // 18
{ 0x01,0x02,0x05,0x0A , 0x04,0x08,0x00,0x00 , 0x01,0x02,0x05,0x0A , 0x04,0x08,0x00,0x00 } , // 19
{ 0x01,0x02,0x04,0x09 , 0x02,0x04,0x08,0x00 , 0x01,0x02,0x04,0x09 , 0x02,0x04,0x08,0x00 } , // 20
{ 0x05,0x00,0x05,0x00 , 0x0A,0x00,0x0A,0x00 , 0x05,0x00,0x05,0x00 , 0x0A,0x00,0x0A,0x00 } , // 21
{ 0x00,0x01,0x02,0x03 , 0x04,0x05,0x06,0x07 , 0x08,0x09,0x0A,0x0B , 0x0C,0x0D,0x0E,0x0F } , // 22
{ 0x00,0x01,0x03,0x02 , 0x06,0x07,0x05,0x04 , 0x0C,0x0D,0x0F,0x0E , 0x0A,0x0B,0x09,0x08 } , // 23
{ 0x00,0x00,0x00,0x00 , 0x0F,0x0F,0x0F,0x0F , 0x00,0x00,0x00,0x00 , 0x0F,0x0F,0x0F,0x0F } // Last
};
//==============================================================================
|
Broncode:
[1: KerstLicht]
[2: De Patroon Library (.CPP)]
[3: De Patroon Library (.H)]
|
Afbeeldingen
1/33: kerstlicht_01-lichtsnoer.jpg.
2/33: kerstlicht_02-lichtsnoer.jpg.
3/33: kerstlicht_03-lichtsnoer.jpg.
4/33: kerstlicht_04-stabilisator-schema.jpg.
5/33: kerstlicht_05-stabilisator-print.jpg.
6/33: kerstlicht_06-print-gebouwd.jpg.
7/33: kerstlicht_07-print-in-plastic.jpg.
8/33: kerstlicht_08-aansturingen.jpg.
9/33: kerstlicht_09-struik_in_duisternis.jpg.
10/33: kerstlicht_10-controle-leds.jpg.
11/33: kerstlicht_11-looplicht.jpg.
12/33: kerstlicht_12-looplicht.jpg.
13/33: kerstlicht_13-metingen.jpg.
14/33: kerstlicht_14-schema.jpg.
15/33: kerstlicht_15-print.jpg.
16/33: kerstlicht_16-soldeer.jpg.
17/33: kerstlicht_17-gebouwd.jpg.
18/33: kerstlicht_18-soldeer.jpg.
19/33: kerstlicht_19-op-arduino.jpg.
20/33: kerstlicht_20-behuizing.jpg.
21/33: kerstlicht_21-behuizing.jpg.
22/33: kerstlicht_22-vier-snoeren.jpg.
23/33: kerstlicht_23-tie-wraps.jpg.
24/33: kerstlicht_24-tie-wraps.jpg.
25/33: kerstlicht_25-werkend.jpg.
26/33: kerstlicht_26-werkend.jpg.
27/33: kerstlicht_27-klaar.jpg.
28/33: kerstlicht_28-in-struik.jpg.
29/33: kerstlicht_29-in-struik.jpg.
30/33: kerstlicht_30-in-struik.jpg.
31/33: kerstlicht_31-kerst-2019.jpg.
32/33: kerstlicht_32-kerst-2020.jpg.
33/33: kerstlicht_33-kerst-2021.jpg.
|
De aansluitingen van KerstLicht
Een 4-kanaals Looplicht voor Kerstverlichting, met 2-staps Timer.
Arduino Uno
|
|
Pwr USB
|
?
|
|
|
|
|
?
|
|
|
|
aref
|
|
|
|
gnd
|
Gnd's (4x)
|
|
?
|
d13
|
Activiteit Led
|
|
ioreff
|
d12
|
MosFet Lamp 4
|
|
reset
|
d11
|
MosFet Lamp 3
|
|
+3.3v
|
d10
|
MosFet Lamp 2
|
+5V (voor 74HCT595)
|
+5v
|
d9
|
MosFet Lamp 1
|
Gnd's (4x)
|
gnd
|
d8
|
|
Gnd's (4x)
|
gnd
|
|
|
|
Vin
|
d7
|
|
|
|
d6
|
|
|
a0
|
d5
|
|
|
a1
|
d4
|
Latch (74HCT595)
|
|
a2
|
d3
|
Clock (74HCT595)
|
|
a3
|
d2
|
Data (74HCT595)
|
|
a4
|
d1
|
Txd (standaard)
|
|
a5
|
d0
|
Rxd (standaard)
|
|