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?
Question about multiplexing mechanical encoders
Re: Question about multiplexing mechanical encoders
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
This is the interupt service routine
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
'------------------------------------------------------------------------------
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
'------------------------------------------------------------------------------
-
- Posts: 69
- Joined: 23 Apr 2014 07:32
Re: Question about multiplexing mechanical encoders
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:
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?
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?