News:

Let's find out together what makes a PIC Tick!

Main Menu

Quadrature (rotary) encoder example

Started by RGV250, Jun 18, 2023, 08:43 AM

Previous topic - Next topic

RGV250

Hi,
I am looking at a quadrature encoder, I wondered if anyone has an example before I spend too much time looking.

Regards,
Bob

basiclover


flosigud

Here is one. Uses IOC interupt and reads two encoders.
'    -------------------------------------------------------------
'    Name    : Quadrature.BAS
'    Author    : Flosi Guðmundssn
'    Notice    : Copyright (c) 2017 Flosi Guðmundsson
'            : All Rights Reserved
'    Date    : 2.4.2017
'    Version : 1.0
'    Notes    : Interrupt on Change is used to read two quadrature
'            : encoders and increment counter. Mainloop sends
'            : result serially over Bluetooth to TouchDRO app.
'    -------------------------------------------------------------
     Device 18F26K22
    Declare Xtal 80
    Symbol PLLEN = OSCTUNE.6                    ' PLL enable
    Symbol PLLRDY = OSCCON2.7                    ' PLL run status
    PLLEN=1                                        ' Enable PLL 4x 16MHz = 64Mhz
    While PLLRDY=0:Wend                            ' Wait until PLL is stable
'    Include "18f26k22intosc64.Inc"
    Declare Hserial_Baud = 115200
    Declare Reminders = Off
'    Declare Optimiser_Level 3
    Declare Dead_Code_Remove = On
   
    On_Hardware_Interrupt Interrupt_handler

    TRISA = %00000000
    TRISB = %11110011                        ' Quadrature inputs, Int0, Int1
    TRISC = %00000000

    Symbol GIE = INTCON.7                    ' Global Interrupt Enable
    Symbol PEIE = INTCON.6                    ' Periferal Interrupt Enable
    Symbol IPEN = RCON.7                    ' Interrupt Priorty Enable

    Dim wFSR1 As FSR1L.Word                    ' Used for look up table

'    Setup for Interrupt On Change for PortB 6-7
'    ----------------------------------------------------------------------------

    Symbol RBIF = INTCON.0
    Symbol RBIE = INTCON.3

'    Setup for Int0
'    ----------------------------------------------------------------------------

    Symbol INT0F = INTCON.1
    Symbol INT0IE = INTCON.4
    Symbol INTEDG0 = INTCON2.6
   
'    Setup for Int1
'    ----------------------------------------------------------------------------

    Symbol INT1F = INTCON3.0
    Symbol INT1IE = INTCON3.3
    Symbol INTEDG1 = INTCON2.5

'    PortB pullups
'    ------------------------------------------------------------------------

    Symbol NOT_RBPU = INTCON2.7
    IOCB = $F0                                 ' PortB 7-4 used
    NOT_RBPU = 0                            ' PortB pullups on

'    Enable interrupts
'    ----------------------------------------------------------------------------

    IPEN = 0                                ' Interrupt priority OFF
    GIE = 1                                    ' Global Interrupt enable
    PEIE = 1                                ' Enable peripheral enable
    INT0IE = 1                                ' Int0 Interrupt Enable
    INT1IE = 1                                ' Int1 Interrupt Enable
    RBIE = 1                                ' PortB Interrupt Enable

'
'    Look up table for incrementing or decrementing the counter   
'    and pointer to look up table
'    ----------------------------------------------------------------------------

    Dim tLookUp[16] As SByte = 0,-1,1,2,1,0,2,-1,-1,2,0,1,2,1,-1,0
    wFSR1 = VarPtr tLookUp

    Dim bNewX As Byte
    Dim bNewZ As Byte
    Dim bOldX As Byte
    Dim bOldZ As Byte

    Dim swCntX As SWord                     ' values to increment/decrement
    Dim swCntZ As SWord
    Dim sbInc As SByte                         ' value of increment,0,1,-1

'    Dim bTmp As Byte
    Dim fCntReady As Bit
   
    swCntX = 0
    swCntZ = 0

    While 1 = 1
        While fCntReady = 0 : Wend
        fCntReady = 0
        HRSOut "x",SDec swCntX,";","Z",SDec swCntZ,";",10   
    Wend

Interrupt_handler:
    Context Save
    If RBIF = 1 Then                        ' On RBIF interrupt
        RBIF = 0
        Swapf PORTB,WREG                    ' WREG 3-0 = PORTB 7-4
        bNewZ =    WREG
        bNewX = WREG & 3                    ' bNewX = PortB 4,5
        Ror bNewZ
        Ror bNewZ
        bNewZ = bNewZ & 3                    ' bNewZ = PortB 6,7

        If bNewX <> bOldX Then
            bOldX = bOldX * 4
            WREG = bOldX + bNewX            ' Index to table
            sbInc = PLUSW1                    ' Get element
            bOldX = bNewX                     ' update old value
            swCntX = swCntX + sbInc            ' change count
            Set fCntReady
        EndIf
        If bNewZ <> bOldZ Then
            bOldZ = bOldZ * 4
            WREG = bOldZ + bNewZ            ' Index to table
            swCntZ = swCntZ + PLUSW1
            sbInc = PLUSW1                    ' Get element
            bOldZ = bNewZ                     ' update old value
            swCntZ = swCntZ + sbInc            ' change count
            Set fCntReady
        EndIf
        RBIF=0
    EndIf
    If INT0F=1 Then                            ' Push button X to clear
        INT0F=0
        swCntX = 0
        Set fCntReady
    EndIf
    If INT1F=1 Then                            ' Push button Z to clear
        INT1F=0
        swCntZ = 0
        Set fCntReady
    EndIf
    Context Restore       

RGV250

Hi Basiclover,
I have got Les's code working but wondered if there will be an issue if the PIC has a lot to do. It is running on a PIC24 at 80mhz so probably not an issue?

Hi Flosigud,
I will have a look at your code later as it would be nice to have both options.

Regards,
Bob

basiclover

@ RGV250
Good news that LES's code works for you. I think a faster pic would be rather a benefit
I'am interested in your findings about rotary encoders.I assume you didn't forget the debouncing RC on the 2 pins

flosigud

My program was written with speed in mind on 18f25k22. It would need major rewrite to work on 24f.Some 16 bit PICs have hardware encoders that should be fast enough.

RGV250

Hi,
I haven't put the caps in as it will be difficult due to the board design, I will keep an eye on it and see if I need it but so far so good using the serial port to show the count and direction. I am only thinking of menu's and things like that so probably not a great issue if it does miss a step.

I did wonder if it would be possible to modify for the 24HJ, the one I have does not have hardware encoders, at least I have the basis to work on if it is possible to change. It will be good to get into PIC24 interrupts as I have only just started with them really.

Bob