View previous topic :: View next topic |
Author |
Message |
Paul H Guest
|
16F873 Interrupts. |
Posted: Wed Oct 24, 2001 7:17 pm |
|
|
Hi all. Trying to get to grips with using Interrupts for
the first time. ''CCS User manual is about useless'' for
this as there is no real explanition of what the actual
INT-XXX Does. Everything is crammed on to one page with
a cheezy example.
Anyway to my question. I have pins RB0, RB2, RB3 configured
as an input. The logic transition on these pins is High to low.
There is an individual switch connected to each pin, when the switch is pressed the pin goes low.
? What is a good way of implementing a interrupt routine
that will catch if the switch on any of these pins gets closed
assuming that in main there is something else going on such as
shifting out data on a pin such as rb6.
The idea is to stop the shifting of data on rb6 and do something
else based on the actual switch closure, then return to shifting
out the data when the switch is released.
A code snip would be a big help if anyone has got one to help
clue me in.
Also I notice in the help file a reference to #INT_BUTTON.
Any idea of what this pertains to and its intended useage.
Thanks for the help....Paul.
___________________________
This message was ported from CCS's old forum
Original Post ID: 824 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: 16F873 Interrupts. |
Posted: Wed Oct 24, 2001 7:41 pm |
|
|
:=Anyway to my question. I have pins RB0, RB2, RB3 configured
:=as an input. The logic transition on these pins is High to low.
:=There is an individual switch connected to each pin, when the switch is pressed the pin goes low.
:=
:=? What is a good way of implementing a interrupt routine
:=that will catch if the switch on any of these pins gets closed
:=assuming that in main there is something else going on such as
:=shifting out data on a pin such as rb6.
--------------------------------------------------------
In Section 3.2 of the data sheet, it says that the "interrupt
on change" feature is available on pind 4-7 of Port B.
So you'll have to move the switches to those pins.
Here's some code that shows how INT_RB works. This is
really just some demo code. It doesn't do de-bouncing.
I have some real code for an interrupt driven keypad,
where when you press a key, it sets a hardware timer
for the debounce period, and then reads the key.
But you need something a bit more simple. Maybe
someone else has that.
-------------------------------------------------------
// Here is a sample program to test Port B interrupt-on-change.
// If you touch pins B4 to B7 with a ground wire,
// this program will send the value of interrupt_count
// to your RS-232 terminal.
// In fact, it will usually send several counts, because of
// "bounce".
#include "16F877.h"
#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use Delay(Clock=8000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#zero_ram
// Declare a variable for the hardware Port B.
// Then we can access Port B by reading or writing
// to this variable.
#byte port_b = 6
//------------------------------------------------
// FUNCTION PROTOTYPES
void int_rb_isr(void);
//------------------------------------------------
// GLOBALS
char got_interrupt;
char interrupt_count;
//=====================================================
void main(void)
{
// Make all port B pins be inputs
set_tris_b(0xff);
// Set port B to a known state
port_b = 0;
// Enable pullups on all port B pins.
port_b_pullups(TRUE);
// Wait for them to pull up.
delay_us(10);
interrupt_count = 0;
got_interrupt = FALSE;
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
// Wait in this loop, and check if we got an interrupt.
// If so, then display the value of interrupt_count.
while(1)
{
disable_interrupts(INT_RB);
if(got_interrupt == TRUE)
{
printf("\%d\n\r", interrupt_count);
got_interrupt = FALSE;
}
enable_interrupts(INT_RB);
}
}
//======================================================
// This function will clear the RBIF flag automatically.
// The CCS compiler inserts the code to do that.
// You can see this by looking at the .LST file.
//
// However, we have to put in code to clear the
// change condition. CCS does not do that for us.
// We can do it by just reading Port B.
#int_rb
void int_rb_isr(void)
{
// This variable should be declared as static, to hopefully
// prevent a CCS bug, in which memory allocated to isr varibles
// is sometimes reused for other variables. (Known to exist
// in vs. 2.xxx. Not known if still exists in 3.xxx).
static char i;
// Clear the change condition by reading Port B.
i = port_b;
interrupt_count++;
got_interrupt = TRUE;
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 825 |
|
|
Guan Choon Lim Guest
|
Interrupt Driven Keypad |
Posted: Wed Oct 01, 2003 10:25 pm |
|
|
Hi. Does anyone have a demo code on interrupt driven keypad? I am trying to understand the theory of design a interrupt driven console program to monitor user inputs from keypad, switches and rotary encoder.
Your help is greatly appreciated!
Regards
Lim |
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Fri Jul 30, 2010 3:20 am |
|
|
Sorry to kick up this very old discussion but I'm having trouble getting my interrupt to work.
I've amended the program PCM programmer posted above to this (additon of set/clear LED and updated fuses and header files for my device):
Code: |
#include "18F4520.h"
#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use Delay(Clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#zero_ram
#byte port_b = 6
//------------------------------------------------
// FUNCTION PROTOTYPES
void int_rb_isr(void);
//------------------------------------------------
// GLOBALS
char got_interrupt;
char interrupt_count;
void main(void)
{
// Make all port B pins be inputs
set_tris_b(0xff);
// Set port B to a known state
port_b = 0;
// Enable pullups on all port B pins.
port_b_pullups(TRUE);
// Wait for them to pull up.
delay_us(10);
interrupt_count = 0;
got_interrupt = FALSE;
//enable_interrupts(INT_RB);
//enable_interrupts(GLOBAL);
// Wait in this loop, and check if we got an interrupt.
// If so, then display the value of interrupt_count.
while(TRUE)
{
//disable_interrupts(INT_RB);
printf("Interrupt Count: \%d\n\r", interrupt_count);
if(got_interrupt == TRUE)
{
printf("Interrupt Count: \%d\n\r", interrupt_count);
got_interrupt = FALSE;
}
output_low(PIN_A5);
delay_ms(100);
output_high(PIN_A5);
delay_ms(100);
enable_interrupts(INT_RB);
}
}
#int_rb
void int_rb_isr(void)
{
static char i;
i = port_b;
interrupt_count++;
got_interrupt = TRUE;
}
|
I'm finding that with the interupts enabled the software only runs once and then hangs - commenting out the enables allows it to run continously.
I've read through the RB section of the datasheet and nothing strikes as being wrong.
Compiler version: 4.087
Hardware: PIC18F4520 CCS Development Board
Programmer: ICD-U64
Circuit:
Push button switch with pull up resistor on A4
LEDs on A5, B4 and B5 going to 5V rail.
Wire connecting Pins A4 to B5.
Voltage level change on Pin B5 checked with DVM. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Fri Jul 30, 2010 3:46 am |
|
|
One really big problem....
Inside the interrupt on change, you need to read portB, to clear the interrupt. You think you are doing this, reading from a variable called 'port_b', and allocated to address 6. However 'portb', is _not_ at address 6, on a PIC18. You need to read the data sheet, and move the port_b variable to the right location....
Best Wishes |
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Fri Jul 30, 2010 4:34 am |
|
|
Thanks, I've amended it but still the same performance:
Datasheet
http://ww1.microchip.com/downloads/en/DeviceDoc/39631a.pdf
Page 65:
New address:
Code: | int16 port_b = 0xF81; |
and updated the interrupt function:
Code: | static int16 i;
// Clear the change condition by reading Port B.
i = port_b; |
|
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Fri Jul 30, 2010 6:21 am |
|
|
I've managed to work out that it never seems to leave the interrupt. Disabling the interrupt inside the interrupt function is the only way I've managed to return it to the main program - which isn't suitable for my program. |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Fri Jul 30, 2010 6:35 am |
|
|
Code: |
int16 port_b = 0xF81;
|
This is wrong.
All this does is create a 16 bit int and assign the value 0xF81 to it.
you need to use #BYTE
Code: |
#BYTE port_b = 0xF81
|
|
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Fri Jul 30, 2010 6:42 am |
|
|
That's not going to work.
You are going to need to change this:
Code: | int16 port_b = 0xF81; |
to this:
Code: | #byte port_b = 0xF81 |
But why do you need to explicitly declare PORTB. The location is already in the header file for your device.
To read the state of PORTB you can just use the CCS function input_x():
Code: | static int8 i;
i = input_b(); //returns the byte representing the input state of PORTB pins |
Last edited by mkuang on Fri Jul 30, 2010 6:46 am; edited 2 times in total |
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Fri Jul 30, 2010 6:42 am |
|
|
Excellent thanks for that, it's working nicely.
A couple of question if I may so I understand it....
In my device header file it lists:
How is
#BYTE port_b
different to
int8 port_b?
Also is BYTE is defined as int8 how can you store a 12bit value in it?
Cheers, |
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Fri Jul 30, 2010 6:46 am |
|
|
mkuang wrote: | But why do you need to explicitly declare PORTB. The location is already in the header file for your device.
To read the state of PORTB you can just use the CCS function input_x():
Code: | static int8 i;
i = input_b(); //returns the byte representing the input state of PORTB pins |
|
I was just looking at sample code on here to better my understanding of it. Didn't want to go deleting lines until I had the program working. |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Fri Jul 30, 2010 6:50 am |
|
|
Please post your working program. |
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Fri Jul 30, 2010 6:53 am |
|
|
Code: |
#include "18F4520.h"
#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use Delay(Clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#zero_ram
#use fast_io(B)
#BYTE port_b = 0xF81
// FUNCTION PROTOTYPES
void int_rb_isr(void);
// GLOBALS
char got_interrupt;
char interrupt_count;
void main(void)
{
set_tris_b(0xff);
set_tris_a(0x00);
port_b = 0;
port_b_pullups(TRUE);
delay_us(10);
interrupt_count = 0;
got_interrupt = FALSE;
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while(TRUE)
{
disable_interrupts(INT_RB);
if(got_interrupt == TRUE)
{
printf("\%d\n\r", interrupt_count);
got_interrupt = FALSE;
}
enable_interrupts(INT_RB);
}
}
#int_rb
void int_rb_isr(void)
{
static int16 i;
i = port_b;
interrupt_count++;
got_interrupt = TRUE;
disable_interrupts(INT_RB);
}
|
|
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Fri Jul 30, 2010 7:03 am |
|
|
You do not need this actually:
#BYTE port_b = 0xF81
If you look at the file "18F4520.h" (I don't have that compiler installed on this PC) you should see something like:
#BYTE PORTB = 0xF81 already in there.
In your code you can simply omit your port_b declaration and use the PORTB already declared by your compiler. |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Fri Jul 30, 2010 8:41 am |
|
|
Geps wrote: | Excellent thanks for that, it's working nicely.
A couple of question if I may so I understand it....
In my device header file it lists:
How is
#BYTE port_b
different to
int8 port_b?
Also is BYTE is defined as int8 how can you store a 12bit value in it?
Cheers, |
Note the difference between BYTE and #BYTE
#BYTE (has a # in front) is a pre-processor directive to tell the compiler to create a variable which has an address of what follows.
#define BYTE int8
This tells the compile to replace all instances of BYTE (no #) with int8
so
Code: |
BYTE myvar;
is the same as
int8 myvar;
|
|
|
|
|