Sunday, 29 April 2012

ProBee Based Home ZigBee Network - Part 3 - Coordinator Software Display

Welcome to part 3 of the ProBee Based Home ZigBee Network series. In this entry I will be looking at how to display the temperature reported from our ProBee based sensor node onto a webpage using a custom Python script and Open Energy Monitor's emoncms software. "Emoncms is a powerful open-source web-app for processing, logging and visualising energy, temperature and other environmental data."
Will will need to have a working sensor node network comprising of a co-ordinator and at least one sensor node, so make sure you have followed the part 2 of this series!
Additional things you will need:
  • A Web Server: A Linux based PC/server with Apache, MySQL Server and Python installed. I'll be using my Beagleboard running Ubuntu Server, but any major Linux distribution should be suitable (including running one from a virtual machine assuming your virtual machine has access to the ZigBee coordinator's USB serial interface).
  • Emoncms  : The latest version of emoncms installed on the server. You can get it here (at time of writing version 3 is that latest). Installing it is quite trivial once you have your Linux server setup, just follow the installation guide here.
This tutorial should work just as well with a Windows based server, but I will leave it up to the reader to investigate.

Flow of temperature data


So we need to do the following:
  1. Verify sensor node and network - Check what serial device our coordinator is connected to and verify we are receiving temperature data from the sensor node through the co-ordinator's serial interface.
  2. Verify  emoncms  Installation - Check that emoncms is working correctly and receiving sample commands from the browser.
  3. Create the serial data parsing script - Write a Python script to parse the serial data  outputted by the ProBee coordinator and send this data to emoncms for storage and display. The script is very basic, so if you don't know Python you could easily port it to your preferred language.
  4. Integration - Integrate it all so our temperature data is displayed on our web server.
  5. Run at start-up (optional) - I will show you how to get the serial data parsing script running automatically when your Ubuntu server is powered on.
Verify Sensor Node and Network
Plug your pre-configured ProBee coordinator (ProBee USB dongle) into your server and power on your ProBee sensor node (you should have followed part 2 to get these ready). 
We now need to connect to the ProBee USB dongle's USB serial port using a terminal application.
To find the device name for your USB dongle, use the dmesg command:
donal@server:~$ dmesg | grep FTDI
[ 62.209960] USB Serial support registered for FTDI USB Serial Device
[ 62.219909] ftdi_sio 1-2.2:1.0: FTDI USB Serial Device converter detected
[ 62.246856] usb 1-2.2: FTDI USB Serial Device converter now attached to ttyUSB0
[ 62.252075] ftdi_sio: v1.6.0:USB FTDI Serial Converters Driver
The Probee dongle uses an FTDI USB to serial interface chip, which in my case is attached to ttyUSB0.
Now use minicom (Linux equivalent of hyperterminal) to view the serial data (containing our sensor node temperature) coming from the co-ordinator. If you haven't use minicom, there is a good tutorial here.
You should get output similar to this:




Verify Emoncms Installation
Html post requests are used to send input data to the emoncms server. Our script will be creating  requests to send the temperature data to the server each time we receive new data from our temperature sensor.
Now to verify the emoncms installation: Browse to your emoncms installation (in my case http://mylocalserver/emoncms3/user/view), and click on the Account tab. Then click on the "try me" link which will send a sample html post request to the server. Then click on the Inputs tab, and you should see two new feeds in there that were updated several seconds ago.
Emoncms validation

Create Serial Data Parsing Script
The script will have to do the following:
  1. Open the serial port to the ProBee dongle.
  2. Wait for and read a line of data from the serial port.
  3. Parse that line and generate the html post request to the emoncms server.
  4. go back to step 

#! /usr/bin/python
"""
Simple script for parsing probee co-ordinator data and passing it on to Emoncms.
Donal Morrissey
http://donalmorrissey.blogspot.com/
"""
import re       # Used for parsing the data string.
import sys      # For exit
import serial   # Serial port interfacing
import requests # To send html post requests to Emoncms

PORT = '/dev/ttyUSB1'
BAUD_RATE = 115200

MY_EMONCMS_API_KEY = 'your_emoncms3_api_key'
URL_TO_MY_EMONCMS = 'http://your_server_address/emoncms3'

# Open serial port
try:
        ser = serial.Serial(PORT, BAUD_RATE)
        ser.open()
except:
        print "Could not open serial port: ", sys.exc_info()[0]
        sys.exit(2)


# Continuously read and print packets
while True:
    try:
        line = ser.readline();

        #Check the line is valid
        if not "++" in line: continue
        line = line.rstrip()

        # Split the line up, we know our raw temperature data will be located in location 2.
        r = re.compile('[|,]+')
        split_line =  r.split(line)

        # Extract the raw value as an int (our data is in location 2).
        raw_value =  int(split_line[2], 16)

        #Get the measured voltage from the raw ADC value.
        vout_mV = raw_value / 10

        temperature_degC = (vout_mV - 500) / 10

        #print temperature_degC

        # Now there is where the magic happens...
        # We send the new value to emoncms as a post request.
        requests.post(URL_TO_MY_EMONCMS+"/api/post?apikey=" + MY_EMONCMS_API_KEY +"&json={temperature_probee:"+str(temperature_degC)+"}")

    except KeyboardInterrupt:
        break

ser.close()


Integration
We are now ready to test the system. Open a browser and browse to your emoncms installation and click on the Inputs tab. Plug in your ZigBee co-ordinator (ProBee dongle), run your serial data parsing script and power on your sensor node.
You should now see the temperature input updating every 5 seconds on the Inputs tab. You can now add widgets to your dashboard and display various graphs, etc of this data.


Run at Start-Up
As the root user, save the following script to /etc/init.d/home_monitoring.sh, not forgetting to add in the full path to your script.
#! /bin/sh
# /etc/init.d/home_monitoring.sh

# Carry out specific functions when asked to by the system
case "$1" in
  start)
    echo "Starting receive_and_post_emon3_d.py "
    /<full path to this script>/receive_and_post_emon3_d.py &
    ;;
  stop)
    echo "Stopping receive_and_post_emon3_d.py"
    killall receive_and_post_emon3_d.py
    ;;
  *)
    echo "Usage: /etc/init.d/home_monitoring.sh {start|stop}"
    exit 1
    ;;
esac

exit 0


Make the script executable: by running the command: "chmod 755 /etc/init.d/home_monitoring.sh".
Now register the script so it will be called at startup/shutdown: "update-rc.d  home_monitoring.sh defaults".
You can test your script runs at startup by restarting your server, your emoncms dashboard should be continuously updated by your sensor node.


Conclusion
You should now have a basic home temperature monitoring system using ProBee based Sensor Node and Co-ordinator and emoncms.


This series:

Sunday, 15 April 2012

ProBee Based Home ZigBee Network - Part 2 - Temperature Reporting End Node

Overview
Welcome to part 2 of the ProbBee based home Zigbee network. In this part of the series I will be detailing how to setup, configure and test a temperature reporting end-node. We will follow these steps:
  1. Design and build the circuit.
  2. Configure the ProBee module to periodically report the temperature and enter a low-power sleep mode.
  3. Configure the network co-ordinator.
  4. Test the system using a terminal app, such as putty or hyperterminal.
and require this hardware:
  1. Breadboard with jump-wires.
  2. ProBee-ZE20S module for the end-node.
  3. A ProBee-ZU10 usb dongle as the co-ordinator.
  4. The ProBee manager software, to configure the end-node and co-ordinator.
  5. A ProBee expansion board, which will allow us to mount the module onto a breadboard. Please contact me if you need an expansion board as I have some spare ones.
  6. A TMP35 temperature sensor in DIP package, used for sensing the room temperature. These are extremely easy to use, for more info please look at ladyada's great overview here.
  7. A DIP LED used for indicating the status of the ProBee module.
  8. A power circuit for regulating our battery power supply to the 3.3 volts required by the ProBee module and TMP36. Alternatively, the easiest thing to do would be to get a Breadboard Power Supply like this from Sparkfun: Breadboard Power Supply 5V/3.3V, it won't be the most efficient approach, but will be fine for what we need.
