Lesson 12 Rotary Encoder

Share for us

Introduction

A rotary encoder is an electro-mechanical device that converts the angular position or motion of a shaft or axle to analog or digital code. Rotary encoders are usually placed at the side which is perpendicular to the shaft. They act as sensors for detecting angle, speed, length, position, and acceleration in automation field.

Components

– 1 * Raspberry Pi

– 1 * Breadboard

– 4 * Jumper wires (Male to Male, 2 red and 2 black)

– 1 * Network cable (or USB wireless network adapter)

– 1 * Rotary Encoder module

– 1 * 5-Pin anti-reverse cable

Experimental Principle

A rotary encoder is an electronic switch with a set of regular pulses with strictly timing sequence. When used with IC, it can achieve increment, decrement, page turning, and other operations such as mouse scrolling, menu selection, and so on.

There are mainly two types of rotary encoders: absolute and incremental (relative) encoders. Here we use an incremental (relative) encoders.

Most rotary encoders have 5 pins with three functions of turning left & right and pressing down. Pin 1 and pin 2 are switch wiring terminals used to press. Pin 4 is generally connected to ground. Pin 3 and pin 5 are first connected to pull-up resistor and connect to VCC. Pin 3 and pin 5 generate two-phase square waves whose phase difference is 90°. Usually the two-phase square waves are called channel A and channel B as shown below: 

We can see from the figure above: If channel A is in low level, and channel B converts from high level to low, it indicates the Rotary Encoder has spun clockwise (CW). If channel A is in low level, and channel B converts from low level to high, it indicates the Rotary Encoder has spun counter-clockwise (CCW). Thus when channel A is in low level, we can know the direction that Rotary Encoder spun by channel B.

The schematic diagram of the Rotary Encoder is shown as below. We can see that pin 3 on the Rotary Encoder is CLK of the module, while pin 5 is DT. Then we can know the Rotary’s rotating direction by the value of CLK and DT.

It is summarized by using oscilloscope to observe the output waveform of CLK and DT and operating the rotary encoder. You can try yourself.

Experimental Procedures

Step 1: Build the circuit

For C language users:

Step 2: Get into the folder of the code.

    cd /home/pi/SunFounder_Super_Kit_V3.0_for_Raspberry_Pi/C

Step 3: Compile

     make 12_rotaryEncoder

Step 4: Run the executable file above

     sudo ./12_rotaryEncoder

For Python users:

Step 2: Get into the folder of the code.

    cd /home/pi/SunFounder_Super_Kit_V3.0_for_Raspberry_Pi/Python

Step 3: Run

    sudo python 12_rotaryEncoder.py

Now, gently rotate the encoder to change the value of the variable in the above program, and you will see the value printed on the screen. Rotate the encoder clockwise, the value will increase; or rotate it counterclockwise, the value will decrease.

Further Exploration

In this experiment, the pressing down function of rotary encoder is not involved. Try to explore this function by yourself! 

C Code

