You are on page 1of 17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

Sparkfun2010AutonomousVehicleCompetition

DigitalcameracontrolusingArduinoUSBHostShield.
Part1basics.

ReadingrotaryencoderonArduino
ByOlegMazurov
Quadraturerotaryencoders,alsoknownasrotarypulsegenerators,
arepopularinputdevicesforembeddedplatforms,includingArduino.
SeveralrotaryencodercodeexamplesarepostedonArduinosite
andelsewhere,however,theytreatencoderasapairofswitches,
addingdecoding/debouncingoverhead.Formanyyears,Iusedan
algorithmbasedonthefactthatquadratureencoderisaGraycode
generatorandiftreatedassuch,canbereadreliablyin3straight
stepwithoutneedfordebouncing.Asaresult,thecodeImusingis
veryfastandsimple,worksverywellwithcheaplowquality
encoders,butissomewhatcrypticanddifficulttounderstand.Soon
afterpostingoneofmyprojectswhereIusedrotaryencodertoset
motorspeedistartedreceivingemailsaskingtoexplainthecode.
ThisarticleisasummaryofmyrepliesImpresentingsmall
examplewrittenforthepurposeofillustratingmymethod.Imalso
goingthroughthecodehighlightingimportantparts.

RotaryencoderconnectedtoArduino

Thehardwaresetupcanbeseenontitlepicture.Theencoderfrom
SparkfunisconnectedtoavintageAtmega168basedArduinoPro.Commonpinoftheencoderisconnectedtoground,
pinsAandBareconnectedtopins14and15,AKAAnalogpins0and1,configuredasdigitalinputs.Wealsoneeda
serialconnectiontothePCtoreceivepower,programtheArduino,andsendprogramoutputtotheterminal.Forthis
purpose,SparkfunFTDIbasicbreakoutisused.
Connectingencoderpinstopins0and1of8bitMCUportmakesencoderreadingcodeverysimple.Ifanalogpinsare
neededforsomethingelse,itispossibletomoveencodertodigitalpins8,9or0,1(losingserialport)withnomodification
ofcodelogic.Whiletechnicallyusinganytwoconsecutiveportpinsispossiblewithabitoftweaking,usingnon
consecutivepinsforencoderinputwiththismethodisnotrecommended.Lastly,itsometimeshardtodeterminewhich
encoderpinisAandwhichisBitiseasiertoconnectthematrandomandifdirectioniswrong,swapthepins.
Examplecodeispostedbelow.ItiscompletesketchyoucancopyitfromthispageandpasteintoArduinoIDE
window,compile,uploadandrun.Theresultofrotatingtheencodercanbeseeninterminalwindow.Notethatserial
speedinthesketchissetto115200,youwillneedtosetyourPCterminaltothatspeedaswell.Theexplanationofthe
codeisgivenafterthelisting.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

/*Rotaryencoderreadexample*/
#defineENC_A14
#defineENC_B15
#defineENC_PORTPINC

voidsetup()
{
/*Setupencoderpinsasinputs*/
pinMode(ENC_A,INPUT);
digitalWrite(ENC_A,HIGH);
pinMode(ENC_B,INPUT);
digitalWrite(ENC_B,HIGH);
Serial.begin(115200);
Serial.println("Start");
}

voidloop()
{
staticuint8_tcounter=0;//thisvariablewillbechangedbyencoderinput

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

1/17

3/31/2015

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

ReadingrotaryencoderonArduinoCircuits@Home

int8_ttmpdata;
/**/
tmpdata=read_encoder();
if(tmpdata){
Serial.print("Countervalue:");
Serial.println(counter,DEC);
counter+=tmpdata;
}
}

/*returnschangeinencoderstate(1,0,1)*/
int8_tread_encoder()
{
staticint8_tenc_states[]={0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0};
staticuint8_told_AB=0;
/**/
old_AB<<=2;//rememberpreviousstate
old_AB|=(ENC_PORT&0x03);//addcurrentstate
return(enc_states[(old_AB&0x0f)]);
}

Firstthree#definessetnamesforportpins.Thisway,ifyouwanttousedifferentpinsforyourencoder,youcandoit
herewithoutsiftingthroughcodelookingforpinnames.IfyoudliketomoveencoderpinstoArduinopins8and9,
ENC_PORTshallbedefinedasPINB,andforpins0,1asPIND.
Insetup()functionhardwareisinitialized.pinModesetsthepinasinputsowecanreaditanddigitalWriteturnsonpull
upresistoronthepinsoitwontdangleintheairwhenswitchisopen.Finally,theserialportisinitializedandmessageis
printedasanindicatorthatportisworkingifyoucantseeStartonyourterminalscreen,checkPCportsettings.
Letsgodowntoline30,whereread_encoder()functionstarts.enc_states[]arrayisalookuptableitisprefilledwith
encoderstates,with1or1beingvalidstatesand0beinginvalid.Weknowthattherecanbeonlytwovalid
combinationofpreviousandcurrentreadingsoftheencoderoneforthestepinaclockwisedirection,anotheronefor
counterclockwise.Anythingelse,whetheritsencoderthatdidntmovebetweenreadsoranincorrectcombinationdueto
switchbouncing,isreportedaszero.
Notethatold_ABisdeclaredstatic.Thismeansthatitsvaluewillberetainedbetweenfunctioncallsthereforeprevious
encoderreadingwillbepreserved.Whenfunctioniscalled,old_ABgetsshiftedlefttwotimes(line36)savingprevious
readingandsettingtwolowerbitsto0sothecurrentreadingcanbecorrectlyORedhere.ThenENC_PORT&003
readstheporttowhichencoderisconnectedandsetsallbuttwolowerbitstozerosowhenyouORitwithold_ABbits2
7wouldstayintact.ThenitgetsORedwithold_AB(line37,old_AB|=(ENC_PORT&003)).Atthispoint,wehave
previousreadingofencoderpinsinbits2,3ofold_AB,currentreadingsinbits0,1,andtogethertheyformindexof(AKA
pointerto)enc_states[]arrayelementcontainingcurrentstateeitherincrement,decrement,ornochange.Allthatisleft
todoisreturnthisstatetothecallingfunction,andline38doesjustthat.Upperhalfofold_ABgetszeroedbyold_AB&
0x0fifwedontdothis,wewillbereadingmemorypastenc_states[]array.
Theaboveparagraphwasprettylongexplanationformere5linesofcode(countingtwodeclarations)ifyouarereading
this,98%ofworkisdone.Therestofthecodeisveryeasy.Wearenowmovinguptoline17,whereloop()functionis
residing.countervariableistheonewhichismodifiedbyencoderandtmpdataisusedtoholdthereading.Online22,
encoderisread.Ifencoderstatehaschanged,i.e.,read_encoder()returnednonzero,currentvalueofcountervariableis
printedandthencounterisupdatedwithtmpdata.Thisisdonewithinconditionalstatementonlines2227.Theloopthen
endsandstartsagain.
Nowletsbrieflytalkaboutreallifeapplicationsofthismethod.IfyoureusingSparkfunencoder,youllnoticethatitgives
4incrementsperclickanditsimpossibletomakeitholdpositionbetweenclicks.Therefore,tocountclicksyouwillneed
todividecountervariableby4.Also,ifcounterlargerthan255isnecessary,thedeclarationforitwouldhavetobe
changedtouint16_torlonger.Anothernicemodification,leftouttokeepcodesimple,wouldbetomoveenc_states[]
arraytoprogrammemoryusingPROGMEMtypesavingseveralbytesofpreciousRAM.

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

2/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

Rotaryencodersingingoutoftune

Inorderforthismethodtoworkwell,read_encoder()functionneeds
tobecalledfairlyoften.Toseewhathappenswhenloopisslow,
lowerserialportspeedgotoline13,change115200to9600,
recompilethesketchandrun(dontforgettoreconfiguretheterminal
onPCside).Pictureontheleftshowstheresult.Notethatencoder
goesdownfrom237to229,thenjumpsupto230,thencontinues
goingdown.Sometimesitcountscorrectlybutgives2or3states
perclickinsteadof4.Instabilitieslikethisaregoodindicationof
slowloop.Ifencoderisusedtothingslikesettingmotorspeedor
soundvolume,thisbehaviorwontdomuchharmbecauseencoder
willneverskipbackmorethanonestateandoverallcountingwould
stillbeintherightdirection.However,ifencoderisusedfor
interfacingwithdisplay,glitcheslikethatareveryannoying.
Therefore,foruserinterfaceapplications,looptimeshouldbekept
shortandinsomecasesitmaybeevennecessarytoconvert
encoderreadingfunctionintointerruptserviceroutine.Giventhesize
andspeedofencoderreadfunction,suchconversioncanbedone

withoutmuchdifficulty.
Tosummarize:Ipresentedamethodtoconvertquadraturerotaryencoderoutputintodirectioninformationusinglookup
table.Themethodmakesdebouncingunnecessary,andasaresult,conversionfunctionimplementedwiththismethodis
veryshort,fast,andworksverywellonsmall8bitMCUplatforms,suchasArduino.
Oleg.
[EDIT]IpostedanewarticledescribingreadinganencoderfromanISR.
Relatedposts:
1. Vigoriusstirringredefined.Part2electronics
April12th,2010|Tags:Arduino,rotaryencoder,sketch|Category:Arduino,MCU,programming|224comments

224commentstoReadingrotaryencoderonArduino
OlderComments 1 2 3

gabriella

November9,2012at11:39amReply
Okthanksalotthatisreallyhelpful.ButassoonasIintegratedthiscodewithsomemorecomplex
codeIhaveusingpulseIn()functiontounderstandtheinputofastandardRCreceiver,andamotordriver
controllingtwomotors,theencoderseemstotallyincorrect:WhenIhadthethesamefunctionsworkingonthe
encoder,Iwasgettingsupercleanvalues.ButwhenIhadmorecodeandtheencoderstuffrunningsidebyside,my
countervaluesaretotallyoff(seebelow,whenspinningtheencoderroundandround).Soitseemslikethetimingis
totallynotworking
ImwonderingwhatImightbedoingwrongbecausenothingtoohighlevelishappeninginmycode,andItookoutall
myprintlns.
Icanattachmycodeifthatdbehelpful,butwaswonderingyourthoughts/experience(reusing2encoderswithsome
otherprocessesgoingoninArduinoUNO)
Thankyousosomuchagainforallthehelpandexplanation.

Ready
Countervalue2:0
Countervalue2:255
Countervalue2:0
Countervalue2:255
Countervalue2:0
Countervalue2:255
Countervalue2:0
Countervalue2:255
Countervalue2:0
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

3/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

Countervalue2:255
Countervalue2:254
Countervalue2:253
Countervalue2:254
Countervalue2:253
Countervalue2:252
Countervalue2:251
Countervalue2:252
Countervalue2:251
Countervalue2:252
Countervalue2:251
Countervalue2:252
Countervalue2:251
Countervalue2:252
Countervalue2:251
Countervalue2:252
Countervalue2:253
Countervalue2:252
Countervalue2:251
Countervalue2:252
Countervalue2:251
Countervalue2:250

oleg

November9,2012at11:49amReply
Thecodeyouveaddedisblockingsomewhere.Youneedtoeitherfixitorswitchtointerruptdriven
encoderreading,likethisone>https://www.circuitsathome.com/mcu/rotaryencoderinterrupt
serviceroutineforavrmicros

gabriella

November9,2012at12:13pmReply
Hm.YeaIcommentedeverythingoutandtheencodersworkgreat.WhenIaddbackinstufftoreadthe
receiver,thatsthepointatwhichtheencodersseemtostopworking:
Channel2Value=pulseIn(RX1,HIGH,20000)//readRCchannel2
Channel1Value=pulseIn(RX3,HIGH,20000)//readRCchannel2
//Serial.print(motor_body:)
Imwonderingwhatyoumeanbythecodeisblockingsomewhereorwhatafixwouldbe??
Thanksalotagain

oleg

November9,2012at12:50pmReply
Blockingiswhenapieceofcodeiswaitingforsomeeventtohappen,interruptingtheflowof
executionofthemainloop.Forexample,delay()isblockingtheprogramwontcontinueuntil
timespecifiedasdelayhasexpired.Ifyouhaveadelayofonesecondinyourmainloop,youcanrotateyour
encoderfullcircleandmisseverypulse.
Fixingmeansfindingblockingcodeandwritingitdifferently.Whatdoes20000meaninpulseIn?

gabriella

November9,2012at5:25pmReply
OkIguessIhavetouseaninterrupt?IwantedtobeabletouseArduinoUNOwiththetwoencoders.
WouldtherebeawaytousetwoencoderswithArduinoUNO,evenifthetwodefaultinteruptpinsare2
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

4/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

and3?
thethirdparameter(20000)isthetimeoutinmicroseconds.
justfyi,PulseIN():Readsapulse(eitherHIGHorLOW)onapin.Forexample,ifvalueisHIGH,pulseIn()waitsfor
thepintogoHIGH,startstiming,thenwaitsforthepintogoLOWandstopstiming.Returnsthelengthofthepulsein
microseconds.Givesupandreturns0ifnopulsestartswithinaspecifiedtimeout.soitseemstheproblemisit
delaysandwaits(ieblocking)

oleg

November10,2012at10:52amReply
Yes,tryinterruptcodeandseeifitworksforyou.Thecodeusesinterruptonchange,youcan
configureanypintobeasourceofthisinterrupt.

KyleRassweiler

November15,2012at12:22amReply
Iwaswonderingwhyyouneededatimeoutof2000?Wouldtheserialnotstillworkfinewithout?(I
thinkthattimeoutmaybeanexampleofblocking).

SteffanoGizzler

November30,2012at3:23pmReply
HiOleg
Ireallyappreciateyourtutorials,theyaregreatandamwonderingifyoucouldputmeintherightdirectionasIam
buildingabidirectionalpeoplesensorandcounterinaroomusingtwoinfraredsensors(S1andS2).WhatIwantisthe
firstsequenceonbreakingS1andS2thechangeshouldsignalentryandincrementacounterwhilstbreakingthe
beaminthesecondsequenceS2firstandS1willsignalexitanddecrementacounteranddisplaythecountvalueona
3digit7segmentdisplay.
Ihavethoughtofusingtheideaofreadingtworotaryencoderusingexternalinterruptsonanarduino.Isthistheright
waytogo??
MuchThanks.
Steffano.

oleg

November30,2012at4:04pmReply
Icantseeanyencoderapplicationhere.Yourprojectisquitestraightforward,justcodeyoursensor
statesdirectly.

SteffanoGizzler

December1,2012at10:45amReply
HiOleg,
Pleasecouldyoukindlyelaborateonwhatyoumeanbycodingthesensorstatesdirectly?sinceitsasequence.
amusingIRsensorswithmakeandbreakbeam.Iwillappreciateanymoreinformation.
Thankyou.
Staffano.

SteffanoGizzler

December3,2012at11:31amReply
HiOleg,
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

5/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

Thisisthefarhavecomesofarandamserialprintingthecounts.AnyideahowIcouldholdoldvalueandupdatethis
oldvaluewiththecurrentvalcounttoa3digitsevensegmentdisplay?dependingonhowthesensorsaretripped?
Anycorrectionorsuggestionsamverywillingtolearn
intcounter,S1_SIG=0,S2_SIG=1
voidsetup(){
attachInterrupt(0,S1_RISE,RISING)//hookedtopin2onmega2560
attachInterrupt(1,S2_RISE,RISING)//hookedtopin3
Serial.begin(115200)
}//setup
voidloop(){
}
voidS1_RISE(){
detachInterrupt(0)
S1_SIG=1
if(S2_SIG==0)
counter++//entry
if(S2_SIG==1)
counter//exit
Serial.println(counter)
attachInterrupt(0,S1_FALL,FALLING)
}
voidS1_FALL(){
detachInterrupt(0)
S1_SIG=0
if(S2_SIG==1)
counter++//entry
if(S2_SIG==0)
counter//exit
Serial.println(counter)
attachInterrupt(0,S1_RISE,RISING)
}
voidS2_RISE(){
detachInterrupt(1)
S2_SIG=1
if(S1_SIG==1)
counter++//entry
if(S1_SIG==0)
counter//exit
Serial.println(counter)
attachInterrupt(1,S2_FALL,FALLING)
}
voidS2_FALL(){
detachInterrupt(1)
S2_SIG=0
if(S1_SIG==0)
counter++//entry
if(S1_SIG==1)
counter//exit
Serial.println(counter)
attachInterrupt(1,S2_RISE,RISING)
}
Steffano

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

6/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

steffano

December27,2012at4:36pmReply
Imanagedtodomy2ISRforthetwosensorsandthe3digitsevensegmentdisplay,howevertheonly
problemhavegotiswhenmysensorsarebrokenatfirstthecountgoesnegativefor2or3cyclesthen
comestopositive(normal)doesanyonehaveanideahowtocorrectthis??please.Ihavedeclaredstaticintiinloop.

Windsor

February1,2013at8:53pmReply
Hi,thanksforthegreattutorial.Iadaptedyourcode(withminorchanges)torunonanSTM32F100B
(ARM)micro.Worksflawlesslywithmyencoderwithouttheneedforanyhardwaredebouncingcircuitry!

Josh

February23,2013at9:03pmReply
HiMr.Oleg,
Gooddaytoyouandthanksforthegreatefforthelpingarookielikemetostartwiththearduino,Ihave
triedyourcodeusingUnoanditworksflawlesslybutwhenitrieditusingtheLeonardo,itdidntwork,wanderingwhat
couldbetheproblem.

Josh

February23,2013at10:14pmReply
HiMr.Oleg,
BelowisthecodeIusedwithUnoandLeonardo,itworkswithUnobutnotwithLeonardo.
/*Rotaryencoderreadexample*/
#defineENC_A14
#defineENC_B15
#defineENC_PORTPINC
//constantswontchange.Theyreusedhereto
//setpinnumbers:
constintbuttonPin=2//thenumberofthepushbuttonpin
constintledPin=13//thenumberoftheLEDpin
//variableswillchange:
intbuttonState=0//variableforreadingthepushbuttonstatus
intswitch0=0
voidsetup(){
/*Setupencoderpinsasinputs*/
pinMode(ENC_A,INPUT)
digitalWrite(ENC_A,HIGH)
pinMode(ENC_B,INPUT)
digitalWrite(ENC_B,HIGH)
//initializeserialcommunicationat9600bitspersecond:
Serial.begin(115200)
Serial.println(Start)
delay(1)
//initializetheLEDpinasanoutput:
pinMode(ledPin,OUTPUT)
//initializethepushbuttonpinasaninput:
pinMode(buttonPin,INPUT)
}
voidloop(){
staticuint8_tcounter=0//thisvariablewillbechangedbyencoderinput
int8_ttmpdata
/**/
tmpdata=read_encoder()
if(tmpdata){
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

7/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

Serial.print(Countervalue:)
Serial.println(counter,DEC)
counter+=tmpdata
}
//readthestateofthepushbuttonvalue:
buttonState=digitalRead(buttonPin)
//checkifthepushbuttonispressed.
//ifitis,thebuttonStateisHIGH:
if(buttonState==LOW){
//turnLEDon:
digitalWrite(ledPin,HIGH)
//printoutthestateofthebutton:
if(switch0==0){
Serial.print(Pinindot)
delay(1)
Serial.println(buttonState)
delay(1)//delayinbetweenreadsforstability
switch0=1
}
}
else{
//turnLEDoff:
digitalWrite(ledPin,LOW)
if(switch0==1){
Serial.print(Pinindot)
delay(1)
Serial.println(buttonState)
delay(1)//delayinbetweenreadsforstability
switch0=0
}
}
}
/*returnschangeinencoderstate(1,0,1)*/
int8_tread_encoder()
{
staticint8_tenc_states[]={0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0}
staticuint8_told_AB=0
/**/
old_AB<<=2//rememberpreviousstate
old_AB|=(ENC_PORT&003)//addcurrentstate
return(enc_states[(old_AB&0x0f)])
}

Josh

February23,2013at10:22pmReply
ThedebouncedidnotworkformebutinsteadIusedtheswitchwhichisperfect.Theonlyoutputshownin
theSerialMonitoriswhentheswitchisbeingpressedbutnottheencoder,Iamusinganencoderwitha
switch.

Mike

March5,2013at1:18pmReply
Ok,IgetitandIlikeitalot.TheonlythingthatIcannotfigureoutishowtokeepitfromgoingfrom255to
0orfrom0to255.IsthereawaythatIcanstopitfromoverflowingtheregisterandjustparkitatmaxor
minuntiltheuserdecreasesthevalue?

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

8/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

alwerner

March14,2013at9:47amReply
UsingtwoormoreencoderwiththeArduino?
ItalldependsonthetotaloftasksbeingperformedbytheArduino,andthenumberof
pulsesreceivedbytheprocessor.
Sayforexampleyouhaveasmallslowmovingxytable,with2rotaryUSDigitalencodersgeneratingsay4000pulses
persecondanddrivingtwosteppermotorswithanEasydriverboardyouwouldsoonberunningoutofheadroomon
yourproject.
Mysuggestionswouldbetouse,twoTiny13chipsfromAtmeltoencodetherotaryencoders,andthanfeedthe
resultantsignalintoyourArduino,whereitwillgiveanexcellentperformance.Inmyhumbleopnionitmayeven
supportthreechannels,XYandZ.
Youwouldneedsomemachinecodeexperiencetodothis,butthiswouldbeworthlearning.
Goodluck.

Seif

April6,2013at1:04pmReply
Hi,
ThankyouforthisgreatusefularticleImwonderingifIcanuseyouideawithArduinoUno??Imeantousethe
rotaryencoderwithArduinoUnoinordertoselectthepowerofmyRCcarwhichImbuilding
thanxagain

oleg

April6,2013at1:26pmReply
UNOshouldwork.

SalvatoreAiello

April15,2013at12:49pmReply
Hi,
Sweetbitofcode!Iamusingitinaprojectatwork,usingtheencodertodisplayamotorspeedselection
onasevensegmentdisplayanditworksverynicelyindeed.Onceyouremovetheserial.printcommandsitisdifficult
tospinthebareencodershaftquicklyenoughtogenerateamisread.Withasuitablysizedknobontheshaftitisgoing
toslowrotationspeedandmakeitvirtuallyimpossibleforthecasualoperatortogetanerroneousreading
Thanks!

Marco

August1,2013at1:23pmReply
Hi,verynicejob
myR2D2Domesencodersensorhas3output,oneofthemreadsjustonespecialdentonthemotor
gear,likeaZEROPOSITION.
HowcanIimplementitinthecode?
AlsoHowcanImakeencoderscountto36or+18to18?
Thanksjustlearninghere

Alex

August14,2013at9:48amReply
Hereisthecodewithzeropositionand3outputs.
intcounter,S1_SIG=0,S2_SIG=1,S3_SIG=1
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

9/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

boolfirstinit=false
voidsetup()
{
attachInterrupt(0,S1_RISE,RISING)//hookedtopin2onmega2560
attachInterrupt(1,S2_RISE,RISING)//hookedtopin3
attachInterrupt(2,S3_RISE,RISING)//hookedtopin21
Serial.begin(115200)
}//setup
voidloop()
{
}
voidS1_RISE()
{
detachInterrupt(0)
S1_SIG=1
if(S2_SIG==0)
counter++//entry
if(S2_SIG==1)
counter//exit
Serial.println(counter)
attachInterrupt(0,S1_FALL,FALLING)
}
voidS1_FALL()
{
detachInterrupt(0)
S1_SIG=0
if(S2_SIG==1)
counter++//entry
if(S2_SIG==0)
counter//exit
Serial.println(counter)
attachInterrupt(0,S1_RISE,RISING)
}
voidS2_RISE()
{
detachInterrupt(1)
S2_SIG=1
if(S1_SIG==1)
counter++//entry
if(S1_SIG==0)
counter//exit
//Serial.println(counter)
attachInterrupt(1,S2_FALL,FALLING)
}
voidS2_FALL()
{
detachInterrupt(1)
S2_SIG=0
if(S1_SIG==0)
counter++//entry
if(S1_SIG==1)
counter//exit
Serial.println(counter)
attachInterrupt(1,S2_RISE,RISING)
}
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

10/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

voidS3_RISE()
{
S3_SIG=1
detachInterrupt(2)
if(!firstinit&&((S2_SIG==1&&S1_SIG==1)||(S1_SIG==0&&S2_SIG==1)))
{
counter=0
firstinit=true
}
attachInterrupt(2,S3_FALL,FALLING)
}
voidS3_FALL()
{
S3_SIG=0
detachInterrupt(2)
if(!firstinit&&((S2_SIG==1&&S1_SIG==1)||(S1_SIG==1&&S2_SIG==0)))
{
counter=0
firstinit=true
}
attachInterrupt(2,S3_RISE,RISING)
}

Marty

August30,2013at9:31pmReply
IamnewtoArduinosandamstartingtoplaywiththem.Ihaveseenmanyexamplesofrotaryencoder
code.ButnonthatusetheLeonardotooutputkeypresscommandswhenrotated.Myapplicationisa
smallCNCverticalmachiningcenter.Thecontrolitselfcannotacceptarotaryencoder(manualpulsegenerator)The
controlisPCbased.ItCANacceptkeypresses,forexample,tomovethetableinthesedirections:
X+Ctrl+RightArrowKey
XCtrl+LeftArrowKey
Y+Ctrl+UpArrowKey
YCtrl+DownArrowKey
Z+Ctrl+PageUpKey
ZCtrl+PageDownKey
A+Ctrl+Plus(+)Key
ACtrl+Minus()Key
IcanmakeitworkwithoutaCtrlkeypress,butbettertohavethecombinationifpossible.Iwasthinkingofusinga4
positionrotaryswitch.Eachpositionwouldbeforeachaxis,X,Y,ZandA.Whentheswitchisintheproperposition,
thendependingonwhichdirectiontheMPGhandwheelwasturned,Leonardowouldsendtheappropriatekeyboard
characterviathePCsUSBport.OnekeypressforeachpulseoftheMPGhandwheel.Itisa100PPRhandwheel.
Isthisdoableandmightsomeonebeabletohelpcutmylearningcurvedownwithanexampleofthecode?Thanks!

faultymonk

September15,2013at10:19pmReply
JustasanotetopeopletryingtouseaLeonardo(orMicro),thecodeexamplewillworkifyouuse:
#defineENC_AA4
#defineENC_BA5
#defineENC_PORTPINF

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

11/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

oleg

September15,2013at10:37pmReply
Thanks!

Ron

September17,2013at4:06amReply
Youmentionthis:
Sparkfunencoder,youllnoticethatitgives4incrementsperclickanditsimpossibletomakeithold
positionbetweenclicks.Therefore,tocountclicksyouwillneedtodividecountervariableby4
MyQuadratureencodersaregiving2countsperclick.Wouldyoumindaquicklessononjusthowtodothis,sincethe
variableisntadecimalnumber?
Manythanks!Yourcodeisforcingmetodiginandlearnmorethanjustthesimpleprogramming,asgivenonthe
Arduinositeexampleswhichiswhatteachingisallabout!

oleg

September17,2013at9:33amReply
Dowhatdivideby2?Thefastestwayistorightshiftonce.

Ron

September17,2013at8:06pmReply
Igotitoneofthosedoh!momentssorry!

Ron

September18,2013at12:48pmReply
(withregardtothesolutionfor24posencoderwhichgives2pulsesperclick)
WhathappenswhenIbitwiseshift(1bit)rightanegativenumber,aswhenImturningCCW?
Doesthesignbitstaywhereitssupposedto?
ImgettingverydifferentresultsCWfromCCW.

oleg

September18,2013at12:53pmReply
Youdontshiftnumbers,youshiftbytes.Whenyourightshifttheleftmostbitbecomeszero.Ifthis
bitrepresentedasign,itwillbegone.

oleg

September18,2013at5:44pmReply
Ifyourencoderclickseverysecondpulseyoucandetermineaclickpositionwithoutdividing.Even
incrementswillhavezeroinbit0andoddincrementswillhaveone.Thisistrueforbothsignedand
unsignedrepresentations.Also,checkingsinglebit,likeif(count&0x01){...,couldbefasterthan
shifting.

fbonan

October3,2013at7:46amReply
ThanksOleg,thissampleisgreatandsavemeyears:)
Manyrequestedacompleteworkingexamplewith2encoders,hereitis:
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

12/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

#defineENC_1_AA0
#defineENC_1_BA1
#defineENC_2_AA2
#defineENC_2_BA3
intencoder_1_value=0
intencoder_2_value=0
staticint8_tenc_states[]={0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0}
voidsetup(){
/*Setupencoderpinsasinputs*/
pinMode(ENC_1_A,INPUT)
digitalWrite(ENC_1_A,HIGH)
pinMode(ENC_1_B,INPUT)
digitalWrite(ENC_1_B,HIGH)
/*Setupencoderpinsasinputs*/
pinMode(ENC_2_A,INPUT)
digitalWrite(ENC_2_A,HIGH)
pinMode(ENC_2_B,INPUT)
digitalWrite(ENC_2_B,HIGH)
Serial.begin(115200)
Serial.println(************Start*************)
}
/*returnschangeinencoderstate(1,0,1)*/
int8_tread_encoder1(){
staticuint8_told_AB=0
old_AB<<=2
old_AB|=((digitalRead(ENC_1_B))?(1<<1):0)|((digitalRead(ENC_1_A))?(1<<0):0)
return(enc_states[(old_AB&0x0f)])
}
/*returnschangeinencoderstate(1,0,1)*/
int8_tread_encoder2(){
staticuint8_told_AB=0
old_AB<<=2
old_AB|=((digitalRead(ENC_2_B))?(1<<1):0)|((digitalRead(ENC_2_A))?(1<<0):0)
return(enc_states[(old_AB&0x0f)])
}
voidloop(){
int8_tencoderdata1
int8_tencoderdata2
encoderdata1=read_encoder1()
if(encoderdata1){
encoder_1_value+=encoderdata1
Serial.print("Encoder1:")
Serial.println(encoder_1_value)
}
encoderdata2=read_encoder2()
if(encoderdata2){
encoder_2_value+=encoderdata2
Serial.print("Encoder2:")
Serial.println(encoder_2_value)
}
}

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

13/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

Fabrice

Brett

October25,2014at4:13pmReply
Forsomereasonyourcodeworkedformewhenolegswouldnot.Thankyouforpostingit!

prins

November2,2013at2:28pmReply
greattutorial.
IfoundHIDboardusingPIC18F4550chipcapableofreading16rotaryencoders(alltypesofrotary)inrealtime,and
noadditionalchip.anyoneknowshowtodothatinarduino.whatmethodisitimplementing,timerorinterrupt?

mark

November14,2013at4:09amReply
howcanIusethiscodeonmega2560.Igetserialtoprintstartbutthatsit.WhatpinedoIuse?

oleg

November14,2013at8:45amReply
For2560,youdontneedtodoanything,thepinsareswitchedinthecodeduringcompile.

mark

November20,2013at1:29amReply
Thanks,
SoImusinganalogpins14and15butgetnoresponsefromtheencoder.Tried14and15Digital,no
response.
IfyoudliketomoveencoderpinstoArduinopins8and9,ENC_PORTshallbedefinedasPINB,andfor
pins0,1asPIND.
whydoesENC_PORTchangewhenchangingpins,isthisuniquetotheboardyourusing?
whatsENC_PORTdo?

OlegMazurov

November20,2013at9:18amReply
ENC_PORTisa#defineforaportname.Doesitworkifyoureusingthesamepinsas
I?

Jay

October7,2014at8:57pm
HiOleg,IalsohavethesameproblemwithaMEGA256,Idontgetresponsefrom
theencoder.
TriedchangingENC_PORTtoPINBPINCandPIND,noneofthemwork.
Anyidea?

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

14/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

OlegMazurov

October7,2014at10:48pm
Makesureyourencoderisconnectedtotheportyoursketchisreading,portbits0
and1.

Jay

October8,2014at1:31pm
Yes,itsproperlywiredandconnectedtotherightpins

OlegMazurov

October8,2014at1:48pm
Itshouldworkthen,butitdoesnt.Maybeyourtestingneedstobechanged?
IncludetheArduinoitself.Forexample,makesureyoucanreadasingepin.
Connectapushbuttontoadatapinandwriteasketchwhichreadsthestateofthispinand
printsitout.Therearemanyexamplesonthenetdoingsimilarthings.Thenmovethebuttonto
oneofthepinsintendedfortheencoderandmakeitworkthere,thenmovetotheotherpin.
Thenconnecttheencoder,itsreallyapairofpushbuttonswithsomecleversequencer.Then
modifymysketchwithwhatyouhavelearneditwillwork.
PostagoodpictureofyoursetuptotheaccompanyingG+communitysothatotherpeoplecan
seeitandhelpyoutoo>https://plus.google.com/u/0/communities/113627505540902841340

Allan

November25,2013at4:18amReply
isitpossobletomeasurewheelspeedusingarotaryencoderincrementalwithoutputA,BanZ

OlegMazurov

November25,2013at9:16amReply
Yesbutyouwillneeddifferentlookuptable.

aditya

December10,2013at5:36amReply
Ihave12V,500RPM,15KgcmDCgearedmotorandencoder.HowcouldIcontroltheDCmotorto
rotateinforward,ReversedirectionandNoofrotationsofDCmotorshaft.

MikeKehrli

December18,2013at12:53pmReply
HiOleg,
IadaptedthiscodetoaPICchipprojectIwas/amworkingonmanymonthsago.Itmademyrotaryknobfunctionality
perfectlycleanforthefirsttime.Thecodewasmorecompactaswell.Ineverdidmentionit,butthiswasreallyhelpful
tome.Itworksveryverywellonarotaryencoderwithabsolutelynohardwaredebouncing.Thesignalisreallyugly.
Justwantedtosaythanks.Ivetriedlotsofdebouncecode.ThisisnotonlythebestIvefound,butthebestbyfar.

LiamGoudge

December22,2013at3:46amReply
HiOleg.
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

15/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

Whatanelegantalgorithmread_encoderisaverynicewaytoimplementthestatemachine.
Thanksforpublishingandsharingyourideas.
VerysimpleporttotheFreescaleplatformonARMsMBED.
WorkedverywellbutIdidneed100nFofantibounceonmyPanasonicEVEKE2F2024Bencoder,perhapsbecause
thisCPUisclockedsomuchfasterthantheATMEGAandAVRs.

JeffBeougher

February16,2014at10:13amReply
Iamattemptingtoconnect6encoderstoanArduinoLeonardowithaMCP23017I2cPortExpander.I
havebeenabletouseoneencoderontheArduinodirectly.WhatIamattemptingtodoisdependingifthe
encoderisturnedupordowntosendakeyboardscankeytotothecomputerforaproject.Iwashopingtohavesome
typeofmultiplexingtobeabletoreadeachencoderandknowiftheyhavebeenturned.TheMCP23017hasnot
helped.IknowitworksbecauseIhavebeenabletousetheexamplecodesandblinkanledandseebuttonpress
input.
SomyquestionishowcanImultiplex6rotaryencoders.EitherusingtheMCP23017oradifferentinputexpanderof
sometype.
LinkstotheencoderandMCP.
http://www.adafruit.com/products/377
http://www.adafruit.com/products/732

Neelam

April17,2014at10:55amReply
Hi,
Myprojectistocontrolthespeedofthedcmotor(Hardware)usingPIDcontrollerinLabVIEW.ForinterfacingLabview
withdcmotor,IamusingArduinoUno.Forencoder,IamusingOptocouplerandaschmitttrigger.Theencoderhas
threeterminals.Redbrown&black.redandblackarefor+5vandgroundrespectivelyandbrownwillreadthevalue
(i.eno.ofrotations)fromthedcmotor.Thisoutputshouldbeconnectedtoarduinowhichinturnwillpassthisvalueto
labview.PleasetellmeonwhichpinofarduinoIshouldconnectthatbrownwire.
Fromdigitalpin3ofarduino,IampassingPWMsignaltothedcmotor.Itriedtoconnectthatbrownwireofencoderto
pin5butIamgettinganunknownerror.
Pleasehelpmeinthis.

peter

January17,2015at11:22pmReply
HiOleg.
thanksforyourdemonstration.

Robert

March28,2015at1:34pmReply
ThanksOleg,yourcodeworksgreatontheSparkfunilluminatedRGBencoders.
TogetittoworkonmyMEGA2560,IusedA0andA1,changingthedefinitionsto:
#defineENC_AA0
#defineENC_BA1
#defineENC_PORTPINF

Herman

March30,2015at5:35pmReply
IamnewatArduino(Uno)andwritingcodesothisisagoodexampleforme.ThanksOleg!
Ihaveabagofencodersthatseemtoworkdifferent.IputsomeLEDsontheterminalstoseehowthey
http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

16/17

3/31/2015

ReadingrotaryencoderonArduinoCircuits@Home

work.Whenturningclockwisebothoutputsbecomehighsimiltanious,thenonegoeslowandthentheothergoeslow.
Whenturningcounter/anticlockwisethefirstonebecomeshigh,thenthesecondoneandthentheybothgetlowatthe
sametime.Likethis:
010010010
011011011
IsthereaneasywayIcanchangethiscodesomyrotaryencoderswillwork?Ihopeyoucanhelpme.

OlegMazurov

March30,2015at6:25pmReply
Imnotsureabouteasyway.ThefundamentalpropertyofGreycodeencoderisthatonlyone
outputischangingatatimesothatwhenbothhaschangedsimultaneouslyyouwouldknowthat
theoutputsarewrongsomehow.Youcanchangethelookuptabletogiveproperincrement/decrementforyour
sequencebutthenyoudhavetoaddadebounce.

OlderComments 1 2 3

http://www.circuitsathome.com/mcu/readingrotaryencoderonarduino

17/17