Tag Archives: interrupt

Timed 1 millisecond interrupt routine for Arduino.

With Arduino (or AVR in general for that matter) you sometimes have the need to execute some code at regular intervals. A timed interrupt routine is the proper solution, but the Arduino IDE doesn’t come with standard code for this and it can be quite complicated for those who are unfamiliar with directly programming the hardware.

I created a simple proof of concept code that runs on AVR-type Arduino’s and uses a timed interrupt to time exact 1 ms, based on the 16MHz system clock. Thus 1000 counts equals 1 second with the same accuracy as the system clock. As proof the standard LED on pin 13 will start to blink in a 0.5Hz rhythm, one second on, one second off.

Timer0 and Timer1 are commonly used for the Arduino and third party libraries, so that leaves us with Timer2. Arduino’s system clock runs at 16MHz. Timer2 is clocked through a prescaler, this basically means that the system clock is first divided before it is fed to the Timer/Counter. I selected a 128 prescaler by configuring TCCR2B. This means the Timer/Counter is clocked at 16MHz / 128 = 125kHz.

Next I decided to make Timer/Counter2 compare to a set value 125 by setting OCR2A to 125 and configuring ‘Clear Timer on Compare’-bit in TCCR2A. This results in an exact 1kHz interrupt. TIMSK2 is configured to enable the Timer/Counter2 CompareA interrupt. Then all that is left is to attach the interrupt to some code, which is done with the ISR( TIMER2_COMPA_vect ) command. The Interrupt Service Routine counts to 1000 and so we arrive at 1 second ticks which can be used in the main loop to make the LED blink.

Simple rotary encoder controlled PWM dimmer

This post is basically a proof of concept for how to use a rotary (quadrature) encoder with an Arduino. Rotary encoders look a bit like classic potentiometers, but instead of changing resistance between its pins, it has two outputs with digital signals 90 degrees shifted with respect to each other. Because of this 90° phase difference between its outputs, it is relatively simple to determine in which direction it was turned as at any given time only one of its outputs will change. An example of the output sequence is given in the table below.

       Left   Right
Step   B A    B A
 a     1 1    1 1
 b     1 0    0 1 
 c     0 0    0 0
 d     0 1    1 0
 a     1 1    1 1
 ...

There are two ways of implementing a rotary encoder in an Arduino sketch. The first one simply polls the state of the input pins and checks the current state with the previous state. The other option is to use one encoder output as interrupt trigger and the other output to indicate direction.

Using pin state polling

In this example Arduino’s inputs are continuously polled and stored in currentState. When currentState is different from the previousState polled, then the rotary encoder has changed its position and the PWM value has to be updated. The if-then construct (lines 37-41 and 45-49) is used to decide whether the change implies an increase or a decrease. Then a second if-then (lines 42 and 50) prevents PWM from changing from 100% to 0% (and the other way around) by passing end of scale.

The code:

/*
This sketch implements a simple dimmer using a rotary encoder. The
encoder is connected to pins 22 and 23.
The standard led on pin 13 will be dimmed using pwm.
More on: https://blog.linformatronics.nl/58/electronics/simple-rotary-encoder-controlled-pwm-dimmer
*/

// Arduino Mega1280

const uint8_t pwmPin = 13;
const uint8_t encoderPinA = 22; // encoder input channel A
const uint8_t encoderPinB = 23; // encoder input channel B
uint8_t previousState = 0;
uint8_t analogValue = 128; // initialize at 50% PWM
const uint8_t stepSize = 2; // step size to increase PWM setting

void setup(){
analogWrite( pwmPin , analogValue );
pinMode( pwmPin , OUTPUT );
pinMode( encoderPinA , INPUT_PULLUP );
pinMode( encoderPinB , INPUT_PULLUP );
}

void loop() {
uint8_t currentState = ( digitalRead( encoderPinA ) << 0 ) | ( digitalRead( encoderPinB ) << 1 );

/*
State
B A
red yellow Digital
1 1 3
1 0 2
0 0 0
0 1 1
*/

if (
( ( previousState == 3 ) & ( currentState == 2 ) ) |
( ( previousState == 2 ) & ( currentState == 0 ) ) |
( ( previousState == 0 ) & ( currentState == 1 ) ) |
( ( previousState == 1 ) & ( currentState == 3 ) ) ) {
if ( analogValue <= ( 255 - stepSize ) ) {
analogValue += stepSize;
}
} else if (
( ( previousState == 1 ) & ( currentState == 0 ) ) |
( ( previousState == 0 ) & ( currentState == 2 ) ) |
( ( previousState == 2 ) & ( currentState == 3 ) ) |
( ( previousState == 3 ) & ( currentState == 1 ) ) ) {
if ( analogValue >= stepSize ) {
analogValue -= stepSize;
}
}

if ( previousState != currentState ) {
analogWrite( pwmPin , analogValue );
previousState = currentState;
}
}

It is fairly easy to adapt this code for any other Arduino board types. It doesn’t rely on any specific hardware, just requires two digital input pins and one pin that can drive PWM.  Just change encoderPinA and encoderPinB. Most Arduino boards have an on board LED on pin 13 which is used for PWM here.

Using interrupts

The second option to implement a rotary encoder is using interrupts. An interrupt can be used to temporarily stop execution of the main program to service an event (interrupt), after which the main program is being resumed. The trick used here is to use one of the encoder outputs as a clock event (both rising and falling edges) attached to the interrupt input and the other input as direction indicator.

All the main loop does in this example is setting PWM value from analogValue, where the interrupt routine increases/decreases this value. This only works because of the fact that both edges (rising and falling) can be used to trigger the routine. Whenever the interrupt routine is entered, both encoder inputs are read. When both inputs are different (LOW, HIGH) the analogValue is increased, if both inputs are identical the analogValue is decreased.

The interrupt driven version for an Arduino Mega:

/*
This sketch implements a simple dimmer using a rotary encoder. The
encoder is connected to pins 21 and 22.
The standard led on pin 13 will be dimmed using pwm.
More on: https://blog.linformatronics.nl/58/electronics/simple-rotary-encoder-controlled-pwm-dimmer
*/

// Arduino Mega1280

/*
Encoder state
B A
red yellow Numeric
1 1 3
1 0 2
0 0 0
0 1 1
*/

const uint8_t pwmPin = 13;
const uint8_t encoderPinA = 21; // encoder input channel A
const uint8_t encoderPinB = 22; // encoder input channel B
const uint8_t interruptChannel = 2; // pin 21, encoder input channel A
const uint8_t stepSize = 1; // step size to increase PWM setting

volatile uint8_t analogValue = 128; // initialize at 50% PWM

static void interruptHandler(){
delay( 10 ); // debounce
if ( digitalRead( encoderPinA ) != digitalRead( encoderPinB ) ) {
if ( analogValue <= ( 255 - stepSize ) ) {
analogValue += stepSize;
}
} else {
if ( analogValue >= stepSize ) {
analogValue -= stepSize;
}
}
}

void setup(){
analogWrite( pwmPin , analogValue );
pinMode( pwmPin , OUTPUT );
pinMode( encoderPinA , INPUT_PULLUP );
pinMode( encoderPinB , INPUT_PULLUP );

attachInterrupt( interruptChannel , interruptHandler , CHANGE );
}

void loop() {
analogWrite( pwmPin , analogValue );
delay( 100 );
}

Notice that the interrupt pins vary with Arduino board type, check its product page which exact pins you have to use and don’t forget to update the settings for interruptChannel and encoderPinA.