Enkel temperaturlogger

Jag gjorde för en tid sedan en första preliminär mätning av UHI (Urban Heat Island) d.v.s. värmenedsmutsning av tätorter. Det är självklart att meteorologiska mätstationer som ligger nära eller i tät bebyggelse bör mäta högre temperaturer än stationer som ligger ostörda på landsbygden. De lärda tvistar idag om hur stor inverkan från UHI har på globala uppskattningar av temperaturen och uppskattningarna varierar från i princip ingen alls till några tiondels grader.

Temperaturloggerns upplösning d.v.s. de minsta temperaturskillnaderna den kan detektera är 0.1 grader C.  Sensorns precision d.v.s. felet i förhållande till en välkalibrerad temperaturgivare ligger antagligen på ca. +/- 0.5 grader C.

Jag har ingen aning om hur sensorn driver med tiden och inte heller hur linjär den i verkligheten är (om jag exempelvis vet att sensorn visar rätt vi 20 grader C, hur stort är felet vid +40?). Min gissning är dock att de relativa felen vid temperatursving på några grader är mycket små d.v.s. i storleksordningen +/- 0.1 grad C.

imgp5759

Fig. 1  Den första loggerprototypen. Det 3D-utskrivna skalet är misslyckat men bättre än ingenting. Följande version kommer ur ”ugnen” efter fyra timmar då detta skrivs. Bilden visar temperaturmätning i mitt arbetsrum kväll-natt. temperaturtoppen på nästan en grad är förorsakad av min kroppsvärme.

arbetsrum20190107

Fig. 2  Mätning av temperatur i mitt arbetsrum natten mellan den 7 och 8.1.2019. Rummet är i andra våningen /därav rätt hög temperatur) och det värms endast av datorer, skrivare etc. Det är intressant att notera hur temperaturen stiger med nästan en grad då jag sitter i rummet. En människa torde producera ungefär 200W värme vilket jag uppfattar att man kan se i mätningen. Andningsluften innehåller rätt mycket fukt vilket kan ses i den röda kurvan som är relativ luftfuktighet. Grafen skapades genom att läsa in mätvärdena i LibreOffice Calc i CSV (Comma Separated Values) format. Inläsningen krävde ingen editering av datafilen.

temp_logger_base

Fig. 3  En virtuell bild av stommen till version #2 av den nya lådan till loggern i programmet Repetier-host som jag använder för utskrift. Lådan är konstruerad i programmet openscad. Processorn och skärmen är skyddade men enkelt åtkomliga. I den första versionen kom kretskortet lite för nära lådans inre vägg vilket har åtgärdats här. Likaså modifierade jag öppningarna till USB-kontakten, SD-kortet och anslutningen för signalsladden till sensorn.  I nedre hörnet finns fack för SD-kortet och Bluetooth givaren HC-05. Nära det övre hörnet finns hjälpväggar som fungerar som kraftavlastare för sensorns sladd. Normalt brukar jag behöva tre iterationer för att designen skall bli ungefär vad jag vill ha.

tloggerboxutskrift

Fig. 4  Utskrift av den nya lådan från föregående bild. 3D-skrivaren är en Geeetech I3 kopia på motsvarande Prusa I3 skrivare. Skrivaren är byggd från en byggsats och den fungerar bra. Det krävdes dock en hel del tid, kanske två veckor,  att få allt korrekt injusterat både mekaniskt och mjukvarumässigt. Fördelen med en byggsats är dock att jag inte har några som helst hämningar att fixa eventuella problem eller göra uppgraderingar.  Det här är den bästa leksak jag har gett mig på många år.

imgp5761

Fig. 5  De i temperaturloggern ingående delarna. Från vänster Arduino Mega 2560 (blå). Därefter SD-kortadapter(ljusgrön). Bluetooth adapter HC-05 (vit) och bildskärmen sedd bakifrån (röd).  I den 3D-printade lådans skruvfästen smälts mässingsgängor vilket på sikt är mycket pålitligare än att skruva direkt i plast.

En Arduino Mega som temperaturlogger

En temperaturlogger kan byggas billigt från följande komponenter:

  • Processor Arduino Mega 2560 (ca. $10 ebay)
  • Display 480×320 pixlar innehåller ofta SD-korthållare ($5-$10 ebay). Kontrollera att displayen är kompatibel med en Arduino Mega och att den inte är gjord för en Arduino Uno (SD-kortet kan vara svårt att få att fungera om kortet är för en UNO). Det lönars ig inte att använda en Arduino Uno som logger om bildskärm används … minnet räcker inte till.
  • Bluetooth adapter HC-05 ($5 på ebay)
  • Någon typ av låda för att skydda loggern jag designade en egen låda och skrev ut den med 3D-skrivare.
  • Temperatur/fuktighetsgivare DHT22 ($3 på ebay). Det finns kombinationsgivare som också mäter lufttryck. Jag byter eventuellt senare ut DHT22 givaren mot en givare som mäter temperatur, luftfuktighet och lufttryck.
  • Ett minneskort t.ex. 8 GByte (det minsta man hittar i en normal butik)
  • Två stycken 1 kohms motstånd

