Thursday 18 July 2013

Homemade Speaker Stands

Quite some time ago I bought a pair of Bowers & Wilkins 685s, and recently I decided to build some small speaker stands to put them on.






The top and bottom are made from 25 mm MDF, and the centre column is made from 3" schedule 40 PVC tube. There is an aluminium disk to strengthen the MDF where it attaches to the tube, and it is all held together by six M3 countersunk screws that tap directly into the walls of the PVC tube.

The central tube is filled with sand, to give the stands some weight, and to dampen vibrations from the speakers.

I sprayed the MDF with several coats of grey primer, sanding it down between coats. I then painted it with satin black spray paint. Finally I sprayed the PVC tubes with a few coats of gloss black lacquer.


Here is the aluminium disk in more detail:


Wednesday 10 July 2013

A Multiple Encoder Library For Arduino

Here is an Arduino library which allows you to connect and decode up to 5 rotary encoders. It is basically an extension of my original encoder library, which can only decode one encoder.

You can download the library here: https://github.com/frodofski/Encoder_Polling_V2

Here is the example sketch:

#include <EncoderV2.h>

const int pin_A = 4;  // Encoder input pins
const int pin_B = 5;
const int pin_C = 6;
const int pin_D = 7;

void setup()
{
  Serial.begin(9600);
  encoder_begin();  // Start the library
  attach_encoder(0, pin_A, pin_B);  // Attach an encoder to pins A and B
  attach_encoder(1, pin_C, pin_D);  // Attach another encoder to pins C and D
}

void loop()
{
  int dir_0 = encoder_data(0);  // First encoder
  int dir_1 = encoder_data(1);  // Second
  
  if(millis() > 10000)
  {
    detach_encoder(1);  // After 10 seconds, detach encoder 1 
  }
  
  if(dir_0 != 0)  // Check for rotation
  {
    Serial.print("Encoder 0: ");
    Serial.println(dir_0);
  }
  
  if(dir_1 != 0)  // Check for rotation
  {
    Serial.print("Encoder 1: ");
    Serial.println(dir_1);
  }
}

The library is super easy to use, as it has only four functions:

  • encoder_begin() starts the library by setting up timer2 (note: this may conflict with the tone library)
  • attach_encoder(encNum, pin_A, pin_B) attaches an encoder to pin_A and pin_B, and sets these pins as inputs. encNum can equal 0, 1, 2, 3, or 4, allowing for up to five rotary encoders. The library will now start polling those two input pins.
  • detach_encoder(encNum) will detach the input pins corresponding to that encoder, and it will stop polling those two input pins. The pins can now be used as regular io again.
  • encoder_data(encNum) returns the state of the specified encoder. It returns a 1 or -1 if the encoder has turned, depending on the direction of rotation. It will return a 0 if the encoder has not turned, or if there is no encoder attached to that particular encNum.

The library will store that last known direction of the rotary encoder, until the encoder_data() function has been called for that encoder. This allows you to run the main sketch at any speed, without having to worry about missing a step.


Finally, you may need to use a hardware debouncer for each of the input pins if your're not using an optical encoder, or if your mechanical rotary encoder is particularly bouncy.

Tuesday 9 July 2013

An Even Better IR Decoder Library


I improved my old IR decoder library by adding some new features, without making it any more complicated. What's nice it that this is all done in the interrupt routine, so the library is still non-blocking. Here are the new features:

  • It no longer records invalid IR codes, and automatically resets when an invalid code is received (who cares if the code is invalid anyway?).
  • It removes the start bits, and the toggle bit from the code, to make it easier to determine what button was pressed on the remote.
  • It can determine whether a code is a repeat, or a new button press by the user.


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


As before, the ir_begin() function starts the decoder, but ir_data() is a little different:
  • If there is no valid code present, it will return a 0. 
  • If there is a new code, it will return the code. 
  • Finally, if it is receiving a string of codes with each one being a repeat of the previous one, it will return -1 until the string is broken.

Whats nice about the repeat detection, is that you don't have to worry about stuff happening more than once when you hold down a button on the remote. And if you do want something to happen for as long as the button is held down, like a volume control for example, you just need to look for the -1s.

Here is the example code:

#include "irDecoderV2.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);
  }
  
  else if(code == -1)  // If its a repeat
  {
    Serial.println("Repeat");  // Print it
  }
  
  delay(250);  // Prevent clogging up serial monitor
}




As before, 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.

Wednesday 3 July 2013

Bit Banging Data with the Arduino

