User Tools

Site Tools


project:brmhive:sketch

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
project:brmhive:sketch [2010/10/26 00:18] – created paskyproject:brmhive:sketch [2011/01/07 18:40] (current) pasky
Line 1: Line 1:
 +<code>
 +/*
 + * brmhive -- low-power sensor data logger
 + *
 + * You can force wake and trigger resonr re-read using the Alert button.
 + *
 + * The info led will blink happily when doing all the work and stay dark
 + * while asleep. Short blinks (up to a second) are o.k. Long blinks (more
 + * than 1.5 seconds) indicate error.
 + *
 + * In case of trouble, try pressing Reset.
 + */
  
 +/* PCF8583 uses pasky's fork at github that adds extra alarm capabilities. */
 +/* Required modification of cores/arduino/HardwareSerial.c:
 + * Change RX_BUFFER_SIZE to 2, head and tail to uint8_t. */
 +
 +/* TODO: Test w/o RX_BUFFER_SIZE hack. */
 +/* TODO: Move taddrs[] to PROGMEM. */
 +
 +#include <avr/sleep.h>
 +#include <avr/pgmspace.h>
 +#include <OneWire.h>
 +#include <Wire.h>
 +#include <PCF8583.h>
 +#include <SdFat.h>
 +#include <SdFatUtil.h>
 +
 +// #define DEBUG // Temperature bus scan.
 +
 +#define NUM_FSR 4 // number of weight sensors
 +#define NUM_TEMP 55 // number of temperature sensors
 +
 +/* Pin definitions. */
 +#define auxPowerPin 6 /* Peripherial power transistor base. */
 +#define alertPin 2 /* Alert button. */
 +#define RTCPin 3 /* RTC alarm. */
 +#define infoPin 7 /* Info LED. */
 +
 +#define oneWirePin 6 /* One-wire temperature sensors. */
 +
 +/* SD Card is occupying fixed pins - SPI. */
 +/* RTC clock is occupying fixed pins - I2C. */
 +
 +void powerdown_pins(void)
 +{
 +        /* Before going to sleep, bring pins to the most low-power state. */
 +        for (int i = 0; i <= 13; i++) {
 + if (i == alertPin || i == RTCPin || i == infoPin
 +     || i == oneWirePin || i == auxPowerPin)
 + continue;
 + pinMode(i, OUTPUT); digitalWrite(i, HIGH);
 +        }
 +        /* TODO: Stop reading analog pins? */
 +}
 +
 +
 +void blink(int count, int length)
 +{
 + for (int i = 0; i < count; i++) {
 + digitalWrite(infoPin, LOW);
 + delay(length);
 + digitalWrite(infoPin, HIGH);
 + delay(length);
 + }
 + digitalWrite(infoPin, LOW);
 +}
 +
 +
 +OneWire oneWire(oneWirePin);
 +PCF8583 RTC(0xA0);
 +
 +
 +Sd2Card card;
 +SdVolume volume;
 +SdFile root;
 +SdFile file;
 +
 +void SD_init(void)
 +{
 + PRR &= ~(1<<PRSPI); // Turn on SPI circuit.
 + if (!card.init(4/*SPI_QUARTER_SPEED*/)) {
 + Serial.println("card init fail");
 + Serial.println(card.errorCode(), DEC);
 + Serial.println(card.type(), DEC);
 + blink(2, 2000);
 + return;
 + }
 + if (!volume.init(&card)) {
 + Serial.println("volume init fail");
 + blink(3, 2000);
 + return;
 + }
 + if (!root.openRoot(&volume)) {
 + Serial.println("root init fail");
 + blink(4, 2000);
 + return;
 + }
 + if (!file.open(&root, "templog.txt", O_CREAT | O_APPEND | O_WRITE)) {
 + Serial.println("file init fail");
 + blink(5, 2000);
 + return;
 + }
 +}
 +
 +void SD_done(void)
 +{
 + /* We must proceed in case of errors - open will fail if we did not
 + * close the file. */
 + if (file.writeError) {
 + Serial.println("file write fail");
 + blink(2, 2000);
 + }
 + if (!file.close()) {
 + Serial.println("file close fail");
 + blink(3, 2000);
 + }
 + if (!root.close()) {
 + Serial.println("root close fail");
 + blink(4, 2000);
 + }
 + /* Turn off SPI. */
 + SPCR &= ~(1 << SPE);
 + PRR |= (1<<PRSPI);
 +}
 +
 +
 +// 0: asleep; 1: reset/bootup; 2: alert; 3: RTC
 +volatile char wake_cause = 1;
 +
 +void alert_int(void)
 +{
 + wake_cause = 2;
 +}
 +
 +void rtc_int(void)
 +{
 + wake_cause = 3;
 + /* Avoid infinite low; and we cannot ack_timer() from within. */
 + detachInterrupt(RTCPin - 2);
 +}
 +
 +
 +void init_device(void)
 +{
 + pinMode(infoPin, OUTPUT);
 + digitalWrite(infoPin, HIGH); // say we're alive
 + delay(100); // make sure we actually see the LED
 +
 + Serial.begin(9600);
 +
 + pinMode(auxPowerPin, OUTPUT);
 +
 + pinMode(alertPin, INPUT);
 + pinMode(RTCPin, INPUT);
 +
 + digitalWrite(infoPin, LOW); // setup complete!
 + delay(200);
 +
 + Serial.println("booted up");
 +
 + blink(5, 100);
 + delay(1000);
 +}
 +
 +void sleep(void)
 +{
 + powerdown_pins();
 +
 + wake_cause = 0;
 + set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 + sleep_enable();
 +
 + RTC.set_timer(RTC_TIMER_HOURS, 1);
 + attachInterrupt(RTCPin - 2, rtc_int, LOW);
 + attachInterrupt(alertPin - 2, alert_int, LOW);
 +
 + sleep_mode(); // We zzzzzz here!
 +
 + detachInterrupt(alertPin - 2);
 + detachInterrupt(RTCPin - 2);
 + RTC.ack_timer();
 + sleep_disable();
 +}
 +
 +
 +char scratch[50];
 +void append_scratch(void)
 +{
 + Serial.print(scratch);
 + file.print(scratch);
 +}
 +
 +void get_timestamp(void)
 +{
 + RTC.get_time();
 +
 + snprintf(scratch, sizeof(scratch),
 + "%d\t%02d/%02d/%02d %02d:%02d:%02d\t",
 + (int)wake_cause, RTC.year, RTC.month, RTC.day,
 + RTC.hour, RTC.minute, RTC.second);
 + append_scratch();
 +
 + blink(2, 500);
 +}
 +
 +void collect_weights(void)
 +{
 + for (int i = 0; i < NUM_FSR; i++) {
 + digitalWrite(infoPin, HIGH);
 + uint16_t weight = analogRead(i);
 + delay(100);
 + digitalWrite(infoPin, LOW);
 + snprintf(scratch, sizeof(scratch), "%d=%d%c",
 + i, weight, i == NUM_FSR - 1 ? '\t' : ' ');
 + append_scratch();
 + delay(50);
 + }
 +}
 +
 +static const uint16_t PROGMEM taddrs[NUM_TEMP] = {
 +#if 0
 + 0x65c1, // 2
 + 0x1b7f, // 3
 + 0x29a2, // 4
 +#else
 +0xD269, 0x9BC6, 0x65C1, 0x1B7F, 0x29A2, 0xABB8, 0x39A8, 0x3697, 0x3A8D, 0xB77B, 0xA8B2, 0xF4D0, 0xAEC9, 0x4CDB, 0x4BC8, 0x03A3, 0xECAB, 0xCA84, 0x9DC5, 0xBB6E, 0x5989, 0x61D7, 0xBD72, 0x3E86, 0x1FCA, 0x4F68, 0xBFC8, 0x3978, 0xBEA8, 0x9EDB, 0x2468, 0x9FCA, 0x467B, 0x0B7C, 0xA0D1, 0x568D, 0x5FCC, 0x0BDF, 0x76BB, 0x3FC7, 0x63D0, 0x9ABF, 0x91C4, 0x01B3, 0x5ABA, 0x9FAF, 0x9190, 0xCEB6, 0x506A, 0x98BE, 0x808A, 0x1F9E, 0x3A68, 0xBCCF, 0x0AAE
 +#endif
 +};
 +
 +void collect_temps(void)
 +{
 + byte addr[8];
 +
 +#ifdef DEBUG
 + while (oneWire.search(addr)) {
 + Serial.print("R=");
 + for (int i = 0; i < 8; i++) {
 + Serial.print(addr[i], HEX);
 + Serial.print(" ");
 + }
 + Serial.print("\n");
 + }
 + oneWire.reset_search();
 +#endif
 +
 + for (int i = 0; i < NUM_TEMP; i++) {
 + addr[0] = 0x28;
 + addr[1] = taddrs[i] >> 8;
 + addr[2] = taddrs[i] & 0xff;
 + addr[3] = 0x7d;
 + addr[4] = 2;
 + addr[5] = 0;
 + addr[6] = 0;
 + addr[7] = OneWire::crc8(addr, 7);
 +
 + digitalWrite(infoPin, HIGH);
 + oneWire.reset();
 + oneWire.select(addr);
 + oneWire.write(0x44);
 + delay(800);
 +
 + int present = oneWire.reset();
 + if (present) {
 + oneWire.select(addr);
 + oneWire.write(0xbe);
 + byte data[12];
 + for (int j = 0; j < 9; j++)
 + data[j] = oneWire.read();
 + digitalWrite(infoPin, LOW);
 +
 + int16_t temp = (data[1] << 8) | data[0];
 + /* data is in 0.0625 increments, fixed-point *100. */
 + temp = temp * 6 + temp / 4;
 + snprintf(scratch, sizeof(scratch), "%d=%d%c",
 + i, temp, i == NUM_TEMP - 1 ? '\t' : ' ');
 + append_scratch();
 + } else {
 + blink(3, 1500);
 + delay(1500);
 + snprintf(scratch, sizeof(scratch), "%d=!%c",
 + i, i == NUM_TEMP - 1 ? '\t' : ' ');
 + append_scratch();
 + }
 + delay(100);
 + }
 +}
 +
 +void collect_data(void)
 +{
 + digitalWrite(auxPowerPin, HIGH);
 + SD_init();
 +
 + get_timestamp();
 +
 + collect_weights();
 +
 + blink(2, 500);
 + delay(500);
 +
 + collect_temps();
 +
 + strcpy(scratch, "\r\n");
 + append_scratch();
 +
 + SD_done();
 + digitalWrite(auxPowerPin, LOW);
 + blink(3, 100);
 +
 + Serial.println("done");
 +}
 +
 +
 +/* This is the one-time routine called when we are turned on. It should
 + * set up the whole device and go through the drill. */
 +void setup(void)
 +{
 + init_device();
 + collect_data();
 + sleep();
 +}
 +
 +/* This is the repeat routine called all the time after setup().
 + * We sleep() between each two calls to it. */
 +void loop(void)
 +{
 + if (wake_cause == 1 || wake_cause == 2 || wake_cause == 3) {
 + blink(2, 200);
 + delay(1000);
 + collect_data();
 + sleep();
 + } else {
 + /* Something wrong happenned. Blink around a bit and try to go
 + * to sleep. */
 + snprintf(scratch, sizeof(scratch), "unknown wake cause %d\r\n",
 + wake_cause);
 + append_scratch();
 + blink(3, 3000);
 + sleep();
 + }
 +}
 +</code>