Utöver ovanstående behövs lödkolv, gärna en universalvoltmätare, tröd, lödtenn o.s.v. normala hobbytillbehör för elektronikhobby.

Egenskaper hos den färdiga loggern

Loggern mäter och lagrar temperatur och luftfuktighet på ett SD minneskort. Mätta data plottas i grafisk form till bildskärmen. Mätintervallat kan ställas från ca. 1s till timmar mellan mätningarna. Bildskärmen kan skalas enligt behov d.v.s. det minsta och det största värdet p skärmen kan ställas via kommandon.

Jag kommer att lägga till funktionalitet i loggern senare. Det är enkelt att lägga till mätning av andra parametrar om det behövs. Jag har för närvarande endast en temperatursensor. Tanken är att lägga till en annan sensor så att jag kan mäta utetemperaturen nära bilens tak och ca. 10 cm högre upp. Det bör vara möjligt att få en uppfattning om hur mycket värmen i bilen stör mätningarna genom att placera två termometrar på olika höjd i luftflödet.

Kontroll/styrning av loggern

Loggern skriver ut mätningar till processorns USB serieport samt till Bluetooth modulen HC-05. Via båda dessa kanaler kan man ge kommandon åt loggern.

Bäst kontrollerar man loggern via t.ex. en mobiltelefon eller en lämplig läsplatta med bluetooth.  En lämplig App för kontroll är appen ”Bluetooth Terminal” som man hittar på Google Play. Appen är gratis (det finns säkert många andra som också fungerar). Då man kopplar på strömmen till loggern och då Bluetooth är aktiv i telefonen så kommer det att dyka upp en enhet HC-05. Om det i omgivningen finns flera HC-05 enheter så känner man igen dem på deras unika id (hexadecimal sträng av bokstäver/siffror). Då anslutningen har lyckats så kan man testa förbindelsen med kommandot ”help” som visar vilka kommandon systemet känner.

Följande kommandon finns för närvarande (kommandot ”help” ger en lista över kommandon):

COMMANDS:
help      --> This help.
start     --> Start logging
stop      --> Stop logging
sdstart   --> Re-initialize SD
sdstop    --> SD write stopped
tlog      --> Print tlog.txt
tdata     --> Print tdata.txt
ls        --> List SD files
ctlog     --> Erase tlog.txt
ctdata    --> Erase tdata.txt
!         --> Comment to tlog.txt.
logint    --> Logging interval secs.
ymin      --> Set plot ymin
ymax      --> Set plot ymax
ytic      --> Set plot ytic
replot    --> Clear screen and replot

Innan man börjar logga lönar det sig att ställa in skärmen:

ymin

Säller in y-axelns minsta värde. Om vi t.ex. vet att temperaturen ute ligger på ca. +5 och vi kommer att göra en körning som kräver några timmar så kan vi sannolikt ställa in skärmen på t.ex. 0 grader C. Commandot är då ”ymin 0” utan citationsteckn.

ymax

På motsvarande sätt ställer vi in det största värdet som ryms påskärmen t.ex. 15 grader C. Kommandor är ”ymax 15”.

logint

Kommandot ställer in intervallet mellan mätningar uttryckt i sekunder. Om vi t.ex. vill logga en gång per minut så ger vi kommandot ”logint 60”.  Intervallet är inte helt exakt. Den löpande tiden d.v.s. tidpunkten för mätningen i sekunder sedan start är relativt noggrann.

replot

Kommandot ”replot” raderar skärmen och ritar ut koordinatsystemet på nytt. Räknaren som håller reda på mätningens ordningsnummer sätts till ett (1).

start

Starta loggningen med de parametrar systemet för närvarande känner (ymin, ymax och logintervall).

stop

Stoppa loggning.  Loggning kan startas på nytt med ”start”.

sdstart

SD minneskortet initialiseras t.ex. om man har tagit ur kortet och kopierat innehållet till en dator ellr om minneskortet har bytts. Samma initialisering görs då loggern startas d.v.s. det är inte nödvändigt att ge kommandot ”sdstart” då loggern startas.

sdstop

Stoppar skrivning till SD minneskortet. Det är säkrast att ge kommandor ”sdstop” innan man tar ur SD-kortet eller innan man stänger av strömmen till loggern. Om man råkar rycka ur kortet precis då loggern skriver data till minnet så kan SD minnet förstöras. På motsvarande sätt kan kortet förstöras om man stänger av strömmen medan loggern skriver till kortet.  Risken för skador på minneskortet är naturligtvis störst om loggningsintervallet är kort. Användning av ”sdstop” förhindrar skador på SD-kortet eftersom skrivning till kortet stoppas.

tlog

Lista (skriv ut) hela loggfilen. Man kan skriva kommentarer till loggfilen genom att börja en kommentar med kommandot ”!”. Den maximala längden på en rad är satt till 50 tecken.

Exempel:

! Sommarö, start

Strängen lagras som sådan i filen tlog.txt men den förses med en tidsstämpel som motsvarar tiden för mätningarna. Man kan alltså senare direkt relatera kommentaren till specifika mätningar.

