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

Reading 2 optical encoders on PortB

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



Joined: 19 May 2009
Posts: 60

View user's profile Send private message

Reading 2 optical encoders on PortB
PostPosted: Mon Oct 24, 2011 7:26 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 24, 2011 11:42 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 24, 2011 12:19 pm     Reply with quote

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

View user's profile Send private message AIM Address

- read the whole port - then sort out the 'state'
PostPosted: Mon Oct 24, 2011 7:39 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Oct 26, 2011 12:53 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Wed Oct 26, 2011 6:32 am     Reply with quote

1- your int handler is as efficient as i could imagine
2- if it works cleanly - whats the problem ? Very Happy
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