Circuit Design
The following is my 'back-of-cigarette-packet' style circuit diagram:
Temperature Sensor Circuit Diagram
You can see the main components: the ProBee module, TMP36 temperature sensor and status LED. For an excellent tutorial on the TMP36, please see LadyAda's page here. Note that I have connected the output of the temperature sensor to PB_5/ADC0 pin of the ProBee module.


My ZigBee Temperature Monitoring Node
We can see from the above picture I have chosen to use a regulator circuit on the board. If you are very new to electronics I'd suggest to make life easier and purchase the previously mentioned Breadboard Power Supply 5V/3.3V.
Also from the picture above you can see that I have the ProBee module pugged into an expansion board so the board can be plugged into a breadboard. I have several of these boards spare and will happily post them to any reader for only the cost of postage.


Configuring The ProBee Modules
First of all make sure your ProBees are using firmware v1.5 or higher.
Secondly, I'm not going to delve too deeply into the config of the sensor node and co-ordinator. Programming the ProBee modules is very straight forward, Sena have some good documentation on their website here. I would highly recommend reading the ZigBee Network Configuration section of the ProBee-ZE20S User Guide!


I have created two configuration files that can be programmed into the ProBee modules using Sena's ProBeeManager application:

  • Our Zigbee temperature sensor node. This configures the ProBee module to sleep for 5 seconds, wake up, take samples of it's digital/analog I/O ports, transmit this to the co-ordinator and go back to sleep (see section
    3.4 Setting up ZE20S as a Sleepy End-Device of the user manual)Probee_SED_Blog_150412_115200baud
  • The ZigBee co-ordinator (program your ProBee usb dongle with this): Probee_ZC_Blog_150412_115200baud

Note the serial interface baud rate for both configurations is set to 115200 baud.


Testing
Connect the Co-ordinator (ProBee usb dongle) into a usb port on your computer and open a serial connection to it using your favourite terminal application. If you are using my config files above, ensure you have the baud rate set to 115200.


Now power on your sensor node. You will notice that the status led flashes on briefly every 5 seconds. This is the ProBee waking from sleep node and transmitting the sample of the analog and digital IO.


Looking at the Co-ordinator's terminal output, you can see the messages coming from the sensor node:
Messages received by the co-ordinator from the sensor node


Each line represents a single message received by the co-ordinator from the sensor node. We are interested in the field reading 1C3F, this is the hexadecimal value for the Analog sample of ADC0 port (which the TMP36 is connected to) on our sensor node.


Decoding the Temperature
There are two steps to the decoding of the actual temperature. First we need to get the measured voltage (TMP36 output voltage):
Vout = AdcValue * 0.1

Then to get the temperature:
Temperature (Celsius): (Vout - 500) * 0.1


Therefore:
Vout = 0x1c3f * 0.1 = 723 mV
Temperature = (723 - 500) * 0.1 = 22 Deg Celsius


Next
So, we now have a working ZigBee temperature sensor node! Next up is to do something with the raw text that is outputted by the co-ordinator over the serial interface. In Part 3 we will be using emoncms to display the temperature data on a web page.


An example Emoncms widget
This series:

Saturday, 7 January 2012

ProBee Based Home ZigBee Network - Part 1

Overview
In this blog series I will be showing you how to create a ZigBee based home network for monitoring room temperature using Sena's ProBee Modules and OpenEneryMonitor's emoncms for recording and displaying the temperature data.
Specifically, I'll be using the ZE20S modules with chip antenna for the sensor nodes and a ProBee-ZU10 usb dongle that will act as the network co-ordinator and feed temperature data into the monitoring computer.
The following are assumptions on the readers knowledge/ability:
  • Basic understanding of ZigBee networks, for more info please see here and here.
  • Basic breadboard skills.
  • Access to a Linux based server for running the emoncms software.

