Lysmåling

Fra HTX Arduino
Spring til navigation Spring til søgning
Lysmåleren som det færdige produkt i V2


Lysmåleren som det færdige produkt i V3

Dette projekt er egentlig en dokumentation af et projekt der er opstået i forbindelse med et andet projekt.

Dokumentationen er lavet for at kunne fastholde projektet som en del af udstyret vi anvender på Holstebro HTX.

Det igangsættende projekt handlede om solceller, der kan afgive effekt når de bestråles af solens lys, og en underen over de forskellige måleenheder på området med Lux og W/m2 som de enheder der er mest anvendt.

Dette projekt har to formål - at kunne anvendes som lysmåler i solcelleprojektet, og kunne fungere som lysmåler i fysikundervisningen / teknologi og anden undervisning.

Dokumentationen er også tænkt som inspiration til hvordan man kan strukturere en teknikfagsrapport, og til at vise hvilke elementer man kan tage med i en sådan. Dokumentationen var stort set færdiggjort, da det besluttedes at udvide med et SD-kort. Den oprindelige verion er omtalt om V2 (Version 2) og versionen med SD-kort er omtalt som V3.

Kravspecifikation

Kravene er opsat ud fra at produktet skal have en rimelig anvendelighed, og at det skal kunne fungere i en undervisnings-sammenhæng.

  • Måleopløsning i lave områder - ned til 1 Lux
  • Måleområder op til fuldt sollys - omkring 1000 W/m2 eller 120.000 Lux
  • Målenøjagtighed bedre end 10%
  • Enkelt og brugbart design til simple målinger
  • Mulighed for logning af målinger

Disse overordnede krav er som sådan ikke ændret fra V2 til V3, men der er i V3 lagt mere vægt på enkelhed og brugbarhed, specielt ved logning af målinger.

Sensor

Til de første prototyper valgtes en Photodiode BPW34[1], da den er relativ billig, er lagervare og er følsom over for synligt lys og har et bredt virkeområde. Som det kan ses under spektralområdet, så har den stor følsomhed inden for det infrarøde område, så den er blevet fravalgt til fordel for en PBW21r[2] som godt nok er noget dyrere, men den har sin følsomhed liggende centralt omkring det synlige lys.

Selve sonsoren på lysmåleren sidder i den ene ende af printet og ser ud som følger:
Sensoren placeret ved kanten af printet
Sensoren placeret ved kanten af printet

Spektralområde

Den ene af de to Photodioder der er relevante er BPW34, som har følgende spektralområde:
Spekralområde for BPW34 Photodiode
Spekralområde for BPW34 Photodiode

Den anden Photodiode, som blev den valgte er BPW21r, der har følgende spektralområde:
Spekralområde for BPW21r Photodiode
Spekralområde for BPW21r Photodiode

Som det ses på grafen ligger følsomheden for BPW21r centralt omkring det synlige spektrum.

Måleområdet

Som det kan ses på den følgende graf fra databladet på BPW21r, så opfylder komponenten en fin linearitet endda ud over det område der er opstillet i kravene - dette var faktisk ikke gældende for BPW34.

Graf for diodestrømmen som funktion af lysintentitet for BPW21r Photodiode
Graf for diodestrømmen som funktion af lysintentitet for BPW21r Photodiode

Læser man i databladet kan man finde, at følsomheden er angivet til at være 9 nA/Lux i et område der strækker fra 0,01 Lux til 100.000 Lux, altså ud over det ønskede område. Det lyder ret flot, men samtidig angives der at den typiske lækstrøm er på 2 nA, hvilket vil svare til en intensitet på 0,22 Lux - det virker lidt modstridende i data, ,em hvis kravet blot er at kunne måle ned til 1 Lux, så vil det være ubetydeligt.

En lidt mere bekymrende ting der kan læses i databladet er at følsomheden på de 9 nA/Lux er en typisk værdi, som kan være så lav som 4,5 nA/Lux, altså det halve, og der er ikke angivet nogen max-værdi for følsomheden. Det betyder at det kan blive nødvendigt at kalibrere hver enkelt måleapparat individuelt.

Det må antages, at hvis vi kan måle strømmen i Photodioden, så vil det være enkelt at beregne lysstyrken i Lux, måske med en korrektion.

Formlen bliver E[Lux] = I[A] / 0.000000009

Målekredsløb

For at kunne måle på Photodioden, så skal der etableres et målekredsløb, der skal kunne fungere i det valgte miljø.

Da vi på HTX-afdelingen i Holstebro arbejder meget med Arduino er der valgt at anvende en sådan til at lave måling og visning med. I dette tilfælde vil en Arduino NANO[3] være praktisk, for at måleudstyret ikke skal fylde for meget.

Det helt grundlæggende målekredsløb vil bestå af Photodioden, som skal tilsluttes i spærreretningen, for at den giver den strøm som dannes af det indstrålede lys, og så en modstand, der vil konverterer denne strøm til en spænding som Arduinoen kan måle. Kredsløbet kan skitseres som følger:
Princippet i målekredsløbet på Photodioden
Princippet i målekredsløbet på Photodioden

I kredløbet er D_SENS den valgte Photodiode BPW21r. Modstanden R konverterer den målte strøm til en spænding, og spændingen måles af en Arduino i punktet MAAL.

Måleopløsningen på en Arduino er på ca. 5 mV, ud fra at den måler i forhold til en 5V reference, og det er en 10 bit A/D-konverter der sidder i Arduinoen. For at kunne opnå en mindste opløsning på 1 lux, så skal modstanden vi måler med være 555 kΩ. Da vi kan have komponenter der har ca. den halve følsomhed vælges en målemodstand på 1000 kΩ

Flere områder i målekredsløbet

Med det simple målekredsløb vil man kunne måle op til ca. 5µA, hvilket svarer til mindre end 500 Lux, altså slet ikke i nærheden af det område vi skal opnå. Det betyder at man er nødsaget til at skifte måleområde ved at udskifte målemodstanden.

Princippet i at udskifte målemodstanden etableres ved at man til det aktuelle måleområde forbinder en modstand til et ben, som kan sætte til output, og ved at sætte dette output lavt, så svarer det til at modstanden går til stel. Da det skal være muligt at bruge andre måleområder på den samme sensor, så er det nødvendigt at alle de andre modstande, som fungerer til andre måleområder bliver sat som input. Dette kan skitseres som vist her:
Princippet i at skifte målekredsløb på Photodioden
Princippet i at skifte målekredsløb på Photodioden

I det viste kredsløb trækkes R_2 til stel (0V) ved at sætte det ben på arduinoen til output og trække det lavt, og de to andre modstande R_1 og R_3 er forbundet til ben på arduinoen, som sættes til input, hvilket gør at de ben svæver, og ikke har indflydelse på målingen.

Måling i områder med høj strøm

Ved høje lysintensiteter stiger strømmen der løber i målemodstanden, ved 100.000 Lux er strømmen oppe på 1 mA. Ved denne strøm kan udgangen stadig trække lavt, men der vil være en lille spænding på udgangen på måske 0,1-0,5 V. Denne spænding vil indgå som en fejl.

Udvidelsen der skal til her er, at vi både kan trække til et lavt niveau med udgangen, men samtidigt kan måle på hvor lavt den er trukket. Det gøres ved at koble et ekstra målepunkt på de modstande der har en større målestrøm (her illustreret ved R_4). Dette kan skitseres som vist her:
Princippet i at måle på større strømme i Photodioden
Princippet i at måle på større strømme i Photodioden

I det viste kredsløb trækkes R_4 ned mod stel (0V) ved at sætte det ben på arduinoen til output og trække det lavt, og de to andre modstande R_1, R_2 og R_3 er forbundet til ben på arduinoen, som sættes til input, hvilket gør at de ben svæver, og ikke har indflydelse på målingen. På benet der trækkes lavt er der samtidigt koblet en analog indgang, som kan måle hvor lavt spændingen er trukket, så man kan beregne spændingen over modstanden, som repræsenterer strømmen.

Samlet målekredsløb V2

Ud fra de ovenstående afsnit sammensættes hele målekredsløbet. Dette kan skitseres som vist her:
Det samlede målekredsløb i V2
Det samlede målekredsløb i V2

De første 5 måleområder er lavet uden Low Måling, mens de sidste 3 har måling af hvor langt udgangen trækker mod stel.

Samlet målekredsløb V3

Printcippet i målekredsløbet har ikke ændret sig fra V2 til V3, men da der skal anvendes nogle udgange og indgange til SD-kortet, så er antallet af måleområder skåret ned fra 8 til 6, på en måde så måleområderne får et bredere område, men også således at det højeste måleområde ikke kan gå så langt op i lysintensitet. Dette kan skitseres som vist her:
Det samlede målekredsløb i V3
Det samlede målekredsløb i V3

De første 5 måleområder er lavet uden Low Måling, mens den sidste har måling af hvor langt udgangen trækker mod stel. Dette skønnes at være i orden, men kan give mulighed fr små målefejl i område 4.

Måleområder V2

For at kunne vurdere om modstandene er korrekte, og om der skiftes i de rigtige måleområder, så beregnes de forskellige størrelser. Beregninerne er foretaget i dette Maple arket med betegnelsen V2.

