Need help with rotary encoder
in BASIC Stamp
I have an incremental quadrature encoder that I'm trying to use with a BS2. It's the mechanical type and has switch bounce. I've tried using the code I found on the Parallax website but apparently it works only with an optical encoder that's free of switch bounce. My encoder is causing erratic jumps in the counter. Here's the code:
' =========================================================================
'
' File...... Rotary Encoder.bs2
' Purpose... Read A Rotary/Optical Encoder
' Author.... Parallax, Inc.
' E-mail.... support@parallax.com
' Started...
' Updated... 07-15-2005
'
' {$STAMP BS2}
' {$PBASIC 2.5}
'
' =========================================================================
'
[ Program Description ]
' This code demonstrates reading a rotary/optical encoder using a BASIC
' Stamp 2 Module. This code will work on the BS2e, BS2sx, BS2p24, BS2p40,
' BS2pe and BS2px24.
'
[ I/O Definitions ]
' A Output Connects To P0
' B Output Connects To P1
'
[ Variables ]
oldBits VAR Nib ' Previous State Of I/O Pins 0 - 3
newBits VAR Nib ' Current State Of I/O Pins 0 - 3
direction VAR Bit ' Direction Encoder Is Turned
counter VAR Byte ' Counter (0-255)
'
[ Initialization ]
OUTS = %0000000000000000 ' Set All Output Pins Low
DIRS = %1111111111111100 ' I/O Pins 0 - 1 Inputs
newBits = INA
'
[ Program Code ]
Main:
DO
newBits = INA ' Get State Of I/O Pins 0 - 3
IF newBits <> oldBits THEN ' Have Bits Changed?
direction = newBits.BIT0 ^ oldBits.BIT1
counter = counter - 1 + (2 * direction)
DEBUG HOME, DEC3 counter ' Show New Counter On DEBUG Screen
oldBits = newBits ' Update oldBits
ENDIF
LOOP
STOP
I've tried a jillion ways to eliminate the effects of the switch bounce with no good results. I need help, please...
' =========================================================================
'
' File...... Rotary Encoder.bs2
' Purpose... Read A Rotary/Optical Encoder
' Author.... Parallax, Inc.
' E-mail.... support@parallax.com
' Started...
' Updated... 07-15-2005
'
' {$STAMP BS2}
' {$PBASIC 2.5}
'
' =========================================================================
'
[ Program Description ]
' This code demonstrates reading a rotary/optical encoder using a BASIC
' Stamp 2 Module. This code will work on the BS2e, BS2sx, BS2p24, BS2p40,
' BS2pe and BS2px24.
'
[ I/O Definitions ]
' A Output Connects To P0
' B Output Connects To P1
'
[ Variables ]
oldBits VAR Nib ' Previous State Of I/O Pins 0 - 3
newBits VAR Nib ' Current State Of I/O Pins 0 - 3
direction VAR Bit ' Direction Encoder Is Turned
counter VAR Byte ' Counter (0-255)
'
[ Initialization ]
OUTS = %0000000000000000 ' Set All Output Pins Low
DIRS = %1111111111111100 ' I/O Pins 0 - 1 Inputs
newBits = INA
'
[ Program Code ]
Main:
DO
newBits = INA ' Get State Of I/O Pins 0 - 3
IF newBits <> oldBits THEN ' Have Bits Changed?
direction = newBits.BIT0 ^ oldBits.BIT1
counter = counter - 1 + (2 * direction)
DEBUG HOME, DEC3 counter ' Show New Counter On DEBUG Screen
oldBits = newBits ' Update oldBits
ENDIF
LOOP
STOP
I've tried a jillion ways to eliminate the effects of the switch bounce with no good results. I need help, please...
Comments
-Phil
Phil: The encoder fails at ALL speeds. I've tried putting PAUSE commands inside the DO loop to try and slow down the polling of the incoming bits but can't get that to work either.
IF newbits ^ oldbits & 3 = 3 THEN DEBUG "Error.", CR
-Phil
I inserted your line and I do get an occasional error. But only an occasional one. In the meantime the counter changes erratically - sometimes by a single step (which is what I want), but more often in steps of 3-5.
I've looked at the encoder outputs using a digital storage scope and they look pretty much as expected. I have simple RC filters connected to both outputs that tend to kill some of the switch bounce but certainly not entirely.
BTW, it might be worth mentioning that the quiescent outputs are both pulled high and that the quadrature pulses pull the outputs to ground (in sequence depending upon rotation direction) and thereafter they go back high. I guess this is normal behavior for this encoder type, but since this is my first experience with them I can't be certain...
Rod
If not, can you post a photo?
-Phil
Yes, it does. Here's a link to it: http://www.digikey.com/product-search/en?keywords=PEC11R-4225F-S0024-ND
Rod
I don't know what to suggest, except to get a better encoder. I'm glad I didn't try incorporating one of these into a project!
-Phil
Thanks for spending your time and for your support..
Rod
Can you post a scope capture.
Maybe this is an example of serious price engineering, and the classic Quadrature rules may need to be modified.
If each detent changes both, and they idle HH, maybe the rule needs to be which edge occurs first ?
As they are made in volumes, there has to be some Software solution to using them.
A microcontroller programmed in machine code would be able to keep up with and track the glitchy signals. In this case the bouncing would not ruin the count except for very short-term up-down or down-up intervals that could easily be filtered out. I suspect the market for these encoders is tilted toward micros or PLDs with faster responses than a BASIC Stamp provides.
-Phil
Like Phil I'm getting multiple counts for each detent - usually 3-5. I want just one count. Note in the scope shot that the time during which the two output pulses are unequal is about 22 ms. I'm thinking the problem is NOT so much from switch bounce but it's the code I'm using. Depending upon the speed of the DO loop it can read multiple instances of "unequalness" during that 22 ms. It seems to me the problem could be resolved simply by adding an appropriate PAUSE command inside the loop, thereby slowing down the sample period. But I can't get that to work.
Rod
The code is designed to change the count on each edge from either channel. Because there's a complete cycle of four edges between detents, you get four counts, nominally.
-Phil
' {$STAMP BS2} ' {$PBASIC 2.5} oldBits VAR Nib ' Previous State Of I/O Pins 0 - 3 newBits VAR Nib ' Current State Of I/O Pins 0 - 3 counter VAR Byte ' Counter (0-255) dcount VAR Nib ' Delta count between detents oldBits = INA & 3 DO newBits = INA & 3 ' Get State Of I/O Pins 0 - 1 IF newBits <> oldBits THEN ' Have Bits Changed? dcount = dcount - 1 + (2 * (newBits.BIT0 ^ oldBits.BIT1)) oldBits = newBits ' Update oldBits IF newBits = 3 AND dcount THEN IF dcount & 8 THEN counter = counter - 1 ELSE counter = counter + 1 dcount = 0 DEBUG HOME, DEC3 counter ENDIF ENDIF LOOP
It takes advantage of the fact that on detent, both outputs are high. So it keeps track of the motion between detents. Then, when both outputs go high, it checks to see if any motion occurred, and in which direction. Only then does it increment or decrement the count. So you get just one count change per detent.-Phil
Your code is working great here. Thanks very much.
You've taught me something I didn't know about Stamp. I didn't think that Stamp could read edges. I thought it could only poll its inputs and that it samples at some time period after acknowledging the IN command. Responding to edges is almost as good as having interrupts and of course we know that Stamp doesn't support interrupts.
So, do I have it correct - that an IN command waits for an edge?
-Phil
I use optical encoders and have never needed debounce but I have shown how this could be implemented at label A1B1
'The encoder signals are referred to as Channel A and Channel B 'There are four possible legal states: 'A=1, B=1 'A=0, B=0 'A=1, B=0 'A=0, B=1 'So, on startup.... 'Jump to the appropriate loop If Chan_A = 1 And Chan_B = 1 Then Goto A1B1 Endif If Chan_A = 0 And Chan_B = 0 Then Goto A0B0 Endif If Chan_A = 1 And Chan_B = 0 Then Goto A1B0 Endif If Chan_A = 0 And Chan_B = 1 Then Goto A0B1 Endif 'Keep looping until a channel changes state and then jump to the loop that 'caters to the new state. A1B1: If Chan_A = 0 Then 'For debounce purposes, a delay could be inserted here, followed by another read of the input 'If Chan_A = 0 Then Dec Counter Wrlong HubCTR,Counter Goto A0B1 'Endif Elseif Chan_B = 0 Then 'For debounce purposes, a delay could be inserted here, followed by another read of the input 'If Chan_B = 0 Then Inc Counter Wrlong HubCTR,Counter Goto A1B0 'Endif Endif Goto A1B1 A0B0: If Chan_A = 1 Then Dec Counter Wrlong HubCTR,Counter Goto A1B0 Elseif Chan_B = 1 Then Inc Counter Wrlong HubCTR,Counter Goto A0B1 Endif Goto A0B0 A1B0: If Chan_A = 0 Then Inc Counter Wrlong HubCTR,Counter Goto A0B0 Elseif Chan_B = 1 Then Dec Counter Wrlong HubCTR,Counter Goto A1B1 Endif Goto A1B0 A0B1: If Chan_A = 1 Then Inc Counter Wrlong HubCTR,Counter Goto A1B1 Elseif Chan_B = 0 Then Dec Counter Wrlong HubCTR,Counter Goto A0B0 Endif Goto A0B1 End
The solution to this would require a more stringent test than simply non-zero. For example, you could make sure it was one of -4 (%1100), -3 (%1101), 3 (%0011), or 4 (%0100) before allowing a change in count.
-Phil
The code you posted is working fine with my encoder.