Hello all,
I recently finished prototyping an indoor/outdoor weather station. For my outdoor unit, I presently have an Arduino Mini Pro, DS18S20, and FS1000A transmitter hooked up to a 9V battery. I included the watchdog sleep code and minimized transmissions to once every 20 minutes, which is fine for this value and since I want to maximize battery life. At the moment, the outdoor unit is using around 0.10V of my battery/day, so it is definitely not going to last very long. Here is my math: 10 days per Volt, so in 40 days it my 9V battery will be down to 5V and then start causing issues once it falls below what the Arduino needs.
Question: My current setup has the DS12S20 & FS1000A powered via vcc connection and this appears to always be 4.98V. Can I power the transmitter and DS18S20 via digital pin by configuring it as OUTPUT and setting HIGH to use and LOW to turn off? If so, I tried this and nothing seemed to work. How do I find out how long to wait after sending HIGH to pin and can I add this delay to my loop? Here is my current code:
#include <OneWire.h>
#include <VirtualWire.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#define DS18S20_SENSOR_PIN 2
#define LED_PIN 13
#define TRANSMIT_PIN 12
#define ADDR 1
#define sleepTime 75 //number of 8 second sleep cycles
volatile byte wdt=100; //used to count number of sleep cycles
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
volatile boolean f_wdt=1;
OneWire ds(DS18S20_SENSOR_PIN);
byte temp;
float tempF;
int tempF1, tempF2;
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
f_wdt=1; // set global flag
}
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCSR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCSR = bb;
WDTCSR |= _BV(WDIE);
}
// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
while (wdt < sleepTime) { // sleep for sleepTime * 8sec
wdt++;
sleep_mode(); // activate system sleep
}
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
wdt=0;
}
void setup(void) {
cbi( SMCR,SE ); // sleep enable, power down mode
cbi( SMCR,SM0 ); // power down mode
sbi( SMCR,SM1 ); // power down mode
cbi( SMCR,SM2 ); // power down mode
setup_watchdog(9);
vw_set_tx_pin(TRANSMIT_PIN);
vw_set_ptt_inverted(true);
vw_setup(2000);
}
void loop(void) {
if (f_wdt==1) {
f_wdt=0;
float tempF = getTemperature();
if (tempF != NULL) {
digitalWrite(LED_PIN, HIGH);
tempF1 = (int)tempF;
tempF2 = (int)((tempF - tempF1) * 100.0); // For two decimal points
char msg[24];
sprintf(msg, "%i.%i", tempF1, tempF2);
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx();
digitalWrite(LED_PIN, LOW);
}
system_sleep();
}
}
float getTemperature() {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius, fahrenheit;
if ( !ds.search(addr)) {
ds.reset_search();
delay(20000); // Pause 20 seconds between passes
return NULL;
}
if (OneWire::crc8(addr, 7) != addr[7]) { //CRC is not valid!
return NULL;
}
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10: //DS18S20
type_s = 1;
break;
case 0x28: //DS18B20
type_s = 0;
break;
case 0x22: //DS1822
type_s = 0;
break;
default: //unknown
return NULL;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
// convert the data to actual temperature
unsigned int raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// count remain gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw << 3; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
fahrenheit = celsius * 1.8 + 32.0;
return fahrenheit;
}
Question: Are there any other things I can turn off to save move power like turning unused pins off and brown-out detection?
Question: Instead of using the fairly expensive Arduino Mini Pro, what are you all going to Production with? Should I wire up one of these breadboard arduinos and go with that? I bought one of these Diavolino boards and it looks like exactly what I need for my final product.
Question: If my indoor unit will be powered by Arduino Mini Pro running at 16Mhz and 5V, can I use something like attiny85 on the outdoor unit or do they need to be the same? I am guessing the transmitter and receiver need to be the same speed.
Thanks in advance,
Brent