/**********************************************************************
* Filename    : rotaryEncoder.c
* Description : Use a Rotary Encoder.
* Author      : Robot
* E-mail      : support@sunfounder.com
* website     : www.sunfounder.com
* Update      : Cavon    2016/07/01
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <wiringPi.h>

#define  RoAPin    0
#define  RoBPin    1
#define  SWPin     2

static volatile int globalCounter = 0 ;

unsigned char flag;
unsigned char Last_RoB_Status;
unsigned char Current_RoB_Status;

void btnISR(void){
	globalCounter = 0;
}

void rotaryDeal(void){
	Last_RoB_Status = digitalRead(RoBPin);

	while(!digitalRead(RoAPin)){
		Current_RoB_Status = digitalRead(RoBPin);
		flag = 1;
	}

	if(flag == 1){
		flag = 0;
		if((Last_RoB_Status == 0)&&(Current_RoB_Status == 1)){
			globalCounter ++;	
		}
		if((Last_RoB_Status == 1)&&(Current_RoB_Status == 0)){
			globalCounter --;
		}
	}
}

int main(void){
	if(wiringPiSetup() <0){
		printf("Unable to setup wiringPi:%s\n",strerror(errno));
		return 1;
	}

	pinMode(SWPin, INPUT);
	pinMode(RoAPin, INPUT);
	pinMode(RoBPin, INPUT);

	pullUpDnControl(SWPin, PUD_UP);

    if(wiringPiISR(SWPin, INT_EDGE_FALLING, &btnISR) < 0){
		printf("Unable to init ISR:%s\n",strerror(errno));	
		return 1;
	}

	printf("\n");
	printf("\n");
	printf("========================================\n");
	printf("|            Rotary Encoder            |\n");
	printf("|    ------------------------------    |\n");
	printf("|        Pin A connect to GPIO0        |\n");
	printf("|        Pin B connect to GPIO1        |\n");
	printf("|     Button Pin connect to GPIO 2     |\n");
	printf("|                                      |\n");
	printf("|         Use a Rotary Encoder         |\n");
	printf("|     Rotary to add/minus counter      |\n");
	printf("|      Press to set counter to 0       |\n");
	printf("|                                      |\n");
	printf("|                            SunFounder|\n");
	printf("========================================\n");
	printf("\n");
	printf("\n");

	int tmp = 0;
	while(1){
		rotaryDeal();
		if (tmp != globalCounter){
			printf("Counter : %d\n",globalCounter);
			tmp = globalCounter;
		}
	}
	return 0;
}

Python Code

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time

# Set up pins
# Rotary A Pin
RoAPin = 17
# Rotary B Pin
RoBPin = 18
# Rotary Switch Pin
RoSPin = 27

def print_message():
	print ("========================================")
	print ("|            Rotary Encoder            |")
	print ("|    ------------------------------    |")
	print ("|        Pin A connect to GPIO0        |")
	print ("|        Pin B connect to GPIO1        |")
	print ("|     Button Pin connect to GPIO 2     |")
	print ("|                                      |")
	print ("|         Use a Rotary Encoder         |")
	print ("|     Rotary to add/minus counter      |")
	print ("|      Press to set counter to 0       |")
	print ("|                                      |")
	print ("|                            SunFounder|")
	print ("========================================\n")
	print 'Program is running...'
	print 'Please press Ctrl+C to end the program...'
	raw_input ("Press Enter to begin\n")

def setup():
	global counter
	global Last_RoB_Status, Current_RoB_Status
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(RoAPin, GPIO.IN)
	GPIO.setup(RoBPin, GPIO.IN)
	GPIO.setup(RoSPin,GPIO.IN, pull_up_down=GPIO.PUD_UP)
	# Set up a falling edge detect to callback clear
	GPIO.add_event_detect(RoSPin, GPIO.FALLING, callback=clear)

	# Set up a counter as a global variable
	counter = 0
	Last_RoB_Status = 0
	Current_RoB_Status = 0

# Define a function to deal with rotary encoder
def rotaryDeal():
	global counter
	global Last_RoB_Status, Current_RoB_Status

	flag = 0
	Last_RoB_Status = GPIO.input(RoBPin)
	# When RoAPin level changes
	while(not GPIO.input(RoAPin)):
		Current_RoB_Status = GPIO.input(RoBPin)
		flag = 1
	if flag == 1:
		# Reset flag
		flag = 0
		if (Last_RoB_Status == 0) and (Current_RoB_Status == 1):
			counter = counter + 1
		if (Last_RoB_Status == 1) and (Current_RoB_Status == 0):
			counter = counter - 1
		print 'counter = %d' % counter

# Define a callback function on switch, to clean "counter"
def clear(ev=None):
	global counter
	counter = 0

def main():
	print_message()
	while True:
		rotaryDeal()

def destroy():
	# Release resource
	GPIO.cleanup()  

# If run this script directly, do:
if __name__ == '__main__':
	setup()
	try:
		main()
	# When 'Ctrl+C' is pressed, the child program 
	# destroy() will be  executed.
	except KeyboardInterrupt:
		destroy()