decoding quadrature encoders


Closed Thread
Results 1 to 40 of 94

Hybrid View

  1. #1
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default

    Thanks Luciano,
    But it's the same program as in the datasheet...
    Im now trying to write the decoding program in assembly..

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


    Did you find this post helpful? Yes | No

    Default

    Rotary encoder in assembly for 16F84:
    http://emp.byui.edu/fisherr/EET255/encdr.asm

    Luciano

  3. #3
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default interrupts are interrupting LCDout

    Luciano,
    I added the code from the lin you posted..
    I'm using interrupt on INT0 connected to channel A..


    I'm able to count and detect directions..with 1 big problem

    i cannot monitor or dispaly the counts either using LCDout or software serial to hyperterminal.
    it's good for 2 seconds and then the whole LCD screen corrupts
    ...is it because the LCDout line is being interrupted by the encoder
    ...if i disable/enable interrupts within the LCDout line..i lose encoder counts


    in the code..i use 2 leds connected to portB.6,7 to show direction.
    LOOP is my main program

    my code is below
    Code:
    		GoTo start 					' Skip around interrupt handler	
    
    
    		DEFINE INTHAND display			' DEFINE INTERRUPT handler
    		Asm
    display 
    		movwf	wsave
    		swapf	STATUS, W
    		clrf	STATUS
    		movwf	ssave
    		movf	PCLATH, W
    		movwf	psave
    		
    	
    		;;;bsf _led 						; Turn on LED (for example)
    		;new=PORTB & %11000000
    
    		;Get intitial input from ENCODER & put the value in OLD.
         	movf	PORTB,W
         	movlw   _old
    
         	;Strip off all but the last  2 LSBs in OLD.
    		movlw	0x03				;Create bit mask for 2 LSBs (bits 6 & 7). 11000000
         	andwf	_old,F          	;Zero bits 0 thru 6.
    
    		;Read latest input from ENCODER & put the value in NEW.
        	movf    PORTB,W
         	movwf	_new
    
         	;Strip off all but the 2 LSBs in OLD.
    		movlw	0x03				;Create bit mask for 2 LSBs (bits 6 & 7). 11000000
         	andwf   _new,F     			;Zero bits 0 thru 6.
    
    
    
    
    
         	movf	_new,W				;Move the contents of NEW to TEMP and OLD to W
         	movwf   _temp      			;in order to compare them with XOR.
         	movf    _old,W     
         	xorwf   _temp,F    			;XOR previous inputs (in W) with latest inputs 
                             			;(in TEMP) to see if they are equal.
         	btfsc   STATUS,Z  			;Test result and skip next line if 0.
         	
         	GoTo	rtrn				;Result is 0.  Previous inputs equal latest 
                             			;inputs.  Rotary encoder did not move.  Return
                             			;to loop
         	
        	;Result is 1.  Rotary encoder moved.  Determine direction.
         	bcf		STATUS,C  			;Clear the carry bit in the status register and
         	rlf     _old,F     			;left shift it into OLD to align bit0 of OLD
                             			;with bit 1 of NEW.
         	movf    _new,W     			;Move the contents of NEW to W in order to XOR.
         	xorwf   _old,F    			;XOR previous inputs (in OLD) with latest
                             			;inputs (in W) to determine CW or CCW.
         	btfsc   _old,1     			;Test bit 1 of result (in OLD).  Skip next line
                             			;if it is 0 (direction is CCW).
         	GoTo    Up        			;Bit is 1 (direction is CW).  Go around Down
         	
         	
         	
    Down
         	;Decrements COUNTER because encoder moved CCW.
    
         	decf	_enc_counter,F 
         	bsf		_led
         	GoTo    rtrn  				;Branch around UP.
    
    Up
         	;Increments COUNTER because encoder moved CW.
    
         	incf    _enc_counter,F
         	bsf		_led2     	
                             			;and increment counter.
    
         	
    rtrn	bcf intcon.1				; clear interrupt flag 
    	    
    	    ; Restore PCLATH, STATUS and W registers
    		movf	psave, W
    		movwf	PCLATH
    		swapf	ssave, W
    		movwf	STATUS
    		swapf	wsave, F
    		swapf	wsave, W
    		retfie
    		EndAsm
     
    start:
    		
    		'SerOut PORTC.0,T9600,[#enc_counter,10,13]
    		TRISB=%00111111
    		TRISC=%00000000
    		Low led 	
    		Low led2				' Turn LED off
    		INTCON = %10010000		' Enable INTERRUPT ON portb INT0
    		option_reg=%01110000
          	
    loop: 	
    		'INTCON = %00000000
    		'LCDOut $fe,1,DEC enc_counter
    		'Pause 4
    		'INTCON = %10010000
    		Low led
    		Low led2
    		GoTo loop
    Last edited by ice; - 11th May 2005 at 11:41.

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


    Did you find this post helpful? Yes | No

    Thumbs down

    Hi!

    If you use INT0 you will lose encoder counts.
    See my Incremental quadrature encoder direction drawing.
    (File encoder.zip posted the 9th April 2005, 13:44).

    The two encoder signals A/B have to be connected to two of
    the PINs RB<7:4> which have an interrupt-onchange feature.

    * * *
    When I post a code sample, the code is well formatted and
    there are no dead commented statements.(I do my best).
    Do you think that people on this forum will spend time
    reading your code if it is not formatted?

    * * *

    See thread LCDOUT & interrupts.
    http://www.picbasic.co.uk/forum/show...dout+interrupt

    * * *

    Luciano

  5. #5
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Default

    Luciano,
    I switched to portB.6 and 7 for interrupt on change and modified the code

    However i cannot decode direction now.I use LEDs to display direction..Now only one of them lights for both directions.Thanks.

    **
    i'm sorry abt my code being all garbled.Ive done my best this time.
    **


    Code:
    movf	PORTB,W
    movlw    _old
    
    ;Strip off all but the last  2 MSBs in OLD.
    movlw	0xc0				
    andwf	_old,F   
           	
    ;Read latest input from ENCODER & put the value in NEW.
    movf    PORTB,W
    movwf	_new
    
    ;Strip off all but the 2 MSBs in NEW
    movlw	0xc0
    andwf   _new,F     			
    
    movf    _new,W	  ;Move the contents of NEW to TEMP and OLD to W
    movwf  _temp      ;in order to compare them with XOR.
    movf    _old,W     
    xorwf   _temp,F   ;XOR previous inputs (in W) with latest inputs 
                             	;(in TEMP) to see if they are equal.
    btfss   STATUS,Z  ;Test result and skip next line if 0.
         	
    GoTo	rtrn	  ;Result is 0.  Previous inputs equal latest 
                      ;inputs.  Rotary encoder did not move.  Return
                      ;to loop
    
    bcf       STATUS,C  ;Clear the carry bit in the status register and
    rlf         _old,F  ;left shift it into OLD to align bit6 of OLD
              	    ;with bit7 of NEW.
    movf    _new,W      ;Move the contents ofNEW to W in order to XOR.
    xrwf    _old,F      ;XOR previous inputs (in OLD) with latest
                	    ;inputs (in W) to determine CW or CCW.
    btfss   _old,7      ;Test bit 1 of result (in OLD).  Skip next line
    	            ;if it is 0 (direction is CCW).
    GoTo    Up          ;Bit is 1 (direction is CW).  Go around Down
         	
    Down
    ;Decrements COUNTER because encoder moved CCW.
    decf	_enc_counter,F 
    bsf	_led	    ;light CCW LED 
    GoTo      rtrn      ;Branch around UP.
    
    Up
    ;Increments COUNTER because encoder moved CW.
    incf       _enc_counter,F    ;and increment counter.
    bsf	_led2       ;light CW LED	
    
    rtrn	bcf intcon.0	;clear interrupt flag on portBinT

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


    Did you find this post helpful? Yes | No

    Default

    Hi,

    Below is one part of the interrupt assembly code.
    (I have tested the code with the MPLAB simulator).

    This is not the end of the difficulties.

    I can help (the forum can help) if you do the following:

    Write a PicBasic program that displays on the LCD the
    rotary encoder count. The program will use an
    interrupt-onchange in assembly for the encoder.
    (Please write a new well formatted program).

    The assembly code I have posted today is only one
    part of the code you will need in the interrupt routine.
    BEFORE my code you will have to save the processor context.
    AFTER my code you will have to restore the processor context.
    See PicBasic manual '9.3. Interrupts in Assembler' for
    everything else you will need in order to use an interrupt
    in assembly.

    For now do not modify my code. Add everything, also the
    two comment lines. (Cut & Paste).
    (;====== BEGINNING OF THE ROTARY ENCODER CODE ========)
    (;========= END OF THE ROTARY ENCODER CODE ===========)

    If you like you can add the code for the two LEDs CCW and CW.
    See comments in the code for the LEDs.

    In my code I use 3 variables that you will have to declare
    in your PicBasic program. These variables have new names.
    (Not the same names you have used in your code).
    I don't like names like 'new' because 'new' can be a
    reserved word for some compiler.

    The 3 variables are:

    enc_new VAR BYTE
    enc_old VAR BYTE
    enc_counter VAR WORD

    Set to 0 (zero) the variable enc_old when you power up
    the PIC, before you enter the main loop of your PicBasic
    program. This is not necessary but it will help you to
    understand how this variable is used.


    * * *

    From your post of the 6th May 2005, 12:06

    ....im using a 16F873A,which has a 4K flash,meaning 4 banks...
    according to the PBP manual, i have to define wsave,wsave1,wsave2,wsave3...
    it takes in wsave and wsave1...but when i declare wsave2 and wsave3..it gives a RAM_END 255 error


    From the PicBasic manual
    2.2. Your First Program

    If you don’t tell it otherwise, the PicBasic Pro Compiler defaults to
    creating code for the PIC16F84. To compile code for PICmicro MCUs
    other than the PIC16F84, simply use the -P command line option
    described later in the manual to specify a different target processor. For
    example, if you intend to run the above program, BLINK.BAS, on a
    PIC16F877, compile it using the command:

    PBP -p16f877 blink

    So verify what you need for the 16F873A.

    Luciano

    Code:
    	;====== BEGINNING OF THE ROTARY ENCODER CODE ========
    	;The Rotary Encoder is connected to PORTB  
    	;The A signal of the encoder connected to the PIN portB.7
    	;The B signal of the encoder connected to the PIN portB.6
    	;
    	;The 3 variables used are declared in the PicBasic code.
    	;
    	;	enc_new VAR BYTE
    	;	enc_old VAR BYTE
    	;	enc_counter VAR WORD
    	;
    	;================================================
    		
    	;Read latest input from PORTB & put the value in _enc_new.
    
         	movf    PORTB,W
         	movwf  _enc_new
    
         	;Strip off all but the 2 MSBs in _enc_new.
    
         	movlw	B'11000000'	;Create bit mask (bits 7 & 6).
         	andwf   _enc_new,F     	;Zero bits 5 thru 0.
    
         	;Determine the direction of the Rotary encoder.  
    
         	rlf     _enc_old,F     	;left shift it into _enc_old to align bit 6 of 
                                    ;_enc_old with bit 7 of _enc_new.
    
         	movf    _enc_new,W     	;Move the contents of _enc_new to W in order to XOR.
         	xorwf   _enc_old,F    	;XOR previous inputs (in _enc_old) with latest
                                    ;inputs (in W) to determine CW or CCW.
     
          	btfsc   _enc_old,7     	;Test bit 7 of result (in _enc_old).  Skip next line
                             	;if it is 0 (direction is CCW).
         	goto    Up        	;Bit is 1 (direction is CW).  Go around Down
                             	;and increment counter.
    
    
    Down
         	;Decrements _enc_counter because the rotary encoder moved CCW.
    	;Decrements _enc_counter (16 bit value), sets Z on exit.
    	     	 
            decf    _enc_counter,F      ; Decrement low byte
            incfsz  _enc_counter,W      ; Check for underflow
            incf    _enc_counter+1,F    ; Update
            decf    _enc_counter+1,F    ; Fixup
            movf    _enc_counter,W
            iorwf   _enc_counter+1,W    ; Set Z bit
    		
    	;Add here code for the CCW LED if needed.
         	
         	goto    Continue  	    ;Branch around UP.
    
    Up
         	;Increments _enc_counter because the rotary encoder moved CW.
    	;Increments _enc_counter (16 bit value), sets Z on exit.
    
            incfsz  _enc_counter,W      ; Add one to low byte
            decf    _enc_counter+1,F    ; No carry (negates next step)
            incf    _enc_counter+1,F    ; Add one to high byte
            movwf   _enc_counter        ; Store updated low byte back.
            iorwf   _enc_counter+1,W    ; Set Z flag
    		
    	;Add here code for the CW LED if needed.
    	
    Continue 
         	
         	;Assign the latest encoder inputs (in _enc_new) to _enc_old.
    
         	movf 	_enc_new,W
         	movwf   _enc_old
    
    	;============ END OF THE ROTARY ENCODER CODE =====
    Last edited by Luciano; - 12th May 2005 at 23:20.

  7. #7
    ice's Avatar
    ice Guest


    Did you find this post helpful? Yes | No

    Thumbs up Working!!

    Thank you so much Luciano...

    The code is..
    working good ,
    direction decoding ok
    counting on LCD[no garbage,dispays properly]


    A few questions
    1>You never clear the Int on PortB change flag in the interrupt.is it because your reading from portB,which is one of the ways to clear the flag.

    2>retfie.. Neither is the retfie used to return from where the program left.

    3>why didnt my program work ,when i used the INT0 interrupt.I cant figure it out.


    4>I use CodeDesigner Lite as an IDE.I get t0 select the chip from a drop down menu.I select 16f873a.I even put the line PBP -p16F873A in the command line option,but the error on using wsave2 and wsave3,still persists.


    Working with enc_counter on 16 bits is a bit difficult to work on the current project.I need 32 bits.so back to my code.

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 : 1

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