Question about multiplexing mechanical encoders

Discussion on projects that are created by users and posted on mikroElektronika website.
Post Reply
Author
Message
alvaroevc5
Posts: 69
Joined: 23 Apr 2014 07:32

Question about multiplexing mechanical encoders

#1 Post by alvaroevc5 » 02 Mar 2022 00:57

Hello MikroE people.

I was wondering if anyone knows a way of how to use multiple encoders with a low end microcontroller, like the PIC 18F2550.

I had the idea to multiplex them, but unfortunately, the cheap KY040 modules have NORMALLY CLOSED channels, which means that, if I multiplex it, every time the encoder turns back on it will trigger the interrupt pins it is connected to.

So I wouldn't know a way to do it correctly, or, if there is a commercial mechanical encoder out there similar in price, but NORMALLY OPEN. Optical encoders are just our of the radar, the cheapest ones are way too expensive for my application, unless there is a cheap one out there I don't know about with a built in pushbutton.

Any ideas?

MicroMark
Posts: 181
Joined: 11 Feb 2011 17:22

Re: Question about multiplexing mechanical encoders

#2 Post by MicroMark » 02 Mar 2022 02:00

You can easily do three encoders with the 18F2550. By using INT0, INT1 and INT2. Here's a code snippet with two encoders. For a third just add a routine for int0 in the ISR. This is cut and paste so you will need make adjustments for your app

Set up

Code: Select all

'==================================================================
SUB PROCEDURE INIT_INT
  TRISB.0  = 1    'INPUT INT0   uart PB.0
  TRISB.1  = 1    'INPUT INT1   Encoder Right
  TRISB.2  = 1    'INPUT INT2   Encoder left
  TRISB.3  = 1    'INPUT        Encoder Right
  TRISB.4  = 1    'INPUT        Button   Encoder Right
  TRISB.5  = 1    'INPUT        Encoder left
  TRISA.0  = 1    'INPUT        Button   Encoder left
  TRISA.1  = 1    'INPUT        Mode Button   Bottom
  INTCON = 0   'CLEAR REG
  INTCON.7 = 1 'ENABLE INTERUPTS   hi
  INTCON.6 = 1 'ENABLE INTERUPTS  low
  INTCON.4 = 1 'ENABLE INT0
  RCON.7  = 1 'interupt priorities enabled
  
  INTCON2 = 0 'Clear
  INTCON2.7 = 0 'int2 lo priority
  INTCON2.6 = 1 'INT0 ON RISING EDGE    Send uart PB.0   Automatic high priority
  INTCON2.5 = 1 'INT1 Edge
  INTCON2.4 = 1 'INT2 Edge   Encoder 1  PB.2
  INTCON2.3 = 0 'INT3 Edge
  INTCON2.2 = 0 'TMR0 priority
  INTCON2.1 = 0 'INT3 priority
  INTCON2.0 = 0 'RBIP priority
  
  INTCON3 = 0
  INTCON3.7 = 0 'int2 lo priority
  INTCON3.6 = 0 'int1 lo priority
  INTCON3.5 = 0 'Enable INT3 interupt
  INTCON3.4 = 1 'Enable INT2 interupt
  INTCON3.3 =1 'Enable INT1 interupt
  INTCON3.2 = 0 'INT3 flag
  INTCON3.1 = 0 'INT2 flag
  INTCON3.0 = 0 'INT1 flag
END SUB

'------------------------------------------------------------------------------
This is the interupt service routine

Code: Select all

Dim enc_counter1 as integer
Dim enc_counter2 as integer
'=============================================================================
sub procedure interrupt_low() iv 0x0018 ics ICS_AUTO
dim tick as byte 


tick = 1 ' Amount to inc or dec enc_counter

 'ENC INT1 -   Encoder AB outputs connected to RB1 and RB3   
  
 If  INTCON3.0 = 1  'INT1 flag = 1 then 'INT1 interrupt Triggered  PORTB.1


       IF PORTB.5 = 1 THEN     '=0 or = 1    'TO REVERSE COUNT		
    	 enc_counter1 = enc_counter1 + tick '  Count up
        		else
        			enc_counter1 = enc_counter1 - tick ' Count down
        		end if

                'LIMITS COUNT TO 0-100 change as needed
                IF enc_counter1 < 1 then    'MIN = 0
                       enc_counter1 = 0
                       end if
                IF enc_counter1 > 100 THEN' Max count =100
                  enc_counter1 = 0
                  end if



 'ENC INT2 -   Encoder AB outputs connected to RB2 and RB5   
  
 If INTCON3.1 = 1 then 'INT2 interrupt Triggered  PORTB.2


       IF PORTB.5 = 1 THEN     '=0 or = 1    'TO REVERSE COUNT		
    	 enc_counter2 = enc_counter2 + tick '  Count up
        		else
        			enc_counter2 = enc_counter2 - tick ' Count down
        		end if

                'LIMITS COUNT TO 0-100 change as needed
                IF enc_counter2 < 1 then    'MIN = 0
                       enc_counter2 = 0
                       end if
                IF enc_counter1 > 100 THEN' Max count =100
                  enc_counter2 = 0
                  end if
                  
            INTCON3.0 =  0 'CLEAR int1 flag
            INTCON3.1 =  0 'CLEAR int2 flag
  end if
end sub
'------------------------------------------------------------------------------

alvaroevc5
Posts: 69
Joined: 23 Apr 2014 07:32

Re: Question about multiplexing mechanical encoders

#3 Post by alvaroevc5 » 10 Mar 2022 23:59

It took me a while to figure out your code, specially because I program PICs with C, but I managed to digest it. I like the way that is being handled, it is quite practical, it works, but it has a bit of a flaw, not too critical though:
Encoder Signals.jpeg
Encoder Signals.jpeg (69.32 KiB) Viewed 1110 times
To explain myself, what you are doing in your code is:

If INT0 = 1 and RB5=1, that means RB5 got triggered first, because INT0 interrupt is what checks which encoder pins are being held high or low, that could be graphically described as going from right to left on the image above. (this is correct, because you are using both channels to determine encoder rotation orientation)

else: encoder is going in the opposite direction. (and here is where the flaw lies)

The reason why quadrature encoders use two channels is to determine precisely which direction the encoder it is turning, and for that, you have to check bot channels at the same time, which is graphically seen as the dashed vertical lines touching the two signals, and you do that by checking both pins after the second channel is activated, because then you have all the information necessary.

else: encoder is going in the opposite direction. ----------> with this, you could make a partial movement, not even entire step of the mechanical encoder, enough to trigger that one pin, and that would be enough to count it as a full step. If you look at the image, that would mean going from left to right on INT0 and assuming an entire step was made just with that flag, not taking into account if RB5 ever got triggered.

Once again, it is a practical solution, but my inner perfectionist engineer doesn't let me do that.

Any other ideas to multiplex or use multiple encoders properly?

Post Reply

Return to “User Projects”