Område Modstand Lav grænse Høj grænse Lav spænding Høj spænding Lav Lux Høj Lux
0 1000kΩ 0 25000 0V 3,81V 0 424
1 330kΩ 7000 24000 1,069V 3,66V 360 1234
2 100kΩ 6500 22000 0,993V 3,36V 1103 3733
3 27kΩ 5000 21000 0,764V 3,21V 3142 13199
4 8,2kΩ 5500 20000 0,840V 3,05V 11383 41392
5 2,2kΩ 4500 20000 0,687V 3,05V 34713 154280
6 680Ω 5500 20000 0,840V 3,05V 137263 499140
7 220Ω 6000 32766 0,916V 5,00V 462839 2525252

Som det kan ses af de høje måleområder, så kommer måleområdet væsentligt over hvad solen kan give af lys - det er dog ind til videre valgt at bevare måleområderne og deres værdier, dels fordi man stadig kan komme til at udnytte det ved variationer i sensoren, og dels fordi der ikke er brug for at opdele måleområderne yderligere, som det ser ud i version 2.

Måleområder V3

Da ideen om et SD-kort opstod, så blev det aktuelt at kunne reducere antallet af måleområder - i første omgang forsøgtes med at reducere med 1, men resultatet blev, at der skulle fjerne to områder. Dette er blevet afbalanceret, så der stadig skulle være luft i måleområderne (væsentligt over solens kraftigste lys) og stadig en fornuftig opløsning i alle måleområder.

Fordelingen af modstandene i V2 blev lavet ud fra at start R0 med 1 MΩ og det laveste måleområde med en 220 Ω. Modstandene her imellem blev så fordelt jævnt logaritmisk. Dette resulterde i at en del modstande afveg en del fra standard-værdierne, mens andre ramte mere præcist, hvilket gjorde at nogle områder dækkede mere end andre.

For at undgå dette blev der taget en anden strategi i brug, hvor den første betingelse for område 0 var den samme, men som udgangspunkt i tabellen over V2, så var område 5 næsten dækkende til formåles - op til solens maksimale intensitet. For at kunne indeholde variationer i sensoren blev det dog vurderet at omkring 1 kΩ ville være en passende maks-område. En anden strategi var at tage udgangspunkt i E12 rækken, som også er dannet ud fra logaritmisk afstand mellem værdierne, med 12 trin fra 10 til 100. Der er således 36 trin fra 1 kΩ til 1MΩ, og hvis dette skulle fordeles jævnt på 5 trin mellem de 6 områder, så kan det passe med at tage 35 trin fra E12-rækken, så området varierer fra 1 MΩ og ned til 1,2 kΩ.

Ud fra disse overvejelser så udvælges modstandene og der beregnes de forskellige størrelser. Beregninerne er foretaget i dette Maple arket med betegnelsen V3.

Område Modstand Lav grænse Høj grænse Lav spænding Høj spænding Lav Lux Høj Lux
0 1000kΩ 0 25000 0V 3,82V 0 424
1 270kΩ 6000 25000 0,916V 3,82V 377 1571
2 68kΩ 5500 25000 0,841V 3,82V 1373 6239
3 18kΩ 6000 25000 0,916V 3,82V 5657 23570
4 4,7kΩ 6000 25000 0,916V 3,82V 21660 90270
5 1,2kΩ 6000 32766 0,916V 5,00V 84850 463400

Som det kan ses af de høje måleområder, så er det kun måleområde 5, der kommer over hvad solen kan give af lys - måleområderne er strukket lidt mere i hver ende her i V3, men det ligger stadig inden for noget der har en ganske fin opløsning.

Beregning af den viste værdi

Selve beregningen af hvilken aflæsning der skal resultere i en lysintensitet tager udgangspunkt i at den typiske værdi for sensoren BPW21r er 9 nA pr. Lux.

Denne strøm omregnes til en spænding, ud fra den modstand som er angivet for det aktuelle måleområde. Omregningen går ud fra AD-konverterens 10 bit opløsning, som giver en faktor på 1024, men også at der er en referencespænding på 5V.

I V2 anvendes den første buffer til at summere 32 læsninger sammen, for at give en middelværdi hen over 20 ms. Der divideres først med de 32 i selve udregningen af Lux-værdien, hvilke kan give en yderligere opløsning på målingen ud over den 10 bit opløsning, som ligger i AD-konverteren.

For at spare denne buffer væk V3, så er det lavet til en simpel summering af 32 værdier før udregningen foretages. De resterende principper følger V2.

Ud over de konkrete størrelser fra målekredsløbet indgår de korrektionsfaktorer som programmet har. Der er en korrektionsfaktor som går på selve sensoren. Den er som udgangspunkt sat til 10000. Der er desuden en korrektionsfaktor for hver modstand i målekredsløbet, hvor de som udgangspunkt er sat til 128.

Dette giver følgende formel for beregning af Lux:
Formel for beregning af Lux til udskrift
Formel for beregning af Lux til udskrift

I koden beregnes dette på følgende måde, hvor der er reduceret lidt i beregningen:
float E = avgHigh * 500000.0 * overallFactor * factor[range] / (arrSize * 1023.0 * resistor[range] * 9.0 * 128.0);

Visning i displayet

Til at få vist Lux værdien i displayet, bliver der anvendt en yderligere midling, som i udgangspunkt er 25 værdier summeret sammen, men som kan korrigeres ved at lave en hurtigere eller langsomere display visning.
Dette gør at der yderligere divideres med avgLgd som er 25 som standard.

Til displayvisningen er der desuden en værdi i W/m2, der anvender en konverteringsfaktor på 120[4] Dette giver følgende formel for beregning af W/m2:
Formel for beregning af W/m2 til displayet
Formel for beregning af W/m2 til displayet

Dette beregnes i koden som vist her:
EE_Wm2 = avgHigh * 500000.0 * overallFactor * factor[range] / (126.58 * avgLgd * arrSize * 1023.0 * resistor[range] * 9.0 * 128.0);

Visningen i displayet kan give følgende visning:
Visningen i displayet med Lux og W/m2
Visningen i displayet med Lux og W/m2

Konvertering mellem Lux og W/m2

Det kan være svært at finde en eksakt omregningsfaktor mellem Lux og W/m2. Årsagen til dette er den ene enhed er lysintensitet, som siger direkte hvor meget lys der er , og den anden er en effekt (W/m2), som afhænger af bølgelængden på lyset[4].

Læser man bredt på nettet, så kan man finde mange forskellige konverteringsfaktorer [5].

De to faktorer der går mest igen, hvis man taler om en gennemsnitskonvertering for synligt sollys er enten 120 Lux = 1 W/2 eller 1 Lux = 0,0079 W/m2, hvilket omregnet giver 126.58 Lux = 1 W/m2. Det ser ikke ud til at der er mere der taler for den ene frem for den anden, men da kilden[4] mest nævner 0,0079, så er det denne konverteringsfaktor der vælges i projektet.

Valg af Microcontroller

For at kunne lave lysmåleren skal der anvendes en microcontroller, og i dette tilfælde er der valgt en Arduino NANO, som er Arduino UNO, bare på et mindre print, men også med den lille forskel, at der er to ekstra analoge indgange, som kan være en fordel, når man skal lave et målekredsløb.

Microcontrolleren der anvendes på en Arduino NANO er en ATMEGA 328P, som er en 8 bit microcontroller der arbejder på 16 MHz.

Ben konfiguration på Arduino NANO til V3

Benfordelingen på Arduinoen er ændret fra V2 til V3 for at give mulighed for lagring på SD-kort. Dette har så betydet at der kan anvendes færre måleområder. Benene er fordelt efter følgende tabel:

Ben Funktion Anvendelse
TXI Serielt input Ikke forbundet - anvendes til Seriel Monitor
RXO Serielt output Ikke forbundet - anvendes til Seriel Monitor
RST1 Reset Ikke forbundet - Resetter processoren ved lavt signal
GND2 Ground Stelben, forbundet til stel (stelplan på printet)
2 Digitalt I/O Styrer måleområde 0
3 Digitalt I/O Forbundet til Displayet Anode af Backlight
4 Digitalt I/O Forbundet til Displayet DB4
5 Digitalt I/O Forbundet til Displayet DB5
6 Digitalt I/O Forbundet til Displayet DB6
7 Digitalt I/O Forbundet til Displayet DB7
8 Digitalt I/O Forbundet til Displayet E
9 Digitalt I/O Forbundet til Displayet RS
1O Digitalt I/O Forbundet til SD-kortet CS
11 Digitalt I/O Forbundet til SD-kortet MOSI
12 Digitalt I/O Forbundet til SD-kortet MISO
13 Digitalt I/O Forbundet til SD-kortet SCK
3V3 3,3V Forsyning Output Ikke forbundet
AREF Analog referencespænding Ikke forbundet - kunne anvendes som reference, hvis der blev brugt andet end 5V
A0 Analogt input / Digitalt I/O Styrer måleområde 5
A1 Analogt input / Digitalt I/O Måler den lave ende af modstanden i måleområde 5
A2 Analogt input / Digitalt I/O Styrer måleområde 4
A3 Analogt input / Digitalt I/O Styrer måleområde 3
A4 Analogt input / Digitalt I/O Styrer måleområde 2
A5 Analogt input / Digitalt I/O Styrer måleområde 1
A6 Analogt input / Digitalt I/O Måler den høje ende af modstandene i alle måleområder
A7 Analogt input / Digitalt I/O Måler på knapperne
+5V 5V forsyning Forbundet til Display, målekredsløb og knapper
RST Reset Ikke forbundet - Resetter processoren ved lavt signal
GND Ground Stelben, forbundet til stel (stelplan på printet)
VIN Forsyning input 7-12V Ikke forbundet, kunne anvendes i forbindelse med batteridrift

