Reading Rotary Encoder on Arduino « Circuits@Home

17
« Sparkfun 2010 Autonomous Vehicle Competition Digital camera control using Arduino USB Host Shield. Part 1 – basics. Rotary encoder connected to Arduino Reading rotary encoder on Arduino By Oleg Mazurov Quadrature rotary encoders, also known as rotary pulse generators, are popular input devices for embedded platforms, including Arduino. Several rotary encoder code examples are posted on Arduino site and elsewhere, however, they treat encoder as a pair of switches, adding decoding/debouncing overhead. For many years, I used an algorithm based on the fact that quadrature encoder is a Gray code generator and if treated as such, can be read reliably in 3 straight step without need for debouncing. As a result, the code I’m using is very fast and simple, works very well with cheap lowquality encoders, but is somewhat cryptic and difficult to understand. Soon after posting one of my projects where I used rotary encoder to set motor speed i started receiving emails asking to explain the code. This article is a summary of my replies – I’m presenting small example written for the purpose of illustrating my method. I’m also going through the code highlighting important parts. The hardware setup can be seen on title picture. The encoder from Sparkfun is connected to a vintage Atmega168based Arduino Pro. Common pin of the encoder is connected to ground, pins A and B are connected to pins 14 and 15, AKA Analog pins 0 and 1, configured as digital inputs. We also need a serial connection to the PC to receive power, program the Arduino, and send program output to the terminal. For this purpose, Sparkfun FTDI basic breakout is used. Connecting encoder pins to pins 0 and 1 of 8bit MCU port makes encoder reading code very simple. If analog pins are needed for something else, it is possible to move encoder to digital pins 8,9 or 0,1 (losing serial port) with no modification of code logic. While technically using any two consecutive port pins is possible with a bit of tweaking, using non consecutive pins for encoder input with this method is not recommended. Lastly, it sometimes hard to determine which encoder pin is A and which is B; it is easier to connect them at random and if direction is wrong, swap the pins. Example code is posted below. It is complete sketch – you can copy it from this page and paste into Arduino IDE window, compile, upload and run. The result of rotating the encoder can be seen in terminal window. Note that serial speed in the sketch is set to 115200, you will need to set your PC terminal to that speed as well. The explanation of the code is given after the listing. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /* Rotary encoder read example */ #define ENC_A 14 #define ENC_B 15 #define ENC_PORT PINC void setup() { /* Setup encoder pins as inputs */ pinMode(ENC_A, INPUT); digitalWrite(ENC_A, HIGH); pinMode(ENC_B, INPUT); digitalWrite(ENC_B, HIGH); Serial.begin (115200); Serial.println("Start"); } void loop() { static uint8_t counter = 0; //this variable will be changed by encoder input

description

code

