/*Arduino Temperature Data Logging Program,
Wittten by Andrew Spangler (andymadman),
KG7BHQ for you hams out there, I would recommend the Seeed Studio SD Card Shield
V3.X (any V3 will work) for the SD card interface, although you can probably change
the code to work with other SD shields/devices. For the LCD, any I2C,(IIC so no one
will be pedantic about it) backpack will work, and for the LCD try and get a hitachi driver
20x4 character LCD as thery have more than double the usuable printing space and displaying
data is a lot easier than it is on a 16x2. I've written this program to work with both 16x2
and 20x4 LCD displays.
*/
/*
_________________ _________
\ / | | \
\ / | | |
\ /\ / | | /
\ / \ / | |________/
\ / \ / | |
\ / \ / | |
\/ \/ ________^_______ |
*/
#include "SdFat.h" /*include SdFat library, not shipped with program see readme for
downloads and hardware information*/
#include "LiquidCrystal.h" //include IIC LiquidCrystal library, not shipped with program.
LiquidCrystal lcd(0); /*create instance of LiquidCrystal called "lcd" with IIC
address 0, change if IIC address on IIC backpack is different, see (not yet existant) readme
for downloads and hardware information*/
//Human controlled variables:
int HTT; /*high temperature threshhold, the maximum temperature before
the Arduino begins cooling with the peltier cell */
int LTT; /*Low temperature threshhold, the maximum temperature before
the Arduino begins heating with the peltier cell */
int MTT; /*Mid temperature threshhold, the temperature
Arduino attempts to achieve with the peltier cell */
int rTime = ""; // time between log readings
int BPin1 = ""; //Pin one for the peltier cell h-bridge
int BPin2 = ""; //Pin two for the peltier cell h-bridge
int TN = ""; /*The number of thermometers to be connected to the Arduino,
0-3, thermometers must be used in order, eg you can't read from
thermometers 1 and 3 if you specify there being 1 thermometer,
you must read from thermometer 1, if you specify there being 2
thermometers, you must read from thermometers 1 and 2, etcetera */
int TR0 = ""; //Thermometer #1 read pin, must be analog, Called "A" on LCD to save space
//Thermometers coded for TMP36 Temperature Sensors, available at http://www.adafruit.com/products/165
int TR1 = ""; //Thermometer #2 read pin, must be analog, Called "B" on LCD
int TR2 = ""; //Thermometer #3 read pin, must be analog, Called "C" on LCD
int TM0; //Storage variable for Thermometer #1
int TM1; //Storage variable for Thermometer #2
int TM2; //Storage variable for Thermometer #3
boolean tUnit = false; //boolean true to convert to fahrenheit, default celcius.
int ProtestPin = 13; /*Pin to pwm output value 127 in the
case of an error, use to blink an led, run a quartz squeeler,
or power a buzzer, by default onboard LED */
int lcdState = ""; // 0 if no lcd, 1 if IIC lcd, different versions to come for UART and Serial LCD.
boolean lcdType = ""; //true if 20x4, false if 16x2
boolean SerState = true; //Enable Serial debugging, False if not wanted.
//Program controlled variables, humans shouldn't touch these:
int lcdL; //initialize lcdL (lcd Length), but don't define it
int lcdH; //initialize lcdH (lcd Height), but don't define it
boolean lcdStatus = false; //Status of whether or not an lcd is connected.
boolean ErrStatus = false; //Status of whether or not an error has occured
/*
Error Number Human Lookup Table:
Error #: Description of error: Possible cause:
0 | Default | Means something triggered the ErrStatus boolean without setting an error number, should never see.
1 | LCD | Numbers in Human LCD Fields invalid
2 | Thermometer (General) | Numbers in Human Thermometer Fields invalid, usually too many thermometers. Check if TN is too high.
3 | Thermometer (HIGH/LOW) | analogRead values yeild results of <32 or >992, means thermometer is probably not connected properly.
4 | SD Card (General) | SD card not found, SD card removed
5 | SD Card (Read) | SD card is corrupt, SD card is not in FAT16 or FAT32 format
6 | SD Card (Write) | SD card is in read-only (little switch is "locked")
7 | SD Card (Memory) | SD card is corrupt, SD card is full
8 | Available, but not used | Shouldn't turn up unless you change the program and add it yourself
9 | Available, but not used | Shouldn't turn up unless you change the program and add it yourself
*/
boolean er1 = false; // \
boolean er2 = false; // \
boolean er3 = false; // \
boolean er4 = false; // \
boolean er5 = false; // }--- booleans used for computing the number of errors, false by default.
boolean er6 = false; // / Changing these may result in false error messages.
boolean er7 = false; // /
boolean er8 = false; // /
boolean er9 = false; // _/
String erStr = ""; //These parenthesis don't need to be changed. IF CHANGED THEY MAY SCREW UP ERROR MESSAGES
char unit;
void setup(){
if (SerState == true){
Serial.begin(9600); //begin serial communication over USB
}
if (tUnit == true) {
unit = "F"
}
else {
unit = "C"
}
if (lcdState > 0) { //if an lcd is of any state other than nil
lcdStatus = true; //change boolean lcdStatus to true, by default
//lcdState is false so if lcdState is 0, do nothing
switch (lcdType) { //Switch based on the Human boolean that says whether the LCD is 20x4 or 16x2
case 0: //If the boolean is false, the LCD is 16x2
lcdL = 16; //Set the LCD's length to 16
lcdH = 2; //Set the LCD's height to 2
break;
case 1: //If the boolean is true, the LCD is 20x4
lcdL = 20; //Set the LCD's length to 20
lcdH = 4; //Set the LCD's height to 4
break;
case >1:
er1 = true;
break;
}
lcd.begin(lcdL,lcdH); //Initializes the LCD, using the variable just set
lcd.setBacklight(High); //turn the backlight on
}
pinMode(BPin1 ,OUTPUT); //h-bridge pins 1 and 2 are set to output
pinMode(BPin2 ,OUTPUT);
pinMode(ProtestPin, OUTPUT): //Set protest pinMode to output
switch (TN) { /*this just eliminates a bunch of "if" statements
regarding the setup of the thermometers */
case 0: //No thermometer, don't setup anything
break;
case 1: //1 Thermometer, setup thermometer 0
pinMode(TRP0, INPUT);
break;
case 2: //2 Thermometers, setup thermometers 0 and 1
pinMode(TRP0, INPUT);
pinMode(TRP1, INPUT);
break;
case 3: //3 Thermometers, setup thermometers 0, 1, and 2
pinMode(TRP0, INPUT);
pinMode(TRP1, INPUT);
pinMode(TRP2, INPUT);
break;
case >= 4:
er1 = true;
break;
}
void loop() {
protest();
if (TN>0) {
tempUpdate();
lcdTempUpdate();
if (SerState == true) {
SerTemp();
}
}
}
void protest() {
erUpdate();
if ((erStr.length)>0){ //if the error string (erStr) has any characters at all, go through the output.
analogWrite(ProtestPin, 127); //Turn on the ProtestPin
if (SerState == true){
Serial.println("")
Serial.println("")
Serial.println(millis()/1000);
Serial.println(erStr);
Serial.println("")
Serial.println("")
}
if (lcdStatus == true){ //If there is an lcd
lcd.setBacklight(LOW); //turn backlight off
delay(100); //wait 1/5th of a second
lcd.setBacklight(HIGH); //turn the backlight on
switch(lcdType) {
case 0:
lcd.setCursor(1,(lcdW-(1+ (erStr.length)));
//here we're calculating the number of characters
//by finding the character length of the string
//erStr and adding it to the 1 needed to print "ER"
//minus the one caused by the memory addresses in
//the IIC counting from zero.
lcd.print("ER"); lcd.print(erStr); //don't ever do this kids ;) this is the lazy way
} //of writing code (although a little easier to visualize)
}
//Here we're printing "ER" Followed by the error message numbers.
/*Because the memory addresses in the IIC library
count from 0, you must subtract by 1 to go from
the ordinal counting system to go to zero-based.
To write to the bottom line of the lcd, the
ordinal number of last line (lcdH) must be reduced
by one (lcdH - 1), (in a 16x2 the second line is
line 1) otherwise the Arduino writes to off-screen
regions of the lcd. (In the case of a 4-Row LCD,
memory line address "4" is actually non-existant
line 5 )
Because there might be data in the earlier parts of the
bottom line of the LCD, the cursor is set to print to
the far right on the bottom line. To do this, the cursor
is set to the right the pre-calculated number of characters
(NumERR, calculated in erUpdate) needed to print all of the
error messages plus the two characters needed to print the
letters "ER" */
}
}
void erUpdate() {
if (er1 =- true) {
erStr += "1"; //add char (not int) "#" to string. # is the number in parenthesis.
//This is true for all of the code in erUpdate below too.
}
if (er2 =- true) {
erStr += "2";
}
if (er3 =- true) {
erStr += "3";
}
if (er4 =- true) {
erStr += "4"
}
if (er5 =- true) {
erStr += "5";
}
if (er6 =- true) {
erStr += "6";
}
if (er7 =- true) {
erStr += "7"
}
if (er8 =- true) {
erStr += "8"
}
if (er9 =- true) {
erStr += "9"
}
}
void tempUpdate(){
}
switch(TN){ //Switch case based on how many thermometers are connected
case 0:
break;
case 1:
TM0 = ((analogRead(TR0) * (5000/1024))-500)/10;
break;
case 2:
TM0 = ((analogRead(TR0) * (5000/1024))-500)/10;
TM1 = ((analogRead(TR1) * (5000/1024))-500)/10;
break;
case 3:
TM0 = ((analogRead(TR0) * (5000/1024))-500)/10;
TM1 = ((analogRead(TR1) * (5000/1024))-500)/10;
TM2 = ((analogRead(TR2) * (5000/1024))-500)/10;
break;
case >=4:
er2 = true;
break;
}
void lcdTempUpdate(){
}
switch(TN){ //Switch case based on how many thermometers are connected
case 0:
break;
case 1:
TM0 = tCon(TM0);
lcd.setCursor(0,0);
lcd.print("T0"); lcd.print(TM0);
lcd.setCursor(0,15);
lcd.print(unit);
break;
case 2:
TM0 = tCon(TM0);
TM1 = tCon(TM1);
lcd.setCursor(0,0);
lcd.print("T0"); lcd.print(TM0);
lcd.setCursor(0,6);
lcd.print("T1"); lcd.print(TM1);
lcd.setCursor(0,15);
lcd.print(unit);
break;
case 3:
TM0 = tCon(TM0);
TM1 = tCon(TM1);
TM2 = tCon(TM2);
lcd.setCursor(0,0);
lcd.print("A"); lcd.print(TM0);
lcd.setCursor(0,5);
lcd.print("B"); lcd.print(TM1);
lcd.setCursor(0,10);
lcd.print("C"); lcd.print(TM0);
lcd.setCursor(0,15);
lcd.print(unit);
break;
case >=4:
er2 = true;
break;
}
tCon(int Q){
if (tUnit == True) {
Q = (9*Q)+32
}
return Q;
}
SerTemp(){
switch(TN){ //Switch case based on how many thermometers are connected
case 0:
break;
case 1:
Serial.println("");
Serial.println("Thermometer 0");
Serial.println(TM0);
Serial.println("");
break;
case 2:
Serial.println("");
Serial.println("Thermometer 0");
Serial.println(TM0);
Serial.println("");
Serial.println("Thermometer 1");
Serial.println(TM1);
Serial.println("");
break;
case 3:
Serial.println("");
Serial.println("Thermometer 0");
Serial.println(TM0);
Serial.println("");
Serial.println("Thermometer 1");
Serial.println(TM1);
Serial.println("");
Serial.println("Thermometer 2");
Serial.println(TM2);
Serial.println("");
break;
case >=4:
er2 = true;
break;
}
|