0% found this document useful (0 votes)
10 views5 pages

Encoder

The author is trying to read the inputs from a quadrature encoder using a PIC16F873 microcontroller with a 4MHz crystal. When rotating the encoder slowly, the PIC reads the correct values but misses counts when rotating faster (around 3rpm). The code provided uses interrupts to read the encoder inputs but is only able to accurately read up to 5000 pulses per second, while the goal is to read 10k pulses per second. Feedback from another user suggests using a more robust quadrature decoding algorithm that can tolerate glitches and detect overruns, as the current code may be missing steps.

Uploaded by

Tai Vovan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views5 pages

Encoder

The author is trying to read the inputs from a quadrature encoder using a PIC16F873 microcontroller with a 4MHz crystal. When rotating the encoder slowly, the PIC reads the correct values but misses counts when rotating faster (around 3rpm). The code provided uses interrupts to read the encoder inputs but is only able to accurately read up to 5000 pulses per second, while the goal is to read 10k pulses per second. Feedback from another user suggests using a more robust quadrature decoding algorithm that can tolerate glitches and detect overruns, as the current code may be missing steps.

Uploaded by

Tai Vovan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 5

Hi,

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)

#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)


#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
#define DATA PIN_C5 // SPI1 hardware SPI data out
#define LOAD PIN_B2 // software SPI
#define CLK PIN_C3 // SPI1 hardware clock

//===============================
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 write(char address, char dis_data)


{
output_low(LOAD);
delay_us(10);
spi_write(address); // spi1 write to default pins
spi_read();
delay_us(10); // used for scope write but not necessary
spi_write(dis_data); // spi1 write to default pins
spi_read();
output_high(LOAD);
delay_us(10);
output_low(LOAD);
}

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
}

void display(int16 number)


{
d3=number/1000;
a=number-(d3*1000);
d2=a/100;
b=a-(d2*100);
d1=b/10;
d0=b-(d1*10);

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.

Here is the code


Code:

void main()
{ // 4 mhz clock, no prescaler, set timer 0
// to overflow in 100us

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_ext);
enable_interrupts(GLOBAL);
enable_interrupts(INT_ext);
output_low(pin_a1);
while(1)
{ display(counter);
// output_toggle(pin_a0);
// delay_ms(1000);

}
}

#INT_ext
void rb_isr(void)
{ ina=input(pin_b4);

//inb=input(pin_b5);
if(ina==0)
{ counter++;
}
else
{ counter--;
}

I'm hoping to at least be able to read 10k pulses per second.

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.

The simple edge


interrupt
decoder is
effective, but
it's not exact.
It's supposed to
loose steps on
direction
reversal.
Possibly you
don't mind.

In both
routines, you're
only counting
one of four
steps. It would
be easier, to
use an encoder
with fewer
pulses.

You might also like