Ben konfiguration på Arduino NANO til V2

Benfordelingen på Arduinoen er lavet for at kunne give mulighed for mange måleområder. Benene er fordelt efter følgende tabel:

Ben Funktion Anvendelse
TXI Serielt input Ikke forbundet - anvendes til Seriel Monitor
RXO Serielt output Ikke forbundet - anvendes til Seriel Monitor
RST1 Reset Ikke forbundet - Resetter processoren ved lavt signal
GND2 Ground Stelben, forbundet til stel (stelplan på printet)
2 Digitalt I/O Styrer måleområde 4
3 Digitalt I/O Styrer måleområde 3
4 Digitalt I/O Styrer måleområde 2
5 Digitalt I/O Styrer måleområde 1
6 Digitalt I/O Styrer måleområde 0
7 Digitalt I/O Forbundet til Displayet RS
8 Digitalt I/O Forbundet til Displayet E
9 Digitalt I/O Forbundet til Displayet DB4
1O Digitalt I/O Forbundet til Displayet DB5
11 Digitalt I/O Forbundet til Displayet DB6
12 Digitalt I/O Forbundet til Displayet DB7
13 Digitalt I/O Forbundet til Displayet Anode af Backlight
3V3 3,3V Forsyning Output Ikke forbundet
AREF Analog referencespænding Ikke forbundet - kunne anvendes som reference, hvis der blev brugt andet end 5V
A0 Analogt input / Digitalt I/O Styrer måleområde 7
A1 Analogt input / Digitalt I/O Måler den lave ende af modstanden i måleområde 7
A2 Analogt input / Digitalt I/O Styrer måleområde 6
A3 Analogt input / Digitalt I/O Måler den lave ende af modstanden i måleområde 6
A4 Analogt input / Digitalt I/O Styrer måleområde 5
A5 Analogt input / Digitalt I/O Måler den lave ende af modstanden i måleområde 5
A6 Analogt input / Digitalt I/O Måler den høje ende af modstandene i alle måleområder
A7 Analogt input / Digitalt I/O Måler på knapperne
+5V 5V forsyning Forbundet til Display, målekredsløb og knapper
RST Reset Ikke forbundet - Resetter processoren ved lavt signal
GND Ground Stelben, forbundet til stel (stelplan på printet)
VIN Forsyning input 7-12V Ikke forbundet, kunne anvendes i forbindelse med batteridrift

Datastrukturer i softwaren

Softwaren anvender en del variabler. En del er ret indlysende, men ret mange ligger som datastrukturer i form af arrays, hvilket vil blive gennemgået her.

Ved udvidelsen fra V2 til V3 er der naturligvis tilføjet datastrukturer, men en del er også blevet tilpasset de ændringer der er sket i hardwaren. Disse tilføjelser behandles i næste afsnit, mens det efterfølgende afsnit er det oprindelige fra V2.

Tilføjelser og ændringer i datastrukturen V3

Da det har været nødvendigt at reducere måleområderne er nu kun 6 målemodstande, og dermed 6 måleområder - dette angives med byte const ranges = 6;

Funktionen af de 5 arrays der anvendes er stadig de samme, men der er kommet nyt indhold i dem som vist her:

byte const control []    = {2, A5, A4, A3, A2, A0};
byte const measureLow [] = {0,  0,  0,  0,  0, A1};
float const resistor [] = { 1E6,  27E4,  68E3,  18E3,  4700,  1200};
int const rangeLow []  = {    0,  6000,  5500,  6000,  6000,  6000};
int const rangeHigh [] = {25000, 25000, 25000, 25000, 25000, 32766};

Der anvendes stadig de samme variabler til at styre måleprocessen med, så det eneste der er rettet er størrelsen på factor-arrayet:

byte factor [] = {128, 128, 128, 128, 128, 128};

Den første midling, som var lavet i to arrays der er arrayene blevet reduceret væk for at spare hukommelse, så der kun er summerings-variablerne og styre-variablerne tilbage

byte const sumSize = 32;
int sumHigh = 0;
int sumLow = 0;
byte arrPtr = 0;

Timingen af målingerne er bibeholdt, og det samme er princippet omkring midling, men der er tilføjet en global variabel, og konverteringskonstanten er rettet

float EE_Wm2;
float const Lux_Wm2 = 126.58;


Da knapperne har fået nye funktioner er der rettet i typen af variablerne, så der anvendes følgende variabler:

int buttonValue;
byte buttonCount1;
unsigned int buttonCount2;

Til styring af hvilke modes og hvad der skal udføres er der tilføjet noget så man kan redigere i logning-timingen. Der kunne måske reduceres lidt mere væk, men der er nu følgende variabler:

boolean printMode = false;
boolean printBuffer = false;
boolean measuring = false;
boolean timeEditMode = false;

Tidsstyringen af målingen på SD-kortet bliver styret af følgende variabler:

unsigned long startMeasure = 0;
unsigned long stopMeasure = 0;
unsigned long measureTime = 0;
unsigned long measureInterval = 0;
unsigned long mmInterval;
unsigned long ssInterval;
unsigned long hour, minute, second;

Til styring af SD-kortet og de tidsvariabler man kan redigere i er der lavet følgende variabler.

File myFile;

boolean sdPresent;
byte p_i_sec = 0;
byte p_i_min = 1;
byte p_t_min = 2;
byte p_t_hour = 3;
byte timingArr [] = {0, 0, 0, 0};
byte editPtr = 0;
byte logNumber = 0;
boolean logging = false;
  • myFile er den variabel, som kan arbejde med en fil, og den anvendes til både timing.txt og til logfilerne
  • sdPresent angiver om der er et SD-kort, som arduinoen kan læse, det testes ved opstart, og den kan slettes hvis skrivning til kortet svigter
  • p_i_sec,p_i_min, p_t_min, p_t_hour er pointere ind i timingArr, så koden kan skrives mere generelt
  • timingArr indeholder de to tider - intervallet mellem målingerne angivet i sekunder og minutter og den samlede måletid angivet i minutter og timer
  • editPtr anvendes til at angive hvilket ciffer i tiderne man redigerer i
  • logNumber angiver den fil der er ved at blive logget i, så 3 vil give et filnavn der hedder LOG3.CSV
  • logging angiver om der er ved at blive logget

Datastrukturer i V2

Der er 8 målemodstande, og dermed 8 måleområder - dette angives med byte const ranges = 8;

Der er laves 5 arrays med 8 konstanter i hver til at angive hvordan måleområderne er definere.

  • control angiver de 8 ben, som sættes op til output, når det aktuelle måleområde skal måle - resten sættes som input
  • measureLow angiver de 3 analoge indgange, som måler i de lave ender af modstandene i måleområde 5-7 - de resterende er angivet som 0, så man kan teste her om der skal måles på den lave ende af modstanden
  • resistor angiver målemodstandendes påstemplede værdi
  • rangeLow angiver den buffer-sum der skal til for det aktuelle måleområde, for at der skal skiftes ned i et lavere måleområde
  • rangeHigh angiver den buffer-sum der skal til for det aktuelle måleområde, for at der skal skiftes op i et højere måleområde
byte const control []    = {6, 5, 4, 3, 2, A4, A2, A0};
byte const measureLow [] = {0, 0, 0, 0, 0, A5, A3, A1};
float const resistor [] = {1E6, 33E4, 1E5, 27E3, 8200, 2200, 680, 220};
int const rangeLow []  = {    0,  7000,  6500,  5000,  5500,  4500,  5500,  6000};
int const rangeHigh [] = {25000, 24000, 22000, 21000, 20000, 20000, 20000, 32766};

Til at styre måleprocessen med anvendes følgende variabler

  • range angiver det aktuelle måleområde - bruges til at indeksere ind i de arrays, der har noget med måleområder at gøre
  • manualRange angiver om der skal autoranges, eller om man skal kunne skifte manuelt på en af knapperne
  • factor er et array, som indeholder de faktorer, som kan korrigere for afvigelser i målemodstandene
  • overallFactor korrigerer for fejlen i sensoren
  • editing er en logisk variabel, som anvendes til at beskytte for redigering - bliver først true, når den korrekte PIN-kode er tastet
byte range = 0;
boolean manualRange = false;
float factor [] = {128.0, 128.0, 128.0, 128.0, 128.0, 128.0, 128.0, 128.0};
float overallFactor = 10000.0;
boolean editing = false;

Disse variabler bruges til den første midling af målingerne

  • arrSize er sat til 32, og er tilpasset således at der kan midles hen over 20 ms ved hjælp af 32 målinger. Tilpasningen er også lavet ud fra at koden kan når "rundt" i hvert loop
  • highArr er et array med de sidste 32 AD målinger på den høje ende af modstanden
  • sumHigh er summen af alle værdierne i highArr
  • lowArr er et array med de sidste 32 AD målinger på den lave ende af modstanden
  • sumLow er summen af alle værdierne i lowArr
  • arrPtr er den variabel, som indekserer ind i de to arrays
byte const arrSize = 32;
int highArr[arrSize];
int sumHigh = 0;
int lowArr[arrSize];
int sumLow = 0;
byte arrPtr = 0;

Disse variabler anvendes til at time målingerne korrekt

