Monday, February 23, 2015

Arduino Wireless Temperature Nodes

I've started working on a wireless network of temperature nodes - using a cheap 2.4Ghz transceiver, an arduino mini, and a cheap DS18B20 digital one-wire temperature sensor. The wireless nodes will run on batteries, so I want to reduce power consumption as much as possible.

Currently, I'm running 3 wireless nodes, communicating back to a main Arduino. In the near future I'll be building a logging interface so that I can track everything.

I selected the Arduino Mini because I wanted something small enough to go directly on to a breadboard, and the Mini was cheap from Deal Extreme - cheaper in . Total cost breakdown per node is:
1x Arduino Mini - $4.39
1x Small 400 tie breadboard - $3.21
1x DS18B20 Temperature Sensor - $1.99
1x NRF24L01+ 2.4Ghz transceiver - $2.22 (not pictured)
2x 1MOhm, 1x 4.7kOhm resistor - $0.02
1x 2AA Battery Holder - $1.61
3x 1N4001 Diode - $0.45 (not pictured)

Total: $13.89

I really like the Arduino Mini for its size. The 5v version I got is pretty much identical to the larger Arduino Unos - with the exception that they don't have a USB interface. You'll need an FTDI USB Cable, or another Arduino to program it. (I used an arduino uno - pictured - to program it. You can either remove the ATMega from the Arduino Uno, or just hold the reset button down while plugging the USB cable in and for the entire time you upload the sketch)
The Mini in front of an Arduino Uno

Now - for the wiring of the nodes. This is a Fritzing sketch that outlines how the Mini is wired, before adding the NRF24L01+ module:
Bare schematic with just the mini, and the temperature sensor

The top power rail is GND/5v, the bottom power rail is Battery v/GND. I'm using 2x 3.7v Trustfire Li-Ion batteries with 900mAh power. This is because 2x standard 1.5v batteries wouldn't give me enough voltage to run the 5v arduino. One of the nodes is running with a 4 battery pack though - and it's working just fine.

From the left side - there are 2 1M Ohm resistors, going from the Battery to ground - this acts as a voltage divider - reducing the voltage by half and going in to Analog 0. This is so that I can measure the battery voltage, which will be over the 5v that the Arduino can handle. The max voltage of my li-ion batteries is 4.25v, so with 2 of them and the voltage divider - the highest voltage the Arduino will see on this input is 4.25v.

I use 1M Ohm resistors because the higher the resistor value, the lower the constant drain on the batteries is. 1M ohm is the highest I had on hand - so that will give me a current draw of about 3 µA (0.003 mA) for this circuit.

Next to the left is the DS18B20 temperature sensor. It is wired to the Arduino's digital pin 4 - with a 4.7k Ohm resitor on the data pin to ground. This is a great little sensor - capable of making measurements in 0.5C increments in as little as 90ms.

The two orange wires from D9 and D5 are optional address select pins. This allows me to use the same code on all the nodes, and just connect different pins to ground to choose a different address.

This is what it looks like in the real world - minus the battery pack:

The Mini all wired up, minus the 3 diodes, the 2.4Ghz transceiver, and the battery case
As it stands here - this will let us measure the temperature. However, we still need to add a transmitter.

I chose the NRF24L01 partially because it was cheap, but also because it's very low power. When the radio is powered down it consumes about 1 µA - and only 9mA when actively transmitting. The only problem is, it runs on ~3.3v. The data pins can be 5v, but it has to be powered with ~3.3v (actually 1.9v-3.6v). With the Arduino mini - there is no simple 3.3v output like on the larger Uno. I also didn't have an 3.3v step down converters on hand - but I did have several 1N4001 diodes - which have about a ~0.8v drop across them. Wiring up 3 of them in serial means that a 5v input is dropped to about 3v (the voltage drop is dependent on current, and the NRF24L01 is fairly low current so there is less voltage drop). This isn't ideal from a power consumption standpoint - you'd be better served with an efficient converter.
Note the addition of the 3 diodes

The NRF24L01 uses the SPI interface - plus 2 digital pins and are connected as follows.

The schematic is ugly, but there isn't a good way to get this module on a breadboard due to the layout of the pins. You'll need female->male jumper cables.
Wired up with the NRF24L01+

  MISO -> 12
  MOSI -> 11
  SCK -> 13

  CSN -> 8
  CE -> 7

  Vcc -> End of the diode chain
  GND -> GND

Next Steps - Programming the Node and Power consumption

As mentioned above, power consumption is the critical component here. This doesn't do much if you have to replace the batteries in it every few days.

There are a few things to note:

1. The Arduino has an LED wired directly to the power rail, which means it's consuming power 100% of the time. This increases the total usage of the board considerably.


2. The Arduino mini, just running idle consumes about 50mA of power (measured from a multimeter). This means, if you have a 900mAh battery you'll get ~18 hours of run time before they are empty. 

The solution to the first point is simple - I removed the power LED from the board using a pair of angle clippers. No LED, no power loss.

The solution to the second point is a bit more complicated. In broad terms - we want to put the arduino in to a deep sleep state any time we are not actively going to be reading the temperature and transmitting it to the base station. In this low power state the arduino consumes several orders of magnitude less power. Some quick research shows that you can get power consumption down to about 1.7µA.

Looking at our various components -


At default precision can take upwards of 700ms to read and return the temperature. The built in libraries assume this time and block the arduino from doing anything else during that time. This means 700-800ms of 50mA power usage.

The data sheet however says that with 9 bit precision, a read only takes 90ms - which uses 12% of the power. Further to that, we can send the command asynchronously - which lets us wake up just long enough to send the temperature read command, sleep for the next 70ms, then wake up again to read the value.


According to the datasheet - Automatically enters a standby mode, which consumes 26 µA. Pretty good - however it also has a power down mode which consumes 900nA (0.9 µA, or 0.0009mA). So, the idea here would be to power down the radio until we need it. Powering on the radio takes ~1.5ms, so we can send the power on command, and then sleep for the next 1.5ms.

Together, it looks something like this, during the loop in the Arduino:

1. Wake up arduino
2. Send T command to DS18B20
3. Send power on command to NRF24L01
4. Low power Sleep for 90ms (to give the radio and sensor time to power up)
5. Read temperature from DS18B20
6. Assemble broadcast packet
7. Transmit packet
8. Power down radio
9. Sleep arduino for X minutes

Power usage here should be a few mA for just a few milliseconds every X minutes. I'd need an oscilloscope to do any real job of measuring the power usage but hopefully once I go through a set of batteries I'll have a better idea.

I use the Jeelib Sleepy Library to make it easy to run low power timers.

The entire code can be found on Github.

In the next iteration I will likely only power on the radio after 88ms sleep has elapsed from the temperature read - that'll save ~88ms of 26 µA usage. Every little bit counts!

For absolute power savings - you'll want a bare bones ATMega 328 chip - and provide regulated 3.3v power with a high efficiency power regulator. You could use the internal clock and get power usage down incredibly low.


chingying cheng said...

So glad you shared this example.
But I compiled wrong, could you please give me some help? Thank you very much.

wireless_node_transmiter.ino:33:20: fatal error: printf.h: No such file or directory
compilation terminated.

Chris Taylor said...

I replied to your issue on Github - but I added this file to my libraries directory for Arduino:

That will let you use printf. I'll add it to the readme and instructions! Thanks.

chingying cheng said...

Thank you for your quick reply
But I still have some small problems
I reply to you on Github. Thank you very much.