News:

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

Main Menu

Quadrature encoder using interrupts

Started by RGV250, Jul 09, 2026, 07:28 PM

Previous topic - Next topic

RGV250

Hi,
I am having a bit of grief trying to convert some working code to use interrupts.
This is the working example from Les which I have converted to PIC24.
Device = 24HJ128GP502
Declare Xtal = 79.23
TRISA = 00000000000000
TRISB = 00000000000000
' Configure for internal 7.37MHz oscillator with PLL
' OSC pins are general purpose I/O
'
    Config FBS = BWRP_WRPROTECT_OFF, BSS_NO_FLASH, BSS_NO_BOOT_CODE
    Config FSS = SWRP_WRPROTECT_OFF, SSS_NO_FLASH, RSS_NO_SEC_RAM
    Config FGS = GWRP_OFF, GCP_OFF
    Config FOSCSEL = FNOSC_FRCPLL, IESO_OFF
    Config FOSC = POSCMD_NONE, OSCIOFNC_ON, IOL1WAY_OFF, FCKSM_CSDCMD
    Config FWDT = WDTPOST_PS256, WINDIS_OFF, FWDTEN_OFF
    Config FPOR = FPWRT_PWR128, ALTI2C_OFF
    Config FICD = ICS_PGD1, JTAGEN_OFF
   
PLL_Setup(43, 2, 2, $0300)                          ' Configure the Oscillator to operate the device at 79.23MHz

'------------------------------------------------
' USART1 declares
' Defult settings for Microstick Plus board
    Declare Hserial_Baud = 19200     
         
    Declare HRSOut1_Pin = PORTB.10           ' Select which pin is to be used for TX with USART1   
    PPS_Output(cOut_Pin_RP10, cOut_Fn_U1TX)  ' Make Pin RB10 U1TX

    Declare HRSIn1_Pin = PORTB.11            ' Select which pin is to be used for RX with USART1   
    PPS_Input(cIn_Pin_RP11, cIn_Fn_U1RX)     ' Make Pin RB11 U1RX
'------------------------------------------------   

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Rotary encoder reader using a bit-table decode mechanism
'
' Written by Les Johnson for the Positron8 BASIC compiler
'
 '   Device = 18F25K22                           ' Choose the device to compiler for
 '   Declare Xtal = 16                           ' Tell the compiler, the device will be running at 16MHz
'
' Setup USART1
'
 '   Declare Hserial_Baud = 9600
 '   Declare HRSOut_Pin = PORTC.6

    Symbol Enc_Pin1 = PORTB.6                   ' Connects to a pin on the rotary encoder
    Symbol Enc_Pin2 = PORTB.7                   ' Connects to the other pin on the rotary encoder
'
' Create some global variables for the rotary encoder read procedure
'
    Dim Enc_bValidValue As Byte                 ' Holds the previous valid reading from the rotary encoder
    Dim Enc_bStore As Byte                      ' Stores the previous manipulated value from the rotary encoder
    Dim Enc_wTable As Word = %0110100110010110  ' Holds the bit table for valid moves of the rotary encoder
'
' Create some variables for the demo
'
    Dim wCounter As SWord = 0
    Dim bEncValue As SByte

'---------------------------------------------------
' The main program starts here
' Read a rotary encoder and increment or decrement a variable depending on the direction of the rotation
' The value and the direction are transmitted to a serial terminal
'
Main:
    Enc_Setup()                                 ' Setup the program and the pins for the rotary encoder reading

    Do                                          ' Create a loop
        bEncValue = Enc_Read()                  ' Read the rotary encoder
        If bEncValue <> 0 Then                  ' Is the value read from it 0?
            wCounter = wCounter + bEncValue     ' No. So add the value to wCounter
            If bEncValue < 0 Then               ' Was the value read -1?
                HRSOut "CCW: "                  ' Yes. So display that is was counter-clockwise
            Else                                ' Otherwise... The value read was 1. So...
                HRSOut "CW:  "                  ' Display that is was clockwise
            EndIf
            HRSOutLn SDec wCounter              ' Display the count value on the serial terminal
        EndIf
    Loop                                        ' Do it forever

