Encoder
Encoder
I've been trying to get the PIC to be able to read the inputs of a quadrature encoder.
If I rotate it slowly, the pic is able to read the correct values. However if I rotate it fast (I'm rotating it
manually, and I guess its roughly about 3 rpm), it seems to miss alot of counts. 1 revolution has 1000
pulses.
Is the problem due to the interrupt unable to happen as quick as the input pulses? I'm using a
pic16f873 with a 4mhz crystal.
Here is my code
Code:
#include "16F873.h"
#include <stdio.h>
#include <stdlib.h>
#fuses XT,NOPROTECT,NOLVP,NOWDT,NODEBUG,NOBROWNOUT
#use delay(clock=4000000)
#use RS232(baud=19200,errors,xmit=PIN_C6,rcv=PIN_C7,parity=n,STREAM=no,stop=2,enable=pin_b1)
//===============================
int d0=0;int d1=0;int d2=0;int d3=0;int16 a=0;int b=0;
int1 preva=0;int1 prevb=0;
int16 counter=0;int pata=0b00000000;int patb=0b00000000;
int y=0;
int1 ina=0;int1 inb=0;
int1 temp=0;int dir=0;
void initdriver()
{
write(0x0C,0x01); // Shutdown 0C00 - normal mode 0C01
write(0x0F,0x00); // test mode off 0F00 - on0F01
write(0x0B,0x03); // scan limit - 00 = 1 column
write(0x09,0xFF); // decode mode on - FF all 8 digits have decode on
write(0x0A,0x0F); // intensity - 0xXF max intensity
write(0x00,0x00); // No Operation
}
write(0x04,d3);
write(0x03,d2);
write(0x02,d1);
write(0x01,d0);
void main()
{
setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_16);
initdriver();
port_b_pullups(TRUE);
delay_us(200);
output_high(pin_a0);
output_high(pin_a5);
EXT_INT_EDGE(L_to_H);
clear_interrupt(int_rb);
enable_interrupts(GLOBAL);
enable_interrupts(INT_rb);
output_low(pin_a1);
while(1)
{ display(counter);
// output_toggle(pin_a0);
delay_ms(100);
}
}
#INT_rb
void rb_isr(void)
{ ina=input(pin_b4);
inb=input(pin_b5);
pata=pata<<1;
bit_clear(pata,4);
if(ina==1)
{ bit_set(pata,0);
}
else
{ bit_clear(pata,0);
}
patb=patb<<1;
bit_clear(patb,4);
if(inb==1)
{ bit_set(patb,0);
}
else
{ bit_clear(patb,0);
}
if(pata==6&&patb==12)
{ counter++;
}
else if(pata==12&&patb==6)
{ counter--;
}
}
I've tested my previous code and it can correctly read up to 2500 pulses per
second.
I've changed the code to use the external interrupt on rb0. This can read
accurately up to 5000pulses per second.
void main()
{ // 4 mhz clock, no prescaler, set timer 0
// to overflow in 100us
}
}
#INT_ext
void rb_isr(void)
{ ina=input(pin_b4);
//inb=input(pin_b5);
if(ina==0)
{ counter++;
}
else
{ counter--;
}
FvM Post
ed:
Wed
Jan 19,
Joined: 27 Aug 2008
Posts: 2337 2011
Location: Germany 2:51
am
I'm unable to
recognize a
reliable
quadrature
encoder
processing
algorithm in one
of the both
codes.
A state-of-the-
art algorithm
counts every A
or B edge,
tolerates
glitches and
detects a speed
overrun from
the input
states. In so
far, it's basically
necessary to
use the input
change
interrupt, or
poll the inputs
(for slow
encoder
applications).
Generally, you
have the
problem of
interrupt
processing
time. Thus the
interrupt
function must
be coded
effectively. I
don't
understand,
why you are
operating a 20
MHz CPU at 4
MHz.
In both
routines, you're
only counting
one of four
steps. It would
be easier, to
use an encoder
with fewer
pulses.