ProBee ZigBee Modules
The main thing I like about these ProBee modules is that they are cheaper than the corresponding XBee modules, and pretty much provide the same functionality (the ProBee modules actually have more digital and analog I/O pins that the XBee).
The cheapest ZigBee compliant ProBee module (ZE20SSC-00 with chip antenna) costs about US$17. The cheapest ZigBee compliant XBee module (Series 2 XBee ZB with chip antenna) retails for around US$25! Interestingly both modules have an underlying Ember ZigBee chip with EmberZNetEmber’s ZigBee compliant embedded mesh networking software.


Sena's ProBee Modules
System Overview
The following diagram outlines the components of the system:
Overview of Network Components
ZigBee Temperature Sensor End Devices - Each end node will comprise of a ProBee ZE20S module, with temperature sensor, power supply circuit and batteries. As these nodes are battery powered, they will be configured to enter battery saving sleep mode and wake up periodically to report the temperature reading.
ZigBee Router - This will route the messages containing the temperature readings from the end devices to the ZigBee coordinator. The router is optional and only necessary if you don't have enough range between your end devices and Coordinator. It will consist of a ZE20S module and power supply. The router must remain powered on all of the time and as such will be mains powered.
ZigBee Coordinator - This will receive our temperature readings from the End Nodes in the network and display/store the measurements using the emoncms software. It will comprise of a ProBee USB dongle and, in my case, a Beagleboard. A PC or MAC could easily be used instead of the Beagleboard, as long as it runs emoncms.

Building The System
The following entries cover the steps that are required to complete our system:

Saturday, 24 December 2011

Beagleboard Ubuntu Backup