unsigned long interval = 20000;
unsigned long mTime = 0;

Til displayet foretages en yderligere midling af de værdier der er midlet i bufferen. Dette gøres ved at summere i avgHigh og avgLow, avgLgd gange.
Ud fra dette beregnes Lux-værdien og den kan omsættes til W/m2 med constanten Lux_Wm2.

byte avgLgd = 25;
byte avgCount = 0;
long avgHigh = 0;
long avgLow = 0;
float EE_Lux;
float const Lux_Wm2 = 120.0;

Til aflæsning af de to knapper anvendes et analogt input og følgende variabler:

int buttonValue;
byte buttonCount1;
byte buttonCount2;

Til styring af hvilke modes og hvad der skal udføres, så anvendes følgende logiske variabler:

boolean printMode = false;
boolean printBuffer = false;
boolean measuring = false;

Tidsstyringen af den måling, som kan printes ud på serielporten bliver styret af følgende variabler:

unsigned long startMeasure = 0;
unsigned long stopMeasure = 0;
unsigned long measureTime = 0;
unsigned long measureInterval = 0;
unsigned long mmInterval;
unsigned long ssInterval;
unsigned long hour, minute, second;

Software Struktur

Softwaren er udviklet i Arduinos eget IDE, som er beskrevet under Software og Udviklingsmiljø her i wikien.

Hele den grundlæggende struktur er baseret på setup(), som afvikles en gang efter reset af Arduinoen og derefter at loop() kaldes lige så hurtigt som den kan afvikles.

Den grundlæggende ide i softwaren er baseret på at meget lys i vores dagligdag svinger med 50 eller 100 Hz, og derfor er der lavet sådan at svingninger på disse to frekvenser bliver elimineret mest muligt. Dette gøres ved at måle et antal gange hen over 20 ms, og så tage gennemsnittet af disse målinger. Dette uddybes senere.

For hvert gennemløb af loop() testes der på 3 forskellige ting:

  1. Er der modtaget noget på den serielle port?
  2. Skal der gemmes en ny måling?
  3. Er der gang i interval-måling?

Hvis der er modtaget noget på den serielle port, så udføres koden som beskrevet i følgende flowchart:

Flowchart som beskriver modtagelsen på den serielle port
Flowchart som beskriver modtagelsen på den serielle port

Om der skal gemmes en ny måling bestemmes ud fra tiden, hvor der anvendes micros() til at bestemme om det er tid. I løbet af 20 ms måles der 32 gange, hvilekt betyder at der er 20.000 / 32 = 625 µs mellem hver måling. Håndtering af hver måling udføres som beskrevet i følgende flowchart:

Flowchart som beskriver optagelsen af en måleværdi
Flowchart som beskriver optagelsen af en måleværdi

Hvis lysmåleren er i gang med at udføre intervalmåling, som udskrives til den serielle port, så udføres koden som beskrevet i følgende flowchart:

Flowchart som beskriver intervalmåling
Flowchart som beskriver intervalmåling

Display

Opkoblingen af displayet er ændret fra V2 til V3, fordi SD-kortet skal anvende nogle bestemte ben til kommunikationen med kortet. Derfor er der to forskellige opkoblinger.

Der anvendes et standard 2x16 karakters LCD Display[6] til visning af målingerne, og opkoblingen er lavet efter eksempler anvendt her. Biblioteket til displayvisning ligger som standard i Arduinos IDE.

Forbindelser til displayet V2

Display med forbindelser i lysmåleren V2
Display med forbindelser i lysmåleren V2

Forbindelser til displayet V3

Display med forbindelser i lysmåleren V3
Display med forbindelser i lysmåleren V3

Software til displayet V2

Opkoblingen af displayet etableres ved at include biblioteket og skabe et lcd objekt, der kan kommunikere med displayet. Det gøres med følgende kode:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
byte const backLight = 13;
boolean lightStatus = true;

Benforbindelserne er tilpasset den fordeling af benene der er lavet i dette projekt.

Udgang 13 er forbundet til Backlight, så man kan tænde og slukke for det. Dette styres ud fra variablen lightStatus.

For at initialisere displayet bliver der i setup() udført følgende kode:

  pinMode(backLight, OUTPUT);
  digitalWrite(backLight, HIGH);
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("LUX Meter");
  lcd.setCursor(0, 1);
  lcd.print("Holstebro HTX");
  delay(2000);
  lcd.clear();

Selve udskiften til displayet er lavet med følgende kode:

        lcd.setCursor(0, 0);
        if (EE_Lux < 100.0) {
          lcd.print(EE_Lux, 1);
        } else {
          lcd.print(EE_Lux, 0);
        }
        lcd.print(" Lux     ");
        lcd.setCursor(0, 1);
        float EE_Wm2 = EE_Lux / Lux_Wm2;
        if (EE_Wm2 < 1000.0) {
          lcd.print(EE_Wm2);
        } else if (EE_Wm2 < 10000.0) {
          lcd.print(EE_Wm2, 1);
        } else {
          lcd.print(EE_Wm2, 0);
        }
        lcd.print(" W/m2  R:");
        lcd.print(range);
        lcd.print("  ");

Software til displayet V3

Der er rettet i benforbindelserne i følgende kode

#include <LiquidCrystal.h>

LiquidCrystal lcd(9, 8, 4, 5, 6, 7);
byte const backLight = 3;
boolean lightStatus = true;

Benforbindelserne er tilpasset den fordeling af benene der er lavet i dette projekt.

Udgang 3 er forbundet til Backlight, så man kan tænde og slukke for det. Dette styres ud fra variablen lightStatus.

Initialiseringen af displayet er ikke ændret.

Selve udskiften til displayet skal skrive status på SD-kortet og hvilken fil der skrives i. Det er lavet med følgende kode:

          lcd.setCursor(0, 0);
          if (EE_Lux < 100.0) {
            lcd.print(EE_Lux, 1);
          } else {
            lcd.print(EE_Lux, 0);
          }
          lcd.print(" Lux R");
          lcd.print(range);
          lcd.print("   ");
          lcd.setCursor(13, 0);
          if (sdPresent) {
            lcd.print("SD ");
          } else {
            lcd.print("-SD");
          }
          lcd.setCursor(0, 1);
          EE_Wm2 = EE_Lux / Lux_Wm2;
          if (EE_Wm2 < 1000.0) {
            lcd.print(EE_Wm2);
          } else if (EE_Wm2 < 10000.0) {
            lcd.print(EE_Wm2, 1);
          } else {
            lcd.print(EE_Wm2, 0);
          }
          lcd.print(" W/m2    ");
          lcd.setCursor(13, 1);
          if (logging) {
            lcd.print("L");
            lcd.print(logNumber);
            lcd.print("  ");
          } else {
            lcd.print("   ");
          }

Trykknapper

Tilslutning af trykknapperne i lysmåleren
Tilslutning af trykknapperne i lysmåleren

Hardwaren til knapperne i V3 er uændret fra V2, men da knapperne skal have mere funktionalitet i V3, så er der lavet tilføjelser i softwaren til håndtering af knapperne. Der er også tilføjet en ekstra display mode.

Som det ses i diagrammet, så aktiverer de to knapper hver sin spændingsdeler mod stel.

Når ingen af knapperne er aktiveret, så kommer der 5V ind på A7.

Hvis man aktiverer knap 1, så kommer der en spændingsdeler mellem R2 og R3, som giver en anden spænding ind på A7. Denne spænding kan beregnes som følger:
Spændingen ind på A7, når knap 1 er aktiveret
Spændingen ind på A7, når knap 1 er aktiveret

Denne spænding giver at helttal fra AD-konverteren, der kan beregnes som følger:
Aflæsningen på A7, når knap 1 er aktiveret
Aflæsningen på A7, når knap 1 er aktiveret

Hvis man aktiverer knap 2, så kommer der en spændingsdeler mellem R1 og R3, som giver en anden spænding ind på A7. Denne spænding kan beregnes som følger:
Spændingen ind på A7, når knap 2 er aktiveret
Spændingen ind på A7, når knap 2 er aktiveret

Denne spænding giver at helttal fra AD-konverteren, der kan beregnes som følger:
Aflæsningen på A7, når knap 2 er aktiveret
Aflæsningen på A7, når knap 2 er aktiveret

Softwaren til trykknapperne V2

Den del af softwaren, som håndterer de to trykknapper er placeret i en selvstændig funktion. Denne funktion kaldes hver gang der lægges en ny aflæsning i lysmålingen, altså hvert 625. µs.

For at man kun registrerer et knap-tryk, så læses A7 flere gange inden knap-trykket registreres. Systemet er lavet så læsningen accepterer 12 AD trin på hver side af den ønskede værdi, men at der skal have været 100 aflæsninger inden for dette område, inden der registreres et knaptryk. Dette er lavet med to variabler buttonCount1 og buttonCount2, som tælles op hver gang værdien er i det accepterede vindue, men som nulstilles hvis det er uden for vinduet. Når tællingen af variablen når 200 tælles der ikke videre. Trykknappen registreres altså når der er talt 100 gange, og kun den ene gang. Det sker når der er læst acceptable værdier i 62,5 ms.

Koden der laver dette for trykknap 1 ser ud som følger:

