Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

reading a rotary encoder

Status
Not open for further replies.

millwood

Advanced Member level 3
Joined
Jul 2, 2009
Messages
733
Helped
80
Reputation
164
Reaction score
35
Trophy points
1,308
Activity points
5,088
I was asked if I know of a way to read a rotary encoder.

so I dug this out of my old code and simplified it to make it easier to understand.

The code was originally written for a LPC21xx class device.


Code:
#include <REGX51.H>
#include <string.h>
#include "gpio.h"
#include "lcd_4bit.h"

//hardware configuration
#define OUT_PORT 	P3 		//leds on p3
#define OUT_DDR 	P3
#define OUTs 		0xff 	//output on pin 8 - 15

#define KEY_PORT 	P2   	//inputs on p2
#define KEY_DDR 	P2
#define KEY1 		(1<<0)	//p2.0
#define KEY2 		(1<<6)	//p2.6
#define KEYs 		(KEY1 | KEY2)

#define KEY_A KEY1 			//encoder's output A to KEY1
#define KEY_B KEY2 			//encoder's output B to KEY2
//end of hardware configuration

//port related macros
//#define IO_FLP(port, bits) 	port ^= (bits) //flip bits on port
//#define IO_SET(port, bits) 	port |= (bits) //set bits on port
//#define IO_CLR(port, bits) 	port &=~(bits) //clear bits on port
//#define IO_GET(port, bits) 	(port & (bits)) //get bits on port
//#define IO_IN(ddr, bits) 	ddr &=~(bits) //bits as input
//#define IO_OUT(ddr, bits) 	ddr |= (bits) //bits as output

//define port type:
//"unsigned int" (a 32-bit type) for 32-bit ports
//"unsigned char" for 8-bit ports
//change PORT_TYPE if you are compiling for a differrent platform

//#define PORT_TYPE unsigned long //works for 32-bit ports
#define PORT_TYPE unsigned char //works for 8-bit ports

const unsigned char str0[]="89C51RotarySwitch";
const unsigned char str1[]="Encoder=         ";
unsigned char vRAM[17];				//display buffer
unsigned char pos;					//encoder position
unsigned char pos_prev;				//encoder previous position

//determine increment / decrement of the encoder
unsigned char encoder_read(PORT_TYPE port, PORT_TYPE pins) {
	const signed char KEY_AB_states[]={0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
	static unsigned char encoder_output=0x00;
	static unsigned char KEY_AB=0x00; //AB key read out, Previous in the high 2 bits and current in the low two bits;
	unsigned char tmp;
	
	KEY_AB <<=2; //bit 2..3 now contain the previous AB key read-out;
	tmp=IO_GET(port, pins); //read ab pins
	if (tmp & KEY_A) KEY_AB |= 0x02; //set the 1st bit if A is high now;
	if (tmp & KEY_B) KEY_AB |= 0x01; //set the 0th bit if B is high;
	KEY_AB &= 0x0f; //only retain KEY_AB' last 4 bits (A_previous, B_previous, A_current, B_current)
	encoder_output += KEY_AB_states[KEY_AB];
	return encoder_output;				//if you want to return absolute steps.
	//return KEY_AB_states[KEY_AB];		//if you want to return relative steps (+1, 0, -1).
}

void ultoa(unsigned char * str, unsigned long ul, unsigned char length) {
	do {
		str[length--]=(ul % 10) + '0';	//conver the lowest digit
		ul = ul / 10;
	} while (ul);
}

//initialize the mcu
void mcu_init(void) {
	IO_CLR(OUT_PORT, OUTs); //clear LED
	IO_OUT(OUT_DDR, OUTs); //leds as output
	IO_IN(KEY_DDR, KEYs); //keys as input
}

//demo program
int main(void) { //main

	mcu_init();												//initiate the mcu
	lcd_init();												//initiate the lcd
	lcd_display(LCD_Line0, str0);							//display str0 on lcd_line0
	pos_prev=encoder_read(KEY_PORT, KEY_A | KEY_B);			//read the encoder and reset pos_prev
	
	while (1) {
	
		//OUT_PORT = encoder_read(KEY_PORT, KEY_A | KEY_B); //read KEY_A and KEY_B and output encoder read-out on OUT_PORT
		pos=encoder_read(KEY_PORT, KEY_A | KEY_B);			//read the encoder
		if (pos ^ pos_prev) {								//position has changed
			pos_prev=pos;									//update pos_prev
			strcpy(vRAM, str1);								//copy str1 to vRAM
			ultoa(&vRAM[8], pos, 7);						//convert pos to vRAM
			lcd_display(LCD_Line1, vRAM);					//display
		}
		//do something else
	}
}

the key routine is the encoder_read(port, keyab) routine, that reads off keya and keyb on port. It can return two types of values:

1) it can return the absolutely value of the encoder position, as it is written now;
2) or it can return the relative value of the encoder, if you uncomment the return line that is commented out. those values would be -1 (indicating counter clock wise turn of the encoder), 0 (indicating no turn of the encoder, or an invalid turn of the encoder), or +1 (indicating a clock-wise turn of the encoder).

---------- Post added at 07:50 PM ---------- Previous post was at 07:47 PM ----------

the principle is actually very simple: the code stores the previous read of Key_A and Key_B, as a two bit number, and reads the current state of Key_A and Key_B, and form a four bit index where by Key_A's previous state is bit 3, Key_B's previous state is bit 2, Key_A's current state is bit 1, and Key_B's current state is bit 0. That four bit index is used to return the relative movement of the encoder from KEY_AB_states, which itself is based on a state machine.

The encoder's initial position is reset to zero but in your code, you can read it off eeprom if you wish to give the routine some "memory" of its previous states before power-off.

here is a quick simulation where the routine is used to send its absolute position to a mcu to be displayed on an LCD.
 

Attachments

  • 15.C51 Rotary Encoder LCD.gif
    15.C51 Rotary Encoder LCD.gif
    35.7 KB · Views: 128

if you uncommend the line that outputs the value of encoder to P3, here is what you see on the digital waveform - it may help you understand how the encoder works.
 

Attachments

  • 15.C51 Rotary Encoder LCD 2.PNG
    15.C51 Rotary Encoder LCD 2.PNG
    29.2 KB · Views: 110
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top