tdata

Skriv ut alla mätdata i mätfilen till både USB serieporten och till Bluetooth (HC-05). Ett sätt att överföra data till en annan apparat är att lista mätdata till serieterminalen och sedan på den kontrollerande enheten kopiera data från terminalen till en fil. Användning av tdata gör att loggningen inte behöver avbrytas och man behöver inte ta ut minneskortet.

ctlog

Radera loggfilen. Allt innehåll i loggfilen försvinner.

ctdata

Radera innehållet i datafilen. Allt innehåll i datafilen försvinner.

Koppling av termometer/luftfuktighetsmätare till loggern

Sensorns signalstift kopplas till Arduino Mega A15.

Sensorns strömmatning VCC koplas till 5V bredvid Arduinons stift 22.

Sensorns jord kopplas till Arduinons jord bredvid Arduinons stift 52.

Koppling av Bluetooth HC-05

Bluetooth VCC går till 5V på Arduino Mega (bredvid VCC för temperatursensorn). Till samma stift kopplas också VCC för SD-kortet.

Bluetooth jord GND kopplas till GND på Arduino (nära A15).

Bluetooth TXD kopplas till A13.

Bluetooth RXD kopplas via spänningsdelare t.ex. så att signalen från Arduino leds till jord via två 1 kohms motstånd kopplade i serie. Signalen till Bluetooth modulen tas ut mellan motstånden. Problemet är att HC-05 RXD är gjord för 3.3V spänningsnivå medan Arduinon använder 5V nivåer. HC-05 kan fungera en tid utan spänniungsdelare men den blir inte långlivad om den kopplas direkt.

Koppling av SD-kort

SD-korthållaren bör vara av en som har inbyggd spänningsregulator och 5V tålig. Orsaken är att SD minnet är konstruerat för endast 3.3V. Ansluter man ett oskyddat SD-kort till ett 5V system så kommer minnet att förstöras snabbt (jfr. HC-05 problemet).

SD 5V kollas till Arduino 5V (kombinerat med HC-05).

SD jord (GND) kopplas till Arduino GND (kombinerat med HC-05),

SD MOSI kopplas till Arduino Mega 2560 ICSP pin 1 (MISO)

SD MOSI kopplas till Arduino Mega 2560 ICSP pin 4 (MOSI)

SD SCK kopplas till Arduino Mega 2560 ICSP pin 3 (SCK)

SD CS kopplas till Arduino Mega 2560 dig. io pin 48

LCD skärmen

LCD skärmen är en billig kinesisk skärm designad för en Arduino UNO. Skärmen har inbyggd SD-kortläsare men problemet är att SPI gränssnittets signaler i en Arduino mega ligger påannan plats (ICSP konnektorn). Jag uppfattade det inte som mödan värt att tjuvkoppla mig runt problemet så jag använder en separat SD-kortläsare.

Problemet med många billiga kinesiska skärmar är att de är totalt ”namnlösa” och det finns ofta ingen information om vilken drivkrets de använder. Drivkretsens typ avgör vilket bibliotek jag måste använda på Arduinon för att skriva till skärmen. Vill jag has en skärm som är enkel att använda för t.ex. mätändamål så vill jag inte ha en skärm som sitter som en skäld ovanpå Arduinon och samtidigt förhindrar åmst till arduinons in/ut kontakter.

Skärmen jag har använt i det här projektet använder UTFT APIN f skärmaccess. Många kinesioska skärmar använder kontrollkretsen ILI9xxx för vilken man oftast hittar drivrutiner på nätet.

Notera att skärmen inte är nödvändig för funktionen.

Om ingen skärm finns kan programmet fortfarande köras genom att kommentera bort

#define HAVESCREEN

genom att skriva // framför definitionen d.v.s:

//#define HAVESCREEN

Programmet använder då inte alls skärmen men kontroll över programmet via Bluetooth och Arduino IDE fungerar fortfarande.

Programmet i Arduino

Programmer är skrivet i Arduinos C/C++ som är standardspråket om man använder Arduino IDE. Programmet är skrivet i en form som är typisk för en mikrokontroller där det ofta helt saknas ett underliggande operativsystem. Programmet sköter alltså själv alla funktioner och det är programmerarens sak att se till att programmet aldrig hamnar i en återvändsgränd och stoppar. Programmet är i princip en oändlig slinga som upprepas på nytt och på nytt. En cykel körs på ungefär 1/10 sekund. Vid varje varv genom programslingan kontrollerar programmet om det är tid att göra en mätning, kontrollerar om det finns något nytt kommando som borde utföras.

Om det är tid att göra en mätning så mäts temperatur och luftfuktighet och mätningens nummer, tiden sedan programstart, temperatur och luftfuktighet loggas till SD-minne. Temperaturen skrivs också ut på skärmen.

Om det finns ett kommando så utförs kommandot varefter programmet väntar på att följande varv genom slingan skall starta. Långa kommandon t.ex. en utskrift av en lång datafil kan ge tidsfel d.v.s. avståndet mellan två mätningar behöver inte vara helt exakt.