// Routine to handle the two buttons at one analog input
void handleButtons() {
  buttonValue = analogRead(pushButton);
  if (buttonValue < 524) {
    if (buttonValue > 500) {
      if (buttonCount1 < 200) {
        buttonCount1++;
      }
      if (buttonCount1 == 100) {
        if (manualRange) {  // Button 1 changes the range in manual range mode
          if (range == ranges - 1) {
            shiftRange(-7);
          } else {
            shiftRange(+1);
          }
        } else {   // Otherwise Button 1 starts and stops intervaled measuring
          startStopMeasuring();
        }
      }
      buttonCount2 = 0;

Knap 1 har to funktioner. Hvis der er angivet et tidsinterval, så kan den starte og stoppe interval-målingen.

Hvis der er angivet at man vil skifte måleområde manuelt (via Serial Monitor), så skifter knap 1 op i måleområdet, og ved måleområde 7 skiftes til måleområde 0.

Knap 2 har kun en enkelt funktion, nemlig at kunne tænde og slukke baggrundslyset i displayet. Dette er lavet i følgende kode:

    } else if (buttonValue < 340) {
      if (buttonValue > 315) {
        if (buttonCount2 < 200) {
          buttonCount2++;
        }
        if (buttonCount2 == 100) {  // Button 2 switches the backgound Light on and off
          lightStatus = ! lightStatus;
          digitalWrite(backLight, lightStatus);
        }
        buttonCount1 = 0;

Den resterende del af koden i funktionen er sikring af at tællingen stoppes når målingen på A7 er uden for de accepterede områder:

      } else {
        buttonCount1 = 0;
        buttonCount2 = 0;
      }
    } else {
      buttonCount1 = 0;
      buttonCount2 = 0;
    }
  } else {
    buttonCount1 = 0;
    buttonCount2 = 0;
  }
}

Softwaren til trykknapperne V3

Strukturen i aflæsningen af knapperne er stadig den samme, men fordi knap 2 skal kunne håndtere et langt tryk (2 sekunder), så skal buttonCount2 være af typen int i stedet for byte, for at kunne håndtere tiden.