Normally if you want to send data over SPI you would use the Arduino's built in hardware SPI controller, which is accessible via the SPI.h library. The problem with this is that you are confined to a specific set of pins, and to sending data in multiples of 8 bits. But what if you want to send data over a different set of pins? Or 12 bits of data for example? Or what if your microprocessor doesn't even have an SPI controller?

Bit banging is the technique of manually manipulating the microprocessor's pins in software to transmit the data, rather than using a dedicated hardware controller. Although it is a lot efficient than a hardware controller, it is a little more flexible.

To keep things simple, we will be looking at SPI mode 1 only. In this mode, the base value for the clock is 0, and data is captured on the rising edge.

Lets take a look at the SPI timing diagram for mode 1:


This first thing we need to do, to communicate with a slave, is pull the SS pin low. This is usually done in software anyway, and not by a dedicated controller, so this isn't really part of the bitbanging process.

Here are the steps we need to do to bitbang the data:

  1. First we need to set the MOSI (Master Out Slave In) pin to a 1 or a 0, according to the first bit in our data variable. 
  2. We then need to set the SCK (Clock) pin high. This causes the slave to capture the state of the MOSI pin (ie. the first 'bit' of the data) into its own memory.
  3. Next, we read the state of the MISO (Master In Slave Out) pin into the first bit of a new variable. When the transmission is complete, this variable will hold the data sent from the slave to the master.
  4. Now the SCK pin can be set low.
  5. Finally, we repeat this process, moving on to the next bit in the variable each time, for however many bits are in the data variable.

I wrote an example sketch to demonstrate this:

const int SS_pin = 11;
const int SCK_pin = 10;
const int MISO_pin = 9;
const int MOSI_pin = 8;

byte sendValue = 74;   // Value we are going to send
byte returnValue = 0;  // Where we will store the value sent by the slave

void setup()
{
  digitalWrite(SS, HIGH);  // Start with SS high
  
  pinMode(SS_pin, OUTPUT);
  pinMode(SCK_pin, OUTPUT);
  pinMode(MISO_pin, INPUT);
  pinMode(MOSI_pin, OUTPUT);
}

void loop()
{
  digitalWrite(SS_pin, LOW);        // SS low
  returnValue = bitBang(sendValue); // Transmit data
  digitalWrite(SS_pin, HIGH);       // SS high again 
}


byte bitBang(byte _send)  // This function is what bitbangs the data
{
  byte _receive = 0;
  
  for(int i=0; i<8; i++)  // There are 8 bits in a byte
  {
    digitalWrite(MOSI_pin, bitRead(_send, i));    // Set MOSI
    digitalWrite(SCK_pin, HIGH);                  // SCK high
    bitWrite(_receive, i, digitalRead(MISO_pin)); // Capture MISO
    digitalWrite(SCK_pin, LOW);                   // SCK low
  }
  
  return _receive;        // Return the received data
}

This is all well and good, but the problem with this code, specifically the bitBang function, is that it is really slow. The reason for this is that the digitalWrite, digitalRead, bitWrite, and bitRead functions are all inherently slow. This is no fault of the people over at arduino, but is just the way it is.

To improve the speed, we can replace these functions with direct port manipulations, and bitwise manipulations.

Here is the bitBang function again, but much faster:

byte bitBang(byte _send)   // This function is what bitbangs the data
{
  byte _receive = 0;
  
  for(int i=0; i<8; i++)   // There are 8 bits in a byte
  {
    if(_send & _BV(i))     // Set MOSI
      PORTB |= _BV(PORTB0);
    else
      PORTB &= ~_BV(PORTB0);
    
    PORTB |= _BV(PORTB2);  // SCK high
    
    if(PINB & _BV(PORTB1)) // Capture MISO
      _receive |= _BV(i);
    else
      _receive &= ~_BV(i);
      
    PORTB &= ~_BV(PORTB2); // SCK low
  }
  
  return _receive;         // Return the received data
}

Much more complicated, isn't it? But faster and more efficient than before. Unfortunately however, this in itself is not without problems. This code is far less portable than the previous example, meaning it probably wont work on a different Arduino board with a different microcontroller. Also, it is not as simple as changing a single variable to choose the pins you want, but the pins that you want to use must be hard coded into the sketch (or else it gets quite complicated).

As a result, we have struck a compromise between portability vs. speed.

If you don't know anything about port manipulations, I would stick with the first example. But if you know what you're doing, then clearly the second option is much better.

One last thing that I nearly forgot: You can change the number of loops in for loop if you want to send fewer or more bits (provided you change _send and _receive to something bigger than a byte).

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.