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

PIC unable to keep up with rotary encoder?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 19369

View user's profile Send private message

PostPosted: Wed Jan 19, 2011 3:38 am     Reply with quote

Do you need to use any other interrupts?.
If not, then you need to consider going the 'int_global' route:
Code:

signed int32 position;
int save_w;
#locate save_w=0x7f
int save_status;
#locate save_status=0x20
#byte status = 3

//This is the decoder for a change in the quadrature inputs. Called on
//port B change interrupt, with encoder connected to B4, and B5.
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;
   //Now I have to decode the quadrature changes. There are four possibilities:
   //I can have a rising or falling edge, on each of the two inputs. I have to
   //look at the state of the other bit, and increment/decrement according to
   //this.
   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;
   bchanged=0;
}

#INT_GLOBAL
void isr()  {
   #asm
   //store current state of processor
   MOVWF save_w
   SWAPF status,W
   BCF   status,5
   BCF   status,6
   MOVWF save_status

#ASM
   //Here for maximum speed, I test the RB interrupt - since it is always
   //enabled, I don't have to test the enable bit
   BTFSS   INTCON,RBIF
   GOTO    FEXIT    //Add other handlers here  if needed
#endasm
   quad();              //Quadrature handler.
#asm
   BCF   RBIF
FEXIT:
   // restore processor and return from interrupt
   SWAPF save_status,W
   MOVWF status
   SWAPF save_w,F
   SWAPF save_w,W
#endasm
}


Will need the register defines for PORTB, RBIF etc., added.

Not an exact match for your code, but close (position, rather than counter etc..).
The decoder, is slightly more efficient than your code, but the key saving, is that it only saves the bare minimum registers needed. Should double the response speed with care.

You may find that adding pull up resistors helps a little. The internal pullups are quite low powered, and as pulse rates rise, you may find these are not good enough to give fast edges. Worth studying the waveform.

Best Wishes
asdf85



Joined: 03 Jan 2011
Posts: 34

View user's profile Send private message

PostPosted: Wed Jan 19, 2011 3:56 am     Reply with quote

actually, the 1st code does check for all 4 steps. Im shifting the bits on each state change and checking to see if it matches the intended waveform pattern(doing this with pata and patb variables).

Initially i could only find a 4mhz crystal lying around. but i just ran out and got my self a 20mhz crystal.

With the 20mhz crystal, the 2nd code works. but the first still does not.

However, as you pointed out, the 2nd code just checks one of the 4 steps, so im afraid the results may be innacurate. Because I noticed when using the 4mhz crystal, it started decreasing(its shud be increasing) the count once i rotated it at a faster speed.


Ttelmah, i need to use RDA and timer interrupts too.
Ttelmah



Joined: 11 Mar 2010
Posts: 19369

View user's profile Send private message

PostPosted: Wed Jan 19, 2011 4:07 am     Reply with quote

You _will_ have problems then.
You can add handlers for other interrupts, but what happens, if you have just started handling one of these, and a RB edge arrives?. The code has to do all the operations associated with the second interrupt, restore the registers this needs, then be called a second time for the RB interrupt. Ouch....

Choices:
Go for a faster CPU clock
Add an external change detector, and feed the CCP channels off this.
Add a full external quadrature counter.
Switch to a 18 PIC, and make the RB interrupt 'high priority'.

Best Wishes
bkamen



Joined: 07 Jan 2004
Posts: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Wed Jan 19, 2011 9:43 am     Reply with quote

Ttelmah wrote:

Choices:
Go for a faster CPU clock
Add an external change detector, and feed the CCP channels off this.
Add a full external quadrature counter.
Switch to a 18 PIC, and make the RB interrupt 'high priority'.


Or use a PIC with a Quadrature decoder like the 18Fxx31.

http://ww1.microchip.com/downloads/en/DeviceDoc/39616d.pdf

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Jan 19, 2011 10:02 am     Reply with quote

Quote:
i need to use RDA and timer interrupts too

This changes everything.
Quote:
the 1st code does check for all 4 steps.

I don't see, how. It checks for a signal pattern, that occurs only once per 4 steps (hopefully).
The code presented by Ttelmah does a state-of-the-art quadrature encoding. It can be possibly speeded up by using a state table.
scottc



