PDA

View Full Version : Instant Interrupts for rotary encoder



fnovau
- 10th August 2014, 13:58
I want to use Darrel Taylor's interrupts for an application with 16F677 and PBP V2.47 to read steps with a

mechanical encoder with detent -Bourns ECW1JB24-B00024. I only have RA0 and RA3 available for reading outputs A and

B and I could use MC14490 for cleaning/debouncing A, B mechanical outputs if really necessary. I pretend to use

basic Ioannis idea seen at message -New approach to Rotary Encoder- I need to say I am a newcomer to assembler

language. My idea is to set 2 different interrupts: A associated with port RA0 and B with port RA3 to simplify

encoder reading. The basic idea is while one interrupt is on the other is disabled

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RAC_INT, _ENCODERA, PBP, yes
INT_Handler RAC_INT, _ENCODERB, PBP, yes
INT_CREATE ; Creates the interrupt processor

ENDASM

@ INT_ENABLE RAC_INT ; enable external RA interrupts
OPTION_REG.6=0 ;Int on falling edge. Is it possible?
IOCA.0=1 ;Enable INT A0
IOCA.3=1 ;Enable INT A3

'---[INT - interrupt handlers]---------------------------------------------------
ENCODERA:
IOCA.3=0 ;Disable INT A3
Pause 1 ;Avoid RA0 reading during bouncing
If PORTA.0=0 then
Counter=Counter+1
lcdout $fe,$c0,#Counter
Endif
while PORTA.0=0 or PORTA.3=0:Pause 1:wend ' while RA=0 standby + debounce time
IOCA.3=1 ;Enable INT A3
@ INT_ENABLE RAC_INT ; enable interrupts Is it necessary?

@ INT_RETURN

ENCODERB:
IOCA.0=0 ;Disable INT A0
Pause 1 ;Avoid RA3 reading during bouncing
If PORTA.3=0 then
Counter=Counter-1
lcdout $fe,$c0,#Counter
Endif
while PORTA.0=0 or PORTA.3=0:pause 1:wend ' while RA=0 standby + debounce time
IOCA.0=1 ;Enable INT A0
@ INT_ENABLE RAC_INT ; enable interrupts Is it necessary?

@ INT_RETURN

'-------------------------------------------------------
'Main program
'-------------------------------------------------------

-Is it OK to set interrupts the way I do, outside assembler block and after @INT_ENABLE RAC_INT sentence?
-Is it possible to disable for example INT A3 while inside INT A0 with IOCA register?
-Is the sentence @ INT_ENABLE RAC_INT OK for enable both interrupts? or IOCA register can do the same?
-Francesc

richard
- 10th August 2014, 14:45
OPTION_REG.6=0 ;Int on falling edge. Is it possible?
no this option is for INT/int

having


INT_Handler RAC_INT, _ENCODERA, PBP, yes
INT_Handler RAC_INT, _ENCODERB, PBP, yes
won't really work as there is only one rac_int ,you only need one isr for it

your isr needs to
1 determine state of enca and encb
2 compare this state to the previous (old_state)
3 determine if the move is forward ,backwards or invalid (bounce) and inc or dec the counter as req
4 save the current state to "old_state"
5 clear the rac interrupt flag (the auto flag clear does not always work for rac int)

having pauses and lcd outputs in isr will lead to tears , make isr's as short as possible is best practice


after thought
add capacitors to ground across the enca/b pins (try 0.1 uf) to minimise contact bounce

towlerg
- 10th August 2014, 20:17
As Richard says, you only need one interrupt. On interupt edge, read the inputB from the encoder . If it's hi then being turned c/w, if lo then being turned ac/w ( or the other way round) Suck it and see.

Also good advice from Richard re caps on both inputs to ground.

You can almost discount switch bounce, int will ignore following spikes and inputB switch will have settled. Only problem is if interupt input is still bouncing after you reenable ints. I added a test for no change on inputB.

George

Demon
- 14th August 2014, 12:38
...You can almost discount switch bounce, int will ignore following spikes and inputB switch will have settled. Only problem is if interupt input is still bouncing after you reenable ints. I added a test for no change on inputB.

George

At 64MHz I couldn't ignore the jitter. I don't remember what cap configuration I used, but it took me quite a while through trial and error to come up with an acceptable transition (regret not having documented work on that project - of course it got put on the shelf and I moved on to something else and undid all my prototyping boards).

Robert

richard
- 14th August 2014, 12:57
I saw this article on "re" decoding. http://letsmakerobots.com/node/24031
and gave it a spin on a 16f684 @8mhz , the full quadrature decoding works perfectly and contact bounce has been eliminated on my cheap and nasty 10 for a dollar ebay specials. these had previously defied efforts to eliminate occasional miscounting and direction reversals.

towlerg
- 14th August 2014, 20:00
That interesting but I repeat, int on A, on interupt read B, if it is c/w if 1 it is ac/w it is 0 (or the other way round). Caps on A and B to gnd, 10k pullup on A and B to Vcc. Bobs your uncle.

Any contact bounce on A will be disrequarded because your interupt routine won't have reenabled ints yet and B will be read dead in the middle of its cycle.

George

Demon
- 15th August 2014, 00:27
I hadn't thought of disabling interrupts momentarily, excellent idea. A short timer could control the interval as well.

My PIC was dedicated so I just looped and checked the state of the pins.

Robert

HenrikOlsson
- 15th August 2014, 08:24
Hi guys,

That interesting but I repeat, int on A, on interupt read B, if it is c/w if 1 it is ac/w it is 0 (or the other way round).

I may be stating the obvious but if you trip the interrupt off of the rising edge of one channel you're effectively dividing the resolution of the encoder by 4. To get the full resolution you need to count all edges of the quadrature cycle.

There are two types of encoders with detents typically used as front-panel controls. One have a full quadrature cycle per detent and using the "interrupt on rising edge of one channel" method can work with these but what you think might be noise on the signal could (and probably is) the second rising edge on the A-signal within the same quadrature cycle. The divide by 4 "issue" doesn't really apply here because you basically can't position the encoder between two detents. Another possible issue though is that when the encoder "clicks" from one detent to another a full quadrature cycle is output. If the interrupt latency is "highish" the firmware might not actually "catch" channel B quick enough. Catching it at the wrong time results in it counting the wrong way.

The other type of encoder have one detent per quadrature state. Using the "interrupt on rising edge of one channel" method with this type will result in the software detecting every 4th click, skipping the other 3.

/Henrik.