'---------------------------------------------------
' Read a rotary encoder
' Input     : Enc_Pin1 and Enc_Pin2 hold the pins used for the encoder
' Output    : A valid Clockwise or Anti-Clockwise move returns 1 or -1, an invalid move returns 0
' Notes     : None
'
Proc Enc_Read(), SByte   
    Result = 0                                      ' Default to a 0 return value
    Enc_bValidValue = Enc_bValidValue << 2          ' \
    Enc_bValidValue.0 = Enc_Pin1                    ' |
    Enc_bValidValue.1 = Enc_Pin2                    ' | Find the position of the encoder's pins
    Enc_bValidValue = Enc_bValidValue & %00001111   ' /

    If GetBit Enc_wTable, Enc_bValidValue <> 0 Then ' Is the move possibly valid?
        Enc_bStore = Enc_bStore << 4                ' Yes. So shift up by 4-bits
        Enc_bStore = Enc_bStore | Enc_bValidValue   ' Or in the pin positions
        If Enc_bStore = %00101011 Then              ' Is the encoder moving Anti-Clockwise?
            Result = -1                             ' Yes. So return a value of -1
        ElseIf Enc_bStore = %00010111 Then          ' Is the encoder moving Clockwise?
            Result = 1                              ' Yes. So return a value of 1
        EndIf
    EndIf
EndProc

'---------------------------------------------------
' Setup the pins and variables to read a rotary encoder
' Input     : None
' Output    : None
' Notes     : None
'
Proc Enc_Setup()
    Input Enc_Pin1                  ' \ Make sure the encoder pins are inputs
    Input Enc_Pin2                  ' /
' Pull ups not needed on the Microstick Plus board.   
'   PinPullup Enc_Pin1              ' \ Enable the internal pullup resistors on the encoder pins
'   PinPullup Enc_Pin2              ' /
    Enc_bValidValue = 0             ' Reset the valid value for the encoder pins
    Enc_bStore = 0                  ' Reset the stored value for the encoder pins
EndProc

I wanted to use it with some other code and decided it needed interrupts and have come unstuck.
I have used PPS to set the pins to external interrupts but I may have got that wrong.
I have added the interrupts but am virtually new to PIC24 so may have them wrong as well.
I could not find if I needed to unlock for PPS but tried both ways and still nothing.
With this code it does not appear to even go to the interrupts.
' ____/\\\\\\\\\_________/\\\\\\\\\\\\__/\\\________/\\\____/\\\\\\\\\_______/\\\\\\\\\\\\\\\______/\\\\\\\____       
'  __/\\\///////\\\_____/\\\//////////__\/\\\_______\/\\\__/\\\///////\\\____\/\\\///////////_____/\\\/////\\\__       
'   _\/\\\_____\/\\\____/\\\_____________\//\\\______/\\\__\///______\//\\\___\/\\\_______________/\\\____\//\\\_     
'    _\/\\\\\\\\\\\/____\/\\\____/\\\\\\\__\//\\\____/\\\_____________/\\\/____\/\\\\\\\\\\\\_____\/\\\_____\/\\\_     
'     _\/\\\//////\\\____\/\\\___\/////\\\___\//\\\__/\\\___________/\\\//______\////////////\\\___\/\\\_____\/\\\_   
'      _\/\\\____\//\\\___\/\\\_______\/\\\____\//\\\/\\\_________/\\\//____________________\//\\\__\/\\\_____\/\\\_   
'       _\/\\\_____\//\\\__\/\\\_______\/\\\_____\//\\\\\________/\\\/____________/\\\________\/\\\__\//\\\____/\\\__ 
'        _\/\\\______\//\\\_\//\\\\\\\\\\\\/_______\//\\\________/\\\\\\\\\\\\\\\_\//\\\\\\\\\\\\\/____\///\\\\\\\/___
'         _\///________\///___\////////////__________\///________\///////////////___\/////////////________\///////_____

Device = 24HJ128GP502
Declare Xtal = 79.23
TRISA = 00000000000000
TRISB = 00000000000000
' Configure for internal 7.37MHz oscillator with PLL
' OSC pins are general purpose I/O
'
    Config FBS = BWRP_WRPROTECT_OFF, BSS_NO_FLASH, BSS_NO_BOOT_CODE
    Config FSS = SWRP_WRPROTECT_OFF, SSS_NO_FLASH, RSS_NO_SEC_RAM
    Config FGS = GWRP_OFF, GCP_OFF
    Config FOSCSEL = FNOSC_FRCPLL, IESO_OFF
    Config FOSC = POSCMD_NONE, OSCIOFNC_ON, IOL1WAY_OFF, FCKSM_CSDCMD
    Config FWDT = WDTPOST_PS256, WINDIS_OFF, FWDTEN_OFF
    Config FPOR = FPWRT_PWR128, ALTI2C_OFF
    Config FICD = ICS_PGD1, JTAGEN_OFF
   
PLL_Setup(43, 2, 2, $0300)                          ' Configure the Oscillator to operate the device at 79.23MHz

'------------------------------------------------
' USART1 declares
' Defult settings for Microstick Plus board
    Declare Hserial_Baud = 19200     
         
    Declare HRSOut1_Pin = PORTB.10           ' Select which pin is to be used for TX with USART1   
    PPS_Output(cOut_Pin_RP10, cOut_Fn_U1TX)  ' Make Pin RB10 U1TX

    Declare HRSIn1_Pin = PORTB.11            ' Select which pin is to be used for RX with USART1   
    PPS_Input(cIn_Pin_RP11, cIn_Fn_U1RX)     ' Make Pin RB11 U1RX
   
   
' Set the encoder pins to external interrupts
    PPS_UnLock()   
    PPS_Input(cIn_Pin_RP6, cIn_Fn_INT1)     ' Make Pin RB6 Ext Interrupt 1
    PPS_Input(cIn_Pin_RP7, cIn_Fn_INT2)     ' Make Pin RB7 Ext Interrupt 2
    PPS_Lock()

' Rotary encoder reader using a bit-table decode mechanism
'
' Written by Les Johnson for the Positron8 BASIC compiler
'
 
    Symbol Enc_Pin1 = PORTB.6                   ' Connects to a pin on the rotary encoder
    Symbol Enc_Pin2 = PORTB.7                   ' Connects to the other pin on the rotary encoder
'
' Create some global variables for the rotary encoder read procedure
'
    Dim Enc_bValidValue As Byte                 ' Holds the previous valid reading from the rotary encoder
    Dim Enc_bStore As Byte                      ' Stores the previous manipulated value from the rotary encoder
    Dim Enc_wTable As Word = %0110100110010110  ' Holds the bit table for valid moves of the rotary encoder
'
' Create some variables for the demo
'
    Dim wCounter As SWord = 0
    Dim bEncValue As SByte

    Dim PosChanged As Byte                  ' For debugging

ISR_Start INT1Interrupt
    bEncValue = Enc_Read()                  ' Read the rotary encoder
        HRSOut "Int 1  "
    PosChanged = 1
    INTCON2bits_INT1EP = 0
ISR_End

ISR_Start INT2Interrupt
    bEncValue = Enc_Read()                  ' Read the rotary encoder
        HRSOut "Int 2  "
    PosChanged = 1
        INTCON2bits_INT2EP = 0
ISR_End

'---------------------------------------------------
' The main program starts here
' Read a rotary encoder and increment or decrement a variable depending on the direction of the rotation
' The value and the direction are transmitted to a serial terminal
'
Main:
    Enc_Setup()                                 ' Setup the program and the pins for the rotary encoder reading

    Do                                          ' Create a loop
   
    If PosChanged = 1 Then
    HRSOut "Pos changed  "                      ' For debugging
   
'        bEncValue = Enc_Read()                  ' Read the rotary encoder
        If bEncValue <> 0 Then                  ' Is the value read from it 0?
            wCounter = wCounter + bEncValue     ' No. So add the value to wCounter
            If bEncValue < 0 Then               ' Was the value read -1?
                HRSOut "CCW: "                  ' Yes. So display that is was counter-clockwise
            Else                                ' Otherwise... The value read was 1. So...
                HRSOut "CW:  "                  ' Display that is was clockwise
            EndIf
            HRSOutLn SDec wCounter              ' Display the count value on the serial terminal
        EndIf
       
        PosChanged = 0
        EndIf
    Loop                                        ' Do it forever

