|
|
View previous topic :: View next topic |
Author |
Message |
andredurao
Joined: 24 Apr 2006 Posts: 15
|
on-change interrupt and rotatory encoder |
Posted: Thu Aug 31, 2006 7:15 am |
|
|
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
|
|
Posted: Thu Aug 31, 2006 9:49 am |
|
|
Could it be switch bounce?
Is there a spec and a circuit we could see? |
|
|
Ttelmah Guest
|
|
Posted: Thu Aug 31, 2006 10:03 am |
|
|
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
|
|
Posted: Thu Aug 31, 2006 2:42 pm |
|
|
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
|
|
Posted: Thu Aug 31, 2006 3:06 pm |
|
|
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
|
|
Posted: Thu Aug 31, 2006 7:32 pm |
|
|
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
|
|
Posted: Fri Sep 01, 2006 6:25 am |
|
|
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. |
|
|
|
|
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
|