project:brmhive:sketch
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| project:brmhive:sketch [2010/11/02 04:09] – pasky | project:brmhive:sketch [2011/01/07 18:40] (current) – pasky | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | < | ||
| + | /* | ||
| + | * 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' | ||
| + | /* Required modification of cores/ | ||
| + | * 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 < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // #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, | ||
| + | } | ||
| + | /* TODO: Stop reading analog pins? */ | ||
| + | } | ||
| + | |||
| + | |||
| + | void blink(int count, int length) | ||
| + | { | ||
| + | for (int i = 0; i < count; i++) { | ||
| + | digitalWrite(infoPin, | ||
| + | delay(length); | ||
| + | digitalWrite(infoPin, | ||
| + | delay(length); | ||
| + | } | ||
| + | digitalWrite(infoPin, | ||
| + | } | ||
| + | |||
| + | |||
| + | OneWire oneWire(oneWirePin); | ||
| + | PCF8583 RTC(0xA0); | ||
| + | |||
| + | |||
| + | Sd2Card card; | ||
| + | SdVolume volume; | ||
| + | SdFile root; | ||
| + | SdFile file; | ||
| + | |||
| + | void SD_init(void) | ||
| + | { | ||
| + | PRR &= ~(1<< | ||
| + | if (!card.init(4/ | ||
| + | Serial.println(" | ||
| + | Serial.println(card.errorCode(), | ||
| + | Serial.println(card.type(), | ||
| + | blink(2, 2000); | ||
| + | return; | ||
| + | } | ||
| + | if (!volume.init(& | ||
| + | Serial.println(" | ||
| + | blink(3, 2000); | ||
| + | return; | ||
| + | } | ||
| + | if (!root.openRoot(& | ||
| + | Serial.println(" | ||
| + | blink(4, 2000); | ||
| + | return; | ||
| + | } | ||
| + | if (!file.open(& | ||
| + | Serial.println(" | ||
| + | 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(" | ||
| + | blink(2, 2000); | ||
| + | } | ||
| + | if (!file.close()) { | ||
| + | Serial.println(" | ||
| + | blink(3, 2000); | ||
| + | } | ||
| + | if (!root.close()) { | ||
| + | Serial.println(" | ||
| + | blink(4, 2000); | ||
| + | } | ||
| + | /* Turn off SPI. */ | ||
| + | SPCR &= ~(1 << SPE); | ||
| + | PRR |= (1<< | ||
| + | } | ||
| + | |||
| + | |||
| + | // 0: asleep; 1: reset/ | ||
| + | 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, | ||
| + | digitalWrite(infoPin, | ||
| + | delay(100); | ||
| + | |||
| + | Serial.begin(9600); | ||
| + | |||
| + | pinMode(auxPowerPin, | ||
| + | |||
| + | pinMode(alertPin, | ||
| + | pinMode(RTCPin, | ||
| + | |||
| + | digitalWrite(infoPin, | ||
| + | delay(200); | ||
| + | |||
| + | Serial.println(" | ||
| + | |||
| + | 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, | ||
| + | attachInterrupt(RTCPin - 2, rtc_int, LOW); | ||
| + | attachInterrupt(alertPin - 2, alert_int, LOW); | ||
| + | |||
| + | sleep_mode(); | ||
| + | |||
| + | 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, | ||
| + | " | ||
| + | (int)wake_cause, | ||
| + | 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, | ||
| + | uint16_t weight = analogRead(i); | ||
| + | delay(100); | ||
| + | digitalWrite(infoPin, | ||
| + | snprintf(scratch, | ||
| + | i, weight, i == NUM_FSR - 1 ? ' | ||
| + | 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(" | ||
| + | for (int i = 0; i < 8; i++) { | ||
| + | Serial.print(addr[i], | ||
| + | Serial.print(" | ||
| + | } | ||
| + | Serial.print(" | ||
| + | } | ||
| + | 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:: | ||
| + | |||
| + | digitalWrite(infoPin, | ||
| + | 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, | ||
| + | |||
| + | int16_t temp = (data[1] << 8) | data[0]; | ||
| + | /* data is in 0.0625 increments, fixed-point *100. */ | ||
| + | temp = temp * 6 + temp / 4; | ||
| + | snprintf(scratch, | ||
| + | i, temp, i == NUM_TEMP - 1 ? ' | ||
| + | append_scratch(); | ||
| + | } else { | ||
| + | blink(3, 1500); | ||
| + | delay(1500); | ||
| + | snprintf(scratch, | ||
| + | i, i == NUM_TEMP - 1 ? ' | ||
| + | append_scratch(); | ||
| + | } | ||
| + | delay(100); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void collect_data(void) | ||
| + | { | ||
| + | digitalWrite(auxPowerPin, | ||
| + | SD_init(); | ||
| + | |||
| + | get_timestamp(); | ||
| + | |||
| + | collect_weights(); | ||
| + | |||
| + | blink(2, 500); | ||
| + | delay(500); | ||
| + | |||
| + | collect_temps(); | ||
| + | |||
| + | strcpy(scratch, | ||
| + | append_scratch(); | ||
| + | |||
| + | SD_done(); | ||
| + | digitalWrite(auxPowerPin, | ||
| + | blink(3, 100); | ||
| + | |||
| + | Serial.println(" | ||
| + | } | ||
| + | |||
| + | |||
| + | /* 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, | ||
| + | wake_cause); | ||
| + | append_scratch(); | ||
| + | blink(3, 3000); | ||
| + | sleep(); | ||
| + | } | ||
| + | } | ||
| + | </ | ||