Knap 1 kan stadig skifte manuelle områder, men skal i timeEditMode også kunne justere tiderne, ved at man kan redigere i cifrene. Dette er implementeret i følgende kode:

      if (buttonCount1 == 100) {
        if (manualRange) {  // Button 1 changes the range in manual range mode
          if (range == ranges - 1) {
            shiftRange(-7);
          } else {
            shiftRange(+1);
          }
        } else {
          if (timeEditMode) {
            byte ePtr = editPtr / 2;
            byte tal = timingArr[ePtr];
            if ((editPtr % 2) == 0) {
              tal = ((tal / 10) * 10) + (((tal % 10) + 1) % 10);
            } else {
              tal = ((((tal + 10) / 10) % 6) * 10) + (tal % 10);
            }
            timingArr[ePtr] = tal;
          } else {   // Otherwise Button 1 starts and stops intervaled measuring
            startStopMeasuring();
          }
        }

Tilføjelsen til knap 2 handler om at den skal kunne skifte timeEditMode, hvis man holder knappen inde i 2 sekunder. Når den er i det mode, så skal man kunne skifte det ciffer man redigerer i. Dette kan ses i følgende kode:

        if (buttonCount2 == 3200) {
          timeEditMode = !timeEditMode;
          lightStatus = true;
          digitalWrite(backLight, lightStatus);
          if (!timeEditMode) {
            setInterval(timingArr[p_i_sec], timingArr[p_i_min]);
            setMeasureTime(timingArr[p_t_min], timingArr[p_t_hour]);
          }
        }
        if (buttonCount2 == 100) {  // Button 2 switches the backgound Light on and off
          if (timeEditMode) {
            editPtr++;
            if (editPtr >= 8) {
              editPtr = 0;
            }
          } else {
            lightStatus = ! lightStatus;
            digitalWrite(backLight, lightStatus);
          }
        }

Display tilføjelse ved redigering i V3

For at kunne se hvad man laver, mens man redigerer i tiderne er der til displaydelen indføjet følgende kode inden den normale visning (derfor afsluttes med else):

        lcd.setCursor(0, 0);
        if (timeEditMode) {
          lcd.print("Interval ");
          dispLeadZero(timingArr[p_i_min]);
          lcd.print("m");
          dispLeadZero(timingArr[p_i_sec]);
          lcd.print("s ");
          lcd.setCursor(0, 1);
          lcd.print("Time  ");
          dispLeadZero(timingArr[p_t_hour]);
          lcd.print("h");
          dispLeadZero(timingArr[p_t_min]);
          lcd.print("m    ");
        } else {

SD-kortet i V3

Den væsentligste tilføjelse der er sket i V3 er at der er kommet et SD-kort på, som kan anvendes til at logge lysmålingerne med.

Rent elektrisk, så skal SD-kortet kommunikere med Arduinoen ved hjælp af en SPI-bus. Denne bus-struktur er implementeret i microcontrolleren ATMEGA328p som harware, og derfor er det bestemte ben på Arduinoen der anvendes til SD-kortet. For at kunne kommunikere med SD-kortet er der startet ud fra en guide på Arduinos hjemmeside[7]

De faste ben til SD-kortet er MOSI på ben 11, MISO på ben 12 og SCK på ben 13. Ud over det skal der anvendes et CS-ben, som kan være et hvilket som helst ben på Arduinoen. Her er der valgt ben 10. Dette giver følgende opkobling:
Diagram over forbindelserne til SD-kortet
Diagram over forbindelserne til SD-kortet

Softwaren til SD-kortet

Det bibliotek der anvendes til SD-kortet bruger ret meget hukommelse, fordi det skal kunne håndtere en buffer til at skrive i filer på SD-kortet. Det betyder at der er begrænsninger som fx at man kun kan arbejde med en fil ad gangen, og at fil-systemet ikke kan bruge de moderne filnavne, men er begrænset til 8 tegn i filnavnet og 3 tegn i filtypen. Til den aktuelle anvendelse af SD-kortet betyder det ikke det store, men en enkelt begrænsning har været betydende for brugen af SD-kortet.

Ud fra eksperimenter med softwaren blev det konstateret, at man kunne kun initialisere SD-objektet een gang. Prøvede man igen, så mistede man kontakten til kortet. Dette gør at man skal have fat i SD-kortet i setup(), altså når man tænder Arduinoen. Det er forsøgt dokumenteret i betjeningen.

For at kunne anvende SD-kortet så includes to biblioteker som vist her:

#include <SPI.h>
#include <SD.h>

Til håndteringen af SD-kortet skal der anvendes en variabel, og fordi der kun kan arbejdes med en fil ad gangen, så er der kun oprettet den ene fil, selvom det er forskellige fil der arbejdes med. De resterende variabler er tilknyttet SD-kortet og logningen af målingerne.

// Variables for the SD Card
File myFile;

boolean sdPresent;
byte p_i_sec = 0;
byte p_i_min = 1;
byte p_t_min = 2;
byte p_t_hour = 3;
byte timingArr [] = {0, 0, 0, 0};
byte editPtr = 0;
byte logNumber = 0;
boolean logging = false;

I setup() læses om der er kontakt til SD-kortet, og hvis der er det, så læses filen med tidsinformation (interval og måletid), hvis den eksisterer. Dette sker i følgende kode:

  sdPresent = SD.begin(10);
  readTimeFile();

Funktionen readTimeFile() kigger først på om der er forbindelse til SD-kortet, og hvis der er det, så forsøges der at åbne filen timing.txt, og hvis den er der, så læses efter linjer der starter med I (interval i min:sec) og linjer der starter med T (måletid i hour:min). Dette er lavet i følgende kode:

void readTimeFile() {
  if (sdPresent) {
    // open the time file for reading:
    myFile = SD.open("timing.txt");
    if (myFile) {
      // read from the file until there's nothing else in it:
      while (myFile.available()) {
        char ch = myFile.read();  // Look for identifying character
        if (ch == 'i' || ch == 'I') {  // Read Interval if I
          timingArr[p_i_min] = myFile.parseInt();
          timingArr[p_i_sec] = myFile.parseInt();
        }
        if (ch == 't' || ch == 'T') {  // Read Time if T
          timingArr[p_t_hour] = myFile.parseInt();
          timingArr[p_t_min] = myFile.parseInt();
        }
      }
      setInterval(timingArr[p_i_sec], timingArr[p_i_min]);
      setMeasureTime(timingArr[p_t_min], timingArr[p_t_hour]);
      // close the file:
      myFile.close();
    }
  }
}

Når man ønsker at starte logningen (tryk på den blå knap eller S i Serial monitor), så kaldes funktionen startLogFile(). Funktionen tjekker om SD-kortet er til stede, og hvis det er det, så leder den på SD-kortet efter det næste filnavn i rækken LOGn.CSV, hvor n er et tal. Den første fil der ikke er til stede bliver oprettet, og der skrives første linje i filen med en overskrift til målingerne, og derefter den første måling til tiden 00:00:00. Fejler skrivningen af filen, så registreres det at SD-kortet ikke er til stede. Dette sker i følgende kode:

void startLogFile() {
  if (sdPresent) {
    logNumber = 0;
    String fileName;
    do {
      fileName = "log" + String(logNumber) + ".csv";
      logNumber++;
    } while (SD.exists(fileName));
    logNumber--;
    myFile = SD.open(fileName, FILE_WRITE);
    if (myFile) {
      myFile.println("Time;Lux;W/m2");
      myFile.close();
      writeLogValue();
      logging = true;
    } else {
      sdPresent = false;
    }
  }
}

Koden der skriver målingerne til SD-kortet er implementeret i funktionen writeLogValue(). Her sikres igen at der er kontakt til SD-kortet, og ud fra det fundne fil-nummer, så åbnes filen for skrivning, og hvis det går godt, så skrives tid og måleværdierne til filen. Filen lukkes hver gang der er skrevet til den. Dette sker for at man vil kunne tage SD-kortet ud mens den måler, uden at man mister indholdet der er skrevet ved de foregående målinger. Dette ser ud som følger:

void writeLogValue() {
  if (sdPresent) {
    String fileName = "Log" + String(logNumber) + ".csv";
    myFile = SD.open(fileName, FILE_WRITE);
    if (myFile) {
      if (hour < 10) {
        myFile.print(0);
      }
      myFile.print(hour);
      myFile.print(":");
      if (minute < 10) {
        myFile.print(0);
      }
      myFile.print(minute);
      myFile.print(":");
      if (second < 10) {
        myFile.print(0);
      }
      myFile.print(second);
      myFile.print(";");
      myFile.print(EE_Lux, 1);
      myFile.print(";");
      myFile.println(EE_Wm2, 2);
      myFile.close();
    } else {
      sdPresent = false;
    }
  }
}

Logningen af værdierne styres ud fra følgende kode, som også sørger for at tids-variablerne opdateres.

  if (measuring) {  // Handle printout of measuring with at user given interval
    if (startMeasure > 0) {
      if ((millis() - startMeasure) > measureInterval) {  // Interval gone?
        startMeasure += measureInterval;
        second += measureInterval / 1000;  // Add time to hh:mm:ss
        while (second >= 60) {
          second -= 60;
          minute += 1;
        }
        while (minute >= 60) {
          minute -= 60;
          hour += 1;
        }
        if (logging) {
          writeLogValue();
        }
// #ifndef nodebug
        printMeasure();
// #endif
        if (stopMeasure > 0) {   // Stop the measuring at a given time
          if (millis() > stopMeasure) {
            startStopMeasuring();
          }
        }
      }
    }
  }

Betjening

Der findes 2 brugbare versioner af lysmåleren. V2 som har været en del af udviklingen af lysmåleren, V2 kræver lidt mere teknisk indsigt og en PC tilsluttet, for at kunne lave logning af målingerne. V3 har fået tilføjet et SD-kort, så man kan lave indstillinger og opsamling i logfil, der opsamles på SD-kortet.

Betjening V3

Betjeningen af lysmåleren i V3 er tænkt, så man udelukkende behøver at betjene den ved at tilslutte USB-kablet til en forsyning (USB-port i PC'en, Mobil-lader eller Powerbank), og ellers bare betjene lysmåleren ved hjælp af de to knapper (rød knap til venstre og blå knap omkring midten, som de ses på billedet i næste afsnit), så kan man lave simple lysmålinger. Hvis man anvender et SD-kort, så kan man også lave logning over en tidsperiode med faste intervaller.

Der kan stadig betjenes ting via seriel-porten i Serial Monitor, men det er kun til specielle ting, eller til at understøtte målingerne.

Sensorens placering i lysmåleren

Selve sonsoren på lysmåleren sidder i den ene ende af printet og ser ud som følger:
Sensoren placeret ved kanten af printet
Sensoren placeret ved kanten af printet

Sensoren placeret i selve printet kan også ses i billederne i de næste afsnit.

Tilslutning af SD-kortet V3

SD-kort læseren kan ikke tage et hvilket som helst SD-kort, men det skulle kunne håndtere både FAT16 og FAT32 og både kunne håndtere standard SD kort og SDHC kort[8]. Der er testet med et 1GB kort og et 2GB kort - umiddelbart, det er ikke testet om læseren kan håndtere større kort end 2GB.

For at lysmåleren skal kunne arbejde med SD-kortet, så skal de sidde korrekt i SD kort modulet. Det sættes i kort modulet med forsiden nedad, og man skal være opmærksom på at den skubber ud hver anden gang man trykker den i bund - kortet kan kun læses når det sidder rigtigt i SD kort modulet.

Lysmåleren med SD kortet liggende ved siden af SD kort modulet
Lysmåleren med SD kortet liggende ved siden af SD kort modulet

Lysmåleren registrerer kun SD kortet ved opstart. Som det ses på ovenstående billede, så skriver den -SD øverst i højre side. Det indikerer at den ikke har registreret SD kortet.

For at få lysmåleren til at registrere SD-kortet skal sidde i mens den tændes, så hvis den skriver -SD i displayet, så skal man lige tage USB-kablet (forsyning) ud, sikre sig at SD-kortet sidder rigtigt i SD kort modulet, og slutte USB kablet til igen. Når den har accepteret SD-kortet ser den ud som på billedet herunder.

Lysmåleren med SD kortet rigtigt i SD kort modulet
Lysmåleren med SD kortet rigtigt i SD kort modulet

Logning bestemt af en fil på SD-kortet V3

En enkelt måde at bestemme tiderne for logningen er ved at skrive tiderne i en fil på SD-kortet, inden man sætter det i lysmåleren.

Filen skal hedde timing.txt, og oprettes nemmet med notesblok eller lignende program.

Filen skal indeholde en eller to linjer som angives på følgende måde:

I 00:15
T 00:30

I den første linje angives at der skal logges hvert 15. sekund - det første tal er i minutter, det andet er i sekunder. Der skal angives et interval for at den vil logge.

I den anden linje angives at der skal logges i 30 minutter - her er det første tal i timer og det andet tal i minutter. Angiver man ikke det andet tal, så vil den logge i en time som standard.

Man kan også angive at den skal logge indtil man stopper den manuelt, eller man slukker for den - det gør man ved at angive tiden til 00:00.

Start af logningen V3

For at starte logningen skal man have angivet måle-intervallet (hvor tit der skal måles), og så er det blot at trykke på den blå knap (lige ved siden af SD-kortet).

Når man har startet målingen, så angives der i displayet at den er i gang med Logning ved at skrive et L efterfulgt af et tal nederst til højre, som vist her:
Visning i displayet når logning på SD-kortet er i gang
Visning i displayet når logning på SD-kortet er i gang

Når måletiden udløber, eller man stopper manuelt (på den blå knap), så forsvinder visningen af Ln i displayet. Der er nu lavet en log-fil, som beskrevet i næste afsnit.

Log-filerne på SD-kortet V3

Når lysmåleren starter en logning på SD-kortet, så bestemmer den selv filnavnene.

Hvis der ikke er logfiler på SD-kortet, så kommer logfilen til at hedde LOG0.CSV. Lysmåleren kigger kortet igennem og finder det første ledige nummer der kan bruges, så den næste fil der oprettes kommer til at hedde LOG1.CSV.

Herunder ses en stifinder-visning af et SD-kort, hvor der er lavet 8 måleserier:
Stifinder visning af filer på SD-kortet
Stifinder visning af filer på SD-kortet

Filformatet er et forsimplet format som Excel forstår - CSV, som også andre programmer kan håndtere - notesblok kan fint håndtere det Logger pro kan også læse det, men har problemer med at tolke tiden.

Som det ses på fil-listen, så er alle filer tidsmærket med samme tidspunkt. Det skyldes at Arduinoen ikke har et egentligt ur indbygget, og derfor ikke kender klokkeslættet der skal sættes på. Det gør at man ikke kan bruge tiden til at bestemme hvilke filer der er nyest. Hvis man sletter filer fra kortet og måler på ny, så vil filnavnet blive det først ledige, så her skal man være opmærksom på at nummereringen kan snyde - det er en fordel at notere det nummer der står i displayet, når man foretager målingen.

Indholdet af filen kan se således ud i Excel:
Excel visning af logfil, med engelsk komma
Excel visning af logfil, med engelsk komma

Som det kan ses i visningen, så er tallene skrevet med . som kommaseparator i stedet for den danske måde med , som kommaseparator. Dette er bibeholdt, fordi programmer som logger pro bedst accepterer dette format, og det er ganske enkelt at lave det om.

Det man gør er at Søge og Erstatte alle punktummer med kommaer (Genvejs-tast Ctrl-H), så man får følgende dialog:
Dialog til at erstatte . med , for at få dansk komma
Dialog til at erstatte . med , for at få dansk komma

Ved at klikke Ctrl-H og indtaste at der skal søges efter . og erstattes med , så kan man klikke Erstat alle - så bliver det til danske tal.

Indholdet af filen vil nu se således ud i Excel:
Excel visning af logfil, med dansk komma
Excel visning af logfil, med dansk komma

Manuel indstilling af log-tiderne V3

Der er også muligheden for at ændre i log-tiderne, uanset om man har angivet dem i filen timing.txt, eller man ikke har oprettet filen.

Inden man går i gang, skal man sikre sig at man har forbindelse til SD-kortet (displayet må ikke vise -SD). Denne kontakt kan man kun opnå, hvis man genstarter, og der nulstilles loggings-tiderne.

Når man har kontakt til SD-kortet, så holdes den røde knap (længst til venstre) nede i 2 sekunder, hvorefter displayet skifter visning til følgende:
Display visning, når tiderne indstilles
Display visning, når tiderne indstilles

På første linje vises interval-tiden, som er tiden mellem hver måling. Den er angivet i minutter(m) og sekunder(s).
På den anden linje vises den samlede måletid der ønskes. Den er angivet i timer(h) og minutter(m). Hvis denne tid sættes til 0, så fortsætter logningen så længe man ønsker det (stoppes med den blå knap).

Det ciffer der blinker kan så "rulles" fra 0-9 eller 0-5, ved at trykke på den blå knap. Hvilket ciffer man retter i vælges ved tryk på den røde knap.

Når man har indstillet tiden, så er lysmåleren klar til at måle ud fra det man har indstillet den til.

Betjening i Serial Monitor V3

Som beskrevet under afsnittet Håndtering af hukommelsesproblemer, så tager udskrift til den serielle port, specielt af konstante tekster, en del hukommelse, og da SD-kortet også sluger meget hukommelse, så er der skåret noget ned på betjeningen via seriel-porten. En del er dog bevaret, da det kan være mere brugervenligt, men også fordi der er ting som er nødvendige at kunne tilgå den vej.

Specielt hjælpen, som også vises i starten er begrænset væsentligt til følgende:


Lux Meter til Arduino
Holstebro HTX 2022

I mm:ss - Measure Interval
T hh:mm - Measure Time
S       - Start / Stop measure
Measure Interval = 00:00:10
Measure Time = 02:30:00

De to sidste linjer her kommer kun, når det sidder et SD-kort i lysmåleren og der er en timing.txt fil på SD-kortet. Tiderne der vises er det der læses i filen.

Som det er angivet kan man indstille de to tider med I og T. Ud over det kan man starte og stoppe målingen. Umiddelbart er det hvad der er tilgængeligt.

Den serielle monitor udskriver så også de målinger der logges ned i filerne på SD-kortet som vist her:

00:00:00	56.97 Lux
00:00:10	61.17 Lux
00:00:20	59.51 Lux
14:42:59.285 -> 00:00:30	60.18 Lux
14:43:09.260 -> 00:00:40	60.07 Lux
14:43:19.267 -> 00:00:50	59.57 Lux

Det tilføjer den mulighed, som er illustreret her, nemlig at man kan få klokkeslettet på. Det er PC'ens ur der udskrives, og er derfor ikke en mulighed, når tingene kun arbejder i Arduinoens miljø.

Måden man får tilføjet det, er ved at man sætter flueben i bunden af Serial monitor ved Show timestamp.

Kalibrering af lysmålingen V3

Det er stadig relevant at kunne kalibrere den enkelte lysmåler, så man kan få den til at måle præcist. Betjeningen er stadig den samme, men der er ikke de samme udskrifter længere, og specielt hjælpen er sparet væk, for at kunne optimere hukommelsen, så alting stadig fungerer.

Kalibreringskommandoerne er som følger:

  • R - udskriver de aktuelle kalibreringsfaktorer
  • U - indtastning af pin-kode, som er nødvendig for at rette i kalibreringsfaktorerne
  • C - stiller kalibreringsfaktorerne tilbage til de typiske data for sensor og modstande
  • O - indlæsning af overall kalibreringsfaktor - bruges til at kalibrere selve sensoren. skrives som O fffff
  • F - indlæsning af kalibreringsfaktor til et givet range. Skrives som F r fff

Betjening V2

Den betjening man kan lave med trykknapperne i V2 af lysmåleren er meget begrænset. Man kan tænde og slukke baggrundsbelysningen på displayet. I normal drift har den anden knap ingen funktion, før man har Serial monitor på.

Hvis man vil betjene lysmåleren yderligere, så sker det ved at bruge Serial Monitor med Baud rate 9600, hvor man kan skrive kommandoer til Arduinoen, og den kan skrive forskelligt ud.

Den serielle monitor ligger som en del af Arduinos Software og Udviklingsmiljø, som man skal have installeret for at kunne bruge det. Alternativt kan man bruge et terminal-program[9].

Lysmåleren tilsluttes en USB-port, og for at kunne kommunikere med den, så skal man have valgt den rigtige COM-port, som man kan læse mere om på siden Kommunikation med Arduinoen.

Når Arduinoen starter efter reset, så udskriver den følgende:

Lux Meter til Arduino
Holstebro HTX - 2022

I mm:ss - Measure Interval
T hh:mm - Measure Time - printing stops after this
S       - Start / Stop measure

D nn    - for number of displaying pr. second
P 0/1   - Printing 50 measurements pr. second
M 0/1   - Manual Ranging on/off
B       - for printing the first buffer

R       - Print out ranging factors
C       - Clears the ranging factors to Default
U pin   - Unlock range setting with PinCode
O nnnnn - Sets the overall range factor to nnnnn
F n xxx - Sets factor n (0-7) to xxx (default 128)

H       - for printing this Helpscreen

Den samme udskrift kan man få ved at taste H.

Opsamling af måledata over længere tid V2

Man kan indstille lysmåleren til at udskrive måleværdier med et fast interval, og man kan får den til at stoppe efter en vis tid.

Intervallet sætte op ved at skrive I mm:ss, hvorved man får angivet antal minutter (mm) og antal sekunder (ss) mellem hver måling der skal udskrives.

Hvis man bare vil have den til at fortsætte udskriften med dette interval, så kan man starte målingen med S.

Ønsker man at målingerne kun skal forløbe i et bestemt tidsrum, så kan man inden starten på målingerne angive tiden ved at skrive T hh:mm, så man får angivet den samlede måletid i timer (hh) og minutter (mm).

Et sæt målinger kunne se ud som følger:

Measure Interval = 00:00:05
Measure Time = 00:01:00
Measuring started
00:00:00	26.89 Lux
00:00:05	27.07 Lux
00:00:10	27.30 Lux
00:00:15	27.33 Lux
00:00:20	27.49 Lux
00:00:25	37.30 Lux
00:00:30	40.63 Lux
00:00:35	43.61 Lux
00:00:40	46.49 Lux
00:00:45	50.29 Lux
00:00:50	51.27 Lux
00:00:55	55.64 Lux
00:01:00	59.58 Lux
Measuring stoped

Specielle målinger V2

Som standard viser lysmåleren en ny værdi i displayet 2 gange i sekundet. Hvis man ønsker at ændre dette kan man angive antallet af målinger pr. sekund, ved at skrive D nn hvor nn er antallet af målinger pr. sekund. Målealgoritmen er baseret på at eliminere 50 og 100 Hz svingninger i lyset, så der måles et gennemsnit hen over 20 ms. Dette gør at det kun er følgende display-værdier der fungerer godt: 1, 2, 4, 5, 10, 25, 50.

Disse muligheder er sparet væk i V3, for at begrænse brugen af hukommelse i Arduinoen.

Man kan også få udskrevet alle målinger hvert 20. ms. Det gør man ved at skrive P 1, hvorefter målingerne kommer indtil man skriver P 0.

Udskriften er ret basal, hvor den angiver hvilket måleområde der anvendes (Range 0-7), der angives summeringen af de sidste 32 målinger inden for 20 ms, og hvad det svarer til i Lux. Det kunne se ud som følger:

Range 0	2915	Lux = 27.26
Range 0	2920	Lux = 27.30
Range 0	3023	Lux = 28.27
Range 0	3262	Lux = 30.50
Range 0	3284	Lux = 30.71
Range 0	3272	Lux = 30.60
Range 0	3247	Lux = 30.36
Range 0	3321	Lux = 31.05
Range 0	3246	Lux = 30.35
Range 0	3234	Lux = 30.24
Range 0	3326	Lux = 31.10
Range 0	3246	Lux = 30.35
printMode = 0

Hvis man ønsker at styre områderne manuelt, så kan man slå det til ved at skrive M 1, herefter vil den ene knap skifte måleområdet stigende op til måleområde 7, indtil den starter forfra på 0.

En sidste speciel måling er at man kan få udskrevet de sidste 32 målinger der er foretaget til at danne et gennemsnit over de 20 ms - dette kan vise om der er svingninger i lysstyrken inden for en 50 Hz svingning. En sådan måling viser målings-nummeret og den tilsvarende AD-værdi for målingen, som vist her:

0	174
1	184
2	187
3	182
4	174
5	163
6	154
7	143
8	135
9	125
10	117
11	125
12	144
13	163
14	175
15	181
16	185
17	188
18	188
19	181
20	173
21	163
22	152
23	141
24	132
25	124
26	116
27	123
28	141
29	161
30	175
31	181

Kalibrerings-indstilling af lysmåleren - Begge versioner

Som gennemgået under beskrivelsen af sensoren, så kan der være en variation på den enkelte sensorer. Dette kan korrigeres ved at indlæse en korrektionsfaktor.

På samme måde kan der være små variationer i de modstande som måler strømmen. Dette vil komme til udtryk ved at der sker et hop i måleværdien, når der skiftes måleområde. Dette kan korrigeres ved at der er en faktor for hver enkelt modstand, altså for hvert måleområde.

Standard-værdierne for faktorerne ser ud som følger:

Overall Factor: 10000
Range 0 : 128
Range 1 : 128
Range 2 : 128
Range 3 : 128
Range 4 : 128
Range 5 : 128
Range 6 : 128
Range 7 : 128

Værdierne kan kun angives som heltal, da de bliver lagret i EEPROM på Arduinoen.

Det at korrigere den enkelte lysmåler skal normalt kun ske en gang, og er ikke en del af den almindelige brugerbetjening. Disse betjeninger er derfor beskyttet af en PIN-kode.

Kalibreringsværdier i EEPROM

For at man kan indstille kalibreringsværdierne og gemme dem efter en Reset af lysmåleren, så lagres værdierne i EEPROM[10], så de kan læses når Arduinoen starter igen.

Læsningen af værdierne sker i setup() ved hjælp af følgende kode:

  unsigned int of;
  EEPROM.get(2, of);
  overallFactor = of;
  for (int n = 0; n < ranges; n++) {
    byte fact;
    EEPROM.get(4 + n, fact);
    factor[n] = fact;
  }

Først læses værdien, som lagres i overallFactor. I EEPROM'en er den lagret som en unsigned int, og kan derfor have en værdi fra 1 til 65535 - defaultværdien af den er på 10000, så der er et bredt justeringsområde til rådighed.

Dernæst læses de 8 faktorer, som skal ende i arrayet factor. Værdierne er lagret i EEPROM'en som bytes, altså med området 1-255, hvor defaultværdien er 128. Dette burde give rigeligt justeringsområde til afvigelser på 5% modstande.

Rettelse af kalibreringsværdierne

Når man har indstillet lysmåleren til kalibrerings-mode, så kan man rette faktorerne, ved at skrive dem i Serial Monitor. Dette sker i følgende kode:

        unsigned int fact = Serial.parseInt();
        overallFactor = fact;
        EEPROM.put(2, fact);
        Serial.print("New Overall Factor ");
        Serial.println(overallFactor);

Hver af de enkelte faktorer til modstandene kan på tilsvarende vis rettes ved at indlæse i Serial monitor hvilket område der skal rettes, og den nye værdi det skal have. Dette sker i følgende kode:

        byte number = Serial.parseInt();
        byte fact = Serial.parseInt();
        if (number < ranges) {
          factor[number] = fact;
          EEPROM.put(4 + number, fact);
          Serial.print("New factor : ");
          Serial.print(fact);
          Serial.print(" at range ");
          Serial.println(number);
        }

Samlet diagram over Lysmåleren V2

Totaldiagram over lysmåleren V2
Totaldiagram over lysmåleren V2

Det samlede diagram er en sammensætning af de forskellige dele, som de er dokumenteret.

Samlet diagram over Lysmåleren V3

Totaldiagram over lysmåleren V3
Totaldiagram over lysmåleren V3

Det samlede diagram er en sammensætning af de forskellige dele, som de er dokumenteret.

Print til lysmåleren V2

Ud fra det samlede diagram tegnet i Eagle[11] er der lavet et layout til print som vist her:
Print layout af V2 lavet i Eagle, set oven fra
Print layout af V2 lavet i Eagle, set oven fra

Print til lysmåleren V3

Ud fra det samlede diagram tegnet i Eagle[12] er der lavet et layout til print som vist her:
Print layout af V3 lavet i Eagle, set oven fra
Print layout af V3 lavet i Eagle, set oven fra

Test af lysmåleren V3

For at få et stabilt lys at måle i, så har det bedste været at være udenfor, da lysfordelingen er meget jævn og ensartet her - lyset kan stadig svinge meget, om der er sol eller overskyet, hvor målinger i januar har svinget fra 20 W/m2 på en overskyet dag op til 480 W/m2 i fuld sol.

Målingerne er sammenlignet med skolens lux-meter, ved at måle udenfor som vist her:
Opstilling af målegrej udendørs i januar-sol
Opstilling af målegrej udendørs i januar-sol

Målingerne er sammenlignet med skolens lux-meter, ved at måle udenfor som vist her:
Skolens lux-måler sammen med lysmåleren V3 udendørs i januar-sol
Skolens lux-måler sammen med lysmåleren V3 udendørs i januar-sol

Lysmåleren V3 er blevet sat op til at logge hvert 10. sekund, hvor Logger Pro måler hvert sekund, så de to tabeller kan ikke sammenlignes 1:1, og noget af målingen er også foretaget på vej ud af døren, men det giver en god ide om at de to lysmålere ligger på samme maksimal-niveau, hvor skolens lysmåler viser ca. 58 kLux (måleområdet 0-150kLux), og lysmåleren V3 kommer op på 57 kLux, så der er kun en afvigelse på ca. 2%.

De to måleserier der vises her er Logger Pro målingen, som angiver sekund for målingen og Luxværdien, og til højre CSV-filen, som angiver tid for målingen, luxværdien og W/m2:
Dump der sammenligner lysmålinger udendørs i januar-sol
Dump der sammenligner lysmålinger udendørs i januar-sol

Test af lysmåleren V2

Denne måling er foretaget efter en kalibrering af lysmåleren efter skolens LoggerPro Lux måler[13]. Målingen er startet et sted, og båret ud i solen på en klar vinterdag, hvor Luxmeteret har haft visninger oppe omkring 52000 Lux - faldet sidst i målingen her kan skyldes lette skyer på himlen.

Measure Interval = 00:00:05
Measure Time = 00:01:00
Measuring started
00:00:00	18307.79 Lux
00:00:05	24351.28 Lux
00:00:10	1489.21 Lux
00:00:15	40661.12 Lux
00:00:20	43872.22 Lux
00:00:25	45363.09 Lux
00:00:30	43053.59 Lux
00:00:35	41903.94 Lux
00:00:40	40324.83 Lux
00:00:45	38788.39 Lux
00:00:50	38241.79 Lux
00:00:55	37249.57 Lux
00:01:00	36285.75 Lux
Measuring stoped

Konklusion

Funktionsmæssigt fungerer lysmåleren som den skal, bortset fra et krav som har været lidt svært at verificere.

Måleområderne dækker fuldt ud det ønskede, hvor der i displayet er en opløsning i de lave måleområder ned til 0.1 Lux, og målingen ser ud til at fungere op til i hvert fald 10000 W/m2, hvis man kan få så kraftigt lys.

Det krav som det har været svært at kontrollere i det givne miljø er målenøjagtigheden. For det første har det ikke været muligt at finde præcisionen af skolens Lux-meter[13], og for det andet, så har det været anvendt forskellige lyskilder med forskelligt spektral-indhold, som har givet variationer i målingerne. De målinger der er foretaget til at lave kalibrering med har være i sollys, og de kan få en præcision på 2-3% i forhold til skolens lux-meter, som burde være kalibreret, så det tænkes at kravet om 10% godt kan betegnes som opfyldt.

Det enkele og brugbare design til simple målinger ses som fuldt opfyldt, da der blot skal tilsluttes 5V fra en USB-port for at lysmåleren kan vise målinger.

Muligheden for at lave logning af målinger er også til stede, det kan laves ved at man anvender Serial Monitor som kommer med Arduinos IDE, eller et tilsvarende terminal-program til serielporten.

Desuden kan der logges på et SD-kort, som kan gøre det mere brugervenligt at lave logning, dog med den begrænsning, at ikke alle computere har SD-kortlæser indbygget.

Referencer

  1. BPW34 Photodiode datasheet
  2. BPW21r Photodiode datasheet
  3. Arduino NANO officiel side
  4. 4,0 4,1 4,2 Forumindlæg på researchgate.net om Lux til W/m2
  5. ieee-dataport.org om konvertering af solstråling
  6. LCD-display fra Arduinos hjemmeside
  7. Arduinos guide til SD-kortet med tilslutning og enkelte software eksempler
  8. SD biblioteket fra Arduinos hjemmeside
  9. Terminal program gratis version
  10. Arduinos guide til brug af EEPROM
  11. Autodesk Eagle Schematics and layout software
  12. Autodesk Eagle Schematics and layout software
  13. 13,0 13,1 Logger Pro lysmåler
Kom i gang med Arduino
Grundlæggende forståelse for Arduino Arduino Hardware - Arduino Prototype Print - Blink Eksempel - Overblik - Serial Monitor - Simple Komponenter - Software og Udviklingsmiljø
Programmering af Arduino Anvendelse af Eksempler - Klasser og Objekter - Programafvikling i Arduino - Test af Programmer
Dokumentationsformer Dokumentation med Kode og Flowchart - Dokumentation med State-machines - Flowchart - Pseudokode - Program-kommentarer - Systemdokumentation - Syntaksfarvning - Blokdiagram - Pulsplaner - UML
Opkoblinger til Arduino Moduler og Biblioteker - Driver - Opkobling af Hardware - Simple Komponenter - Tips til anvendelse af ben på Arduino UNO
Kompliceret Programmering Arduino kombineret med Processing - Kommunikation fra Arduino til Processing - Kommunikation fra Processing til Arduino - CopyThread Multitasking - Dokumentation med State-machines - Tid og Samtidighed i Software - Arduino Memory
Kompliceret Hardware I2C - Andre Processorboards - Internet of Things (IoT)
Oprindelige Dokumenter PDF-Version - Forfattere
Software Udviklingsteknikker Agile metoder - Brugertest - SCRUM

Fasemodellen - Kravspecifikation - Databasedesign - Struktur eller Arkitektur - Softwaretest

Projekter Afstand programforslag - Lysmåling - Projektforslag - Prototyper
Undervisningsforløb 4t Valgfag til Folkeskolen - Læsevejledning 4t Valgfag - Materialer til 4t Valgfag - Undervisningsnoter 4t Valgfag - Undervisningsplan 4t Valgfag - Slides til Undervisning

Kort Valgfag til Folkeskolen - Læsevejledning Kort Valgfag - Materialer til Kort Valgfag - Undervisningsnoter Kort Valgfag - Undervisningsplan Kort Valgfag