Tuesday, 17 July 2012

Frankenstein's Thermometer Mk2

Well it's been just over a year since this blog started and what better way to celebrate than revising an old project? I'd had a look at Frankenstein's thermometer before, using a neat trick with a mono jack plug and a stereo socket to switch the power. However I wasn't really pleased with this arrangement, because it separated the thermistor from the main box when it wasn't in use.

The idea was to upgrade the firmware to put the ATtiny into deep sleep after a short time. The complete code is now:

The main additions are:
  • the sleep() routine which causes the ATtiny to enter a power-down mode,
  • the PCINT1_vect which wakes it up again when the push-button is pressed.
The port PB1, which the push-button connects to ground, generates PCINT9. On the ATtiny84, there are two pin-change interrupts, PCINT0 and PCINT1. The former handles pin change signals on Port A, while the latter handles those from Port B. Our handler simply checks whether the interrupt has woken us up, or was to change the units of temperature.

The sleep routine switches off all of the LEDs and the ADC before putting the ATtiny to sleep. When it wakes up again, the ADC must be re-enabled.

With the new software installed,  the device consumes about 11mA when on but 0.16mA when off. With a nominal capacity of 1000mAh, this would drain the batteries in about 6000 hours (or 250 days). This was a bit surprising, as was the discovery that this current was still drawn when the AVR was removed altogether. This indicated that the source of the drain was the voltage divider comprising the thermistor and a 10k resistor. (See the circuit diagram in the original posting.) At room temperature, the current drawn would be 3v/20k or 0.15mA.

Rather than complicate the circuit with a MOSFET switch, we decided simply to increase the value of the bias resistor from 10k to 47k. This reduced the current by a factor of 4 increasing the battery life to over 2 years. (The calculation of the Thermistor equation has been cleaned up a bit too: the original made the assumption that the 10k resistor would cancel the thermistor's resistance at 25C.)

Thursday, 5 July 2012

Pulse Width Modulation

The LED is an interesting beast and dimming one is an interesting problem. Unlike an incandescent bulb, simply changing the voltage across it does not work. The diagram below shows why: its I-V curve is almost vertical around Vd and any lower voltage will cause it to turn off. (It's also why a current-limiting resistor is essential: connecting it to a supply even slightly greater than Vd will cause a huge current to flow, destroying it with a pop.)

In the analog world, varying the brightness of an LED might be achieved with a dependent current-source, involving an op-amp perhaps. However in the digital world of this blog, the only way is to vary a square-wave's duty-cycle (the ratio of on-time to off-time) quickly enough for flickering to be indistinguishable to the eye, so the average brightness is perceived. This method is known as pulse-width modulation or PWM.

On Arduino, PWM is achieved in hardware using the analogWrite() function. Confusingly this does not use the analog input pins, but a subset of the digital I/O pins. However analogWrite() provides limited control, for one thing the frequency is fixed; should more control be required you have to go under the Arduino API (this excellent tutorial has the answers).

Although the ATtiny85 also has hardware PWM, your author was unable to make it work without flicker using the ATtiny Arduino core, probably because the internal oscillator was running too slowly at 1MHz. Software bit-banging, as shown in the following sketch, did work well enough at this frequency.

By varying the duty-cycle from low to high and back again, this little sketch brightens and dims an LED attached to the desired pin in a manner similar to Apple's breathing LED. Varying the delay parameter also allows control over the rate of breathing.