Sunday, 30 June 2013

Button Debouncing Library for Arduino



I decided to write a small library to handle polling and debouncing of a button for the Arduino. The library is really simple, and uses a timer interrupt to do the polling and debouncing, much the same as my IR decoder and rotary encoder libraries. This allows it to run in the background, without affecting your main sketch, a bit like the millis() function does.

The library can be downloaded here: https://github.com/frodofski/Debouncer

Here is the example sketch:

#include "Debounce.h"

const int buttonPin = 10;

int buttonState = 0;
int buttonStateOld = 0;

int ledState = 0;

void setup()
{
  pinMode(13, OUTPUT);
  debounce_begin(buttonPin); // State debouncing a button on buttonPin
}

void loop()
{
  buttonState = button_data(); // Check button state
  
  // Toggle pin 13 LED if the button's been pressed
  if(buttonState != buttonStateOld)
  {
    buttonStateOld = buttonState;
    if(buttonState == 1)
    {
      ledState = !ledState;
      digitalWrite(13, ledState);
    }
  }
}

The debounce_begin() function sets up the library and the input pin you enter, and button_data() returns the debounced state of the button.

Debouncing is done using a state machine with three states, standby, waiting, and delaying.
  • In the standby state, it reads in the value of the button pin, then moves on to the waiting state.
  • In the waiting state, it keeps checking the button pin, waiting for a change. If it sees one (ie. the button was pressed/released) it moves on to the delaying state.
  • When its in the delaying state, it just delays for a period of time set by DEBOUNCE_DELAY using a counter. When the time is up, it reads the value of the button pin into the data variable, which is now the debounced state of the button. It then goes back to the standby state.

The debounce delay can be set in the Debounce.h file by changing DEBOUNCE_DELAY. It is measured in multiples of 300 us, which the time between each interrupt. The default debounce delay is approximately 20 ms, but some experimentation may be needed to find a reliable time.

The library can only handle one button at the moment, but I hope to add support for multiple buttons in the future.

Just one more thing: the library configures timer2 in a way which might conflict with the Tone library, and also may cause problems when trying to use pwm on digital pins 9 and 10.

Rotary Encoder Library for Arduino



Here is a simple library for the Arduino which polls and decodes a rotary encoder. It is based on a timer interrupt, just like my IR decoder, so it runs in the background, and doesn't affect your main sketch.

If you're using a mechanical encoder, you'll need to use pull-up resistors, and a hardware debouncer for each of the two pins.

The library can be downloaded here: https://github.com/frodofski/Encoder_Polling

Here's an example sketch:

#include "RotaryEncoder.h"

const int encoderPin_A = 8;
const int encoderPin_B = 9;

void setup()
{
  Serial.begin(9600);
  encoder_begin(encoderPin_A, encoderPin_B); // Start the decoder
}

void loop()
{
  int dir = encoder_data(); // Check for rotation
  
  if(dir != 0)              // If it has rotated...
  {
    Serial.println(dir);    // Print the direction
  }  
}

The encoder_begin() function takes in the pins connected to your encoder, and sets them as inputs, then it sets up timer2 to trigger the ISR every 300 us.

The encoder_data() function will return a 1 or a -1 depending on the direction of rotation. If the encoder hasn't rotated at all since the last time the function was called, it will just return a 0.

The decoder is implemented by a state machine in the ISR. It has three states, standby, waiting, and idle.

  • In the standby state, it reads in the value of pin_A into a variable. It then moves on to the waiting state.
  • In the waiting state, it continually polls pin_A, looking for a change. If it sees a change, it then reads in the value of pin_B to determine the direction of rotation. It stores the direction in the data variable, then it moves on to the idle state.
  • Finally, in the idle state, it simply does nothing and waits for your sketch to read in the data, and reset the state machine with the encoder_data() function.

There are only two functions, encoder_begin() and encoder_data() so the library is very easy to use. One thing to note, is that the library configures timer2 in a way which might conflict with the Tone library, and also may cause problems when trying to use pwm on digital pins 9 and 10.

