Menu

algorithm for qadrature encoder

Help
fisyon
2016-06-15
2016-07-03
  • fisyon

    fisyon - 2016-06-15

    hi,
    i wrote a sub for counting encoder wheel's position change and direction:

    sub GetEncoder1
    
    if E1APin=0 and WFF1=1 then
    
    MainCounter1 += 1
    
        WFF1=0
    
        Locate 0,12
            Print "A"
        locate 1,6
            print "     "
        locate 1, 6
            print MainCounter1
    
    end if
    
    if E1BPin=0 and WFF1=1 then
        MainCounter1 -= 1
    
        WFF1=0
    
        Locate 0,12
            Print "B"
        locate 1,6
            print "     "
        locate 1, 6
        print MainCounter1
    
    end if
    
    if E1APin &  E1BPin = 1 then WFF1=1
    
    end sub
    

    of course i defined the variables as like:
    E1APin, E1BPin and WFF1 as bits, MainCounter1 as word.

    The code works but i am sure pulses are missing at high speed (>1000 pps) and i am not sure if it counts correct at low speeds (<100 pps ). I am not sure about pps but i am driving the motor with 5v for low speed and 12v for high speed.

    I need a fast and reliable example for encoding a quadrature encoder on regular pins (without using any interrupt)

    BTW the pic is 16f877a @ 20Mhz

    Edit: I found noise cause some reading problems then i added 4093 schmitt trigger. The reading became better but i still get some missing/wrong readings.

    i need a better code w/out using interrupts, anyone?

     

    Last edit: fisyon 2016-06-16
  • fisyon

    fisyon - 2016-06-19

    i wrote another subroutine. i saw this sub is more reliable on vibrating motor situation but the speed is worse.

    sub GetEncoder1
    E1Pos=0 : E1PosPre=0
    
    E1Pos.0 = E1BPin
    rotate E1Pos left
    E1Pos.0 = E1APin
    
    E1PosPre.0 = E1BOld
    rotate E1PosPre left
    E1PosPre.0 = E1AOld
    
    locate 0,12
    print E1PosPre
    locate 1,12
    print E1Pos
    
    select case E1Pos
        case 0
            if E1PosPre=1 Then
            MainCounter1 += 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "F"
        end if
            if E1PosPre=2 Then
            MainCounter1 -= 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "R"
        end if
    
      case 1
            if E1PosPre=3 Then
            MainCounter1 += 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "F"
        end if
            if E1PosPre=0 Then
            MainCounter1 -= 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "R"
        end if
    
        case 2
            if E1PosPre=0 Then
            MainCounter1 += 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "F"
        end if
            if E1PosPre=3 Then
            MainCounter1 -= 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "R"
        end if
    
        case 3
            if E1PosPre=2 Then
            MainCounter1 += 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "F"
        end if
            if E1PosPre=1 Then
            MainCounter1 -= 1
                E1AOld = E1APin : E1BOld = E1BPin
          locate 0,10
          print "R"
        end if
    end Select
    
    
            locate 1,0
                print E1Target
            locate 1,6
                print "     "
            locate 1, 6
            print MainCounter1
    end sub
    

    E1Pos and E1PosPre are byte variables.

    only a few pulses per second captured correctly. This is very slow to drive a small DC motor with 32 stripe encoder wheel. it works moving slowly by hand but driving motor even by PWM causes stalled motor or missing pulses.

    PS: i figured out i misspelled "quadrature" as "qadrature", can any admin/moderator edit that?

     
  • William Roth

    William Roth - 2016-07-01

    I think your print commands may be interfering with pulse detection. A pulse cannot be detected/processed while the program printing to the LCD. Any pulse that arrives while the Print is active will be missed.

    Your requirement of "no interrupt" is a deal killer for me. I would probably not consider quadrature encoder code without using interrupts.

    Good Luck

     
  • Chris Roper

    Chris Roper - 2016-07-01

    I agree with William.

    I don't know why people try to avoid Interrupts, they are no more difficult to grasp than any other peripheral and are probably the most important.

    It is Interrupts that truly allow Microcontrollers to interact with the Real Word in Real Time.

    Keep interrupt routines short and put anything that is not time sensitive in the Main loop.

    You will get far more power out of a given processor if Interrupts are used sensibly.

    Don't be shy to use them, but do your homework first and use them properly.

    This is not aimed at Fisyon, he may have good reasons for avoiding interrupts in this instance, but it is aimed at anyone who is scared to use interrupts. Don't be, they are your friend.

    Cheers
    Chris

     
  • Chuck Hellebuyck

    Agree on interrupts but also, if you aren't ready to tackle interrupts dont be afraid to use multiple PICs.
    When capturing data, an 8 pin PIC can do the job uninterrupted and a second larger device handles the calculations and control. They are so cheap, sometimes its easier than trying to do it all in one program. A simple serial communication stream is easy between them. The 8 pin can also buffer the data.

     
  • fisyon

    fisyon - 2016-07-03

    thank you all for the replies,

    i agree, using interrupts a must for most of timing sensitive applications. I thought the pic fast enough to capturing inputs while printing LCD but obviously i was wrong.

    I am avoiding to use interrupts and timers because:
    - lack of understanding how they works and/or how can i use them. gcbasic help has not enough examples about them for dumbs (me)...
    - i have one external interrupt and at least i will need 2+ of them. Chuck's suggestion needs much more complicated design + serial communication which i don't know anything about it too.

    I will try to switch to an analog absolute encoder with much bigger and slower encoder wheel.

    however, i want to understand:
    to calling my subs with the ext. interrupt (except printing LCD lines) will work?

    Thanks

     

    Last edit: fisyon 2016-07-03
  • kent_twt4

    kent_twt4 - 2016-07-03

    Yet another option would be to convert to a PIC18f4431 which would be a drop in replacement for the PIC16f877A. Why the 18f4431?, because it has a quadrature encoder module which can help calculate the velocity. To put it another way, the hardware can determine/capture the period between the rising edges of the switch going forward or backward. Even so, it still takes a bit of doing to accomplish what you want.

    I used the '4431 in a project for an encoder switch that selected the modes of a rgb led color wheel. And, it still needed an interrupt sub to reset the modes on counter rotation or counter maxcount overflow.

    Simple demonstration:

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.