Joined: 16 Aug 2010
Posts: 95

View user's profile Send private message

PostPosted: Wed Jan 19, 2011 10:22 am     Reply with quote

Is the encoder one of the Mechanical types that has 3 pins

gnd, A - B

Thanks Scott
Ttelmah



Joined: 11 Mar 2010
Posts: 19369

View user's profile Send private message

PostPosted: Wed Jan 19, 2011 11:23 am     Reply with quote

FvM wrote:
Quote:
i need to use RDA and timer interrupts too

This changes everything.
Quote:
the 1st code does check for all 4 steps.

I don't see, how. It checks for a signal pattern, that occurs only once per 4 steps (hopefully).
The code presented by Ttelmah does a state-of-the-art quadrature encoding. It can be possibly speeded up by using a state table.

A state table, works out slower. I tried it... Very Happy

If you run through the possible 'routes', it only takes a handful of instructions to go through each possibility. With the table, the total timing is about 'neck and neck', _but_ you then have to also save the registers used to access the table, which makes it worse (in the given example, with minimum register saves).

I have to say though, that assuming the code outside, is looping quickly doing whatever it does, one has to remember, that you don't need an interrupt handler to service serial (just ensure you are polling the receive interrupt at least as frequently as a character time), and the same applies to timer interrupts.
If you only need to do some very small operation with the timer, then add a test for this interrupt flag in the global code, and do this operation. However otherwise, just poll the interrupt flag in the main code. You are using interrupt flags, but not interrupt handlers. Then the only interrupt using the hardware handlers becomes the quadrature system, and you can get the required speed.

I just compiled my code (a few bugs), but with these fixed, it takes a total of 36 instruction times 'worst case' to handle any quadrature state (including the interrupt call/return). Potentially means this can handle 30000 edges per second.

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Jan 20, 2011 6:05 am     Reply with quote

Quote:
A state table, works out slower. I tried it...
Yes, I believe. It's however faster on a 8051, that has a fast MOVC ROM lookup instruction.

Quote:
Potentially means this can handle 30000 edges per second.
Good!
asdf85



Joined: 03 Jan 2011
Posts: 34

View user's profile Send private message

PostPosted: Thu Jan 20, 2011 6:55 pm     Reply with quote

Sorry, I'm actually not from an electronics background. What exactly is handlers for interrupts?

scott, the encoder has 6 pins, its Koyo TRD-J 1000 RZW.
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Thu Jan 20, 2011 7:00 pm     Reply with quote

Interrupt Handler = ISR = Interrupt Service Routine -- the code that gets control any time an interrupt goes off. If you are using interrupts, you MUST have a handler to take control when that interrupt goes off or it will wander off into never never land.

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
asdf85



Joined: 03 Jan 2011
Posts: 34

View user's profile Send private message

PostPosted: Thu Jan 20, 2011 11:29 pm     Reply with quote

oh okay, its the same thing as isr
asdf85



Joined: 03 Jan 2011
Posts: 34

View user's profile Send private message

PostPosted: Fri Jan 21, 2011 3:00 am     Reply with quote

May i also know if its OKAY to be enabling and disabling interrupts in an interrupt service routine? Thanks
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Jan 21, 2011 4:09 am     Reply with quote

Unless working with priority, all interrupts are disabled during ISR execution automatically. In some applications, individual IE bits are manipulated in ISR, e.g. a TX send interrupt will be disbled, when the last circular buffer character has been sent out. In your application, I don't see a purpose for it. Encoder interrupts must be expected at any time, there's no reason to delay other interrupts.
mbradley



Joined: 11 Jul 2009
Posts: 118
Location: California, USA

View user's profile Send private message Visit poster's website

PostPosted: Sun Feb 13, 2011 7:49 pm     Reply with quote

You can try this:

http://www.picstuff.com/index.php?route=product/product&path=37_41&product_id=56
_________________
Michael Bradley
www.mculabs.com
Open Drivers and Projects
sseidman



Joined: 14 Mar 2005
Posts: 159

View user's profile Send private message

PostPosted: Mon Feb 14, 2011 9:15 am     Reply with quote

Ditto for going with one of the motor control 18Fxx31. It will make your life easier
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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