Time Sensitive Coding for Arduino

Say if you wanted to read a sensor every 100 ms, and then send the data over serial. How would you do it? That's easy, isn't it? Just a few lines of code like this should do the trick:

const int sensorPin = A0;

void setup()
{
  pinMode(sensorPin, INPUT); // Initialize pin as input
  Serial.begin(9600); // Start serial com
}

void loop()
{
  int reading = analogRead(sensorPin); // Get reading
  
  Serial.println(reading); // Print it
  
  delay(100); // Wait for 100 ms             
}


Lets take a closer look at this code:
  1. Firstly the sensor value is read into the 'reading' variable. This takes around 100 microseconds.
  2. Next, the 'reading' variable is then sent via Serial comms to the computer. This is quite fast to execute, as we do not have to wait for the data to be sent.
  3. Finally, we delay for 100 ms. This in itself isn't even 100% accurate. If we take a good look at the function, we will see that in only guarantees a delay of at least 100 ms.

So by the time we get back to reading the sensor again, its been over 100 ms. Not really what we want.

Another issue it that while we are in the delay() function, we are essentially wasting time, and nothing else can  be done in the meantime. (except for an interrupt of course)

Now we could adjust the delay to be a little less, but but that's still not very accurate, and what if you wanted to add more code? Do more than just Serial.println()? Or what if your code takes an unknown amount of time to execute? Like if there's a lot of 'if' and 'switch' statements. This is not how we want to write our code, as things could get very messy timing wise.

Lets look at some better, and more efficient alternatives.


This first way is the simplest, and easiest way to improve the timing:

const int sensorPin = A0;

unsigned long time = 0;
unsigned long timeOld = 0;

void setup()
{
  pinMode(sensorPin, INPUT); // Initialize pin as input
  Serial.begin(9600); // Start serial com
}

void loop()
{
  time = millis(); // Get current millis()
  
  if(time - timeOld >= 100) // If its been 100 ms or more...
  {
    int reading = analogRead(sensorPin); // Get reading
  
    Serial.print(reading); // Print it
    
    timeOld = time; // Reset timeOld
    
    // Can put more code here,
    // as long as it takes
    // less time than 100 ms
  }

  // Can also put more code here,
  // provided it it takes significantly
  // less time than 100 ms
  // (Putting code here does however affect
  // the timing accuracy significantly)
}


This is very similar to the BlinkWithoutDelay example in the Arduino IDE. Here we are using the millis() function to control our timing, rather than the delay() function. This has a few distinct advantages:
  • Our timing is much better and is taken care of by the millis() function.
  • We can execute much more code, as we aren't wasting any time with delay() functions.
  • Code which takes an unknown amount of time won't cause any problems, provided it takes less than 100 ms.

Although better than the first code example, this example it has its own problems:
  • Putting code outside of the 'if' statement will not affect the average rate at which we read the sensor, but it may cause small variations in the timing between reads. This is because we can't check the millis() function as often, so there may be a small delay between the exact moment we hit 100 ms and when we can actually check the time.
  • If our code locks up, or takes an unexpectedly long time to complete, we wont be able to read the sensor and the timing goes to hell.


This next way is much better, but somewhat more advanced than using the millis() function. It allows you to achieve near perfect timing and is done by using an ISR (Interrupt Service Routine).

You may have heard of an interrupt before as a block of code which can be executed by a pin change, called an external interrupt. Well that block if code can be triggered by much more than just an external pin change. We can use one of the Arduino's (specifically the Atmega328p, but this applies to most, if not all Arduino boards) hardware timers to trigger the ISR at a regular interval, regardless of what the main loop is doing. This means we can poll the sensor at exactly 10 Hz (every 100 ms) for example, and not have to worry about what happens in the main loop. And because we're using an interrupt, the main loop could be doing almost anything, and the sensor will still be read at the same time, every time.

Here's an example of using an ISR triggered by timer1:

