decoding quadrature encoders


Closed Thread
Results 1 to 40 of 94

Hybrid View

  1. #1
    ice's Avatar
    ice Guest

    Default decoding quadrature encoders

    Hello,
    is there a sample code for interfacing quadrature encoders[a/b channels]
    I need to determine position/direction...
    i searchd for posts in the pbp forum,but they were all for 1 channel

    Thank you
    -Gerry

  2. #2
    Join Date
    Oct 2003
    Location
    holland
    Posts
    251


    Did you find this post helpful? Yes | No

    Default

    Here is a small example how to count up and down a position counter.
    How to initialise the position counter you must do by yourself.

    A_INPUT VAR PORTA.0
    B_INPUT VAR PORTA.1

    HULP1 VAR BIT
    HULP2 VAR BIT

    COUNTER VAR WORD

    Clear
    COUNTER = 32768

    START:


    HULP2 = A_INPUT & ~ HULP1 'EVERY POSITIVE GOWING EDGE OF A_INPUT
    HULP1 = A_INPUT 'GIVES A PULSE OF ONE PROGRAMM CYCLE

    IF HULP2 = 1 AND B_INPUT = 1 THEN 'MOTOR TURNS RIGHT
    COUNTER = COUNTER + 1
    ENDIF

    IF HULP2 = 1 AND B_INPUT = 0 THEN 'MOTOR TURNS LEFT
    COUNTER = COUNTER - 1
    ENDIF

  3. #3
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Default

    Hi!

    Maybe these two links will help you out.

    Nuts and Volts:
    http://www.parallax.com/dl/docs/cols...l1/col/nv8.pdf

    See State machine: two-bit quadrature encoder
    http://www.emesystems.com/BS2fsm.htm#twobit%20encoder

    Luciano

  4. #4
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default

    mat janssen>>
    Thank yoiu very much for the code snip..but i cant understand whats going on in the code ,esp the "&~" part
    I tried using the code...however ,whatever maybe the direction the motor is running ....i get the same reading ,say always "left"



    Luciano>>
    Thanks for the links..
    i ported the foll code from nv8 [http://www.parallax.com/dl/docs/col...ol1/col/nv8.pdf --pg7]
    Code:
        let new = pins & %11000000 ' Mask off all but bits 6 & 7
    start:
       let old = new & %11000000 ' Mask bits and copy new into old.
    again:
       let new = pins & %11000000 ' Copy encoder bits to new.
       if new = old then again ' If no change, try again.
       let directn = bit6 ^ bit15 ' XOR right bit of new w/ left bit of old.
       if directn = 1 then CW ' If result=1, encoder turned clockwise.
       serout 0,n2400,(I,left) ' If result=0, counterclock (scroll left).
       goto start ' Do it again.
    CW:
       serout 0,n2400,(I,right) ' Clockwise (scroll right).
       goto start ' Do it again.

    To pbp


    Code:
    old VAR BYTE
    new VAR BYTE
    direct VAR BIT
    
    quad:
    	new= PORTC && %00000011
    	
    start:
    	old=new && %00000011
    
    again:
    	new= PORTC && %00000011
    	Pause 10
    	LCDOut $fe,1,"no movement"	
    	IF new=old Then again
    	direct=new.bit1 ^ old.bit0	
    	IF direct=0 Then GoTo cw
    	LCDOut $fe,1,"one dir"
    	Pause 10
    	GoTo start
    		
    cw:
    	LCDOut $fe,1,"2nd dir"
    	Pause 10
    	GoTo start
    with the above code...there is alot of fluctuation between the 2 directions..

    ..anything going wrong in my code?.i sat on it the whole day..still cant figure out the problem

  5. #5
    Join Date
    Oct 2003
    Location
    holland
    Posts
    251


    Did you find this post helpful? Yes | No

    Default

    Hallo,
    I completed the programm for testing and it works ok.
    With the & ~ look in the manual it takes the not value of the bit.

    here is the complete source and also the hex file

    'PIC 16F628A test


    @ DEVICE PIC16F628A,INTRC_OSC
    @ DEVICE PIC16F628A,MCLR_OFF
    @ DEVICE PIC16F628A,BOD_OFF
    @ DEVICE PIC16F628A,LVP_OFF
    @ DEVICE PIC16F628A,CPD_OFF
    @ DEVICE PIC16F628A,PROTECT_OFF


    DEFINE OSC 4




    CMCON = 7
    VRCON = 0
    OPTION_REG.7 = 0

    TRISA = %11111111
    TRISB = %00000000


    A_INPUT VAR PORTA.0
    B_INPUT VAR PORTA.1

    HULP1 VAR BIT
    HULP2 VAR BIT

    COUNTER VAR WORD

    Clear

    COUNTER = 128

    START:


    HULP2 = A_INPUT & ~ HULP1 'EVERY POSITIVE GOWING EDGE OF A_INPUT
    HULP1 = A_INPUT 'GIVES A PULSE OF ONE PROGRAMM CYCLE

    IF HULP2 = 1 AND B_INPUT = 1 Then 'MOTOR TURNS RIGHT
    COUNTER = COUNTER + 1
    EndIF

    IF HULP2 = 1 AND B_INPUT = 0 Then 'MOTOR TURNS LEFT
    COUNTER = COUNTER - 1
    EndIF

    PORTB = COUNTER
    GoTo START
    Attached Files Attached Files

  6. #6
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Default

    Hello ICE!

    You need the Bitwise Operator:
    &

    Not the logical Operator AND:
    && (AND and && are the same)


    From the PBP manual:

    4.17.14. Bitwise Operators

    Bitwise operators act on each bit of a value in boolean fashion.
    They can be used to isolate bits or add bits into a value.


    4.19. Logical Operators

    Logical operators differ from bitwise operations. They yield a true/false
    result from their operation. Values of 0 are treated as false. Any other
    value is treated as true.


    Luciano
    Last edited by Luciano; - 8th April 2005 at 12:33.

  7. #7
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default

    Luciano,
    I tried it with & [bitwise operators]...actually everything..
    still no go...

    mat janssen>>
    are u by any chance using a dual D f/f between the encoder and the PIC,because im not..
    Thanks for ur code snip
    Last edited by ice; - 8th April 2005 at 13:52.

  8. #8
    Join Date
    Apr 2011
    Location
    León
    Posts
    5


    Did you find this post helpful? Yes | No

    Lightbulb Re: decoding quadrature encoders

    Quote Originally Posted by mat janssen View Post
    Hallo,
    I completed the programm for testing and it works ok.
    With the & ~ look in the manual it takes the not value of the bit.

    here is the complete source and also the hex file

    'PIC 16F628A test


    @ DEVICE PIC16F628A,INTRC_OSC
    @ DEVICE PIC16F628A,MCLR_OFF
    @ DEVICE PIC16F628A,BOD_OFF
    @ DEVICE PIC16F628A,LVP_OFF
    @ DEVICE PIC16F628A,CPD_OFF
    @ DEVICE PIC16F628A,PROTECT_OFF


    DEFINE OSC 4




    CMCON = 7
    VRCON = 0
    OPTION_REG.7 = 0

    TRISA = %11111111
    TRISB = %00000000


    A_INPUT VAR PORTA.0
    B_INPUT VAR PORTA.1

    HULP1 VAR BIT
    HULP2 VAR BIT

    COUNTER VAR WORD

    Clear

    COUNTER = 128

    START:


    HULP2 = A_INPUT & ~ HULP1 'EVERY POSITIVE GOWING EDGE OF A_INPUT
    HULP1 = A_INPUT 'GIVES A PULSE OF ONE PROGRAMM CYCLE

    IF HULP2 = 1 AND B_INPUT = 1 Then 'MOTOR TURNS RIGHT
    COUNTER = COUNTER + 1
    EndIF

    IF HULP2 = 1 AND B_INPUT = 0 Then 'MOTOR TURNS LEFT
    COUNTER = COUNTER - 1
    EndIF

    PORTB = COUNTER
    GoTo START
    I'm trying to do the example with PIC16f877a but i have problems for example the VRCON = 0 my compiler says it's a bad instruction how can i probe with this pic

    thanks

  9. #9
    Join Date
    Oct 2005
    Posts
    34


    Did you find this post helpful? Yes | No

    Default Re: decoding quadrature encoders

    Hi mat I see you are using ASM to set up your config word, it is a greate idea, but I get a compiler error when I do it. I always edit the device include file 16F628.INC:
    NOLIST
    ifdef PM_USED
    LIST
    include 'M16F62x.INC' ; PM header
    device pic16F628, intrc_osc, wdt_off, pwrt_off, mclr_off, lvp_off, protect_off
    XALL
    NOLIST

    You can't teach an old dog new tricks, but I'm always willing to try.

  10. #10
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default

    Thank you for all your help.
    Theres a small problem though.

    The encoder program counts faster in one direction and slower in the other...

    is it because ...
    When im counting in one of the directions ,im utilizing the ADC[ADCIN and an IF statement]

    ..whereas in the other direction,im not.
    The program logic is the same as above.
    Last edited by ice; - 18th April 2005 at 09:38.

  11. #11
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Default

    I don't understand.
    If you need help post your code.

    Luciano

  12. #12
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default

    before i go ahead with my code....ill explain wht i have to do

    I need to control the position of a DC motor[geared],using a potentiometer

    I have to first detect the endpoints of a gear assembly.
    say, i start with a count of 32500 and the count at one end of the gear assembly is 32600
    ..now i rotate it to the other side ,say the count at this point is 32400

    The above was just the calibration routine.Using the above values ,i have to
    scale the 200 counts[32600-32400] to a potentiometer value[0 to 255]

    How am i detecting the end points?
    ..im using the LMD18200T motor driver .Using the current sense feature of the chip,i detect wheteher the gear assembly has reached an end point.The current sense pin is connected to an ADC port..portA.1 namely


    my program flow...
    1> set counter to 32500
    2> move motor in one direction
    3> count pulses..if CW,increment.if CCW decrement
    ...say it is CW and counter increments to 32600 till the end
    4>counter_1 has 32600
    5>move the motor to the other side,count the pulses..it is decrementing now
    6>so counter_2 has 32400
    7>now i have to scale the gear assembly range to a potentiometer
    difference=counter_1-counter_2
    =32600-32400
    =200
    8> scale to a pot value
    pot_val holds the pot value connected to analog portA.0

    hence required count value=[difference/256]*pot_val+counter_2
    =[difference*pot_val]/256+counter_2 (rearranging)

    example...if potvalue in 128,then
    required count value=(200*128)/256+32400
    =32500

    now i dont know where to go from here..how do i get the motor to move to position 32500,when the pot is moved to 128

    ...this is a long post..but its the best i could do to explain wht im trying to do.
    -Gerry

  13. #13
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Default

    If you are losing encoder counts, then use an interrupt service routine.
    Four of PORTB’s pins, RB<7:4>, have an interrupt-onchange feature.
    Use two of these pins for the A/B encoder signals.

    Luciano

  14. #14
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default

    ok,heres my program ,using interrupts..

    the problems i'm encountering are below the code
    ..
    Code:
    DEFINE LOADER_USED 1
    
    
    led     VAR     PORTB.7
    old 			VAR BYTE
    new 			VAR BYTE
    direction_bit 	VAR BIT
    counter 		VAR WORD
    counter_1		VAR WORD
    counter_2		VAR WORD
    direction_store	VAR BIT
    adval			VAR	WORD				' Create adval to store result
    potval			VAR WORD
    servo_val		VAR	WORD
    difference		VAR WORD
    	
    
    counter=32500		
    	
        	HPwm 0,150,20000    
            OPTION_REG = $7f        
            ON INTERRUPT GoTo myint     ' Define interrupt handler
            INTCON = $90                     ' Enable INTE interrupt
    
    	
    
    loop:   High led                ' Turn LED on
    
    		LCDOut $fe,1,"count:"
    		LCDOut $fe,$c0,DEC counter
    		'Pause 10
    		
            GoTo loop               ' Do it forever
    
    
    
    
    		' Interrupt handler
            Disable                 ' No interrupts past this point
    myint:  Low led                 ' If we get here, turn LED off
           
           
    enc:    new= PORTB & %00000011
    
    
    start_1:
    		old=new & %00000011	
    		
    again:
    
    		new= PORTB & %00000011					'load new value of A/B channels into new by anding with HEX3
    			
    		
    	    'IF new=old Then again
    	    direction_bit=old.bit1 ^ new.bit0		'check direction 
    	
    		
    		IF direction_bit = 1 Then  
    		LCDOut $fe,1,"Last was CW"
    		counter = counter + 1				'increment counter
    		LCDOut $fe,$c0,DEC counter," ",BIN direction_bit
    	
    		Else
    			LCDOut $fe,1,"Last was CCW"
    			counter = counter - 1				'decrement counter
    			LCDOut $fe,$c0,DEC counter," ", BIN direction_bit	
    		
    		EndIF
    		Pause 10
    	   			
    
                  
    		INTCON.1 = 0           ' Clear interrupt flag
    	    Resume                 ' Return to main program
    	    Enable
    1>The interrupts are worng fine,however the code is still unable to distinguish between CW and CCW,because of which the counting goes awry..

    2>if i remove the "if then " statement for CW/CCW direction and only put a
    counter=counter+1,it works well


    The whole problem seems to be the direction decoding part..
    ..i cant seem to find a solution to it..
    Last edited by ice; - 3rd May 2005 at 14:00.

  15. #15
    J_Brittian's Avatar
    J_Brittian Guest


    Did you find this post helpful? Yes | No

    Default

    Luciano,
    Thank you for the clarity and detail with which you answered Ice's questions. I was able to get my own optical encoder running using your guidance and assembly language code.

  16. #16
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Smile

    You're welcome!

    Luciano

  17. #17
    J_Brittian's Avatar
    J_Brittian Guest


    Did you find this post helpful? Yes | No

    Default Variable Incrementation

    Is it possible to increment/decrement enc_counter by 10's or 100's once some threshold has been reached? My encoder is a front panel switch with pushbutton which is used to select and change setpoints, turning the switch 32000 times can't be good for its lifetime not to mention my hand.

  18. #18
    Join Date
    Oct 2004
    Location
    Italy
    Posts
    695


    Did you find this post helpful? Yes | No

    Default

    Hi,

    I'm not sure I understand your problem.

    * * *

    Set the variable enc_counter to 30000.

    If the encoder does one step you will
    have either 29999 or 30001 in enc_counter. (CCW or CW).

    The interrupt assembly code only decrements or increments
    the 16 bit value stored in the variable enc_counter.

    Is up to your PicBasic code in the main program loop to do
    something with the value stored in the variable enc_counter.

    Best regards,

    Luciano
    Last edited by Luciano; - 29th October 2005 at 22:44.

Similar Threads

  1. Quick thoughts: DT Ints with encoders
    By kevlar129bp in forum mel PIC BASIC Pro
    Replies: 19
    Last Post: - 7th January 2010, 02:01
  2. PMDC SERVO MOTOR WITH quadrature encoder DRIVE ?
    By phoenix_1 in forum Schematics
    Replies: 37
    Last Post: - 22nd November 2009, 20:45
  3. 32-bit Quadrature Counter With Serial Interface
    By precision in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 10th June 2008, 03:49
  4. quad encoders
    By cpayne in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 13th March 2007, 18:49
  5. "momentary" IR decoding
    By sporker in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 20th June 2005, 02:53

Members who have read this thread : 4

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts