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

portB change int problem

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



Joined: 07 May 2004
Posts: 263

View user's profile Send private message

portB change int problem
PostPosted: Sun Jun 04, 2006 8:51 pm     Reply with quote

I have an encoder hooked up to a pic18f452 to pin B4. B5 is set low at all times, and B6 and B7 are always outputs to leds.
Here is my code;
Code:

#int_RB
B4_isr()
{
   int portval;
// printf("encoder=%ld\r\n",Actual_Pos_L);
   portval=input_b();//clear the int
   if(input(PIN_Enc1_B)==1) //only on rising edge
   {
         Actual_POS_L++;
   }
}


I would think that with every encoder tick it would increment by 1. But what happens is it incrememts by 2 or 3 or 4. If I uncomment the print statement then it works perfectly. Can the portval=input_b(); be taking too long to clear the int and it is happening again or something? I tried disabling that int at the beginning and enabling it at the end of the routine but get the same results. What am I doing wrong?
Thanks
Ringo
_________________
Ringo Davis
newguy



Joined: 24 Jun 2004
Posts: 1911

View user's profile Send private message

PostPosted: Sun Jun 04, 2006 9:04 pm     Reply with quote

You're seeing classic switch bounce. To you, one turn is actually several (2 or 3 or 4) bounces. Without the printf, the PIC is fast enough to catch them all. With the printf, the first transition causes the interrupt to fire, and the printf within the interrupt takes a relatively long time to perform. By the time it's done performing, the switch has physically stopped bouncing and the code "seems" to work as it should.

What you should really do is something like this:

- at first switch transition, set a timer to go off in something like 30 - 70 ms (depends on the switch and to some extent on the person operating it)
- until the timer goes off, ignore further switch transitions
- when the timer goes off, if the switch state is different from the last one you detected, something happened. Reset/disable the timer, record this switch state as the "old" value (for use next time), and set a flag for the main program to let it know that a switch was pressed or your rotary encoder was turned.
Ringo42



Joined: 07 May 2004
Posts: 263

View user's profile Send private message

PostPosted: Sun Jun 04, 2006 9:11 pm     Reply with quote

It is an optical encoder, so no bounce. I'm watching it in an O'scope and don't see any bounce at all. I have the exact same thing hooked up to B0 and I'm using the external int and don't have this problem. That is why I was wonder is reading portB to clear the int was happening too slowly or something.
Ringo
_________________
Ringo Davis
newguy



Joined: 24 Jun 2004
Posts: 1911

View user's profile Send private message

PostPosted: Sun Jun 04, 2006 10:10 pm     Reply with quote

Ringo42 wrote:
It is an optical encoder, so no bounce. I'm watching it in an O'scope and don't see any bounce at all. I have the exact same thing hooked up to B0 and I'm using the external int and don't have this problem. That is why I was wonder is reading portB to clear the int was happening too slowly or something.
Ringo


Interesting. Sorry but I don't have any clue what the problem is.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 04, 2006 10:56 pm     Reply with quote

What is the oscillator frequency of the PIC, and what is the frequency
of the encoder signal on Pin B4 ?
Ttelmah
Guest







PostPosted: Mon Jun 05, 2006 2:37 am     Reply with quote

Being an 'optical encoder', does _not_ guarantee that there is no 'switch bounce'. It makes it likely that the bounce will be at a much higher frequency, but unfortunately, depending on the design of the encoder (some have filtration in them to stop this), it is possible on some optical encoders to see oscillation at the transition (not 'bounce' as such, but the effect is the same...). I must admit to suspecting that this is the problem, with the signal taking a few uSec to stabilise.
The data sheet for the encoder, should show if any protection is needed to prevent this. Normally using a comparator with significant hysteresis present, combined with a little high frequency blocking, may be required. Another similar problem can exist with encoders that have their own internal comparator, if the supply is not adequately decoupled, with the output transition, causing the supply rail to droop, and resulting in a second spurious transition.

Best Wishes
Ringo42



Joined: 07 May 2004
Posts: 263

View user's profile Send private message

PostPosted: Mon Jun 05, 2006 7:39 am     Reply with quote

If is bounce or oscillation I cannot see it on my Oscope which would mean it has to be very fast. But if that was the case I should be able to debounce it in software, but i can put a delay in as much as 200ms either before or after reading portb to clear the interrupt and I still get the problem. But printing just 1 byte seems to fix the problem (which is much less than 200ms). Could it be something with the way I'm checking the input or something? The pic is running at 20Mhz and the encoder right now I'm doing manually so I would say 1/4 to 1 hz. It is a slot type encoder and if I break the beam with a piece of paper then remove the paper I get several counts. But the same thing hooked up to B0 works great. The encoder attaches to a wheel on a robot so it will be running around 1khz or so when attached, but for now I'm just trying to make sure it works at slow speeds. There is no internal comparator or anything on the encoder, just a basic IR-led and a phototransistor in a slot package with an external pullup on the line. I'm using LVP so I think B5 is always an input even though I set it as an output in the SW, but it has a 1K pulldown to ground, so I can't imagine it is causing any noise. There must be something I'm missing here. Any thoughts?
Ringo
_________________
Ringo Davis
Ttelmah
Guest







PostPosted: Mon Jun 05, 2006 8:11 am     Reply with quote

OK.
Some questions arise.
Have you selected 'fast_io' on B?. If not, then potentially, when you read from port b, the compiler will change the state of the TRIS, and it is possible that you then 'see' the output pins as a signal change!. The test:

if(input(PIN_Enc1_B)==1) //only on rising edge

if 'true', for as long as the pin is high (not just on the rising edge), so if something else like this causes a recall of the interrupt, you would get the multiple counts described...

So, I'd try the following:
Make sure you have a '#use fast_io(b)', as well as a tris statement (which your comments suggest you have), and alter the code to:
Code:

#int_RB
B4_isr()
{
   int portval;
   static int oldport;
   portval=input_b() & 0x10;//clear the int and mask the required bit
   if(portval) {
      //Here input is high
      if (oldport==0) {
         //here on rising edge only
         Actual_POS_L++;
      }
   }
   oldport=portval;
}


Best Wishes
Ringo42



Joined: 07 May 2004
Posts: 263

View user's profile Send private message

PostPosted: Mon Jun 05, 2006 9:06 am     Reply with quote

Thanks, I'll try that code tonight when I get home.
I'm currently not using tris at all, I just set my outputs low and and do a
dummy_variable = input(PIN_B0);
for my inputs in my init section to set everything up.

Just to make sure I understand I should have #use fast_io(b); in my init code then something like
set_tris_b(0b1101100);
so that B0,1,4,5 are inputs and the rest are outputs. I should only need to do this once right? I'm not changing any of these from inputs to outputs or vice-versa.
Thanks
Ringo
_________________
Ringo Davis
Ttelmah
Guest







PostPosted: Mon Jun 05, 2006 9:17 am     Reply with quote

This is the core of the problem then.
As soon as you perform the 'input_b' instruction, the compiler will set _all_ the pins of portB, to be inputs. At this point, if you have driven pins feeding LED's, they will at this instant be 'on' driving the LEDs, and will start to turn off. A short time latter, the interrupt will trigger again, because of this change!...
Hence the interrupt is triggering multiple times.
In the outside loop, the LEDs are presumably reset, so the whole thing happens again.
Basically add a #use fast_io(b) statement at the top of your program, and before you try to use the pins, a single tris statement.
You have your tris byte reversed as shown. The correct value is:
set_tris_b(0b00110011);

A '1' is an Input, and a '0', an output, with the bits laid out MSB....LSB.
Just this change, ought to make it work.

Best Wishes
Ringo42



Joined: 07 May 2004
Posts: 263

View user's profile Send private message

PostPosted: Mon Jun 05, 2006 9:24 am     Reply with quote

Cool, thanks. I'll give it a try tonight and let you know.
Ringo
_________________
Ringo Davis
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