'---------------------------------------------------
' Read a rotary encoder
' Input     : Enc_Pin1 and Enc_Pin2 hold the pins used for the encoder
' Output    : A valid Clockwise or Anti-Clockwise move returns 1 or -1, an invalid move returns 0
' Notes     : None
'
Proc Enc_Read(), SByte   
    Result = 0                                      ' Default to a 0 return value
    Enc_bValidValue = Enc_bValidValue << 2          ' \
    Enc_bValidValue.0 = Enc_Pin1                    ' |
    Enc_bValidValue.1 = Enc_Pin2                    ' | Find the position of the encoder's pins
    Enc_bValidValue = Enc_bValidValue & %00001111   ' /

    If GetBit Enc_wTable, Enc_bValidValue <> 0 Then ' Is the move possibly valid?
        Enc_bStore = Enc_bStore << 4                ' Yes. So shift up by 4-bits
        Enc_bStore = Enc_bStore | Enc_bValidValue   ' Or in the pin positions
        If Enc_bStore = %00101011 Then              ' Is the encoder moving Anti-Clockwise?
            Result = -1                             ' Yes. So return a value of -1
        ElseIf Enc_bStore = %00010111 Then          ' Is the encoder moving Clockwise?
            Result = 1                              ' Yes. So return a value of 1
        EndIf
    EndIf
EndProc

'---------------------------------------------------
' Setup the pins and variables to read a rotary encoder
' Input     : None
' Output    : None
' Notes     : None
'
Proc Enc_Setup()
    Input Enc_Pin1                  ' \ Make sure the encoder pins are inputs
    Input Enc_Pin2                  ' /
' Pull ups not needed on the Microstick Plus board.   
'   PinPullup Enc_Pin1              ' \ Enable the internal pullup resistors on the encoder pins
'   PinPullup Enc_Pin2              ' /
    Enc_bValidValue = 0             ' Reset the valid value for the encoder pins
    Enc_bStore = 0                  ' Reset the stored value for the encoder pins
EndProc

Hopefully it is something pretty basic.

Regards,
Bob

charliecoutas

#1
Hi Bob

I don't know if this is any use, I'm sure the 24 series will be very similar....

    Device = 33EP512GP806                                               ;DSP with 52K ram 
    Declare Xtal = 140.03                                               ;
    PLL_Setup(76, 2, 2, $0300)

   
    $define In_Fn_U1RX    RPINR18bits_U1RXR                             ;assign UART1 to pins
    $define In_Pin_RPI41  41

    $define Out_Pin_RP100 RPOR9bits_RP100R
    $define Out_Fn_U1TX   1
       
    PPS_Unlock()
    PPS_Output(Out_Pin_RP100, Out_Fn_U1TX)                              ;make Pin RF4 (RP100) U1TX
    PPS_Input(In_Pin_RPI41, In_Fn_U1RX)                                 ;make Pin RB9 (RPI41) U1RX
    PPS_Lock()

    U1MODE = $8808
    U1MODEbits_UARTEN = 0                                               ;disable UARTEN bit
    U1STA = $00
    U1BRG = 1823                                                        ;baudRate = 9600
    U1MODEbits_UARTEN = 1                                               ;enable UARTEN bit
    U1STAbits_UTXEN = 1


; Example Int Rtn:

     Isr - T3Interrupt
            IFS0bits_T3IF = 0                                           ;clear Timer3 interrupt flag
            T3RUN = 0                                                    ;stop the timer which times the width of the audio pulse (144uS)
            audio_pulse = 0                                            ;turn the drive to the loudspeaker mosfet off again     
     EndIsr
   

RGV250

Hi Charlie,
Thanks for the reply, the serial output works fine as in the first example, strange that I did not need PPS lock/unlock?
The issue I am having is the encoder inputs as neither seem to work so I can only assume there is something wrong with the way I have done the PPS assign for the interrupts or the interrupt itself. Unfortunately they are quite different to the 8 bit I am used to.

I am starting to like the Microstick now I have found Pickit minus programs it and I found a Microstick plus board.

Regards,
Bob

top204

#3
A few things wrong with your code Bob.

There is no setups for the INT1 and INT2 interrupts in your code, so they are not enabled, or set for rising or falling triggering etc...

There is no logical pattern to the start of the code, and everything is all bunched together before the code starts. Take a look at my templates, and make a Setup procedure, that is called from the Main section, and the first in the Setup should be the oscillator configuration.

I'll see if I can dig out a PIC24H device tomorrow, and create a code listing for an encoder, but it is so darn hot here, it is difficult to even think straight, never mind actually do anything. :-) It must be crazy hot down in Kent! I know Rachel's mum is suffering from it down there.

Regards
Les

RGV250

Hi Les,
I was on the Isle of Man where it was supposed to be cooler but I still got burnt.

The only example I could find for PIC24 interrupts was Traps_Demo and that did not have any set up for the interrupts. I assume those ones are permanently enabled?

Regards,
Bob