Rotary encoder with DT interrupts


Closed Thread
Results 1 to 34 of 34

Hybrid View

  1. #1
    Join Date
    Jun 2005
    Location
    West Australia
    Posts
    116


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Well, I found and tried another (new) 1788 but no difference. Fully isolating the programming cable and interface also made no difference, the fault persists.

    I then went to a 16F886 and made appropriate changes - works without 'resets' (with programming cable and interface attached as normal) and only some rare serial corruption but maintaining its RE count still, both CW and CCW. This tells me my hardware test setup is not at fault and the code is basically correct. So is there an issue with 16F1788's? Richard's setup hasn't identified any so I'm mystified. Below is what current code is:

    Code:
    
    '****************************************************************************************************
    '*  Name    : RE test WJS.pbp                                                                       *                                      
    '*  Author  : WJ Sherwood                                                                           *
    '*  Notice  : Copyright (c) 2021  	                                                                *
    '*          : All Rights Reserved                                                                   *
    '*  Date    : 07/02/21                                                                              *
    '*  Device  : 16F1788  [tests using 16F886 (and appropriate Reg changes) works correctly.]          *
    '*  Version : 1    (PBP 3.0.10.4)                                                                   *
    '*  Notes   : Spurious "I'm Alive" serial traffic following RE action (still) and corrupt chars if  *
    '*          : Pause at line 75 (following MaxLimit = 60) removed - what am I missing?               *
    '*          : 											                                            *
    '*          : REa portb.6, REb portb.5, REsw portb.4 all pulled up, active low.                     *
    '*          : 											                                            *
    '****************************************************************************************************
    
    '=========================================================================================================
    '        CONFIGURE DEVICE 
    '=========================================================================================================
    #CONFIG ; 16F1788.
            __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON &  _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
            __config _CONFIG2, _WRT_OFF & _VCAPEN_OFF & _PLLEN_OFF & _LVP_OFF & _BORV_HI & _LPBOR_OFF ;& _STVREN_OFF
    #ENDCONFIG
    
    '' What happens with a different PIC?
    '#CONFIG ; F886 
    '    __config _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _LVP_OFF & _CP_OFF
    '#ENDCONFIG
    
    ' -----[ Initialization F1788]--------------------------------------------------------------------------------- 
        TRISA = %00000000       ' Set I/O.
    '    TRISB = %01111111       ' Set I/O.
        TRISB = %01110000       ' Set I/O.  Only RE bits set as inputs.
        TRISC = %00000000       ' Set I/O.
    
    define  OSC  4
            OSCCON = %01101010   ' 4Mhz (F1788).
    'define  OSC  32
    '        OSCCON = %11110000   ; 32 MHz, 
    
        ANSELA = 0           ; all digital          
        ANSELB = 0           ; all digital 
    ' -------------------------------------------------------------------------------------------------------------- 
    
    '' -----[ Initialization F866]----------------------------------------------------------------------------------------------- 
    '    CM1CON0 = 0         	' Comparators off.
    '    ANSEL = %00000000       ' Make PortA AN0-AN7 digital.
    ''    ANSEL = %00000011       ' All digital except An0 and An1.
    '    TRISA = %00000000       ' Set I/O.
    
    '    CM2CON0 = 0         	' Comparators off.
    '    ANSELH = 0              ' Make PortB AN8-AN13 digital.
    
    '' PortB Int-On-Change: 1 = Int enabled. 0 = Int disabled.
    '    IOCB.0 = 0              ' No.
    '    IOCB.4 = 1              ' Yes, encoder pushbutton.
    '    IOCB.5 = 1              ' Yes, encoder Channel A.
    '    IOCB.6 = 1              ' Yes, encoder Channel B.
    '    IOCB.7 = 0              ' No.
    
    '    TRISB = %01110000       ' 4-6 encoder inputs.
    '    CCP1CON = %00000000     '
    
    '    TRISC = %00000000       ' Set I/O.
        
    ''    ADCON0 = %11001000      ' Set A/D to Frc, Channel 3, On (F88).                   
    '    ADCON0 = 0              ' Disable A/D.
    '    ADCON1 = %00000110      ' All digital.
    ''    ADCON1 = %10000000      ' R justify (where the 6 MSB of ADRESH read as 0 i.e. 10 bit), Vdd for Vref.
    
    '	Define 	OSC    4        ' Set Operating Frequency
    '    OSCCON = %01100000      ' 4Mhz (F886).
    
    ''    Define 	OSC    8        ' 
    ''    OSCCON = %01110000      ' 8Mhz (F886).
    
    '    INTCON = %10001000      ' Port B int on change and global interrupt enable. 
    
    '    clear                           ' ****** Clear statement must be before the INC file.******
    
    'wsave   VAR BYTE $70    SYSTEM      ' alternate save location for W 
    '' -------------------------------------------------------------------------------------------------------------- 
    
    ' Define LCD connections       
        DEFINE  LCD_DREG        PORTA  ' LCD Data Port
        DEFINE  LCD_DBIT        0      ' Starting Data Bit
        DEFINE  LCD_RSREG       PORTA  ' Register Select Port
        DEFINE  LCD_RSBIT       4	   ' Register Select Bit
        DEFINE  LCD_EREG        PORTA  ' Enable Port
        DEFINE  LCD_EBIT        7      ' Enable Bit
        DEFINE  LCD_BITS		4      ' Data Bus Size
        DEFINE  LCD_LINES       2      ' Number of Lines on LCD
    
    '=========================================================================================================
    '        PIN ASSIGNMENTS, SYSTEM CONSTANTS, TEMPORARY VARIABLES
    '=========================================================================================================
    ' Rotary Encoder stuff
    Old_Bits    VAR BYTE bank0  ' Encoder port bits before change.
    New_Bits    VAR BYTE bank0  ' Encoder port bits after change.
    RotEnc1_val VAR word bank0  ' Connected to PORTB<6:5>.
    MaxLimit    var word bank0  ' Used for setting upper limit for encoder counts.
    RotEncDir   VAR BIT  bank0  ' Direction of rotation bit.
    ButtPush    var bit  bank0  ' Flag shows button was pushed, allows quick exit from Int handler.
    REdec       var bit  bank0  ' Flag shows RE decrement, allows quick exit from Int handler.
    REinc       var bit  bank0  ' Flag shows RE increment, allows quick exit from Int handler.
    
    'Temp        var byte        ' Used for Int clearing by reading PortB. F886
                        
        Include "MODEDEFS.BAS"      ' Include Shiftin/out modes.
        INCLUDE "DT_INTS-14.bas"    ' Needs to be assembled with MPASM **********
        INCLUDE "ReEnterPBP.bas"    ; Include if using PBP interrupts	
    
        OPTION_REG.6 = 0        ' INTEDG set to interrupt on falling edge.
    '    OPTION_REG.6 = 1        ' INTEDG set to interrupt on rising edge.
    
    ' ----- F1788 -------------------------------------------------------------------------------------------------- 
    '   IOCBP = %01110000        ; REa portb.6, REb portb.5  pos edge trigger
       IOCBN = %01110000        ; REa portb.6, REb portb.5, REsw portb.4  neg edge trigger - falling edge only.
       IOCBF = 0                ; Reset the PortB flag.
       INTCON = %11001000       ; GIE, PEIE, IOCIE.
    ' -------------------------------------------------------------------------------------------------------------- 
       
    clear                        ' Clear all vars.
       
      MaxLimit = 60           ' Menu value limit.  
    '  pause 100               ' Let everything settle...
    
    serout2 PORTC.6, 16468, ["Power-on: ",BIN8 STATUS, "  -  ",BIN8 PCON,10,13]   ' thanks to Henrik.
    PCON = %00011111
    serout2 PORTC.6,16468,["Priming PCON: ",BIN8 STATUS,"  -  ",BIN8 PCON,10,13]
    serout2 PORTC.6,16468,[13,10,"I'm Alive",13,10,10]
    
    ' ----- F1788 -------------------------------------------------------------------------------------------------- 
    ASM
    INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
            INT_Handler    IOC_INT,  _Rot_Encoder,   PBP,  yes  ; Newer PICs.
        endm
        INT_CREATE              ; Creates the interrupt processor .
    ENDASM
    
    @    INT_ENABLE   IOC_INT   ; Newer PICs.
    ' -------------------------------------------------------------------------------------------------------------- 
    
    '' ----- F886 --------------------------------------------------------------------------------------------------- 
    'ASM
    'INT_LIST  macro    ; IntSource,         Label,  Type, ResetFlag?
    '        INT_Handler    RBC_INT,  _Rot_Encoder,   PBP,  yes
    '    endm
    '    INT_CREATE               ; Creates the interrupt processor
    'ENDASM
    
    '@    INT_ENABLE   RBC_INT     ; RB Port Change Interrupt
    '' -------------------------------------------------------------------------------------------------------------- 
    
    Old_Bits = PORTB & (%01100000)  ; RE uses B.6,B.5 - REa and REb.
    
    
    Main:   
      if PortB.4 = 0 then            ' Check if Encoder pushbutton was pushed.
      while PortB.4 = 0:wend         ' Wait for release.
      pause 50                       ' Debounce delay.
      serout2 PORTC.6,16468,[13,10,"ButtPush = 1, RE ",dec5 RotEnc1_val]
    'serout2 PORTC.6,16468,[13,10,BIN8 STATUS," - ",BIN8 PCON,10,13]   ' thanks to Henrik.
      endif
      
      if REdec or REinc = 1 then 
      serout2 PORTC.6,16468,[13,10,"RE_val ",dec5 RotEnc1_val]
      REdec = 0:REinc = 0           ' Reset the flags.  
      endif
      
    goto main                       ' endless loop waiting for INT. 
    
    
       
    '---[IOC - interrupt handler]---------------------------------------------------
    ' Don't forget 4 counts per detent (Quadrature).
    Rot_Encoder:
         New_Bits = PORTB & (%01100000)         ' Set port bits for Encoder's chosen A and B channels.
         IF (New_Bits & %01100000) = (Old_Bits & %01100000) then DoneRotEnc ' No change.
         RotEncDir = New_Bits.6 ^ Old_Bits.5    ' Bit XOR compare to get direction of rotation.
         if RotEncDir = 0 then                  ' CCW so decrement.
            if PORTB.6 and PORTB.5 = 1 then     ' Only when RE both pins high (convert quad counts to singles).
            RotEnc1_val = RotEnc1_val - 1       ' Decrement the count.
              if RotEnc1_val => 65530 then RotEnc1_val = 0  ' Limit the max.
              if RotEnc1_val <= 4 then RotEnc1_val = 0      ' Limit the min.
            REdec = 1                                       ' Flag the event.
            endif
         ELSE                                   ' RotEncDir = 1, CW so increment.
            if PORTB.6 and PORTB.5 = 1 then     ' Only when RE both pins high (convert quad counts to singles).
              RotEnc1_val = RotEnc1_val + 1     ' Increment the count.
              if RotEnc1_val >= MaxLimit then RotEnc1_val = MaxLimit ' Limit the count.
            REinc = 1                           ' Flag the event.
            endif                               
         ENDIF
    
    DoneRotEnc:
        Old_Bits = New_Bits
        INTCON.0 = 0        ; Clean up and exit - clear IOCIF. F1788
        IOCBF = 0           ; Reset the flag. F1788
    '    Temp = PORTB        ' Read PortB to clear the Int (F886).
    @ INT_RETURN
    
    end
    Next up I'm going to try a 16F1938 (and maybe some 18F's) but out of time now and it will have to wait for the weekend. While I can use the F886 for this project it gives me no confidence to use F1788's for Int duties in future until sorted.

    Cheers,
    Bill

  2. #2
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    A STACK Underflow condition is caused by more RETURNs than CALLs (GOSUBs). I have a suggestion; in your ISR Rot_Encoder: change
    Code:
    IF (New_Bits & 100000) = (Old_Bits & 100000) then DoneRotEnc ' No change.
    to
    Code:
    IF (New_Bits & 100000) = (Old_Bits & 100000) then 
    @ GOTO DoneRotEnc ; No change.
    ENDIF

  3. #3
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,115


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Mike, why your suggestion is not the same?

    Ioannis

  4. #4
    Join Date
    Apr 2014
    Location
    OK
    Posts
    557


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Louis stated there was a STACK Underflow flag set in the PCON Register. I looked over his/her posted code and the only place I could find where a CALL/RETURN mis-match could occur was in the posted line of code. By specifying a "GOTO" there, the Stack would not be modified with a RETURN PC Address. I suggested a test to eliminate the possibility of the STACK Underflow condition being caused by that line of code.

  5. #5
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,115


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    The
    Code:
    then DoneRotEnc
    is exactly the same as
    Code:
    then goto DoneRotEnc
    or
    Code:
    @ goto DoneRotEnc
    Or not?

    Ioannis

  6. #6
    Join Date
    May 2013
    Location
    australia
    Posts
    2,631


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    not to mention that mine ,same code same chip does not reboot
    Warning I'm not a teacher

  7. #7
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,115


    Did you find this post helpful? Yes | No

    Default Re: Rotary encoder with DT interrupts

    Then maybe a bad supply voltage, bad decoupling capacitors, bad breadboard connections...

    Ioannis

Similar Threads

  1. Rotary encoder subroutine
    By Fanias in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 10th October 2018, 13:13
  2. Using an incremental rotary encoder?
    By keithv in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 12th January 2016, 22:23
  3. Instant Interrupts for rotary encoder
    By fnovau in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 15th August 2014, 08:24
  4. New approach to Rotary Encoder
    By Ioannis in forum Code Examples
    Replies: 90
    Last Post: - 11th July 2013, 21:05

Members who have read this thread : 6

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