View previous topic :: View next topic |
Author |
Message |
Guest
|
Question regarding INT_RB behaviour. |
Posted: Sat Nov 17, 2007 12:12 pm |
|
|
Here is the program that I have:
Code: |
#include <16f877a.h>
#fuses HS
#fuses NOWDT
#fuses NOPROTECT
#fuses NOLVP
#use delay(clock=20000000)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include <stdlib.h>
#include <stdlibm.h>
long counterb;
#INT_RB
void encoder_ISR()
{
++counterb;
printf("\n\r%lu", counterb);
}
void main(void)
{
set_tris_B(0xFF);
counterb = 0;
port_b_pullups(TRUE);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while (!kbhit())
{
if (counterb != 0)
{
// Do whatever here.
}
}
disable_interrupts(INT_RB);
disable_interrupts(GLOBAL);port_b_pullups(TRUE);
}
|
I'm forced to use the CCS PIC16F877A board which has those two LEDs attached to port B leaving B6 and B7 available for external interrupts, which is what we require for two encoders (Timer2 is being used for PWM and not even sure T2 can be externally driven since I never looked into the datasheet for that timer ... I digress).
I would eventually like to create a simple INT_RB handler which will simply run each time there is a change on the upper nibble of port B (B6 and B7) and increment global variables depending on which is actually triggered.
The code compiles fine but nothing happens when I bring B6 or B7 to 5v.
Could that be because I don't have a switch available and it's going from floating voltage to 5 volts? I know it should be going between GND and 5V but I should get at least *something* to indicate that it's running.
What exactly does the port_b_pullups() do exactly? Create an internal resistance to measure a voltage across? I thought that's what a Set_Tris_B() does?
Any other thoughts/suggestions? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Nov 17, 2007 1:49 pm |
|
|
Inside the #int_rb routine, you need to read Port B to clear the
mismatch condition. If you don't do this, you will get Port B interrupts
continuously and your program will appear to be locked up.
Example:
Code: |
#byte PortB = 6 // Address of PortB for 16F-series PICs
#int_rb
void rb_isr()
{
int8 c;
// Put your code here.
c = PortB; // Read PortB to clear mismatch condition
} |
Also, in your main() code, you need to read Port B, and then clear
the INT_RB interrupt flag before you enable Port B interrupts and
global interrupts. Also, the RB6 and RB7 inputs should not be left
floating. I suggest that you enable the pull-ups at the start of the
program. Then cause an interrupt by momentarily connecting one
of the pins (RB6 or RB7) to ground.
Also, be aware that these two pins are used by the debugger or
programmer to talk to the PIC. You can't use these pins for normal
i/o while the programmer or debugger is connected.
Example:
Code: |
void main()
{
char c;
port_b_pullups(TRUE);
delay_us(10); // Allow time for them to pull-up to +5v
c = PortB; // Clear mismatch condition
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
// Put your code here.
while(1); // Prevent PIC from going to sleep
} |
|
|
|
Guest
|
|
Posted: Sat Nov 17, 2007 3:25 pm |
|
|
Yeah, I knew about the debugger pins. I figured that might have been the problem if pins B6 and B7 were left high by the ICD so I've been disconnecting the ICD, then running the program. I can't do much about the floating voltages at home except using the switch on PIN_A4 (normally HIGH).
With that connected I'd expect the ISR to continue counting until the button was held down (driving the pin to GND).
My program doesn't appear to be locking up. It just won't execute the interrupt at all. I know I shouldn't put a printf() statement in my routine but I wanted to have something that I knew for sure would show that something was being done. It just constantly outputs 0, which shouldn't be the case. It should be incrementing and I don't think you can exactly overflow a long in the time for one printf() to occur. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Nov 17, 2007 4:57 pm |
|
|
To cause an INT_RB interrupt, a change in logic levels must occur on
one or more of pins B4-B7. You can't have the pins be in a floating
state. You need to put either a pull-down or a pull-up resistor on the
pins, to provide a well-defined logic level for the idle state. Then put
the opposite voltage on the pin. An interrupt should occur. A 2nd
interrupt will occur when you remove the voltage and the pin returns
to the idle state.
You need to make all the changes that I suggested, and you need to
put pull-up or pull-down resistors on your INT_RB pins. (10K will work). |
|
|
Guest
|
|
Posted: Sun Nov 18, 2007 10:02 am |
|
|
I gather there it interrupts on an edge.
No way to make it interrupt on only one edge or just simply divide by two? I suppose we don't have to be exact and off by one but...
As for the whole port_x_pullup() issue, I'm still not sure why that is needed? I always thought that's what set_Tris_x() does. |
|
|
Ttelmah Guest
|
|
Posted: Sun Nov 18, 2007 10:12 am |
|
|
Very much, no.....
TRIS, configures the individual pins as inputs, or outputs. Once a pin is an input, it can trigger the interrupt. However if it is floating, it can trigger this randomly, at any time, and draw extra power as the input transitions.
An input, _must_ be connected at all times to something, to ensure it is held either high or low. The port_B_pullups, allow a 'floating' input, to reliably be pulled gently high, till a switch or similar source, pulls it low.
The RB interrupt, triggers on both edges. All you do, is in the interrupt, read the level, and see if it is the edge you want.
The separate interrupts (INT_EXTn), can be programmed to occur on a specific edge, but are not available on the pins you want to use.
Best Wishes |
|
|
Guest
|
|
Posted: Sun Nov 18, 2007 4:24 pm |
|
|
So, pullups are only necessary if I cannot ensure a digital logic level and/or the voltage is floating for a period?
Another issue is how to handle debounce? In our case, we are using phototransistors as the interrupt source(s) so should we be concerned about it? |
|
|
SET
Joined: 15 Nov 2005 Posts: 161 Location: Glasgow, UK
|
|
Posted: Mon Nov 19, 2007 5:21 am |
|
|
Yes, phototransistors are effectively light to current converters, so unless they are feeding into a comparator or similar then you might see 'in between' voltages. If you however the phototransistors see only 'light' and 'dark' then it should be fine. |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Mon Nov 19, 2007 7:14 am |
|
|
The port B pullups are already taking the line to 5v. You need to take the line to GND in order to generate your interrupt OR you can remove the port B pullups and fit external pull DOWNS to the pins. That way when you take the pin to 5v you should have your interrupt. |
|
|
zagoaristides
Joined: 08 Jul 2007 Posts: 15 Location: Cordoba - Argentina
|
Hi, the int_rb doesn't work. I've read many threads |
Posted: Tue Feb 23, 2010 2:37 pm |
|
|
Code: |
#include <16F917.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES MCLR //Master Clear pin enabled
#FUSES NOCPD //No EE protection
#FUSES BROWNOUT //Reset when brownout detected
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES NODEBUG //No Debug mode for ICD
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include "C:\Documents and Settings\Aristides\Escritorio\gus\main.h"
char Arriba, Abajo, Enter, Escape;
#int_RB
void RB_isr(void)
{
char auxiliar;
disable_interrupts(INT_RB);
Enter = !input (PIN_B4);
Arriba = !input (PIN_B5);
Abajo = !input (PIN_B6);
Escape = !input (PIN_B7);
delay_ms (20); //anti-rebotes
auxiliar = input_b();
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
/*
#asm movf Port_B,0 #endasm*/
}
void main()
{
char c;
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_lcd(LCD_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
//Setup_Oscillator parameter not selected from Intr Oscillator Config tab
// TODO: USER CODE!!
port_b_pullups(TRUE);
delay_us(10); // Allow time for them to pull-up to +5v
c = input_b(); // Clear mismatch condition
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
// Put your code here.
while(1); // Prevent PIC from going to sleep
}
|
What can I do to make it work ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 23, 2010 3:35 pm |
|
|
How are you testing this ? I don't see any printf statements to show
the output. How do you know if it's working or not working ?
Are you testing this in real hardware, or in Proteus ?
What is the signal source that is driving pins B4 to B7 ? Do you have
push-button switches on those pins ? Or some other signal ?
What are the voltage levels of the signals ? |
|
|
zagoaristides
Joined: 08 Jul 2007 Posts: 15 Location: Cordoba - Argentina
|
Thanks my friend |
Posted: Tue Feb 23, 2010 4:03 pm |
|
|
PCM programmer wrote: | How are you testing this ? I don't see any printf statements to show
the output. How do you know if it's working or not working ?
Are you testing this in real hardware, or in Proteus ?
What is the signal source that is driving pins B4 to B7 ? Do you have
push-button switches on those pins ? Or some other signal ?
What are the voltage levels of the signals ? |
I've tested on Proteus. The others work, this doesn't |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 23, 2010 4:31 pm |
|
|
I can't test anything on Proteus because I don't have it. |
|
|
zagoaristides
Joined: 08 Jul 2007 Posts: 15 Location: Cordoba - Argentina
|
|
Posted: Mon May 03, 2010 7:38 am |
|
|
PCM programmer wrote: | I can't test anything on Proteus because I don't have it. |
in real simulation doesn't work either. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon May 03, 2010 11:14 am |
|
|
I looked at your code and found a problem with this line:
Quote: |
port_b_pullups(TRUE);
|
In the 16F917, PortB pullups are individually enabled. You need to
use a bitmask instead of True/False. If you want pull-ups on pins B4-B7
then you need to set those bits high, in the function parameter. Example:
Code: |
port_b_pullups(0xF0); // Enable pull-ups on pins B4-B7
|
|
|
|
|