Overview
I use my Ubuntu 11.10 based Beagleboard as a low-power home server, which mainly stores my subversion repositories for my mobile apps development business. The server is headless and remains plugged in 24/7.
So I wanted to have some sort of cloud backup system, where my repositories and some parts of the Linux filesystem (mainly /etc) were backed-up to a remote location. At most I wanted to backup about 150MB of data.
After much searching around, I came up with the following two lists of possible solutions for backing up a home linux server:
Free:
  • Dropbox - Obvious choice given that your backups would also be accesible on various different platforms, but unfortunately they don't officially support an ARM CLI client (there have been some people who have been able to hack their packages to get them working, but I didn't want the hassle). You can login to Dropbox and vote for ARM support here.
  • UbuntuOne - This is available for ARM, but requires a GUI interface to manage, see here. There are ways around this, as described here, but I want a simple solution.
  • Using the standard backup-manager tool to backup to your own online server (unfortunately I don't have access to one). For those that do, you can use either of the following methods for transferring your archive: FTP, SSH, S3 and RSYNC. From the user guide: "The FTP, SSH and S3 methods are dedicated to upload archives, using those method depends on the use of at least one backup method. On the opposite, the RSYNC method uploads a directory to remote locations, this directory can be your repository or whatever other location of your file system".

Paid:
  • Amazon Simple Storage Service (Amazon S3), which the standard backup-manager tool can upload to. The pricing for this is flexible, and very very cheap for small amounts of data! To upload and store 1GB of data per month, the cost is less than $1.00!!! You can play around with the calculator here, be sure to select the "Amazon S3" tab along the left hand side. (Instructions for how to do this here.)
  • rsync.net - Min cost per month is $5.60 (7GBs)
  • Many other paid services, some with their own clients and others that can be used with the backup-manager package.

Which Solution?
Based on the lists above and the drawbacks of each possible solution, I decided to go with using backup-manager with Amazon S3. The backups are for my business's subversion repositories, so I don't mind spending a little each month.
You can follow the instructions I have created to setup backups from your Ubuntu based Beagleboard to Amazon S3 here.

Backing up to Amazon S3 from Ubuntu 11.10


These are the steps to setup a periodic backup directories on an Ubuntu 11.10 server to the Amazon S3 service:


WARNING: Some irony here, but make sure you backup your data before attempting this, there *shouldn't* be much risk, but I won't be responsible if you loose any data or incur any financial loss from following any of this.


1. Create Amazon S3 account & storage bucket
  1. Check you projected costs are acceptable here.
  2. Register with Amazon S3.
  3. Go to the Amazon S3 console and create a bucket for your backup.

2. Install the necessary software packages on Ubuntu
Run the following to install the packages:
apt-get install backup-manager libnet-amazon-s3-perl

3. Configure backup-manager
You configure backup manager by editing the /etc/backup-manager.conf configuration file. There are settings I have modified from the default, I haven't given the values for all of the config parameters as I recommend you think about these and use your own:
  • export BM_ARCHIVE_TTL="..." 
  • export BM_ARCHIVE_METHOD="tarball-incremental" - Note, this is recommended to reduce the amount of data transferred and stored on the S3 servers.
  • export BM_TARBALL_DIRECTORIES="..." - space separated list of the directories you would like to backup.
  • export BM_TARBALLINC_MASTERDATETYPE="..."
  • export BM_TARBALLINC_MASTERDATEVALUE="..."
Amazon S3 specific parameters of the config file, you will get the access and secret keys from the Security Credentials section of the Amazon S3 website:
  • export BM_UPLOAD_S3_DESTINATION="your_bucket_name"
  • export BM_UPLOAD_S3_ACCESS_KEY="..."
  • export BM_UPLOAD_S3_SECRET_KEY="..."
  • export BM_UPLOAD_S3_PURGE="false"

4. Test your settings
You can test your settings by running a manual backup (this will cost money, as you will be uploading to the Amazon S3 server):
backup-manager -v 
You can verify you backups were uploaded by looking at your Amazon S3 console.



5. Add the backup task to CRON
I decided to have my incremental backups run daily. So created a backup-manager script in /etc/cron.daily/backup_manager, containing with the following:
#!/bin/sh
/usr/sbin/backup-manager -v
Don't forget to make the script executable.


Conclusion
That's it, you should now have your backups setup and backing up to the bucket you created on the Amazon S3 service.


Disclaimer
I take no responsibility what-so-ever for any loss of data or financial costs incurred by someone following the info in this blog! Remember, each time you backup to the S3 service, it will cost you a certain amount of money.

Sunday, 27 November 2011

Sleeping Arduino - Part 5 Wake Up Via The Watchdog Timer

Overview
Welcome to the fifth and final part of the "Sleeping Arduino" series, where we will cover how to wake the Arduino from sleep mode using the Watchdog Timer (WDT). When waking your Arduino from sleep, you could use one of the standard internal timers of an Arduino as I have detailed in Part 4, but if you are looking for the maximum sleep time and/or minimum sleep power consumption, you have the use the WDT;


As I have mentioned in this table, the WDT can give us a sleep time of 8 seconds, whereas the 'longest' 8/18bit timer will only give us a sleep time of ~4 seconds.


Watchdog Timer (WDT)
The Watchdog Timer on the Arduino's microprocessor only has one source to drive it: it's own separate internal 128kHz oscillator (as opposed to the 8/16bit internal timers, which can use either the 16Mhz system clock or an external clock). It is this separate oscillator that enables the WDT to function in the lowest power mode: SLEEP_MODE_PWR_DOWN (see here for more detailed info on the Arduino's power modes).

The WDT also has a prescaler, which is used to configure the timeout period. It supports timeout periods from 16ms to 8 seconds: 


Also it has three modes of operation:


  1. Interrupt - The WDT_vect interrupt sub-routing will be called when the WDT times out. Can be used to wake the micro from sleep modes, including the lowest power sleep mode (SLEEP_MODE_PWR_DOWN), where other timers are not available.
  2. System Reset - A watchdog time-out reset will occur, i.e. the micro-controller will be restarted. For use in handling code lockups.
  3. Interrupt and System Reset - First the WDT_vect interrupt sub-routing will be called, when completed a watchdog time-out reset will occur.






Please refer to my post here for the other operation modes of the WDT. The post is for the Atmega1281, but the functionality is pretty much the same.




Code


So, we will be using interrupt mode in our code to wake the Arduino from sleep every 8 seconds to toggle the state of the LED:


/*
 * Sketch for testing sleep mode with wake up on WDT.
 * Donal Morrissey - 2011.
 *
 */
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

#define LED_PIN (13)

volatile int f_wdt=1;



/***************************************************
 *  Name:        ISR(WDT_vect)
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Watchdog Interrupt Service. This
 *               is executed when watchdog timed out.
 *
 ***************************************************/
ISR(WDT_vect)
{
  if(f_wdt == 0)
  {
    f_wdt=1;
  }
  else
  {
    Serial.println("WDT Overrun!!!");
  }
}


/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  
  sleep_enable();
  
  /* Now enter sleep mode. */
  sleep_mode();
  
  /* The program will continue from here after the WDT timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */
  
  /* Re-enable the peripherals. */
  power_all_enable();
}



/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the serial comms and the
 *                Watch dog timeout. 
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
  Serial.println("Initialising...");
  
  /*** Setup the WDT ***/
  
  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);
  
  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1<<WDCE) | (1<<WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */
  
  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);
  
  Serial.println("Initialisation complete.");
}