Notera att indenteringarna iprogrammet har förlorats vid inklistringen  i bloggen.

Jag kommer senare att lägga ut programmet på Github som fri programvara. Tillåtelse att använda programmet fritt ges här.

// Temperature_logger
// (c) 2019 Lars Silén
// Version 1.0
//
// Runs on an Arduino Mega 2560
//
// Using a 480×320 TFT diplay will hide the ICSP connector which caries
// the HW SPI signals. The are two options going around this problem.
// The first option is th solder the signals to the ICSP allowing us to use
// the ICSP connector with the display mounted (this option is selected here).
// The other option is to use a SW SPI library driving the SD memory card.
// This option is not selected.
//
// Any free text comin in over BT is stored including clock stamp.
// This allows simple input of location.
//
#include <Arduino.h>
#include <dhtnew.h>
#include <SPI.h>
#include <SD.h> // Support library for SD memory
#include <SoftwareSerial.h>

#define HAVESCREEN

#ifdef HAVESCREEN
//################################################
// GLUE class that implements the UTFT API
// replace UTFT include and constructor statements
// remove UTFT font declaration e.g. SmallFont
//################################################

#include <UTFTGLUE.h> //use GLUE class and constructor
UTFTGLUE myGLCD(0,A2,A1,A3,A4,A0); //all dummy args

// Declare which fonts we will be using
//extern uint8_t SmallFont[]; //GLUE defines as GFXFont ref

#define ORG_X 10
#define ORG_Y 10
#define MAX_X 470
#define MAX_Y 300

#define SCALE_MINY -10.0
#define SCALE_MAXY 30.0
#define SCALE_TICY 2.5
#define CIRCLE 0
#define CIRCLE_SIZ 2
#define SQUARE 1
#define TRIANGLE 2
#define LINES 1
float miny = SCALE_MINY;
float maxy = SCALE_MAXY;
float ytic = SCALE_TICY;

#endif

#define SDavailable // We have access to a sd memory
#define REPORTINTERVAL 60*10 // For testing reporting is done ar one minute interval.
int reportinterval=REPORTINTERVAL;

// ****************************************************
// Thermo and humidity sensor
// ****************************************************

#define connectedTSens1 true
#define connectedTSens2 false

// Looks like digital IO 22-53 don’t work properly.
// Use PWM pins or A-series pins.
#define DHT22Sens1 A15
#define DHT22Sens2 A12

DHTNEW mySensor1(DHT22Sens1);
#ifdef DHT22Sens2
DHTNEW mySensor2(DHT22Sens2);
#endif

// ****************************************************
// SD-memory support
// ****************************************************
// MISO, MOSI and SCLK in ICSP header.
// CD on pin 53.

Sd2Card card;
SdVolume volume;
SdFile root;
int SDstop = false;

int measured = false;
float Temperature = -999.0;
float Humidity = -999.0;
unsigned long timeSecs = 0; // Updated at 1s intervals using interrupts this is the main clock
unsigned long timeSinceStart=0; // Time in seconds since start
unsigned long stepper_rotate=0; // How often should we rotate the tower by one movement step (one turn of the motor).

int reportCnt = 0;
boolean stringComplete = false;
String inputString = ””; // a String to hold incoming sewrial needs initialization in setup().
String sysString = ””; // Handles writing/reading data
SoftwareSerial BTSerial(A13, A14); // RX, TX

unsigned long t;
int counter=0;
int shortcnt=REPORTINTERVAL;
int isRunning = false;
unsigned long tOffs;

void setup() {
// Serial interface towards supervising computer at 9600 baud
Serial.begin(9600);
pinMode(A14,OUTPUT);
BTSerial.begin(9600);

// Set up the temperature/humidity sensor type DHT2x (AOSONG AM230x)
//pinMode(50,INPUT);
if(connectedTSens1){
mySensor1.read();
}
#ifdef DHT22Sens2
if(connectedTSens2){
mySensor2.read();
}
#endif
Serial.println(”Started the Temperature/humidity sensor”);
BTSerial.println(”Started the Temperature/humidity sensor”);

// Start the system
inputString.reserve(50);
sysString.reserve(50);

// ***********************************************
// Setup SD-memory
// ***********************************************
#define SDCS 48
//pinMode(SDCS,OUTPUT);
if (!card.init(SPI_HALF_SPEED, SDCS)) {
Serial.println(”initialization failed. Things to check:”);
Serial.println(”* is a card inserted?”);
Serial.println(”* is your wiring correct?”);
Serial.println(”* did you change the chipSelect pin to match your shield or module?”);

BTSerial.println(”initialization failed. Things to check:”);
BTSerial.println(”* is a card inserted?”);
BTSerial.println(”* is your wiring correct?”);
BTSerial.println(”* did you change the chipSelect pin to match your shield or module?”);
return;
} else {
Serial.println(”Wiring is correct and a card is present.”);
BTSerial.println(”Wiring is correct and a card is present.”);
}
SD.begin(SDCS);
if (!volume.init(card)) {
Serial.println(”Could not find FAT16/FAT32 partition.\nMake sure you’ve formatted the card”);
BTSerial.println(”Could not find FAT16/FAT32 partition.\nMake sure you’ve formatted the card”);
return;
}
if(SDstop==true){
Serial.println(”SD stopped use SDstart”);
BTSerial.println(”SD stopped use SDstart”);
}

#ifdef HAVESCREEN
// ***********************************
// Setup the LCD
// ***********************************
Serial.println(”Trying to init LCD”);
BTSerial.println(”Trying to init LCD”);
myGLCD.InitLCD();
myGLCD.setFont(SmallFont);
#endif
}

