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 CCS Technical Support

on-change interrupt and rotatory encoder

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



Joined: 24 Apr 2006
Posts: 15

View user's profile Send private message MSN Messenger

on-change interrupt and rotatory encoder
PostPosted: Thu Aug 31, 2006 7:15 am     Reply with quote

I have this code running in a pic18f452, the interrupt code seems to be ok
when i turn the encoder CW the value increases and CCW it decreases, but
the problem is that when I turn 1 round it counts something like 4 times the value of pulses of the encoder, I don't know exactly what is happen seems like the same interrupt it's been called more than one time,
Does someone know something that can help me

PIC18F452
XTAL at4MHZ
Rotatory encoder, A -> portB4 b->portB5
all the rest of portB is grounded.

Code:


//proj2.h file
#include <18F452.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOOSCSEN                 //Oscillator switching is disabled, main oscillator is source
#FUSES NOBROWNOUT               //No brownout reset
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOSTVREN                 //Stack full/underflow will not cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOCPD                    //No EE protection
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads

#use delay(clock=4000000)
//end of .h file

//.c file

#include  proj2.h
#include <LCD>

long cont=1L;
int reg_a,reg_b;

#int_RB
RB_isr()
{

   int a,b,direcao;

   a = input(PIN_B4);
   b = input(PIN_B5);

   //CW
   //00 <-> 10 <-> 11 <-> 01 <-> 00
   //CCW
   //00 <-> 01 <-> 11 <-> 10 <00>CW  0->CCW
   !(reg_a XOR b) && (reg_b XOR a)
   */
   direcao = !(reg_a ^ b) && (reg_b ^ a);
   
   if (direcao == 1)
      cont++;
   else
      cont--;
   
   //save old values to compare in next call
   reg_a = a;
   reg_b = b;


}



void main()
{
   long salvacont;
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   lcd_init();
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);
   setup_oscillator(False);


   lcd_init();

   while (true){

      if (cont != salvacont){
         salvacont = cont;
         printf(lcd_putc,"\fc=%Lu",cont);
         //delay_ms(15);
      }

   }

}


//end of .c file




thanks
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

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

PostPosted: Thu Aug 31, 2006 9:49 am     Reply with quote

Could it be switch bounce?
Is there a spec and a circuit we could see?
Ttelmah
Guest







PostPosted: Thu Aug 31, 2006 10:03 am     Reply with quote

Er. You do realise why this is called a 'quadrature' encoder...
For each cycle of one line of the encoder, there are _four_ clock edges. The two clocks are phase shifted by 90 degrees, so you have:
Code:


A 01100110011001100110011001100110011
B 001100110011001100110011001100110011
    |      |      |   

For each cycle of one clock (marked by the lines), there are _four_ countable edges. You have implemeted a full quadrature decoder (cycles on each change of each line), so will see four times as many pulses as there are lines in the encoder. If you want to only count at the line interval, then connect one of the pulses to a normal interrupt (rather than the interrupt on change), and call the code with this.

Best Wishes
andredurao



Joined: 24 Apr 2006
Posts: 15

View user's profile Send private message MSN Messenger

PostPosted: Thu Aug 31, 2006 2:42 pm     Reply with quote

thanks Ttelmah, I've read your replies in other topics in this subject.
I didn't realize that the "quadrature" term is related with this realy =) =)
thanks for that!
So I'll try to count only when the cycle ended...

one more doubt: Is there some way to only call the printf routine
when the processor is in idle? I guess that with this I will not miss the count so often or is there some better way to do this kind of count?


About the switch bouncing, I'll test it more times to be sure. Because I'm not sure about it now.

Thanks for your help,
Ttelmah
Guest







PostPosted: Thu Aug 31, 2006 3:06 pm     Reply with quote

The 'quadrature' name, comes from the two signals being 'in quadrature' (90 degrees out of phase). This brings with it the ability to get the four counts per line on the encoder.
How many lines do you have on the encoder?. How fast do you want to spin it?.
Printf, should not have any effect on the ability to handle the pulses. The biggest problem is the latency of the interrupt. Typically on the 18 series chips, there is about 30 instructions 'overhead', before calling the actual interrupt handler. There is then a similar delay, leaving the handler, and the time in the handler itself (about 20 instructions). This gives a total period at 4MHz, of perhaps 80uSec. If pulses arrive at shorter intervals than this, then they are likely to be missed. If this is (say) a 512 line encoder, counting on all four edges as it does at present (2048 counts/rev), gives a maximum rotational rate of (60/80E-6)/2048 rpm. Just 366 RPM.
There are two ways to deal with this. First, use a fast interrupt handler, with custom (not standard CCS) code. I have published such a routine in the past, and provided you don't need any other interrupts, this would improve things massively. The other is to use hardware to do the count. Microchip AN718, shows how to use a single 7474 chip, to generate two pulse trains, corresponding to the 'up', and 'down' pulses, at the encoder frequency (one quarter the current rate), and feed these to two hardware counters, to give a design that could handle thousands of rpm. I really would suggest considering this, since this would count whatever else the chip as doing, and remove a lot of timing problems that might otherwise arise latter...

Best Wishes
andredurao



Joined: 24 Apr 2006
Posts: 15

View user's profile Send private message MSN Messenger

PostPosted: Thu Aug 31, 2006 7:32 pm     Reply with quote

I'm using a 512 pulse per revolution encoder, exactly like you said
I'll consider using the 7474 so I can divide the train pulse and do less
interrupts, I guess that is your suggestion.

About the rotational rate, in the application the encoder will not rotate more than 100 RPM, because there is a mechanical reduction of 10:1, and in my measures the rotation will not pass over 100RPM

thanks again!
libor



Joined: 14 Dec 2004
Posts: 288
Location: Hungary

View user's profile Send private message

PostPosted: Fri Sep 01, 2006 6:25 am     Reply with quote

You could try using the CCP1, CCP2 counters in your 18F452, they even have built-in 1, 4, 16 prescalers. Though you'll have to do some tricks if direction change detection is also required. (is this an independent movement? or you're driving the motor also with the PIC ?)
You can also combine the two methods, the slower, tighter interrupt-on-change monitoring method for slow speeds (and possible direction change) and a preventive switching to (programmatically I mean) a counter-based method (done completely in hardware, with prescalers if you wish) with or w/o interrupts (eg. interrupt at certain counter value reached) at faster RPMs before the interrupt-on-every-edge strategy overloads the PIC processing power.
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