Lesson 18 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 an analog or digital code. Rotary encoders are usually placed at the side which is perpendicular to the shaft. Rotary encoders act as sensors for detecting angle, speed, length, position and acceleration in automation field.

Components

– 1 * Raspberry Pi

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

– 1 * Rotary Encoder module

– Jumper wires

Experimental Principle

Most rotary encoders have 5 pins with three functions of turning left, turning right and pressing down. Pin 4 and Pin 5 are switch wiring terminals used to press. They have no difference with buttons previously used, so we will no longer discuss them in this experiment. Pin 2 is generally connected to ground. Pin 1 and Pin 3 are first connected to pull-up resistor and then to microprocessor. In this experiment, they are connected to GPIO0 and GPIO1 of Raspberry Pi. When we rotate left and right, there will be pulse inputs in pin 1 and pin 3.

The figure shows, if both GPIO0 and GPIO1 are at high level, it indicates the switch rotates clockwise; if GPIO0 is at high level but GPIO1 is at low level, it indicates the switch rotates anti-clockwise. Therefore, during programming, you only need to check the state of pin 3 when pin 1 is at high level, then you can tell whether the switch is rotates clockwise or anti-clockwise.

Experimental Procedures

Step 1: Build the circuit

                           Raspberry Pi                            Rotary Encoder

                              GPIO0 ———————————- CLK

                              GPIO1 ———————————- DT

                                3.3V  ———————————– +

                               GND  ———————————– GND

Step 2: Edit and save the code (see path/Rpi_SensorKit_code/17_RotaryEncoder/ rotaryEncoder.c)

Step 3: Compile

              gcc  rotaryEncoder.c -lwiringPi

Step 4: Run

              ./a.out

Now, gently spin the knob of the rotary encoder to change the value of the variable in the above program, and you will see the value printed on the screen. When you spin it clockwise, the value will increase; when counterclockwise, the value will decrease.

Summary

Through this lesson, you have been familiar with the principle of rotary encoder and preliminarily mastered the interruption programming way of Raspberry Pi. Interruption is a very important concept and is widely used in modern computers. Interruption greatly reduces the CPU load.

rotaryEncoder.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <wiringPi.h>

#define  SWPin     0
#define  RoAPin    1
#define  RoBPin    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){
		fprintf(stderr, "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){
		fprintf(stderr, "Unable to init ISR\n",strerror(errno));	
		return 1;
	}
	
	while(1){
		rotaryDeal();
		printf("%d\n", globalCounter);
		//printf("%d\n",globalCounter);
	}

	return 0;
}

Python Code

#!/usr/bin/env python
import RPi.GPIO as GPIO
import time

RoAPin = 11    # pin11
RoBPin = 12    # pin12
BtnPin = 13    # Button Pin

globalCounter = 0

flag = 0
Last_RoB_Status = 0
Current_RoB_Status = 0

def setup():
	GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
	GPIO.setup(RoAPin, GPIO.IN)    # input mode
	GPIO.setup(RoBPin, GPIO.IN)
	GPIO.setup(BtnPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
	GPIO.add_event_detect(BtnPin, GPIO.FALLING, callback=btnISR)

def rotaryDeal():
	global flag
	global Last_RoB_Status
	global Current_RoB_Status
	global globalCounter
	Last_RoB_Status = GPIO.input(RoBPin)
	while(not GPIO.input(RoAPin)):
		Current_RoB_Status = GPIO.input(RoBPin)
		flag = 1
	if flag == 1:
		flag = 0
		if (Last_RoB_Status == 0) and (Current_RoB_Status == 1):
			globalCounter = globalCounter - 1
		if (Last_RoB_Status == 1) and (Current_RoB_Status == 0):
			globalCounter = globalCounter + 1

def btnISR(channel):
	global globalCounter
	globalCounter = 0

def loop():
	global globalCounter
	tmp = 0	# Rotary Temperary

	while True:
		rotaryDeal()
		if tmp != globalCounter:
			print 'globalCounter = %d' % globalCounter
			tmp = globalCounter

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

if __name__ == '__main__':     # Program start from here
	setup()
	try:
		loop()
	except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
		destroy()