Hot Yet? (a tiny85 project)

The concept is simple, if a thermistor detects a temperature change when the tiny85 wakes which was significantly different from the previous awake period, turn PWM on a RGB led based upon the current temperature and track the change until it stabilizes.

The example here is just for fun, but was intended to provide a visual feedback for a hot water faucet; that is, as the temperature moves from cold to hot, the RGB LED goes from Blue to Green to Red with overlap in the crossover ranges.

The code is simple. The sleep routines are a combination of Nick Gammon low-power settings, Watchdog settings from the InsideGadgets site, and the tiny core from Coding Badly.

This is a project that simply screams for hacking. If the temperature has not changed during the wakeup, the circuit goes back to sleep. Here in the lab, I have been running the project off of a CR2032 (already half-dead) for several weeks. So, what about a wearable “mood” pendant, or “mood” wrist-band? Using surface mount tiny, you may be able to get this into a large ring?

Whatever you decide to do, have fun and keep us posted!

Ray

/* 
   M. Ray Burnette 20140210 Open Source: for "Hot Yet?" publication
   Coding Badly Tiny core: https://code.google.com/p/arduino-tiny/
   Binary sketch size: 2,852 bytes (of a 8,192 byte maximum)
   Arduino 1.0.5 No bootloader used.  Upload via ISP.
   Project 3.3V Attiny85 @8MHz internal,  under 10mA idle at 68F

   Schematic:
   x-----------------/\/\/\/\/\/\/\/---------------x---/\/\/\/\/\/\/\----xGND
   |                NTC 10K Thermistor             |  10K 1% Resistor
   |                                               |
   |              ATTINY85 / ARDUINO               |
   |                     +-\/-+                    |
   |    Ain0 (D 5) PB5  1|    |8  Vcc              |
   x--- Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1 --- 
(Blue)- Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1  (Green) ----------|<---x
   |               GND  4|    |5  PB0 (D 0) pwm0  (Red) ------------|<---x
   |                     +----+                                          |    100 Ohm
   x----------------------------------------------------------------|<---x---/\/\/\/\/---Vcc 3.3V

*/
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

boolean flag_wdt = 1;

int pinT = PB3;           // Thermistor source voltage
int pinR = PB0;           // Digital pin #0  Red
int pinG = PB1;           // Digital pin #1  Green
int pinB = PB4;           // Digital pin #4  Blue
int r; int g; int b;
const int nToSleep = 50 ; // # of stable temp readings before sleep
const int Delay =    100; // main loop delay in mS
double ADCcount;
double ADCprevious;
int nCount;
int ThermistorPin  = 1 ;  // A1 is physical pin #7 (PB2)

void setup()
{
  // WDTO_15MS, WDTO_30MS, WDTO_60MS, WDTO_120MS, WDTO_250MS, WDTO_500MS, 
  // WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S
  setup_watchdog(WDTO_4S);  // Periodic Heartbeat to awaken deep sleep()
  sleep_disable();
  pinMode(pinT, OUTPUT); digitalWrite(pinT, HIGH);  // Thermistor Source
  pinMode(pinR, OUTPUT);
  pinMode(pinG, OUTPUT);
  pinMode(pinB, OUTPUT);
}
  
void loop() 
{
  wdt_reset();    // pat K9
  ADCcount = analogRead(ThermistorPin) ;
  if (ADCcount == ADCprevious) ++nCount;
  if ( nCount > nToSleep )
  { // prepare for low current power-down state
    pinMode(pinR, INPUT); digitalWrite(pinR, HIGH);  // pullup enabled
    pinMode(pinG, INPUT); digitalWrite(pinG, HIGH);
    pinMode(pinB, INPUT); digitalWrite(pinB, HIGH);
    SleepLonger:    // Come here to re-sleep
    pinMode(pinT, INPUT); digitalWrite(pinT, HIGH);
      system_sleep();
      sleep_disable();  // deep sleep until WDT kicks
      pinMode(pinT, OUTPUT); digitalWrite(pinT, HIGH);
      delay(50);
      // Yawn, exercise a few reads for stabilization
      for (uint8_t z=0; z<5; z++) {
        ADCcount = analogRead(ThermistorPin) ;
      }
      if (abs(ADCcount - ADCprevious) < 4) goto SleepLonger;  // hysteresis
    // restore LED output drivers ... temp has gone up
    pinMode(pinR, OUTPUT); digitalWrite(pinR, HIGH);
    pinMode(pinG, OUTPUT); digitalWrite(pinG, HIGH);
    pinMode(pinB, OUTPUT); digitalWrite(pinB, HIGH);
    nCount = 0;
  } else {
  // 261 = 32F, 447 = 64F, 537 = 75F, 575 = 82F
  b = map(ADCcount, 261,  447, 100, 255 );
  g = map(ADCcount, 435,  574, 250, 100);  // overlap green & blue
  r = map(ADCcount, 575, 1023, 250,  50);

  if (ADCcount > 574)              // HOT: ADCcount goes up with increase temperature
    {
      // Show only Red when Hot with Red intensity increasing with temperature
      analogWrite(pinR,   r);
      analogWrite(pinG, 255);      // 255 = 100% High == NO LED Current Common Anode --> Vcc
      analogWrite(pinB, 255);      // Blue Off
    } else {                       // Cold to Cool transition with Blue fading into Green
      analogWrite(pinR, 255);      // Red Off
      analogWrite(pinG, g);
      analogWrite(pinB, b);        // Brighter Blue with colder temp
    }
  }
  ADCprevious = ADCcount;
  delay(Delay);
}

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// http://www.insidegadgets.com/wp-content/uploads/2011/02/ATtiny85_watchdog_example.zip
void system_sleep()
{
    cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF
    power_all_disable ();                // power off ADC, Timer 0 and 1, serial interface
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
    noInterrupts ();                     // timed sequence coming up
    sleep_enable();
    interrupts ();                       // interrupts are required now
    sleep_mode();                        // System sleeps here
    sleep_disable();                     // System continues execution here when watchdog timed out
    power_all_enable ();                 // power everything back on
    sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}

// 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
  WDTCR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCR = bb;
  WDTCR |= _BV(WDIE);
}
  
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
     // wdt_disable();  // disable watchdog
}

Very cool 8) ... or hot ]:slight_smile:
My 85s should be here this week, great project to play around with.
The wrist band idea is neat, could be done with a few segments of an RGB strip.