const int sensorPin = A0;

volatile int reading = 0; // Variables used in the ISR need to be volatile

int readingOld = 0;

void setup()
{
  pinMode(sensorPin, INPUT);
  Serial.begin(9600);
  
  // This configurres timer1 to CTC every 100 ms
  // It also attaches an interrupt to the CTC
  noInterrupts();
  TCCR1A = 0x00;         // Clear timer1's control registers
  TCCR1B = 0x00;
  TCCR1C = 0x00;
  TCNT1 = 0;             // Pre-load the timer to 0
  OCR1A = 6250;          // Set output compare register to 6250
  TCCR1B |= _BV(WGM12);  // Turn on CTC mode
  TCCR1B |= _BV(CS12);   // Set prescaler to 256   
  TIMSK1 |= _BV(OCIE1A); // Enable timer compare interrupt 
  interrupts();
}

void loop()
{
  // As a rule of thumb, we try to minimize the amount of code
  // in the ISR itself, so the Serial stuff (and whatever else) 
  // goes in the main loop.
  if(reading != readingOld)
  {
    Serial.println(reading);
    readingOld = reading;
  }
}

// This is the interrupt service routine
ISR(TIMER1_COMPA_vect)  
{
  // Code in here gets executed every time the counter
  // reaches, in this case, 6250 (every 100 ms)
  reading = analogRead(sensorPin); 
}


In the block of code between noInterrupts() and interrupts() we are configuring timer1. You may not recognise some of the names here like 'TCCR1A'. These are the registers that relate to the timer, and we are accessing them directly, to set up the timer.

In the ISR macro, the 'TIMER1_COMPA_vect' connects the interrupt routine to the timer, causing the block of code below it to execute every time timer1 reaches 6250, in this case.

To keep things simple, I used analogRead (like I did in the previous examples) in the ISR. This isn't the best way to go about it, because the analogRead function has a small period where it waits for the conversion to complete. Ideally, we would start the conversion in the first interrupt, then take in the reading in the seccond interrupt, and start a new conversion again, etc.

The nice thing about this technique, it that the code in the interrupt routine (or ISR for short) will always be executed at the right time. As the name suggests, an interrupt causes the processor to drop whatever its doing, and tend to the interrupt itself. This means that we will always be reading the sensor on time.

This is how I poll the inputs in my IR decoder, rotary encoder, and debouncer libraries, and this is probably the best way to execute your code at a regular interval, if timing is very important. It is however not without some small disadvantages. Timer1 is used for pwm control on digital pins 11 and 12, so these pins cannot be used for pwm when the timer is configured like this. Also, the servo library relies on timer1, so there may be a conflict if you're trying to use this library and reconfigure the timer.

Saturday, 29 June 2013

IR Decoder Library for Arduino



In a previous post we looked at a method (or algorithm) for decoding the Philips RC-5 protocol with the Arduino. The code was very simple, but not very efficient as it was 'blocking code'.
As a follow up to this, I have written a simple library for the Arduino which can decode RC-5 codes in the background, whilst your main sketch runs un-encumbered in the foreground.

The library can be downloaded here: https://github.com/frodofski/RC5_Decoder

Here is an example of using the library:

#include "irDecoder.h"

const int IR_pin = 10;

int code = 0;

void setup()
{
  Serial.begin(9600);  
  ir_begin(IR_pin);      // Start the decoder
}

void loop()
{
  code = ir_data();      // Check for IR code
  
  if(code != 0)          // If a code is available...
  {
    Serial.print("Code: ");  // Print it
    Serial.println(code);
  }
}




The code is very efficient and only uses a small percentage of the Arduino's computing power. This leaves plenty of computing power left for the rest of your sketch to run. One thing to note, is that the library configures timer2 in a way which might conflict with the Tone library, and also may cause problems when trying to use pwm on digital pins 9 and 10.

Friday, 28 June 2013

How To Enable TRIM In Windows 7

