CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Rotory encoder

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Gerrit



Joined: 15 Sep 2003
Posts: 58

View user's profile Send private message

Rotory encoder
PostPosted: Sat Apr 10, 2004 11:08 am     Reply with quote

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

View user's profile Send private message Send e-mail

Quadrature encoder routine
PostPosted: Sun Apr 11, 2004 5:33 am     Reply with quote

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
PostPosted: Mon Apr 12, 2004 5:00 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Apr 12, 2004 8:52 am     Reply with quote

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...
PostPosted: Mon Apr 12, 2004 9:15 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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