summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bounce.cpp90
-rw-r--r--src/Bounce.h71
-rw-r--r--src/main.cpp347
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);
+ }
+}