Enabling TRIM allows an SSD to remove unused blocks of data to improve performance. Here's how to enable TRIM in Windows 7:

1)   Open an elevated command prompt.

Go to the Start Menu and find command prompt, then Right-click on it and select 'Run as administrator'



2)   Type in "fsutil behavior set disabledeletenotify 0" and hit Enter.

To disable it just type "fsutil behavior set disabledeletenotify 1" and hit Enter.



Its really that easy! If you're using an SSD there's no reason not to enable TRIM as it gives you a tangible performance increase. 

How To Disable Hibernation In Windows 7

If you're using an SSD, you might want to disable hibernation to save on some valuable storage space. Here's an easy way to do it:

1)   Open an elevated command prompt.

Go to the Start Menu and find command prompt, then Right-click on it and select 'Run as administrator'


2)   Type in "powercfg -h off" and hit Enter.

Type it in without the inverted commas of course. (If you want to enable hibernation just type "powercfg -h on" and hit Enter.)




And that's it! You've saved potentially a few GBs of valuable space on your SSD or hard drive!

Thursday, 27 June 2013

A Simple IR Decoder For Arduino

One of the design goals for the project I'm working on is to have IR control, so I set about writing some simple code for the Arduino to do just that.
A quick search revealed that the Philips RC-5 IR protocol is by far the most common and so my decoder is based on this type of encoding: Manchester Coding.




Looking at the diagram we see that each 'bit' is signified by a transition, a rising or a falling edge, whereby a rising edge means a logical '1' and a falling edge a logical '0'. These transitions lie within a window of approximately 1778 uS (889 uS x2) and there are 14 'bits' or transitions in one transmission.

The first two bits are the 'start bits' and are always a logical 1. These give the decoder time to recognise that there is an incoming transmission. The next bit is the 'toggle bit' which changes every time a key is pressed, this tells the decoder whether a key is being constantly held down, or repeatedly pressed by the user.
The next five bits signify the device in question (ie. CD player, TV, etc.) and the last six signify the command (ie. volume up, volume down, mute, etc.)

We need to detect these transmissions, but ensure that we don't detect the wrong transitions, like the transitions in between bits for example. As a result we need to look very carefully at timing in our code.


Proof of concept sketch:

#define irPin 10

void setup()
{
  Serial.begin(9600);
  pinMode(irPin, INPUT);
}

void loop()
{
  // We need to keep checking for the first start bit
  // If the first start bit is detected...
  if(!digitalRead(irPin))
  {
    // ...decode the rest!
    int code = irDecode();
    
    Serial.print("Code: ");
    Serial.println(code);
  }
}

// This is the decoder function itself
int irDecode()
{
  int data = 0;
  for(int i=12; i>=0; i--) 
  {
    delayMicroseconds(1333); // We wait 1333 uS (1.5 x 889 uS)
    unsigned long microsOld = micros(); // For timeout
    boolean irOld = digitalRead(irPin); //Read current pin state    
    
    while(1) // This is our 'transition detector'
    {
      if(digitalRead(irPin) != irOld)   // Look for transition
      {
        bitWrite(data, i, irOld);       // Write the bit to 1 or 0
        break;                          // Done for this bit!
      }
   
      if((micros() - microsOld) > 889)  // Timeout
      {
        return -1;
      }
    }
  }
  
  delayMicroseconds(1333);  // Ignore "tail" of transmission
  return data;
}


A fully commented and explained version can be found on my GitHub here: https://github.com/frodofski/RC5_Decoder

I uploaded this to my Arduino Uno and hooked up an IR receiver to pin 10. I then opened the serial monitor, pressed some buttons on my Philips remote, and lo and behold, codes! It works! :D



Now unfortunately this code isn't very efficient, we need to continually check for the start bit in our code, and when its decoding, the Arduino can't do anything else in the meantime (ie. its blocking code) but it does show that this algorithm for decoding the RC-5 protocol does work.

I will revisit this decoder in the future with some more complicated, but much more efficient code.