|
|
View previous topic :: View next topic |
Author |
Message |
Gerrit
Joined: 15 Sep 2003 Posts: 58
|
Rotory encoder |
Posted: Sat Apr 10, 2004 11:08 am |
|
|
Hello,
I am using an alpha low-ocst rotory encoder.
At this moment I have extra pulses when I just turn the
knop to and from the detent point.
Is there a way to avoid fals pulses?
I have added some code whitch will be called from insite the timer_1
Regards,
Gerrit
Code: |
New_Rotary=(Port_B&0x30);
tmp_Value = New_Rotary^Old_Rotary;
if( tmp_Value != 00)
{
Enc_Cur = New_Rotary ;
if(Old_Rotary & 0x10)
bit_set(Enc_Cur,6);
if(Old_Rotary & 0x20)
bit_set(Enc_Cur,7);
Old_Rotary = New_Rotary;
swap(Enc_Cur);
switch(Enc_Cur)
{
case ROTORY_0010:
case ROTORY_1101: Rotory_Action = RIGHT_TURN;
Rotory_Turned = TRUE; break;
case ROTORY_0001:
case ROTORY_1110: Rotory_Action = LEFT_TURN;
Rotory_Turned = TRUE; break;
}
} |
|
|
|
Steph
Joined: 06 Dec 2003 Posts: 3
|
Quadrature encoder routine |
Posted: Sun Apr 11, 2004 5:33 am |
|
|
Hi gerrit
In my case, i am using a IC from US Digital:
LS7083; encoder to counter interface.
I am using an optical encoder.
If you are using a mechanical encoder,
you will need to debounce with a time delay.
Some examples:
if you look on CCS examples folder
look for: EX_ENCODE.C
i found that one on internet too:
PIC Micro Controller C Input / Output Routine
Quadrature Encoder ISR
by David Kott
struct RotaryEncoderStruct {
int unused:4; // RB[0:3]
int A:1; // RB4
int B:1; // RB5
int unused2:2; // RB6-7
};
struct RotaryEncoderStruct RotaryEncoder;
#pragma BYTE PORTB = 0x06
#pragma BYTE RotaryEncoder = 0x06 // Place structure right over PORTB at
location 0x06
USHORT g_usEncoderCount = 0;
#pragma INT_RB
void
PortBInterrupt (void)
{
static BYTE OldPortB;
BYTE byTemp;
static struct RotaryEncoderStruct OldEncoder;
if (OldPortB != (byTemp=(PORTB & 0x30))) {
OldPortB = byTemp;
if (RotaryEncoder.A == OldEncoder.A) {
if (RotaryEncoder.B == RotaryEncoder.A)
--g_usEncoderCount;
else
++g_usEncoderCount;
} else {
OldEncoder.A = RotaryEncoder.A;
if (RotaryEncoder.B == RotaryEncoder.A)
++g_usEncoderCount;
else
--g_usEncoderCount;
}
}
}
Good luck |
|
|
Ttelmah Guest
|
Re: Rotory encoder |
Posted: Mon Apr 12, 2004 5:00 am |
|
|
Gerrit wrote: | Hello,
I am using an alpha low-ocst rotory encoder.
At this moment I have extra pulses when I just turn the
knop to and from the detent point.
Is there a way to avoid fals pulses?
I have added some code whitch will be called from insite the timer_1
Regards,
Gerrit
Code: |
New_Rotary=(Port_B&0x30);
tmp_Value = New_Rotary^Old_Rotary;
if( tmp_Value != 00)
{
Enc_Cur = New_Rotary ;
if(Old_Rotary & 0x10)
bit_set(Enc_Cur,6);
if(Old_Rotary & 0x20)
bit_set(Enc_Cur,7);
Old_Rotary = New_Rotary;
swap(Enc_Cur);
switch(Enc_Cur)
{
case ROTORY_0010:
case ROTORY_1101: Rotory_Action = RIGHT_TURN;
Rotory_Turned = TRUE; break;
case ROTORY_0001:
case ROTORY_1110: Rotory_Action = LEFT_TURN;
Rotory_Turned = TRUE; break;
}
} |
|
There are a series of things you have to consider. It appears you are reading the encoder inside the 'timer' routine. This is _only_ OK, if you can guarantee that the state will not change by more than one condition between successive calls. Otherwise there is a risk of the code missing one of the changes. So what can happen if you move the knob by a small amount, and then back is that the routine sees one change, when two have occurred, and loses alignment. Seperately, you need to look at the specifications of the encoder itself, to see if the signals are guaranteed to display a 'clean' switch, or may experience a 'bounce' on some edges. If the latter, you need to look at either software debouncing, or adding external hardware filtering to the switches.
Personally, I'd use the 'interrupt on change' ability of the processor, and use this to trigger reading the encoder, rather than timer based code. Especially since it appears the encoder is already wired to the correct pins for this. Then in the routine, given that a few uSec will have passed between the 'trigger', and actually reaching the routine, re-read the input.
The code below, is designed to be used this way:
Code: |
#INT_RB
void quad(void) {
static int old;
static int new;
static int value;
//Here I have an edge on one of the quadrature inputs
new=portb;
value=new^old;
//'value', now has the bit set, which has changed
if (value & 0x10) {
//Here the low bit has changed
if (new & 0x10) {
//Here a rising edge on A
if (new & 0x20) --position;
else ++position;
}
else {
//Here a falling edge on A
if (new & 0x20) ++position;
else --position;
}
}
else {
//Here the high bit (B) must have changed
if (new & 0x20) {
//Here a rising edge on B
if (new & 0x10) ++position;
else --position;
}
else {
//Here a falling edge on B
if (new & 0x10) --position;
else ++position;
}
}
old=new;
}
|
This decodes all four quadrature states, while you are only using two. Hence you would have to remove half of the test states.
Though the code looks bulky, it is very quick indeed, since the path just does three 'tests', and arrives at the required increment/decrement.
You might find that your existing code will work fine, if you test on the other 'edge'. One edge will change allmost in the middle of the detent, while the other will change 'between' the detents. If you are testing on the edge that happens to fall in the detent, you will get triggers for only a tiny movement at this point. So if you reverse the use of 0x10, and 0x20, in your code, it may fix the problem. :-)
Best Wishes |
|
|
Gerrit
Joined: 15 Sep 2003 Posts: 58
|
|
Posted: Mon Apr 12, 2004 8:52 am |
|
|
Hi Ttelmah,
I print it out and start reading today, tomorrow I wil try this
to see if this is more conviniend.
Thanks Steph and Ttelmah you for you response.
Kind regards,
Gerrit Faas |
|
|
valemike Guest
|
Mechanical rotary encoder/bcd switches... |
Posted: Mon Apr 12, 2004 9:15 am |
|
|
Hi,
This has been addressed in the comp.arch.embedded newsgroup
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&threadm=1079035907snz%40amleth.demon.co.uk&rnum=14&prev=/groups%3Fq%3Dvalemike%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26scoring%3Dd%26start%3D10%26sa%3DN
I had that same problem once before. Bottom line is - these mechanical rotary switches are good to find the position of the switch, but not for counting. For example, going from position 1 to position 2 will look like:
0001 -> 0000 (intermediate) -> 0010.
These contacts break intermediately before the others make. A worse scenario is going from 7 to 8:
0111 -> 0011 -> 0001 -> 1000 -> 1000 (something like that. basically, you can have up 3 intermediate states).
All the debouncing in the world won't help you if the person has a very steady hand and wants to fool it. You'll need a few hundred milliseconds of delay to get to detent position, but even that's not guaranteed against a slow and steady hand. Trying doing printf() to Hyperterminal and dump the values you see. You'll find that when you go backwards, it is more "predictable". For example, if you're at position 8 (1000), and you go backwards, you'll probably see an intermediate value of 0 (0000) before the 0111 (7) eventually gets detented. So when you see an intermediate 0, you can "predict" that the guy is going backwards to 7, and don't have to worry about further intermediate positions.
Mike |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|