|
|
View previous topic :: View next topic |
Author |
Message |
Nandus2000
Joined: 17 Sep 2008 Posts: 10
|
PIC16F877A external EXT interrupt problem |
Posted: Wed Sep 17, 2008 6:41 am |
|
|
Dear Friends,,
I'm using CCS C compiler for PIC16F877.
In the hardware, two push buttons are connected at RB0 and RB1.
I've written code to handle RB0/INT using following code.
I don't know how to handle an external interrupt on RB1 pin.
The following code is able to recognise the button press at RB0 only ones.
It seems I'm missing something simple.
I sincerely appreciate your prompt help.
Following is my code snippet:
Code: |
/************************************************************
System Includes
************************************************************/
#include <16F877.H>
/**********************************************************
compiler directives
**********************************************************/
#if defined(__PCM__)
#fuses HS,NOWDT,NOPROTECT // Preprocessor directive that defines the chip fuses
#use delay(clock=4M) // Preprocessor directive that specifies clock speed
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Preprocessor directive that includes RS232 libraries
#endif
/*******************************************************
Global variables
*******************************************************/
short B0_Pressed = FALSE;
short B1_Pressed = FALSE;
// external interrupt when button pushed and released
#INT_EXT
void ext_isr(void)
{
volatile unsigned int uiDelay = 0x1FF;
// debounce button delay
while(uiDelay--);
B0_Pressed = TRUE;
clear_interrupt(INT_EXT);
}
/***********************************************************
Function Name : main
Description : Main - Start of Program
Parameters : None
Returns : int
************************************************************/
int main(void)
{
long counter;
ext_int_edge(H_TO_L); // init interrupt triggering for button press
enable_interrupts(INT_EXT);// turn on interrupts
enable_interrupts(GLOBAL);
printf("Hi \n\n");
counter=0; // reset the counter
while(TRUE)
{
if(B0_Pressed == TRUE)
{
printf("Button B0 pressed \r\n");
B0_Pressed = FALSE;
counter = 0;
}
if(B1_Pressed == TRUE)
{
printf("Button B1 pressed \r\n");
B1_Pressed = FALSE;
counter = 0;
}
printf("The count value is: %5ld \r\n",counter);
counter++; // display count value and increment
delay_ms(1000); // every second
}
while(1);
return(0);
}
|
|
|
|
drh
Joined: 12 Jul 2004 Posts: 193 Location: Hemet, California USA
|
|
Posted: Wed Sep 17, 2008 8:10 am |
|
|
There is no external interrupt associated with pin 1 of port b, only pin 0.
Your other choice is to use RB4 - RB7 pins with the "interrupt on change" feature. It's all in the data sheet for the PIC16F887. _________________ David |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Sep 17, 2008 2:40 pm |
|
|
Some small remarks for improving your code:
Code: | volatile unsigned int uiDelay = 0x1FF; | 1) 'Volatile' is used for variables that can be changed at any point during execution. This is a rarely used directive and then only for variables outside an interrupt. This piece of code is inside an interrupt so there is nothing in the PIC processor that could come in between. Remove the volatile directive to get easier to read and perhaps even smaller code.
2) Integers in the CCS compiler are always 'unsigned' unless declared as signed. Your code is not wrong but the extra unused keyword makes your code larger without any positive effect.
3) The 'int' type in the CCS compiler is 8 bit and is too small for the 0x1FF value, this is according to the K&R C specifications where the integer type is to follow the natural size of the processor used.
Luckily you didn't specify 0x200 or the loop wouldn't have looped at all.
Change to 'long' or int16.
Code: | #if defined(__PCM__) | Unless you intend to use your code for both PIC16 and PIC18 processors this line has little use and is again code bloating.
Code: | #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) | It is good practice to add the ERRORS directive to this line. In fact I would have thought it better for CCS to always enable this useful feature and have a NOERRORS directive instead for the rare cases where people want to disable it. The ERRORS directive causes the compiler to generate extra code for resetting the UART receiver flags on every call to getc(). This prevents the UART from stalling on buffer overflows.
Code: | clear_interrupt(INT_EXT); | The CCS compiler automatically adds this instruction at the end of the ISR, so effectively you are clearing the interrupt twice. It won't hurt but is a waste of resources.
Your main ends with:In the PIC there is no OS for the main function to return to so it makes no sense to return a value; there is no hardware present that will do anything with the returned value. Simplify your program by removing the return (and change 'int main()' to 'void main()'). |
|
|
drdelphi
Joined: 22 Apr 2007 Posts: 22 Location: Romania
|
|
Posted: Wed Sep 17, 2008 11:51 pm |
|
|
Code: | // make sure you connect the push buttons to B0/B1 and to VSS
#include <18F2520.H> //16F877 doesn't have EXT_INT1
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=8M,int)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, errors)
short B0_Pressed = FALSE, B1_Pressed = FALSE;
#INT_EXT
void ext_isr(void) {
int16 uiDelay = 0x1FF;
while(uiDelay--);
B0_Pressed = TRUE;
}
#INT_EXT1
void ext_isr1(void) {
int16 uiDelay = 0x1FF;
while(uiDelay--);
B1_Pressed = TRUE;
}
void main(void) {
long counter;
port_b_pullups(true);
ext_int_edge(0, H_TO_L);
ext_int_edge(1, H_TO_L);
enable_interrupts(INT_EXT);
enable_interrupts(INT_EXT1);
enable_interrupts(GLOBAL);
printf("Hi \n\n");
counter = 0;
for (;;) {
if (B0_Pressed) {
printf("Button B0 pressed \r\n");
B0_Pressed = FALSE;
counter = 0;
}
if (B1_Pressed) {
printf("Button B1 pressed \r\n");
B1_Pressed = FALSE;
counter = 0;
}
printf("The count value is: %5ld \r\n",counter);
counter++;
delay_ms(1000);
}
} |
|
|
|
Nandus2000
Joined: 17 Sep 2008 Posts: 10
|
|
Posted: Thu Sep 18, 2008 6:31 am |
|
|
Dear All,
Thanks a lot for your prompt & kind reply.
Since port pin B1 does not have any interrupt (for PIC16F877)), I've implemented it using timer & polling based logic.
I'm using the " volatile signed long iDelay = DEBOUNCE_DELAY; " so that the the compiler don't generate any optimised code for the de-bouncing delay loop.
This is just a test code timer calculation may be incorrect @ 4MHz..
Please let me know your comments.
Code: |
/**************************************************************************************************
System Includes
**************************************************************************************************/
//#include <16F883.H>
#include <16F877.H>
//Switch debounce
#define DEBOUNCE_DELAY (500)
/**************************************************************************************************
compiler directives using __PCM__ compiler
***************************************************************************************************/
// Preprocessor directive that defines the chip fuses
#fuses HS,NOWDT,NOPROTECT
// Preprocessor directive that specifies clock speed
#use delay(clock=4M)
// Preprocessor directive that includes RS232 libraries
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
/**************************************************************************************************
Global variables
***************************************************************************************************/
volatile BOOLEAN flg_B0_Pressed = FALSE;
volatile BOOLEAN flg_B1_Pressed = FALSE;
//Initialize g_LastData to set port B0 & B1 to high by default (connected to pull-ups).
unsigned char g_LastData = 3;
/**************************************************************************************************
Function Name : isr_timer2
Description : Interrupt service routine called every milli-second.
Parameters : None
Returns : None
****************************************************************************************************/
#int_timer2
void isr_timer2(void)
{
volatile signed long iDelay = DEBOUNCE_DELAY;
unsigned char bChanges;
bChanges = (g_LastData ^ input_b()); //Check B0 or B1 changed.
g_LastData = input_b();
//Checking SW0/B0 and SW1/B1 if it goes High to Low
if( bit_test(bChanges,0) && (!bit_test(g_LastData,0)) )
{ //B0 went to low
flg_B0_Pressed = TRUE;
while(idelay --); //Debouncing wait.
}
else if( bit_test(bChanges,1) && (!bit_test(g_LastData,1)) )
{ //B1 went to low
flg_B1_Pressed = TRUE;
while(idelay --); //Debouncing wait.
}
//keep a running timer every milli-second
//output_toggle(PIN_B7); // To test timer2 on waveform.
}
/**************************************************************************************************
Function Name : main
Description : Main - Start of Program
Parameters : None
Returns : None
****************************************************************************************************/
void main(void)
{
long counter = 0;
/* Configur the camera after power-on reset.*/
//SCCB_Config_Camera();
setup_timer_2(T2_DIV_BY_4,79,16); //setup up timer2 to interrupt every 1ms if using 20Mhz clock
enable_interrupts(INT_TIMER2); //enable timer2 interrupt
enable_interrupts(GLOBAL); //enable all interrupts (else timer2 wont happen)
while(TRUE)
{
if(flg_B0_Pressed == TRUE)
{
flg_B0_Pressed = FALSE;
printf("Button B0 pressed \n");
counter = 0;
}
if(flg_B1_Pressed == TRUE)
{
flg_B1_Pressed = FALSE;
printf("Button B1 pressed \n");
counter = 0;
}
//printf("The count value is: %5ld port B: 0x%X \n",counter, input_b());
counter++; // display count value and increment
delay_ms(20); // every second
}
}
|
|
|
|
|
|
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
|