|
|
View previous topic :: View next topic |
Author |
Message |
Ringo42
Joined: 07 May 2004 Posts: 263
|
portB change int problem |
Posted: Sun Jun 04, 2006 8:51 pm |
|
|
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: 1907
|
|
Posted: Sun Jun 04, 2006 9:04 pm |
|
|
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
|
|
Posted: Sun Jun 04, 2006 9:11 pm |
|
|
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: 1907
|
|
Posted: Sun Jun 04, 2006 10:10 pm |
|
|
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
|
|
Posted: Sun Jun 04, 2006 10:56 pm |
|
|
What is the oscillator frequency of the PIC, and what is the frequency
of the encoder signal on Pin B4 ? |
|
|
Ttelmah Guest
|
|
Posted: Mon Jun 05, 2006 2:37 am |
|
|
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
|
|
Posted: Mon Jun 05, 2006 7:39 am |
|
|
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
|
|
Posted: Mon Jun 05, 2006 8:11 am |
|
|
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
|
|
Posted: Mon Jun 05, 2006 9:06 am |
|
|
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
|
|
Posted: Mon Jun 05, 2006 9:17 am |
|
|
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
|
|
Posted: Mon Jun 05, 2006 9:24 am |
|
|
Cool, thanks. I'll give it a try tonight and let you know.
Ringo _________________ Ringo Davis |
|
|
|
|
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
|