Quadrature encoder and ASM Interrupts. questions..


Closed Thread
Results 1 to 11 of 11

Hybrid View

  1. #1
    godfodder's Avatar
    godfodder Guest


    Did you find this post helpful? Yes | No

    Smile

    I just implemented the changes Darrel suggested and IT WORKS!!! works really well! Thank you again!

    I also solved my problem of the encoder routine counting by 4's, added a little asm in the
    beginning that checks to see if the encoder has moved, my first bit of asm I've made.. slowly
    getting a handle on things.. I also made sure to set portb<5:4> bits to outputs so they don't float.
    here is the working code if anyone needs it. the connection diagram is the same as
    my first post.

    Code:
    'Read Quadrature Encoder and display value on LCD. for pic16f876a
    
    'setup PIC Config Fuses
        @ Device pic16F876A, HS_OSC, BOD_OFF, PWRT_ON, WDT_OFF, PROTECT_OFF
    
    '************************ DEFINES HERE *************************************
    DEFINE OSC 20               ' set to 20mhz
    DEFINE LCD_DREG PORTA       ' Set Data Registers port
    DEFINE LCD_DBIT 0           ' Set starting data bit
    DEFINE LCD_RSREG PORTB      ' Set LCD RS Port
    DEFINE LCD_RSBIT 1          ' Set LCD RS Bit
    DEFINE LCD_EREG PORTB       ' Set LCD Enable Port
    DEFINE LCD_EBIT 2           ' Set LCD Enable Bit
    DEFINE LCD_BITS 4           ' Set LCD 4bit Mode
    DEFINE LCD_LINES 2          ' Set number of LCD Lines
    DEFINE LCD_COMMANDUS 2000   ' Set Command Delay time in uS
    DEFINE LCD_DATAUS 60        ' Set Data delay time in uS 
    
    clear                       'clear out variables
    
    '*********************** CHIP REGISTER SETUP *******************************
    
    ADCON0 = 7              ' turn off analog porta, set to digital IO
    ADCON1 = 7              '
    CMCON =  7              ' Turn off Port A Comparator
    TRISA = 0               ' output ports
    TRISB = %11000001       ' set input and output ports
    TRISC = 0               ' output ports
    
    '************************ PROGRAM VARIABLES HERE ***************************
    
    symbol led = portc.2        ' status led
    symbol led2 = portc.0       ' status led2
    symbol lcdbkl = portc.7     ' lcd pannel backlight
    symbol sw1 = portb.0        ' encoder switch
    
    enc_old VAR BYTE
    enc_new VAR BYTE
    enc_tmp var byte
    enc_counter VAR WORD
    enc_counter_old VAR WORD
    enc_scaler var word
    
    
    
    
    '*********************** ASSEMBLY INTERUPT VARIABLES ***********************
    wsave   var     byte $20 system
    wsave1  var     byte $a0 system  ' Necessary for devices with RAM in bank1
    wsave2  var     byte $120 system ' Necessary for devices with RAM in bank2
    wsave3  var     byte $1a0 system ' Necessary for devices with RAM in bank3
    ssave   var     byte bank0 system
    psave   var     byte bank0 system     
    
    goto start			'skip over interupt handler
    '*********************** ASSEMBLY INTERUPT HANDLER *************************
    
    define  INTHAND myint
    Asm
           
    myint 
    	; Save W, STATUS and PCLATH registers
    	; Not Necessary for Chips with >2k of Codespace
           ; movwf   wsave
           ; swapf   STATUS, W
           ; clrf    STATUS
           ; movwf   ssave
           ; movf    PCLATH, W
           ; movwf   psave  
             
    
    
    
    	;====== 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 4 variables used are declared in the PicBasic code.
    	;
    	;	enc_new VAR BYTE
    	;	enc_old VAR BYTE
    	;       enc_tmp 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	0xc0    	     ;Create bit mask (bits 7 & 6). b'11000000' ?
         	andwf   _enc_new,F       ;Zero bits 5 thru 0.
    
            ;check to see if encoder has moved
            movf    _enc_old,W         ;move enc_old to W
            movwf   _enc_tmp           ;put W to enc_tmp
            movf    _enc_new,W         ;move enc_new to W for XOR
            xorwf   _enc_tmp,F         ;XOR enc_tmp to detect encoder movement
            btfsc   _enc_tmp,7         ;if bit is clear, encoder moved.
            goto    Continue           ;no movement exit isr
    
         	;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.
         	bsf     _led		    ;turn on led
         	
         	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.
    	   bsf     _led2		    ;turn on led
    	
    Continue     	
         	;Assign the latest encoder inputs (in _enc_new) to _enc_old.
         	movf 	_enc_new,W
         	movwf   _enc_old
    
            ; Restore saved registers
            movf    psave, W
            movwf   PCLATH
            swapf   ssave, W
            movwf   STATUS
            swapf   wsave, F
            swapf   wsave, W
            bcf     INTCON, RBIF		  ; Clear the Interupt Flag
            RETFIE                 	  	  ; Return from interrupt
    endasm
    
    '***************************************************************************
    '************************* PROGRAM STARTS HERE *****************************
    '***************************************************************************
    
    START:              ' Main Program starts here
    
    LCDOUT $FE,1		'Init The LCD
    pause 500		    'wait for LCD to start 
    
    lcdout $FE,1,"ENCODER"	    'display splash screen
    LCDOUT $FE,$C0," TEST "       
    high lcdbkl                 ' turn on backlight
    
    
    '************************** SET DEFAULT SETTINGS HERE **********************
    pause 2000		    ' just wait a bit to read splash screen
    enc_counter = 1024	' set default encoder value
    enc_counter_old = 1024	
    
    lcdout $FE,1,"ENCODER"  ' change display
    lcdout $fe,$C0, DEC5 enc_counter
    INTCON = %10001000      ' Enable PortB Change Interupts  
    
    
    '************************** TESTING ROUTINES HERE **************************
    test:
                if  enc_counter <> enc_counter_old then 'see if value has changed
                    enc_counter_old = enc_counter		'move new value to old
                    lcdout $fe,$C0, DEC5 enc_counter	'display enc_counter value
                    low led		                        'turn off CCW led
                    low led2	                        'turn off CW led
                endif
    goto test

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    WooHoo! We're on a roll.

    People maken stuff happen ... I love it!

    Stick around godfodder.
    <br>
    DT

  3. #3


    Did you find this post helpful? Yes | No

    Default

    After trying your code I got the following compiler error ?

    Warnin[207] C:\pbp..... Filename.asm 81 : Found label after column 1. (Device)
    Error[122] C:\pbp........ Filename.asm 81 : Illegal opcode (Pic16F876A)

    Any idea ?

    PBP2.50 and MPASM

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by RFsolution View Post
    Any idea ?
    DEVICE statements are for the PM assembler.

    You could compile it with PM, or change them to __config's for MPASM.
    <br>
    DT

  5. #5


    Did you find this post helpful? Yes | No

    Default Re: Quadrature encoder and ASM Interrupts. questions..

    Quote Originally Posted by godfodder View Post
    I just implemented the changes Darrel suggested and IT WORKS!!! works really well! Thank you again!

    I also solved my problem of the encoder routine counting by 4's, added a little asm in the
    beginning that checks to see if the encoder has moved, my first bit of asm I've made.. slowly
    getting a handle on things.. I also made sure to set portb<5:4> bits to outputs so they don't float.
    here is the working code if anyone needs it. the connection diagram is the same as
    my first post.

    Code:
    'Read Quadrature Encoder and display value on LCD. for pic16f876a
    
    'setup PIC Config Fuses
        @ Device pic16F876A, HS_OSC, BOD_OFF, PWRT_ON, WDT_OFF, PROTECT_OFF
    
    '************************ DEFINES HERE *************************************
    DEFINE OSC 20               ' set to 20mhz
    DEFINE LCD_DREG PORTA       ' Set Data Registers port
    DEFINE LCD_DBIT 0           ' Set starting data bit
    DEFINE LCD_RSREG PORTB      ' Set LCD RS Port
    DEFINE LCD_RSBIT 1          ' Set LCD RS Bit
    DEFINE LCD_EREG PORTB       ' Set LCD Enable Port
    DEFINE LCD_EBIT 2           ' Set LCD Enable Bit
    DEFINE LCD_BITS 4           ' Set LCD 4bit Mode
    DEFINE LCD_LINES 2          ' Set number of LCD Lines
    DEFINE LCD_COMMANDUS 2000   ' Set Command Delay time in uS
    DEFINE LCD_DATAUS 60        ' Set Data delay time in uS 
    
    clear                       'clear out variables
    
    '*********************** CHIP REGISTER SETUP *******************************
    
    ADCON0 = 7              ' turn off analog porta, set to digital IO
    ADCON1 = 7              '
    CMCON =  7              ' Turn off Port A Comparator
    TRISA = 0               ' output ports
    TRISB = %11000001       ' set input and output ports
    TRISC = 0               ' output ports
    
    '************************ PROGRAM VARIABLES HERE ***************************
    
    symbol led = portc.2        ' status led
    symbol led2 = portc.0       ' status led2
    symbol lcdbkl = portc.7     ' lcd pannel backlight
    symbol sw1 = portb.0        ' encoder switch
    
    enc_old VAR BYTE
    enc_new VAR BYTE
    enc_tmp var byte
    enc_counter VAR WORD
    enc_counter_old VAR WORD
    enc_scaler var word
    
    
    
    
    '*********************** ASSEMBLY INTERUPT VARIABLES ***********************
    wsave   var     byte $20 system
    wsave1  var     byte $a0 system  ' Necessary for devices with RAM in bank1
    wsave2  var     byte $120 system ' Necessary for devices with RAM in bank2
    wsave3  var     byte $1a0 system ' Necessary for devices with RAM in bank3
    ssave   var     byte bank0 system
    psave   var     byte bank0 system     
    
    goto start			'skip over interupt handler
    '*********************** ASSEMBLY INTERUPT HANDLER *************************
    
    define  INTHAND myint
    Asm
           
    myint 
    	; Save W, STATUS and PCLATH registers
    	; Not Necessary for Chips with >2k of Codespace
           ; movwf   wsave
           ; swapf   STATUS, W
           ; clrf    STATUS
           ; movwf   ssave
           ; movf    PCLATH, W
           ; movwf   psave  
             
    
    
    
    	;====== 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 4 variables used are declared in the PicBasic code.
    	;
    	;	enc_new VAR BYTE
    	;	enc_old VAR BYTE
    	;       enc_tmp 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	0xc0    	     ;Create bit mask (bits 7 & 6). b'11000000' ?
         	andwf   _enc_new,F       ;Zero bits 5 thru 0.
    
            ;check to see if encoder has moved
            movf    _enc_old,W         ;move enc_old to W
            movwf   _enc_tmp           ;put W to enc_tmp
            movf    _enc_new,W         ;move enc_new to W for XOR
            xorwf   _enc_tmp,F         ;XOR enc_tmp to detect encoder movement
            btfsc   _enc_tmp,7         ;if bit is clear, encoder moved.
            goto    Continue           ;no movement exit isr
    
         	;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.
         	bsf     _led		    ;turn on led
         	
         	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.
    	   bsf     _led2		    ;turn on led
    	
    Continue     	
         	;Assign the latest encoder inputs (in _enc_new) to _enc_old.
         	movf 	_enc_new,W
         	movwf   _enc_old
    
            ; Restore saved registers
            movf    psave, W
            movwf   PCLATH
            swapf   ssave, W
            movwf   STATUS
            swapf   wsave, F
            swapf   wsave, W
            bcf     INTCON, RBIF		  ; Clear the Interupt Flag
            RETFIE                 	  	  ; Return from interrupt
    endasm
    
    '***************************************************************************
    '************************* PROGRAM STARTS HERE *****************************
    '***************************************************************************
    
    START:              ' Main Program starts here
    
    LCDOUT $FE,1		'Init The LCD
    pause 500		    'wait for LCD to start 
    
    lcdout $FE,1,"ENCODER"	    'display splash screen
    LCDOUT $FE,$C0," TEST "       
    high lcdbkl                 ' turn on backlight
    
    
    '************************** SET DEFAULT SETTINGS HERE **********************
    pause 2000		    ' just wait a bit to read splash screen
    enc_counter = 1024	' set default encoder value
    enc_counter_old = 1024	
    
    lcdout $FE,1,"ENCODER"  ' change display
    lcdout $fe,$C0, DEC5 enc_counter
    INTCON = %10001000      ' Enable PortB Change Interupts  
    
    
    '************************** TESTING ROUTINES HERE **************************
    test:
                if  enc_counter <> enc_counter_old then 'see if value has changed
                    enc_counter_old = enc_counter		'move new value to old
                    lcdout $fe,$C0, DEC5 enc_counter	'display enc_counter value
                    low led		                        'turn off CCW led
                    low led2	                        'turn off CW led
                endif
    goto test
    Re-opening this thread because I'm having trouble with my rotary encoder ISR routine also seemingly happening 4 times per detent. I thought I had a similar check on whether anything changed in my PBP ISR but for some reason MotorRPM is always incrementing by 4. Any ideas?

    Code:
    ' ***************************************************************
    ' [IOC - interrupt handler]
    ' ***************************************************************
    RotEncAdjust:
        New_Bits = PORTA & (%00000011)
    
        IF New_Bits = Old_Bits Then DoneRotEnc
    
        RotEncDir = New_Bits.1 ^ Old_Bits.0
        IF RotEncDir = 1 Then
            ; CW rotation - increase speed but only to a max of 'MaxDuty'
            IF MotorRPM < MaxDuty then MotorRPM = MotorRPM + 1
        Else
            ' CCW rotation - decrease speed to a min of 0
            IF MotorRPM > 0 Then MotorRPM = MotorRPM - 1
        EndIF
    
    DoneRotEnc:
        Old_Bits = New_Bits
    
        IOCAF.0 = 0                     ' Clear interrupt flags
        IOCAF.1 = 0
    
    @ INT_RETURN
    (A/B outputs of rotary encoder connected to PORTA.1/0)

Similar Threads

  1. Instant Int and encoder (Elect. Gearing)
    By boroko in forum mel PIC BASIC Pro
    Replies: 13
    Last Post: - 29th November 2009, 02:29
  2. Probe to read quadrature encoder with DT_INT need help
    By phoenix_1 in forum mel PIC BASIC Pro
    Replies: 11
    Last Post: - 31st August 2009, 20:43

Members who have read this thread : 0

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