float get_temperature(int sensorNo){
switch(sensorNo){
case 1: if(connectedTSens1){
Serial.println(”mySensor1.temperature”);
BTSerial.println(”mySensor1.temperature”);
return mySensor1.temperature;
} else {
return -999.0;
}
break;
case 2: if(connectedTSens2){
Serial.println(”mySensor2.temperature”);
return mySensor2.temperature;
} else {
Serial.print(”Not connected connectedTSens2=”);Serial.println(connectedTSens2);
return -999.0;
}
break;
}
Serial.println(”Fell through no such sensor number”);
BTSerial.println(”Fell through no such sensor number”);
return -999.0;
}

unsigned long get_time_since_start(){
// Get time in seconds since start
return timeSinceStart;
}

void ck_serial(){
// ***********************************
// Handle incoming serial data
// ***********************************
// CheclUSB serial typically Arduino Serial Monitor
while (Serial.available()>0) {
// get the new byte:
char inChar = (char)Serial.read();
inputString += inChar;
// if the incoming character is a newline the command is complete
// set a flag so the main loop can
// do something about it:
if (inChar == ‘\n’) {
stringComplete = true;
//Serial.println(”Got CR”);
}
}
// Check Bluetooth connection to phone/pad
while (BTSerial.available()>0) {
// get the new byte:
char inChar = (char)BTSerial.read();
inputString += inChar;
// if the incoming character is a newline the command is come,
// set a flag so the main loop can
// do something about it:
if (inChar == ‘\n’) {
stringComplete = true;
//Serial.println(”Got CR”);
}
}
serial_cmd();
}

void writeToLog(String ipStr){
if(SDstop==true) return;

File wrf=SD.open(”tlog.txt”,FILE_WRITE);
wrf.print(counter);
wrf.print(”,”);
wrf.println(ipStr);
wrf.close();
}

