|
|
View previous topic :: View next topic |
Author |
Message |
Skirmitt
Joined: 19 May 2009 Posts: 60
|
Reading 2 optical encoders on PortB |
Posted: Mon Oct 24, 2011 7:26 am |
|
|
I have problems reading 2 optical encoders connected to port B. I use IOC to have accurate reading. I does work with only one encoder connected but with two connected it spits out code for both encoders which isn't right. I tried a bit mask but that doesn't work. What could be wrong ?
Encoder one is connected to RB0 and RB1.
Encoder two is connected to RB2 and RB3.
The other Port B pins are not connected to anything.
Code: |
void encoder(void)
{
if(newencoder != lastencoder) //Check for a change
{
if (bit_test(newencoder,1) == bit_test(lastencoder,0))
midiout(144,40,127); else midiout(144,40,1);
if (bit_test(newencoder,3) == bit_test(lastencoder,2))
midiout(145,40,127); else midiout(145,40,1);
}
lastencoder = newencoder; // save state
}
#int_rb
void int_rb_isr(void)
{
newencoder = PortB;
}
void main()
{
port_b_pullups(TRUE);
delay_us(10); // Allow time for them to pull-up to +5v
b = PortB; // Clear mismatch condition
clear_interrupt(INT_RB);
enable_interrupts(INT_RB0);
enable_interrupts(INT_RB1);
enable_interrupts(INT_RB2);
enable_interrupts(INT_RB3);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while(1)
{
encoder();
}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 24, 2011 11:42 am |
|
|
You didn't tell us your PIC or your compiler version.
Then below, you are making an assumption that interrupt enables
are sequential. But that's just not true. The latest line will overwrite
the settings in the previous line. This is generally the case for CCS
functions that setup some feature in the PIC.
Quote: |
enable_interrupts(INT_RB0);
enable_interrupts(INT_RB1);
enable_interrupts(INT_RB2);
enable_interrupts(INT_RB3);
enable_interrupts(INT_RB); |
Ttelmah shows how to combine INT_RBx parameters in this post:
http://www.ccsinfo.com/forum/viewtopic.php?t=45432&start=6
This technique is not applicable to all interrupts in the general case, but
it does work for INT_RBx.
If it still doesn't work and you want more help, then you will have to
post your PIC and compiler version. Also posta description of the external
circuits, including the voltage levels of the logic signals output by the
encoders, and the Vdd voltage of the PIC, and the part numbers and
manufacturers of the encoders. Etc. |
|
|
Skirmitt
Joined: 19 May 2009 Posts: 60
|
|
Posted: Mon Oct 24, 2011 12:19 pm |
|
|
I have a 16f887 with these encoders http://mylantec.be/upload/grigsby%20encoder.pdf . CCS PCM C Compiler, Version 4.114. It does output 5V levels.
I tried with the:
Code: |
enable_interrupts(INT_RB); |
but this couldn't generate an interrupt on the lower pins. That's the reason I added all the int's separately. I had a clue this isn't very correct but it does work.
To make the encoders work I made I like this now but I am sure this is messy. I read it once and add 2 bitmasks and read them in 2 functions. It does react very good now.
Code: |
void encoder1(void)
{
if(newencoder != lastencoder) //Check for a change
{
if (bit_test(newencoder,1) == bit_test(lastencoder,0))
midiout(144,40,127); else midiout(144,40,1);
}
lastencoder = newencoder; // save state
}
void encoder2(void)
{
if(newencoder2 != lastencoder2) //Check for a change
{
if (bit_test(newencoder2,3) == bit_test(lastencoder2,2))
midiout(145,40,127); else midiout(145,40,1);
}
lastencoder2 = newencoder2; // save state
}
#int_rb
void int_rb_isr(void)
{
newencoder = PortB & 0b00000011;
newencoder2 = PortB & 0b00001100;
}
|
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
- read the whole port - then sort out the 'state' |
Posted: Mon Oct 24, 2011 7:39 pm |
|
|
i wrote this handler for a gadget - and was able to do what you see-
take the all purpose interrupt - and based on the states i needed to detect
just sort out what has changed in the int handler.
i hope it takes you in a useful direction - i am still wanting to learn to
program better myself.
Code: |
void DISR_INIT(void){
byte junk;
clear_interrupt( int_rda );
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
enable_interrupts(int_rda); // for EUSART i/o buffer handler
enable_interrupts(global);
junk=input_b(); // to be sure ints are cleared
}
#INT_RB
void bintisr(){
byte junk;
// check whatever you want on B port
if (!input_state(PIN_B7)) { // PHYSICAL safety kill sw is OK
bext=1;
if (armed) {
output_low(pin_d0); // open hiside power - reverse arms closed
output_low(pin_d1); // disable servo motion
output_high(pin_d2); // hold "not step" safey
output_low(pin_d3); // safety disable laser
set_pwm1_duty(0); //
gearmotor_run=0;
crash=1;
}
}
// check for APC crash inlet
// kill GM. ILED , servo
if (!input_state(PIN_B5)) {
output_low(pin_d0);
output_high(pin_d1); // enable servo to escape limit
set_pwm1_duty(cur_pwm); // last selected power step
yesjog=1;
gmrun=1; // GM DEAD
servogo=1;
crash=2;
armed=1;
}
junk=input_b(); // clr int
}
|
then any other pins subject to interrupt handling -
you want to check inside the INT.
worked in my case -
but only presented for the idea
BUT
you might need some simple external logic that guarantees you
a Hit to low or Low to hi transition for any of the bits of of say 2 - 4 bit encoders so you can collect one bit of the encoder value from an A, C, or D port pin
or
PIN_E3 as digital input and trigger on a single B port pin to indicate the CHANGE in the word- then you could read on ANY port - say D
it requires external 4 bit priority encoders -
but then all changes would be simply registered on any 8 bit port
or through an SPI conversion |
|
|
Skirmitt
Joined: 19 May 2009 Posts: 60
|
|
Posted: Wed Oct 26, 2011 12:53 am |
|
|
I did try it as your code has but with no success. I got the code working but I'm not sure if it is THE way to do it. The result is good but the way to get there ? now like this:
Code: | #include <16F887.h>
#byte PortB = 6
#device ADC=10
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=8000000)
#use rs232(baud=31250, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
int b=0;
int newencoder=0;
int lastencoder=0;
int newencoder2=0;
int lastencoder2=0;
void encoder1(void)
{
if(newencoder != lastencoder) //Check for a change
{
if (bit_test(newencoder,1) == bit_test(lastencoder,0))
midiout(144,40,127); else midiout(144,40,1);
}
lastencoder = newencoder; // save state
}
void encoder2(void)
{
if(newencoder2 != lastencoder2) //Check for a change
{
if (bit_test(newencoder2,3) == bit_test(lastencoder2,2))
midiout(145,40,127); else midiout(145,40,1);
}
lastencoder2 = newencoder2; // save state
}
#include "readbuttons.h"
#int_rb
void int_rb_isr(void)
{
newencoder = PortB & 0b00000011;
newencoder2 = PortB & 0b00001100;
}
void main()
{
output_e(0);
setup_adc_ports(sAN0,sAN1);
setup_adc(ADC_CLOCK_INTERNAL);
port_b_pullups(TRUE);
delay_us(10); // Allow time for them to pull-up to +5v
b = PortB; // Clear mismatch condition
clear_interrupt(INT_RB);
enable_interrupts(INT_RB0);
enable_interrupts(INT_RB1);
enable_interrupts(INT_RB2);
enable_interrupts(INT_RB3);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while(1)
{
encoder1();
encoder2();
readbuttons();
}
}
|
|
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Oct 26, 2011 6:32 am |
|
|
1- your int handler is as efficient as i could imagine
2- if it works cleanly - whats the problem ? |
|
|
|
|
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
|