Transcript of Reading Rotary Encoder on Arduino « Circuits@Home

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    Sparkfun2010AutonomousVehicleCompetition DigitalcameracontrolusingArduinoUSBHostShield.Part1basics.

    RotaryencoderconnectedtoArduino

    ReadingrotaryencoderonArduinoByOlegMazurov

    Quadraturerotaryencoders,alsoknownasrotarypulsegenerators,arepopularinputdevicesforembeddedplatforms,includingArduino.SeveralrotaryencodercodeexamplesarepostedonArduinositeandelsewhere,however,theytreatencoderasapairofswitches,addingdecoding/debouncingoverhead.Formanyyears,IusedanalgorithmbasedonthefactthatquadratureencoderisaGraycodegeneratorandiftreatedassuch,canbereadreliablyin3straightstepwithoutneedfordebouncing.Asaresult,thecodeImusingisveryfastandsimple,worksverywellwithcheaplowqualityencoders,butissomewhatcrypticanddifficulttounderstand.SoonafterpostingoneofmyprojectswhereIusedrotaryencodertosetmotorspeedistartedreceivingemailsaskingtoexplainthecode.ThisarticleisasummaryofmyrepliesImpresentingsmallexamplewrittenforthepurposeofillustratingmymethod.Imalsogoingthroughthecodehighlightingimportantparts.

    Thehardwaresetupcanbeseenontitlepicture.TheencoderfromSparkfunisconnectedtoavintageAtmega168basedArduinoPro.Commonpinoftheencoderisconnectedtoground,pinsAandBareconnectedtopins14and15,AKAAnalogpins0and1,configuredasdigitalinputs.WealsoneedaserialconnectiontothePCtoreceivepower,programtheArduino,andsendprogramoutputtotheterminal.Forthispurpose,SparkfunFTDIbasicbreakoutisused.

    Connectingencoderpinstopins0and1of8bitMCUportmakesencoderreadingcodeverysimple.Ifanalogpinsareneededforsomethingelse,itispossibletomoveencodertodigitalpins8,9or0,1(losingserialport)withnomodificationofcodelogic.Whiletechnicallyusinganytwoconsecutiveportpinsispossiblewithabitoftweaking,usingnonconsecutivepinsforencoderinputwiththismethodisnotrecommended.Lastly,itsometimeshardtodeterminewhichencoderpinisAandwhichisBitiseasiertoconnectthematrandomandifdirectioniswrong,swapthepins.

    Examplecodeispostedbelow.ItiscompletesketchyoucancopyitfromthispageandpasteintoArduinoIDEwindow,compile,uploadandrun.Theresultofrotatingtheencodercanbeseeninterminalwindow.Notethatserialspeedinthesketchissetto115200,youwillneedtosetyourPCterminaltothatspeedaswell.Theexplanationofthecodeisgivenafterthelisting.

    12345678910111213141516171819

    /*Rotaryencoderreadexample*/#defineENC_A14#defineENC_B15#defineENC_PORTPINCvoidsetup(){/*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

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    2021222324252627282930313233343536373839

    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

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    Rotaryencodersingingoutoftune

    Inorderforthismethodtoworkwell,read_encoder()functionneedstobecalledfairlyoften.Toseewhathappenswhenloopisslow,lowerserialportspeedgotoline13,change115200to9600,recompilethesketchandrun(dontforgettoreconfiguretheterminalonPCside).Pictureontheleftshowstheresult.Notethatencodergoesdownfrom237to229,thenjumpsupto230,thencontinuesgoingdown.Sometimesitcountscorrectlybutgives2or3statesperclickinsteadof4.Instabilitieslikethisaregoodindicationofslowloop.Ifencoderisusedtothingslikesettingmotorspeedorsoundvolume,thisbehaviorwontdomuchharmbecauseencoderwillneverskipbackmorethanonestateandoverallcountingwouldstillbeintherightdirection.However,ifencoderisusedforinterfacingwithdisplay,glitcheslikethatareveryannoying.Therefore,foruserinterfaceapplications,looptimeshouldbekeptshortandinsomecasesitmaybeevennecessarytoconvertencoderreadingfunctionintointerruptserviceroutine.Giventhesizeandspeedofencoderreadfunction,suchconversioncanbedone

    withoutmuchdifficulty.

    Tosummarize:Ipresentedamethodtoconvertquadraturerotaryencoderoutputintodirectioninformationusinglookuptable.Themethodmakesdebouncingunnecessary,andasaresult,conversionfunctionimplementedwiththismethodisveryshort,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

    gabriellaNovember9,2012at11:39amReply

    Okthanksalotthatisreallyhelpful.ButassoonasIintegratedthiscodewithsomemorecomplexcodeIhaveusingpulseIn()functiontounderstandtheinputofastandardRCreceiver,andamotordriver

    controllingtwomotors,theencoderseemstotallyincorrect:WhenIhadthethesamefunctionsworkingontheencoder,Iwasgettingsupercleanvalues.ButwhenIhadmorecodeandtheencoderstuffrunningsidebyside,mycountervaluesaretotallyoff(seebelow,whenspinningtheencoderroundandround).SoitseemslikethetimingistotallynotworkingImwonderingwhatImightbedoingwrongbecausenothingtoohighlevelishappeninginmycode,andItookoutallmyprintlns.

    Icanattachmycodeifthatdbehelpful,butwaswonderingyourthoughts/experience(reusing2encoderswithsomeotherprocessesgoingoninArduinoUNO)Thankyousosomuchagainforallthehelpandexplanation.

    ReadyCountervalue2:0Countervalue2:255Countervalue2:0Countervalue2:255Countervalue2:0Countervalue2:255Countervalue2:0Countervalue2:255Countervalue2:0

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

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

    olegNovember9,2012at11:49amReply

    Thecodeyouveaddedisblockingsomewhere.Youneedtoeitherfixitorswitchtointerruptdrivenencoderreading,likethisone>https://www.circuitsathome.com/mcu/rotaryencoderinterrupt

    serviceroutineforavrmicros

    gabriellaNovember9,2012at12:13pmReply

    Hm.YeaIcommentedeverythingoutandtheencodersworkgreat.WhenIaddbackinstufftoreadthereceiver,thatsthepointatwhichtheencodersseemtostopworking:

    Channel2Value=pulseIn(RX1,HIGH,20000)//readRCchannel2

    Channel1Value=pulseIn(RX3,HIGH,20000)//readRCchannel2//Serial.print(motor_body:)

    Imwonderingwhatyoumeanbythecodeisblockingsomewhereorwhatafixwouldbe??

    Thanksalotagain

    olegNovember9,2012at12:50pmReply

    Blockingiswhenapieceofcodeiswaitingforsomeeventtohappen,interruptingtheflowofexecutionofthemainloop.Forexample,delay()isblockingtheprogramwontcontinueuntil

    timespecifiedasdelayhasexpired.Ifyouhaveadelayofonesecondinyourmainloop,youcanrotateyourencoderfullcircleandmisseverypulse.

    Fixingmeansfindingblockingcodeandwritingitdifferently.Whatdoes20000meaninpulseIn?

    gabriellaNovember9,2012at5:25pmReply

    OkIguessIhavetouseaninterrupt?IwantedtobeabletouseArduinoUNOwiththetwoencoders.WouldtherebeawaytousetwoencoderswithArduinoUNO,evenifthetwodefaultinteruptpinsare2

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    and3?thethirdparameter(20000)isthetimeoutinmicroseconds.

    justfyi,PulseIN():Readsapulse(eitherHIGHorLOW)onapin.Forexample,ifvalueisHIGH,pulseIn()waitsforthepintogoHIGH,startstiming,thenwaitsforthepintogoLOWandstopstiming.Returnsthelengthofthepulseinmicroseconds.Givesupandreturns0ifnopulsestartswithinaspecifiedtimeout.soitseemstheproblemisitdelaysandwaits(ieblocking)

    olegNovember10,2012at10:52amReply

    Yes,tryinterruptcodeandseeifitworksforyou.Thecodeusesinterruptonchange,youcanconfigureanypintobeasourceofthisinterrupt.

    KyleRassweilerNovember15,2012at12:22amReply

    Iwaswonderingwhyyouneededatimeoutof2000?Wouldtheserialnotstillworkfinewithout?(Ithinkthattimeoutmaybeanexampleofblocking).

    SteffanoGizzlerNovember30,2012at3:23pmReply

    HiOleg

    Ireallyappreciateyourtutorials,theyaregreatandamwonderingifyoucouldputmeintherightdirectionasIambuildingabidirectionalpeoplesensorandcounterinaroomusingtwoinfraredsensors(S1andS2).WhatIwantisthefirstsequenceonbreakingS1andS2thechangeshouldsignalentryandincrementacounterwhilstbreakingthebeaminthesecondsequenceS2firstandS1willsignalexitanddecrementacounteranddisplaythecountvalueona3digit7segmentdisplay.Ihavethoughtofusingtheideaofreadingtworotaryencoderusingexternalinterruptsonanarduino.Isthistherightwaytogo??

    MuchThanks.

    Steffano.

    olegNovember30,2012at4:04pmReply

    Icantseeanyencoderapplicationhere.Yourprojectisquitestraightforward,justcodeyoursensorstatesdirectly.

    SteffanoGizzlerDecember1,2012at10:45amReply

    HiOleg,

    Pleasecouldyoukindlyelaborateonwhatyoumeanbycodingthesensorstatesdirectly?sinceitsasequence.amusingIRsensorswithmakeandbreakbeam.Iwillappreciateanymoreinformation.

    Thankyou.Staffano.

    SteffanoGizzlerDecember3,2012at11:31amReply

    HiOleg,

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    Thisisthefarhavecomesofarandamserialprintingthecounts.AnyideahowIcouldholdoldvalueandupdatethisoldvaluewiththecurrentvalcounttoa3digitsevensegmentdisplay?dependingonhowthesensorsaretripped?Anycorrectionorsuggestionsamverywillingtolearn

    intcounter,S1_SIG=0,S2_SIG=1

    voidsetup(){attachInterrupt(0,S1_RISE,RISING)//hookedtopin2onmega2560attachInterrupt(1,S2_RISE,RISING)//hookedtopin3Serial.begin(115200)}//setup

    voidloop(){

    }

    voidS1_RISE(){detachInterrupt(0)S1_SIG=1

    if(S2_SIG==0)counter++//entryif(S2_SIG==1)counter//exitSerial.println(counter)attachInterrupt(0,S1_FALL,FALLING)}

    voidS1_FALL(){detachInterrupt(0)S1_SIG=0

    if(S2_SIG==1)counter++//entryif(S2_SIG==0)counter//exitSerial.println(counter)attachInterrupt(0,S1_RISE,RISING)}

    voidS2_RISE(){detachInterrupt(1)S2_SIG=1

    if(S1_SIG==1)counter++//entryif(S1_SIG==0)counter//exitSerial.println(counter)attachInterrupt(1,S2_FALL,FALLING)}

    voidS2_FALL(){detachInterrupt(1)S2_SIG=0

    if(S1_SIG==0)counter++//entryif(S1_SIG==1)counter//exitSerial.println(counter)attachInterrupt(1,S2_RISE,RISING)}

    Steffano

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    steffanoDecember27,2012at4:36pmReply

    Imanagedtodomy2ISRforthetwosensorsandthe3digitsevensegmentdisplay,howevertheonlyproblemhavegotiswhenmysensorsarebrokenatfirstthecountgoesnegativefor2or3cyclesthen

    comestopositive(normal)doesanyonehaveanideahowtocorrectthis??please.Ihavedeclaredstaticintiinloop.

    WindsorFebruary1,2013at8:53pmReply

    Hi,thanksforthegreattutorial.Iadaptedyourcode(withminorchanges)torunonanSTM32F100B(ARM)micro.Worksflawlesslywithmyencoderwithouttheneedforanyhardwaredebouncingcircuitry!

    JoshFebruary23,2013at9:03pmReply

    HiMr.Oleg,Gooddaytoyouandthanksforthegreatefforthelpingarookielikemetostartwiththearduino,Ihave

    triedyourcodeusingUnoanditworksflawlesslybutwhenitrieditusingtheLeonardo,itdidntwork,wanderingwhatcouldbetheproblem.

    JoshFebruary23,2013at10:14pmReply

    HiMr.Oleg,BelowisthecodeIusedwithUnoandLeonardo,itworkswithUnobutnotwithLeonardo.

    /*Rotaryencoderreadexample*/#defineENC_A14#defineENC_B15#defineENC_PORTPINC//constantswontchange.Theyreusedhereto//setpinnumbers:constintbuttonPin=2//thenumberofthepushbuttonpinconstintledPin=13//thenumberoftheLEDpin

    //variableswillchange:intbuttonState=0//variableforreadingthepushbuttonstatusintswitch0=0voidsetup(){/*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//thisvariablewillbechangedbyencoderinputint8_ttmpdata/**/tmpdata=read_encoder()if(tmpdata){

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    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)//delayinbetweenreadsforstabilityswitch0=1}}else{//turnLEDoff:digitalWrite(ledPin,LOW)if(switch0==1){Serial.print(Pinindot)delay(1)Serial.println(buttonState)delay(1)//delayinbetweenreadsforstabilityswitch0=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

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    alwernerMarch14,2013at9:47amReply

    UsingtwoormoreencoderwiththeArduino?

    ItalldependsonthetotaloftasksbeingperformedbytheArduino,andthenumberofpulsesreceivedbytheprocessor.

    Sayforexampleyouhaveasmallslowmovingxytable,with2rotaryUSDigitalencodersgeneratingsay4000pulsespersecondanddrivingtwosteppermotorswithanEasydriverboardyouwouldsoonberunningoutofheadroomonyourproject.

    Mysuggestionswouldbetouse,twoTiny13chipsfromAtmeltoencodetherotaryencoders,andthanfeedtheresultantsignalintoyourArduino,whereitwillgiveanexcellentperformance.Inmyhumbleopnionitmayevensupportthreechannels,XYandZ.

    Youwouldneedsomemachinecodeexperiencetodothis,butthiswouldbeworthlearning.

    Goodluck.

    SeifApril6,2013at1:04pmReply

    Hi,

    ThankyouforthisgreatusefularticleImwonderingifIcanuseyouideawithArduinoUno??ImeantousetherotaryencoderwithArduinoUnoinordertoselectthepowerofmyRCcarwhichImbuilding

    thanxagain

    olegApril6,2013at1:26pmReply

    UNOshouldwork.

    SalvatoreAielloApril15,2013at12:49pmReply

    Hi,Sweetbitofcode!Iamusingitinaprojectatwork,usingtheencodertodisplayamotorspeedselection

    onasevensegmentdisplayanditworksverynicelyindeed.Onceyouremovetheserial.printcommandsitisdifficulttospinthebareencodershaftquicklyenoughtogenerateamisread.Withasuitablysizedknobontheshaftitisgoingtoslowrotationspeedandmakeitvirtuallyimpossibleforthecasualoperatortogetanerroneousreading

    Thanks!

    MarcoAugust1,2013at1:23pmReply

    Hi,verynicejobmyR2D2Domesencodersensorhas3output,oneofthemreadsjustonespecialdentonthemotor

    gear,likeaZEROPOSITION.HowcanIimplementitinthecode?AlsoHowcanImakeencoderscountto36or+18to18?Thanksjustlearninghere

    AlexAugust14,2013at9:48amReply

    Hereisthecodewithzeropositionand3outputs.

    intcounter,S1_SIG=0,S2_SIG=1,S3_SIG=1

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    boolfirstinit=false

    voidsetup(){attachInterrupt(0,S1_RISE,RISING)//hookedtopin2onmega2560attachInterrupt(1,S2_RISE,RISING)//hookedtopin3attachInterrupt(2,S3_RISE,RISING)//hookedtopin21Serial.begin(115200)}//setup

    voidloop(){

    }

    voidS1_RISE(){detachInterrupt(0)S1_SIG=1

    if(S2_SIG==0)counter++//entryif(S2_SIG==1)counter//exitSerial.println(counter)attachInterrupt(0,S1_FALL,FALLING)}

    voidS1_FALL(){detachInterrupt(0)S1_SIG=0

    if(S2_SIG==1)counter++//entryif(S2_SIG==0)counter//exitSerial.println(counter)attachInterrupt(0,S1_RISE,RISING)}

    voidS2_RISE(){detachInterrupt(1)S2_SIG=1

    if(S1_SIG==1)counter++//entryif(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++//entryif(S1_SIG==1)counter//exitSerial.println(counter)attachInterrupt(1,S2_RISE,RISING)}

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    voidS3_RISE(){S3_SIG=1detachInterrupt(2)

    if(!firstinit&&((S2_SIG==1&&S1_SIG==1)||(S1_SIG==0&&S2_SIG==1))){counter=0firstinit=true}

    attachInterrupt(2,S3_FALL,FALLING)}

    voidS3_FALL(){S3_SIG=0detachInterrupt(2)

    if(!firstinit&&((S2_SIG==1&&S1_SIG==1)||(S1_SIG==1&&S2_SIG==0))){counter=0firstinit=true}

    attachInterrupt(2,S3_RISE,RISING)}

    MartyAugust30,2013at9:31pmReply

    IamnewtoArduinosandamstartingtoplaywiththem.Ihaveseenmanyexamplesofrotaryencodercode.ButnonthatusetheLeonardotooutputkeypresscommandswhenrotated.Myapplicationisa

    smallCNCverticalmachiningcenter.Thecontrolitselfcannotacceptarotaryencoder(manualpulsegenerator)ThecontrolisPCbased.ItCANacceptkeypresses,forexample,tomovethetableinthesedirections:X+Ctrl+RightArrowKeyXCtrl+LeftArrowKeyY+Ctrl+UpArrowKeyYCtrl+DownArrowKeyZ+Ctrl+PageUpKeyZCtrl+PageDownKeyA+Ctrl+Plus(+)KeyACtrl+Minus()Key

    IcanmakeitworkwithoutaCtrlkeypress,butbettertohavethecombinationifpossible.Iwasthinkingofusinga4positionrotaryswitch.Eachpositionwouldbeforeachaxis,X,Y,ZandA.Whentheswitchisintheproperposition,thendependingonwhichdirectiontheMPGhandwheelwasturned,LeonardowouldsendtheappropriatekeyboardcharacterviathePCsUSBport.OnekeypressforeachpulseoftheMPGhandwheel.Itisa100PPRhandwheel.

    Isthisdoableandmightsomeonebeabletohelpcutmylearningcurvedownwithanexampleofthecode?Thanks!

    faultymonkSeptember15,2013at10:19pmReply

    JustasanotetopeopletryingtouseaLeonardo(orMicro),thecodeexamplewillworkifyouuse:

    #defineENC_AA4#defineENC_BA5#defineENC_PORTPINF

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    olegSeptember15,2013at10:37pmReply

    Thanks!

    RonSeptember17,2013at4:06amReply

    Youmentionthis:Sparkfunencoder,youllnoticethatitgives4incrementsperclickanditsimpossibletomakeithold

    positionbetweenclicks.Therefore,tocountclicksyouwillneedtodividecountervariableby4

    MyQuadratureencodersaregiving2countsperclick.Wouldyoumindaquicklessononjusthowtodothis,sincethevariableisntadecimalnumber?

    Manythanks!Yourcodeisforcingmetodiginandlearnmorethanjustthesimpleprogramming,asgivenontheArduinositeexampleswhichiswhatteachingisallabout!

    olegSeptember17,2013at9:33amReply

    Dowhatdivideby2?Thefastestwayistorightshiftonce.

    RonSeptember17,2013at8:06pmReply

    Igotitoneofthosedoh!momentssorry!

    RonSeptember18,2013at12:48pmReply

    (withregardtothesolutionfor24posencoderwhichgives2pulsesperclick)

    WhathappenswhenIbitwiseshift(1bit)rightanegativenumber,aswhenImturningCCW?Doesthesignbitstaywhereitssupposedto?

    ImgettingverydifferentresultsCWfromCCW.

    olegSeptember18,2013at12:53pmReply

    Youdontshiftnumbers,youshiftbytes.Whenyourightshifttheleftmostbitbecomeszero.Ifthisbitrepresentedasign,itwillbegone.

    olegSeptember18,2013at5:44pmReply

    Ifyourencoderclickseverysecondpulseyoucandetermineaclickpositionwithoutdividing.Evenincrementswillhavezeroinbit0andoddincrementswillhaveone.Thisistrueforbothsignedand

    unsignedrepresentations.Also,checkingsinglebit,likeif(count&0x01){...,couldbefasterthanshifting.

    fbonanOctober3,2013at7:46amReply

    ThanksOleg,thissampleisgreatandsavemeyears:)Manyrequestedacompleteworkingexamplewith2encoders,hereitis:

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    #defineENC_1_AA0#defineENC_1_BA1

    #defineENC_2_AA2#defineENC_2_BA3

    intencoder_1_value=0intencoder_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

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    Fabrice

    BrettOctober25,2014at4:13pmReply

    Forsomereasonyourcodeworkedformewhenolegswouldnot.Thankyouforpostingit!

    prinsNovember2,2013at2:28pmReply

    greattutorial.

    IfoundHIDboardusingPIC18F4550chipcapableofreading16rotaryencoders(alltypesofrotary)inrealtime,andnoadditionalchip.anyoneknowshowtodothatinarduino.whatmethodisitimplementing,timerorinterrupt?

    markNovember14,2013at4:09amReply

    howcanIusethiscodeonmega2560.Igetserialtoprintstartbutthatsit.WhatpinedoIuse?

    olegNovember14,2013at8:45amReply

    For2560,youdontneedtodoanything,thepinsareswitchedinthecodeduringcompile.

    markNovember20,2013at1:29amReply

    Thanks,

    SoImusinganalogpins14and15butgetnoresponsefromtheencoder.Tried14and15Digital,noresponse.

    IfyoudliketomoveencoderpinstoArduinopins8and9,ENC_PORTshallbedefinedasPINB,andforpins0,1asPIND.

    whydoesENC_PORTchangewhenchangingpins,isthisuniquetotheboardyourusing?

    whatsENC_PORTdo?

    OlegMazurovNovember20,2013at9:18amReply

    ENC_PORTisa#defineforaportname.DoesitworkifyoureusingthesamepinsasI?

    JayOctober7,2014at8:57pm

    HiOleg,IalsohavethesameproblemwithaMEGA256,Idontgetresponsefromtheencoder.

    TriedchangingENC_PORTtoPINBPINCandPIND,noneofthemwork.Anyidea?

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    OlegMazurovOctober7,2014at10:48pm

    Makesureyourencoderisconnectedtotheportyoursketchisreading,portbits0and1.

    JayOctober8,2014at1:31pm

    Yes,itsproperlywiredandconnectedtotherightpins

    OlegMazurovOctober8,2014at1:48pm

    Itshouldworkthen,butitdoesnt.Maybeyourtestingneedstobechanged?IncludetheArduinoitself.Forexample,makesureyoucanreadasingepin.

    Connectapushbuttontoadatapinandwriteasketchwhichreadsthestateofthispinandprintsitout.Therearemanyexamplesonthenetdoingsimilarthings.Thenmovethebuttontooneofthepinsintendedfortheencoderandmakeitworkthere,thenmovetotheotherpin.Thenconnecttheencoder,itsreallyapairofpushbuttonswithsomecleversequencer.Thenmodifymysketchwithwhatyouhavelearneditwillwork.

    PostagoodpictureofyoursetuptotheaccompanyingG+communitysothatotherpeoplecanseeitandhelpyoutoo>https://plus.google.com/u/0/communities/113627505540902841340

    AllanNovember25,2013at4:18amReply

    isitpossobletomeasurewheelspeedusingarotaryencoderincrementalwithoutputA,BanZ

    OlegMazurovNovember25,2013at9:16amReply

    Yesbutyouwillneeddifferentlookuptable.

    adityaDecember10,2013at5:36amReply

    Ihave12V,500RPM,15KgcmDCgearedmotorandencoder.HowcouldIcontroltheDCmotortorotateinforward,ReversedirectionandNoofrotationsofDCmotorshaft.

    MikeKehrliDecember18,2013at12:53pmReply

    HiOleg,

    IadaptedthiscodetoaPICchipprojectIwas/amworkingonmanymonthsago.Itmademyrotaryknobfunctionalityperfectlycleanforthefirsttime.Thecodewasmorecompactaswell.Ineverdidmentionit,butthiswasreallyhelpfultome.Itworksveryverywellonarotaryencoderwithabsolutelynohardwaredebouncing.Thesignalisreallyugly.

    Justwantedtosaythanks.Ivetriedlotsofdebouncecode.ThisisnotonlythebestIvefound,butthebestbyfar.

    LiamGoudgeDecember22,2013at3:46amReply

    HiOleg.

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    Whatanelegantalgorithmread_encoderisaverynicewaytoimplementthestatemachine.Thanksforpublishingandsharingyourideas.VerysimpleporttotheFreescaleplatformonARMsMBED.WorkedverywellbutIdidneed100nFofantibounceonmyPanasonicEVEKE2F2024Bencoder,perhapsbecausethisCPUisclockedsomuchfasterthantheATMEGAandAVRs.

    JeffBeougherFebruary16,2014at10:13amReply

    Iamattemptingtoconnect6encoderstoanArduinoLeonardowithaMCP23017I2cPortExpander.IhavebeenabletouseoneencoderontheArduinodirectly.WhatIamattemptingtodoisdependingifthe

    encoderisturnedupordowntosendakeyboardscankeytotothecomputerforaproject.Iwashopingtohavesometypeofmultiplexingtobeabletoreadeachencoderandknowiftheyhavebeenturned.TheMCP23017hasnothelped.IknowitworksbecauseIhavebeenabletousetheexamplecodesandblinkanledandseebuttonpressinput.

    SomyquestionishowcanImultiplex6rotaryencoders.EitherusingtheMCP23017oradifferentinputexpanderofsometype.

    LinkstotheencoderandMCP.

    http://www.adafruit.com/products/377http://www.adafruit.com/products/732

    NeelamApril17,2014at10:55amReply

    Hi,

    Myprojectistocontrolthespeedofthedcmotor(Hardware)usingPIDcontrollerinLabVIEW.ForinterfacingLabviewwithdcmotor,IamusingArduinoUno.Forencoder,IamusingOptocouplerandaschmitttrigger.Theencoderhasthreeterminals.Redbrown&black.redandblackarefor+5vandgroundrespectivelyandbrownwillreadthevalue(i.eno.ofrotations)fromthedcmotor.Thisoutputshouldbeconnectedtoarduinowhichinturnwillpassthisvaluetolabview.PleasetellmeonwhichpinofarduinoIshouldconnectthatbrownwire.

    Fromdigitalpin3ofarduino,IampassingPWMsignaltothedcmotor.Itriedtoconnectthatbrownwireofencodertopin5butIamgettinganunknownerror.

    Pleasehelpmeinthis.

    peterJanuary17,2015at11:22pmReply

    HiOleg.thanksforyourdemonstration.

    RobertMarch28,2015at1:34pmReply

    ThanksOleg,yourcodeworksgreatontheSparkfunilluminatedRGBencoders.

    TogetittoworkonmyMEGA2560,IusedA0andA1,changingthedefinitionsto:#defineENC_AA0#defineENC_BA1#defineENC_PORTPINF

    HermanMarch30,2015at5:35pmReply

    IamnewatArduino(Uno)andwritingcodesothisisagoodexampleforme.ThanksOleg!Ihaveabagofencodersthatseemtoworkdifferent.IputsomeLEDsontheterminalstoseehowthey

  • 3/31/2015 ReadingrotaryencoderonArduinoCircuits@Home

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

    work.Whenturningclockwisebothoutputsbecomehighsimiltanious,thenonegoeslowandthentheothergoeslow.Whenturningcounter/anticlockwisethefirstonebecomeshigh,thenthesecondoneandthentheybothgetlowatthesametime.Likethis:010010010011011011

    IsthereaneasywayIcanchangethiscodesomyrotaryencoderswillwork?Ihopeyoucanhelpme.

    OlegMazurovMarch30,2015at6:25pmReply

    Imnotsureabouteasyway.ThefundamentalpropertyofGreycodeencoderisthatonlyoneoutputischangingatatimesothatwhenbothhaschangedsimultaneouslyyouwouldknowthat

    theoutputsarewrongsomehow.Youcanchangethelookuptabletogiveproperincrement/decrementforyoursequencebutthenyoudhavetoaddadebounce.

    OlderComments 1 2 3