/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
void loop()
{
  if(f_wdt == 1)
  {
    /* Toggle the LED */
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    
    /* Don't forget to clear the flag. */
    f_wdt = 0;
    
    /* Re-enter sleep mode. */
    enterSleep();
  }
  else
  {
    /* Do nothing. */
  }
}



All parts of this series:



References

  • Martin's excellent tutorial here.
  • Darius's  excellent blog here.

Saturday, 26 November 2011

Sleeping Arduino - Part 4 Wake Up Via Internal Timer

Overview
Welcome to part 4 of the Sleeping Arduino Series. In this entry we will cover how to get the Arduino to wake from sleep using one of the micro-controller's internal timers. This does not require any external hardware, all is implemented in code.


Arduino Timers
So,we need to go into a little detail on the micro controller's internal timers. The Atmega168 in the Arduino Diecimila has three internal timers:
  • Timer/Counter 0 - 8 bit (Max timer duration: 16.4ms)
  • Timer/Counter 1 - 16 bit (Max timer duration: 4.1s)
  • Timer/Counter 2 - 8 Bit (Max timer duration: 16.4ms)
Whether the timer is 8 bit or 16 bit defines how much the timer can count up to: an 8 bit timer counting to 256 and 16 bit to 65536. What drives the counter to count can be configured to be either the internal 16Mhz clock or an external clock source on T1 pin. We will be using the internal timer in this tutorial.
Once a timer's counter has reached its maximum value and increments once more, it will overflow and the counter will reset to zero. This overflow event can be configured to trigger an overflow interrupt, which we will use to wake the Arduino from sleep mode. Note you can also modify the value within a timer's counter from your code to tune the overflow period.

Figure 1. Timer source
One thing I haven't mentioned yet is the prescaler, this is another counter that is used in conjunction with the the timer counter to extend the time between timer overflows. The prescaler can be set the the following values: 1:1, 1:8, 1:64, 1:256, 1:1024, these are the ratios of prescaler overflow to clock cycles.
The following formula shows the calculation of the timeout period.


Figure 2. Timeout period formula


Take the following examples:


16 bit Timer1 no prescaler (1:1)
Overflow period =  1/16Mhz x 1 x 2^16 = 4.09 milliseconds
16 bit Timer1 with prescaler of 1:1024
Overflow period = 1/16Mhz x 1024 x 2^16 = 4.09 seconds  
So we can see that using the maximum prescaler value of 1:1024, we can get maximum Timer1 overflow period of 4.09 seconds, this is the maximum time we can put the Arduino to sleep for using Timer1. If you want a longer sleep period than this, you can use the Watch Dog Timer, which can provide a sleep time of about 8 seconds (it can also be used in a lower power/sleep mode than Timer1, see Arduino/Atmega168 Timers For Sleeping). Using the WDT for waking from sleep is described in the 5th part of this series.

Timers and Power Modes
As I have mentioned in part 1 of this series, not all hardware peripherals of the micro-controller are available in all power modes. Looking at our table here, we can see that timer1's lowest running power mode is IDLE, so when we put the micro-controller to sleep, we need to make sure we don't enter a sleep mode below this, or the timer will be disabled.


Control Registers
The following are the timer related control registers we will use to configure Timer1
  • TCCR1B - CS10, CS11 & CS12 - Timer control register B and the pre-scaler selection bits.
  • TCNT1 - 16bit counter register. This is the actual register that will count up each timer tick. When the value in this register rolls over from 65536 to 0, the overflow interrupt will fire.
  • TIMSK1 - TOIE1 - Interrupt mask register and  overflow interrupt enable bit. This register contains the control bits to enable the various interrupts available to timer1, including TOIE1 which we will set to enable the overflow interrupt.


For more information on these registers, see section 16.11 of the datasheet here.


Operation

Our code will operate as follows:
  1. Configure the serial port and LED pin.
  2. Configure Timer1's prescaler so the timer will expire every 4.09 seconds (TCCR1B).
  3. Clear Timer1's counter TCNT1
  4. Enable Timer1 overflow interrupt (TIMSK1).
  5. The main loop will then:
    1. Enter IDLE sleep mode.
    2. When the Timer1 overflow occurs, the interrupt will wake the processor
    3. The LED state will be toggled.
    4. Re-enter IDLE sleep mode.
Code



In the following code the Arduino board will go to sleep (SLEEP_MODE_IDLE) for 4.09 seconds, wake up and toggle the LED and go back to sleep again.
/*
 * Sketch for testing sleep mode with wake up on timer.
 * Donal Morrissey - 2011.
 *
 */
#include <avr/sleep.h>
#include <avr/power.h>

#define LED_PIN (13)

volatile int f_timer=0;



/***************************************************
 *  Name:        ISR(TIMER1_OVF_vect)
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Timer1 Overflow interrupt.
 *
 ***************************************************/
ISR(TIMER1_OVF_vect)
{
  /* set the flag. */
   if(f_timer == 0)
   {
     f_timer = 1;
   }
}


/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_IDLE);
  
  sleep_enable();
  
  /* Now enter sleep mode. */
  sleep_mode();
  
  /* The program will continue from here after the timer timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */
  
  /* Re-enable the peripherals. */
  power_all_enable();
}



/***************************************************
 *  Name:        setup
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Setup for the serial comms and the
 *                timer. 
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
  
  /*** Configure the timer.***/
  
  /* Normal timer operation.*/
  TCCR1A = 0x00; 
  
  /* Clear the timer counter register.
   * You can pre-load this register with a value in order to 
   * reduce the timeout period, say if you wanted to wake up
   * ever 4.0 seconds exactly.
   */
  TCNT1=0x0000; 
  
  /* Configure the prescaler for 1:1024, giving us a 
   * timeout of 4.09 seconds.
   */
  TCCR1B = 0x05;
  
  /* Enable the timer overlow interrupt. */
  TIMSK1=0x01; 
}



/***************************************************
 *  Name:        enterSleep
 *
 *  Returns:     Nothing.
 *
 *  Parameters:  None.
 *
 *  Description: Main application loop.
 *
 ***************************************************/
void loop()
{
  if(f_timer==1)
  {
    f_timer = 0;
    /* Toggle the LED */
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    
    /* Re-enter sleep mode. */
    enterSleep();
  }
}