Archive for the ‘Project Idea’ Category

experimenting with a incremental encoder switch

Wednesday, September 8th, 2010

Here is a simple example of how to use a incremental encoder. It nicely shows how to handle buttons and interrupts with the MSP430. The particular encoder I am using is a Bourns PEC11-4020F-S0024 ( http://www.bourns.com/PDFs/pec11.pdf ) incremental encoder with push button.

The encoder has 5 pins.  The two pins on the top are the push button function when the encoder is pressed in the switch closes and is working like any oher push button. The three pins on the bottom are the encoder with the function A, Common and B. The common pin needs to be connected to ground and the pins A and B need to be connected to a pull up resistor. I opted to use the internal pull up resistors in the MSP430 to safe external components. But like with all mechanical buttons we need a debounce circuit (or do it in software). I personally prefer using a simple RC debounce circuit.

To visualize the encoder I choose to output the current state of the encoder on P1.0 to P1.5 with P1.0 toggling every time the encoder is pushed and P1.1 to P1.5 moving left and right based on the rotation of the encoder. I used a 74LS06 hex inverter / driver chip to drive the LED.

So here is the complete circuit:

encoder_circuit.png

The diagram shows the signals of the encoder signals A and B. I choose to use the low to high transition on encoder pin A to trigger a interrupt. Based on the rotation direction the signal on enc oder pin B will be either low for clockwise turns or high for counter clockwise turns.

encoder_signal1.png

So with all this here is the code (main.c):


/* Enoder example

Simple program to test a rotary encoder with pushbutton

Setup:

+—————-+
LED — | P1.0 P2.6 | — NC
LED — | P1.1 P2.7 | — Push Button
LED — | P1.2 |
LED — | P1.3 |
LED — | P1.4 P1.7 | — Encoder B
LED — | P1.5 P1.6 | — Encoder A
+—————-+

Function:
* Every time the encoder is pushed the LED on P1.0 will be toggled
* The LED on P1.1 to P1.5 will move left/right according to the encoder
* The script uses the internal pullup resistors

*/

#include
#include

unsigned char encoder_pos = BIT3; // Set starting pos to P1.3
unsigned char push_pos = 0;

// interrupt function toggling P1.0 on every push of encoder
interrupt (PORT2_VECTOR) p1_encoder_int(){
dint();

if( P2IFG & 0x80 ) {
push_pos ^= BIT0;
P1OUT = BIT7 | BIT6 | encoder_pos | push_pos; // output P1 with push status and encoder pos
}
P2IFG = 0x00;
eint();
}

// interrupt function moving positin bit per encoder
interrupt (PORT1_VECTOR) p1_encoder_move(){
dint();

if( P1IFG & 0x40 ) {
if ( P1IN & BIT7 ) { // b is high -> counter clockwise
if ( encoder_pos > BIT1 ) { // only move down if not already at bottom
encoder_pos = encoder_pos >> 1;
}
} else { // b is low -> clockwise
if ( encoder_pos < BIT5 ) {
encoder_pos = encoder_pos << 1;
}
}
P1OUT = BIT7 | BIT6 | encoder_pos | push_pos; // output P1 with push status and encoder pos
}
P1IFG = 0x00;
eint();
}

int main(void) {
WDTCTL = WDTPW | WDTHOLD;

// Setup port
P1SEL = 0x00; // select io function for all ports (this is actually default for P1)
P1REN = 0xC0; // select pullup resistors for pin 1.7 and 1.6
P1DIR = 0x3F; // iioo oooo
P1OUT = 0xC8; // need to set P1.6 and P1.7 to high so PULLUP resistor will be selected
P1IES = 0x00; // select low to high transition for interrupts on all port pins (this actually the default)
P1IE = 0x40; // enable interrupt for P1.6 to reader status of encoder every time Encoder sigal A goes high
P1IFG = 0x00; // clear interrupt register

P2SEL = 0x00; // selection io function for all ports (default is actually XIN.XOUT for P2.7/2.6)
P2REN = 0x80; // select pullup resistors for pin 2.7
P2DIR = 0x7F; // iooo oooo
P2OUT = 0x80; // need to set P2.7 to high so PULLUP resistor will be selected
P2IES = 0x00; // select low to high transition for interrupts on all port pins
P2IE = 0x80; // enable interrupt P2.7 for push button
P2IFG = 0x00; // clear interrupt register

eint();

for (;;) {
// loop forever
}

}