void serial_cmd(){
int n=0;
float h;
float energy=0;
float price=0;
// Some very basic commands
if(stringComplete==true){
// Ensure that case doesn’t matter when entering commands.
inputString.toLowerCase();
if(inputString.startsWith(String(”#”))){
// Handle comments
// Allows us to use scripts on the PC to set parameters on the controller.
Serial.print(”# ”);
Serial.println(”inputString”);
BTSerial.print(”# ”);
BTSerial.println(”inputString”);
stringComplete=false;
return;
}
// Restart use of the SD memory card after a SD stop.
if(inputString.startsWith(String(”sdstart”))){
Serial.print(”# command=sdstart ”);
BTSerial.print(”# command=sdstart ”);
// Re-initialize the card. The card may have been replaced.
if (!card.init(SPI_HALF_SPEED, SDCS)) {
Serial.println(”initialization failed. Things to check:”);
Serial.println(”* is a card inserted?”);
Serial.println(”* is your wiring correct?”);
Serial.println(”* did you change the chipSelect pin to match your shield or module?”);
BTSerial.println(”initialization failed. Things to check:”);
BTSerial.println(”* is a card inserted?”);
BTSerial.println(”* is your wiring correct?”);
BTSerial.println(”* did you change the chipSelect pin to match your shield or module?”);
inputString=””;
return;
} else {
Serial.println(”Wiring is correct and a card is present.”);
BTSerial.println(”Wiring is correct and a card is present.”);
}
SD.begin(SDCS);
if (!volume.init(card)) {
Serial.println(”Could not find FAT16/FAT32 partition.\nMake sure you’ve formatted the card”);
BTSerial.println(”Could not find FAT16/FAT32 partition.\nMake sure you’ve formatted the card”);
return;
}
SDstop = false;
inputString=””;
stringComplete=false;
return;
}
// Secure removal of the SD memory card.
if(inputString.startsWith(String(”sdstop”))){
Serial.print(”# command=sdstop”);
BTSerial.print(”# command=sdstart ”);
SDstop=true;
inputString=””;
stringComplete=false;
return;
}
// Start logging
if(inputString.startsWith(String(”start”))){
Serial.println(”# command=start”);
BTSerial.println(”# command=start”);
isRunning=true;
tOffs=millis()/1000;
stringComplete=false;
inputString=””;
return;
}
// Stop logging
if(inputString.startsWith(String(”stop”))){
Serial.println(”# command=stop”);
BTSerial.println(”# command=stop”);
isRunning=false;
stringComplete=false;
inputString=””;
return;
}
if(inputString.startsWith(String(”ymin”))){
Serial.print(”# command=ymin value=”);
BTSerial.print(”# command=ymin value=”);
#ifdef HAVESCREEN
miny=inputString.substring(4).toFloat();
Serial.println(miny);
BTSerial.println(miny);
#else
Serial.println(”Error: No screen defined”);
BTSerial.println(”Error: No screen defined”);
#endif
stringComplete=false;
inputString=””;
return;
}
if(inputString.startsWith(String(”ymax”))){
Serial.print(”# command=ymax value=”);
BTSerial.print(”# command=ymax value=”);
#ifdef HAVESCREEN
maxy=inputString.substring(4).toFloat();
Serial.println(maxy);
BTSerial.println(maxy);
#else
Serial.println(”Error: No screen defined”);
BTSerial.println(”Error: No screen defined”);
#endif
stringComplete=false;
inputString=””;
return;
}
if(inputString.startsWith(String(”ytic”))){
Serial.print(”# command=ytic value=”);
BTSerial.print(”# command=ytic value=”);
#ifdef HAVESCREEN
ytic=inputString.substring(4).toFloat();
Serial.println(ytic);
BTSerial.println(ytic);
#else
Serial.println(”Error: No screen defined”);
BTSerial.println(”Error: No screen defined”);
#endif
stringComplete=false;
inputString=””;
return;
}
if(inputString.startsWith(String(”logint”))){
Serial.print(”# command=logint value=”);
BTSerial.print(”# command=logint value=”);
reportinterval=inputString.substring(6).toInt();
Serial.println(reportinterval);
BTSerial.println(reportinterval);
reportinterval=10*reportinterval;
stringComplete=false;
inputString=””;
return;
}
if(inputString.startsWith(String(”replot”))){
Serial.println(”# command=replot”);
BTSerial.println(”# command=replot”);
#ifdef HAVESCREEN
setup_graph_screen();
#else
Serial.println(”Error: No screen defined”);
BTSerial.println(”Error: No screen defined”);
#endif
counter=1;
stringComplete=false;
inputString=””;
return;
}
if(inputString.startsWith(String(”tlog”))){
Serial.println(”# command=tlog”);
BTSerial.println(”# command=tlog”);
#ifdef SDavailable
dumpTLog();
#else
Serial.println(”SD card not available”);
BTSerial.println(”SD card not available”);
#endif
inputString = ””;
stringComplete=false;
return;
}
if(inputString.startsWith(String(”tdata”))){
Serial.println(”# command=tdata”);
BTSerial.println(”# command=tdata”);
#ifdef SDavailable
dumpTData();
#else
Serial.println(”SD card not available”);
BTSerial.println(”SD card not available”);
//BTSerial.println(”SD card not available”);
#endif
inputString = ””;
stringComplete=false;
return;
}
if(inputString.startsWith(String(”ls”))){
Serial.print(”# command=ls: ”);
BTSerial.print(”# command=ls: ”);
File root = SD.open(”/”);
printDirectory(root,0);
root.close();
//root.openRoot(volume);
// list all files in the card with date and size
//root.ls(LS_R | LS_DATE | LS_SIZE);
inputString = ””;
stringComplete=false;
return;
}
if(inputString.startsWith(String(”ctlog”))){
Serial.print(”# command=ctlog”);
BTSerial.print(”# command=ctlog”);
clearTLog();
Serial.println(”tlog.txt cleared (erased)”);
BTSerial.println(”tlog.txt cleared (erased)”);
inputString = ””;
stringComplete=false;
return;
}
if(inputString.startsWith(String(”!”))){
Serial.print(”# command=”);
Serial.println(inputString);
BTSerial.print(”# command=”);
BTSerial.println(inputString);
#ifndef SDavailable
return;
#endif
t = millis()/1000;

File wrf=SD.open(”tlog.txt”,FILE_WRITE);
wrf.print(counter);wrf.print(”,”);
wrf.print(t);wrf.print(”, ”);
wrf.println(inputString);
wrf.close();
inputString = ””;
stringComplete=false;
return;
}
if(inputString.startsWith(String(”ctlog”))){
Serial.print(”# command=ctlog”);
BTSerial.println(”# command=ctlog”);
clearTLog();
Serial.println(”tlog.txt file erased”);
BTSerial.println(”tlog.txt file erased”);
inputString = ””;
stringComplete=false;
return;
}
if(inputString.startsWith(String(”ctdata”))){
Serial.println(”# command=ctdata”);
clearTData();
Serial.println(”tdata.txt file erased”);
BTSerial.println(”tdata.txt file erased”);
inputString = ””;
stringComplete=false;
return;
}
if(inputString.startsWith(String(”help”))){
Serial.println(””);
Serial.println(”COMMANDS:”);
Serial.println(”help –> This help.”);
Serial.println(”start –> Start logging”);
Serial.println(”stop –> Stop logging”);
Serial.println(”sdstart –> Re-initialize SD”);
Serial.println(”sdstop –> SD write stopped”);
Serial.println(”tlog –> Print tlog.txt”);
Serial.println(”tdata –> Print tdata.txt”);
Serial.println(”ls –> List SD files”);
Serial.println(”ctlog –> Erase tlog.txt”);
Serial.println(”ctdata –> Erase tdata.txt”);
Serial.println(”! –> Comment to tlog.txt.”);
Serial.println(”logint –> Logging interval secs.”);
Serial.println(”ymin –> Set plot ymin”);
Serial.println(”ymax –> Set plot ymax”);
Serial.println(”ytic –> Set plot ytic”);
Serial.println(”replot –> Clear screen and replot”);
Serial.println(””);

BTSerial.println(”COMMANDS:”);
BTSerial.println(”help –> This help.”);
BTSerial.println(”start –> Start logging”);
BTSerial.println(”stop –> Stop logging”);
BTSerial.println(”sdstart –> Re-initialize SD”);
BTSerial.println(”sdstop –> SD write stopped”);
BTSerial.println(”tlog –> Print tlog.txt”);
BTSerial.println(”tdata –> Print tdata.txt”);
BTSerial.println(”ls –> List SD files”);
BTSerial.println(”ctlog –> Erase tlog.txt”);
BTSerial.println(”ctdata –> Erase tdata.txt”);
BTSerial.println(”! –> Comment to tlog.txt.”);
BTSerial.println(”logint –> Log interval secs.”);
BTSerial.println(”ymin –> Set plot ymin”);
BTSerial.println(”ymax –> Set plot ymax”);
BTSerial.println(”ytic –> Set plot ytic”);
BTSerial.println(”replot –> Clear screen and replot”);
inputString = ””;
stringComplete=false;
return;
}
// Any comman that isn’t recognized is assumed to be a comme that is loged
// into the tlog.txt logfile.
Serial.print(”inputString”);
Serial.println(inputString);
writeToLog(inputString);
inputString = ””;
stringComplete=false;
return;
}
return; // Never reached
}

void report_serial(){
// Write as comma separated values for easy import to a spread sheet program

Serial.print(”Time,”); Serial.print(t); Serial.print(”, ”);
BTSerial.print(”Time,”); BTSerial.print((timeSecs/3600.0)); BTSerial.print(”, ”);
if(connectedTSens1){
Serial.print(”Temp1, ”); Serial.print(mySensor1.temperature); Serial.print(”, ”);
Serial.print(”Hum1, ”); Serial.print(mySensor1.humidity); Serial.print(”\n”);
BTSerial.print(”Temp1, ”); Serial.print(mySensor1.temperature); Serial.print(”, ”);
BTSerial.print(”Hum1, ”); Serial.print(mySensor1.humidity); Serial.print(”\n”);
}
//if(connectedTSens2){
// Serial.print(”Temp2, ”); Serial.print(mySensor2.temperature); Serial.print(”, ”);
// Serial.print(”Hum2, ”); Serial.print(mySensor2.humidity); Serial.print(”\n”);
//}
}

// ********************************************
// SD related functions
// ********************************************

void printDirectory(File dir, int numTabs) {
while (true) {

File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
// Repaced ‘\t’ with ‘ ‘ to save screen space
Serial.print(‘ ‘);
BTSerial.print(‘ ‘);
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println(”/”);
BTSerial.println(”/”);
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print(”\t\t”);
Serial.println(entry.size(), DEC);
BTSerial.print(”\t\t”);
BTSerial.println(entry.size(), DEC);
}
entry.close();
}
}

void dumpTLog(){
// Dump the logfile to the external computer
char c;
#ifndef SDavailable
Serial.println(”Error: No SD memory available”);
BTSerial.println(”Error: No SD memory available”);
return;
#endif
File rdf = SD.open(”tlog.txt”,FILE_READ);
if (rdf){
while (rdf.available()) {
c=rdf.read();
Serial.write(c);
BTSerial.write(c);
}
rdf.close();
} else {
Serial.println(”Error: Could not open tlog.txt”);
BTSerial.println(”Error: Could not open tlog.txt”);
}
}

void clearTLog(){
#ifndef SDavailable
Serial.println(”Error: No SD memory available”);
BTSerial.println(”Error: No SD memory available”);
return;
#endif
SD.remove(”tlog.txt”);
}

void dumpTData(){
// Dump the logfile to the external computer
char c;
#ifndef SDavailable
Serial.println(”Error: No SD memory available”);
BTSerial.println(”Error: No SD memory available”);
return;
#endif
File rdf = SD.open(”tdata.txt”,FILE_READ);
if (rdf){
while (rdf.available()) {
c=rdf.read();
Serial.write(c);
BTSerial.write(c);
}
rdf.close();
} else {
Serial.println(”Error: Could not open usrlog.txt”);
BTSerial.println(”Error: Could not open usrlog.txt”);
}
}

void clearTData(){
#ifndef SDavailable
Serial.println(”Error: No SD memory available”);
BTSerial.println(”Error: No SD memory available”);
return;
#endif
SD.remove(”tdata.txt”);
}

#ifdef HAVESCREEN
int cy(int y){
// Convert y into screen coordinate sy)
int v=0;
v = MAX_Y – y;
if(v<0){
v = ORG_Y;
return v;
} else if(v>MAX_Y){
v= MAX_Y;
return v;
}
return v;
}

int cx(int x){
// Dummy conversion of x-coordinate to screen coordinate
int v=0;
v = x+ORG_X;
if(v<ORG_X){
return ORG_X;
} else if(v>MAX_X){
return MAX_X;
}
return v;
}

void draw_axisX(){
// Draw x-axis
myGLCD.drawLine(cx(0), cy(0), cx(MAX_X), cy(0));
}

void draw_axisY(){
// Draw y-axis
myGLCD.drawLine(cx(0), cy(0), cx(0), cy(MAX_Y-10));
}

int cnvYfloatToInt(float y){
int intY;
//intY = MAX_Y*(y-SCALE_MINY)/(SCALE_MAXY-SCALE_MINY);
intY = MAX_Y*(y-miny)/(maxy-miny);
//Serial.print(”y=”);
//Serial.println(y);
//Serial.print(”Conv intY=”);
//Serial.println(intY);
return intY;
}

void ticX(int dx){
// Starts from x=0
// Draw x-ticks
myGLCD.setBackColor(0, 0, 0);
for (int i=0; i<460; i+=dx){
myGLCD.drawLine(cx(i), cy(0), cx(i), cy(10));
sysString=String(i);
myGLCD.print(sysString, i+5, cy(15));
}
}

void ticY(float dy,int ltype){
float ypos;
int intY;
int i;
//for (int i=0; i<MAX_Y; i+=dy) myGLCD.drawLine(cx(0), cy(i),cx(10), cy(i));
ypos = miny;
while(ypos < maxy){
intY = cnvYfloatToInt(ypos);
myGLCD.drawLine(cx(0), cy(intY),cx(10), cy(intY));
if(ltype==LINES){
myGLCD.setBackColor(0, 0, 0);
for(i=10; i<469; i=i+10){
myGLCD.drawLine(cx(i), cy(intY),cx(i+3), cy(intY));
}
}
sysString=String(ypos);
myGLCD.print(sysString, 15, cy(intY+9));
ypos = ypos + dy;
}
}

void setup_graph_screen(){
myGLCD.clrScr();
myGLCD.setColor(255, 0, 0);
myGLCD.print(”* Temperature logger V1.0 *”, 30, 20);
// Draw a background
myGLCD.setColor(255, 0, 0);
myGLCD.fillRect(0, 0, 479, 13);
myGLCD.setColor(64, 64, 64);
myGLCD.fillRect(0, 306, 479, 319);
myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(255, 0, 0);
draw_axisX();
ticX(60);
draw_axisY();
ticY(ytic,LINES);
}

void plot_point(int x, float flY, int symb){
int y;
//Serial.print(”Initial float Y=”);
//Serial.println(flY);
y = cnvYfloatToInt(flY);
//Serial.print(”Converted intY=”);
//Serial.println(y);
switch(symb){
case CIRCLE: myGLCD.drawCircle(cx(x), cy(y), CIRCLE_SIZ);
break;
}
}
#endif

void store_data_SD(){
if(SDstop==true) return;
File wrf=SD.open(”tdata.txt”,FILE_WRITE);
wrf.print(t-tOffs);
wrf.print(”,”);
wrf.print(counter);
wrf.print(”, T , ”);
wrf.print(mySensor1.temperature);
wrf.print(”, h , ”);
wrf.println(mySensor1.humidity);
wrf.close();
}

// ********************************************************************************************
// MAIN PROGRAM
// We run, very roughly one loop per second.
// Notice that variables defined within the loop are local to loop() and they
// are initialized when a new loop starts. To preserve data between loops variables have
// to be declared outside the loop().
// ********************************************************************************************

void loop() {
// ******************************************************
// Main loop for actual work
// ******************************************************
ck_serial();

if (counter==0){
#ifdef HAVESCREEN
setup_graph_screen();
#endif
counter=1;
}
shortcnt–;
if((shortcnt<=0) & isRunning==true){
mySensor1.read(); // Read Temperature and Humidity sensor #1
t = millis()/1000; // Seconds since start
Serial.print(t-tOffs);
Serial.print(” , ”);
Serial.print(counter);
Serial.print(” , T , ”);
Serial.print(mySensor1.temperature);
Serial.print(” ,h, ”);
Serial.println(mySensor1.humidity);
BTSerial.print(t-tOffs);
BTSerial.print(”,”);
BTSerial.print(counter);
BTSerial.print(” , T , ”);
BTSerial.print(mySensor1.temperature);
BTSerial.print(” , h , ”);
BTSerial.println(mySensor1.humidity);
shortcnt = reportinterval;
#ifdef HAVESCREEN
plot_point(counter,mySensor1.temperature,CIRCLE);
#endif
store_data_SD();
counter++;
}

delay(100);
}

Kommentera

Fyll i dina uppgifter nedan eller klicka på en ikon för att logga in:

WordPress.com-logga

Du kommenterar med ditt WordPress.com-konto. Logga ut /  Ändra )

Twitter-bild

Du kommenterar med ditt Twitter-konto. Logga ut /  Ändra )

Facebook-foto

Du kommenterar med ditt Facebook-konto. Logga ut /  Ändra )

Ansluter till %s


%d bloggare gillar detta: