Reading Rotary Encoder On Arduino Circuits@Home
Reading Rotary Encoder On Arduino Circuits@Home
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