diff options
author | Florian Pritz <bluewind@xinu.at> | 2013-07-28 14:12:59 +0200 |
---|---|---|
committer | Florian Pritz <bluewind@xinu.at> | 2013-07-28 14:12:59 +0200 |
commit | ede898fe5f786d261e1b1791ac102e9cf3fa7366 (patch) | |
tree | cd5a11dd12e786078b18294ae65c16d48d10b9f2 /src | |
download | temp-logger-ede898fe5f786d261e1b1791ac102e9cf3fa7366.tar.gz temp-logger-ede898fe5f786d261e1b1791ac102e9cf3fa7366.tar.xz |
inital commit
Signed-off-by: Florian Pritz <bluewind@xinu.at>
Diffstat (limited to 'src')
-rw-r--r-- | src/Bounce.cpp | 90 | ||||
-rw-r--r-- | src/Bounce.h | 71 | ||||
-rw-r--r-- | src/main.cpp | 347 |
3 files changed, 508 insertions, 0 deletions
diff --git a/src/Bounce.cpp b/src/Bounce.cpp new file mode 100644 index 0000000..40709e4 --- /dev/null +++ b/src/Bounce.cpp @@ -0,0 +1,90 @@ +
+// Please read Bounce.h for information about the liscence and authors
+
+#include <Arduino.h>
+#include "Bounce.h"
+
+Bounce::Bounce() {
+}
+
+Bounce::Bounce(uint8_t pin,unsigned long interval_millis)
+{
+ interval(interval_millis);
+ previous_millis = millis();
+ state = digitalRead(pin);
+ this->pin = pin;
+}
+
+
+void Bounce::write(int new_state)
+ {
+ this->state = new_state;
+ digitalWrite(pin,state);
+ }
+
+
+void Bounce::interval(unsigned long interval_millis)
+{
+ this->interval_millis = interval_millis;
+ this->rebounce_millis = 0;
+}
+
+void Bounce::rebounce(unsigned long interval)
+{
+ this->rebounce_millis = interval;
+}
+
+
+
+int Bounce::update()
+{
+ if ( debounce() ) {
+ rebounce(0);
+ return stateChanged = 1;
+ }
+
+ // We need to rebounce, so simulate a state change
+
+ if ( rebounce_millis && (millis() - previous_millis >= rebounce_millis) ) {
+ previous_millis = millis();
+ rebounce(0);
+ return stateChanged = 1;
+ }
+
+ return stateChanged = 0;
+}
+
+
+unsigned long Bounce::duration()
+{
+ return millis() - previous_millis;
+}
+
+
+int Bounce::read()
+{
+ return (int)state;
+}
+
+
+// Protected: debounces the pin
+int Bounce::debounce() {
+
+ uint8_t newState = digitalRead(pin);
+ if (state != newState ) {
+ if (millis() - previous_millis >= interval_millis) {
+ previous_millis = millis();
+ state = newState;
+ return 1;
+ }
+ }
+
+ return 0;
+
+}
+
+// The risingEdge method is true for one scan after the de-bounced input goes from off-to-on.
+bool Bounce::risingEdge() { return stateChanged && state; }
+// The fallingEdge method it true for one scan after the de-bounced input goes from on-to-off.
+bool Bounce::fallingEdge() { return stateChanged && !state; }
+
diff --git a/src/Bounce.h b/src/Bounce.h new file mode 100644 index 0000000..68cdbd8 --- /dev/null +++ b/src/Bounce.h @@ -0,0 +1,71 @@ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + Main code by Thomas O Fredericks + Rebounce and duration functions contributed by Eric Lowry + Write function contributed by Jim Schimpf + risingEdge and fallingEdge contributed by Tom Harkaway +* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef Bounce_h +#define Bounce_h + +#include <inttypes.h> + +class Bounce +{ + +public: + // Initialize + Bounce(); + Bounce(uint8_t pin, unsigned long interval_millis ); + // Sets the debounce interval + void interval(unsigned long interval_millis); + // Updates the pin + // Returns 1 if the state changed + // Returns 0 if the state did not change + int update(); + // Forces the pin to signal a change (through update()) in X milliseconds + // even if the state does not actually change + // Example: press and hold a button and have it repeat every X milliseconds + void rebounce(unsigned long interval); + // Returns the updated pin state + int read(); + // Sets the stored pin state + void write(int new_state); + // Returns the number of milliseconds the pin has been in the current state + unsigned long duration(); + // The risingEdge method is true for one scan after the de-bounced input goes from off-to-on. + bool risingEdge(); + // The fallingEdge method it true for one scan after the de-bounced input goes from on-to-off. + bool fallingEdge(); + +protected: + int debounce(); + unsigned long previous_millis, interval_millis, rebounce_millis; + uint8_t state; + uint8_t pin; + uint8_t stateChanged; +}; + +#endif + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..8058f46 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,347 @@ +// simple data logger +// +// using Arduino Leonardo and an Adafruit Logger Shield +// +// uses Adafruit's RTClib +// +// Based on https://github.com/cnvogelg/ardu/blob/master/datalog/datalog/datalog.ino + +#include <Arduino.h> +#include <Wire.h> +#include <SD.h> +#include <RTClib.h> +#include <DallasTemperature.h> +#include <stdlib.h> + +#include "Bounce.h" + +// Pin setup +const int ledGreenPin = 8; +const int ledRedPin = 4; +const int buttonPin = 6; +const int oneWirePin = 7; +const int chipSelect = 10; + +#define DEBOUNCE 10 +#define BUFSIZE 32 + +// ----- GLOBALS ----- +RTC_DS1307 RTC; +OneWire oneWire(oneWirePin); +DallasTemperature sensors(&oneWire); + +uint16_t delta = 10; // measurement delta in seconds +uint32_t next_ts; + +static uint16_t year; +static uint8_t month, day, hour, minute, second; + +Bounce logToggleButton; + +File file; + +// offsets: 0123456789012 +byte name[] = "yymmdd_x.log"; + +// ----- FUNCTIONS ----- +static void led(int pin, int on) +{ + digitalWrite(pin, on ? HIGH : LOW); +} + +// fatal error - blink led and wait for reset +static void fail() { + while(1) { + led(ledRedPin, 1); + delay(200); + led(ledRedPin, 0); + delay(200); + } +} + +static int sd_init() +{ + pinMode(chipSelect, OUTPUT); + //if (!SD.begin(chipSelect)) { + if (!SD.begin(10,11,12,13)) { + Serial.println("SD init failed"); + fail(); + } +} + +static void rtc_init() +{ + Wire.begin(); + RTC.begin(); + + if (! RTC.isrunning()) { + Serial.println("RTC is NOT running!"); + } + + // get value for first measurement + next_ts = RTC.now().unixtime(); +} + +static uint16_t parse_dec(byte *buf, byte num) +{ + uint16_t val = 0; + for(byte i=0;i<num;i++) { + val = val * 10; + if ((buf[i] >= '0')&&(buf[i] <= '9')) { + byte v = buf[i] - '0'; + val += v; + } else { + return 0xffff; + } + } + return val; +} + +static void to_dec(uint16_t val, byte *buf, byte num) +{ + byte *ptr = buf + num - 1; + for(byte i=0;i<num;i++) { + byte r = val % 10; + val = val / 10; + *(ptr--) = '0' + r; + } +} + +static void store_name() +{ + DateTime now = RTC.now(); + to_dec(now.year(),name,2); + to_dec(now.month(),name+2,2); + to_dec(now.day(),name+4,2); +} + +static byte log_find_name() +{ + store_name(); + for(int i=0;i<26;i++) { + name[7] = 'a' + i; + if (!SD.exists((char *)name)) { + return 1; + } + } + return 0; +} + +static byte log_open() +{ + // log already open! + if (file) { + return 1; + } + // try to find name + if (!log_find_name()) { + return 2; + } + file = SD.open((char *)name, FILE_WRITE); + if (!file) { + return 3; + } + + Serial.print("O: "); + Serial.println((char *)name); + return 0; +} + +static byte log_close() +{ + // log is not open! + if (!file) { + return 1; + } + file.close(); + + Serial.print("C: "); + Serial.println((char *)name); + return 0; +} + +static void store_byte_val(byte v, byte cmd) +{ + switch (cmd) { + case 'm': month = v; break; + case 'd': day = v; break; + case 'H': hour = v; break; + case 'M': minute = v; break; + case 'S': second = v; break; + } +} + +static void store_word_val(uint16_t v, byte cmd) +{ + switch (cmd) { + case 'y': year = v; break; + case 'D': delta = v; break; + } +} + +static void adjust_clock() +{ + DateTime set(year,month,day,hour,minute,second); + RTC.adjust(set); + + // check new time + uint32_t ts = RTC.now().unixtime(); + + // update next time + next_ts = ts + delta; +} + +static void print_time() +{ + DateTime now = RTC.now(); + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(' '); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); +} + +const byte ERR_CMD = 9; +const byte ERR_SYNTAX = 8; +const byte OK = 0; + +static byte handle_command(char *buf, int len) +{ + uint16_t v; + switch (buf[0]) { + case 'y': // set year + case 'D': // set delta + if (len==5) { + v = parse_dec((byte*) buf+1,4); + if (v==0xffff) { + return ERR_SYNTAX; + } + Serial.write(buf[0]); + Serial.println(v); + store_word_val(v,buf[0]); + } else { + return ERR_SYNTAX; + } + break; + case 'm': // set month + case 'd': // set day + case 'H': // set HOUR + case 'M': // set MINUTE + case 'S': // set SECOND + if (len==3) { + v = parse_dec((byte*) buf+1,2); + if (v==0xffff) { + return ERR_SYNTAX; + } + Serial.write(buf[0]); + Serial.println(v); + store_byte_val((byte)v,buf[0]); + } else { + return ERR_SYNTAX; + } + break; + case 'a': // adjust clock + adjust_clock(); + break; + case 'o': // open log + return log_open(); + case 'c': // close log + return log_close(); + case 'r': // read clock + print_time(); + break; + default: + return ERR_CMD; + } + return OK; +} + +static void serial_in() +{ + // read serial + if (Serial.available()) { + char buf[BUFSIZE]; + int len = Serial.readBytesUntil('\n', buf, sizeof(buf)); + byte err = handle_command(buf, len); + if (err == 0) { + Serial.println("OK"); + } else { + Serial.print("ERR"); + Serial.print(err); + Serial.println(); + } + } +} + +static void handle_button(void) +{ + if (file) { + log_close(); + } else { + log_open(); + } +} + +// ----- MAIN ----- +void setup () { + Serial.begin(9600); + + //while (!Serial) { + //; // wait for serial port to connect. Needed for Leonardo only + //} + + Serial.println("Starting up"); + + pinMode(buttonPin, INPUT_PULLUP); + logToggleButton = Bounce(buttonPin, DEBOUNCE); + + pinMode(ledRedPin, OUTPUT); + pinMode(ledGreenPin, OUTPUT); + + rtc_init(); + sd_init(); +} + +void loop () { + led(ledRedPin, file ? 1 : 0); + + serial_in(); + + logToggleButton.update(); + if (logToggleButton.fallingEdge()) { + handle_button(); + } + + uint32_t ts = RTC.now().unixtime(); + + if (ts >= next_ts) { + led(ledGreenPin, 1); + next_ts += delta; + // do measurement + sensors.requestTemperatures(); + float t = sensors.getTempCByIndex(0); + char temp[BUFSIZE]; + + // format: <timestamp> t:1=<temp> + String line = ""; + line += ts; + + line += " t:1="; + dtostrf(t, 5, 2, temp); + line += temp; + + Serial.println(line); + if (file) { + file.println(line); + file.flush(); + } + led(ledGreenPin, 0); + } +} |