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 support@ccsinfo.com

PIC16F877A external EXT interrupt problem

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



Joined: 17 Sep 2008
Posts: 10

View user's profile Send private message

PIC16F877A external EXT interrupt problem
PostPosted: Wed Sep 17, 2008 6:41 am     Reply with quote

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: 192
Location: Hemet, California USA

View user's profile Send private message

PostPosted: Wed Sep 17, 2008 8:10 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 17, 2008 2:40 pm     Reply with quote

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:
Code:
return(0);
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

View user's profile Send private message Yahoo Messenger

PostPosted: Wed Sep 17, 2008 11:51 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Sep 18, 2008 6:31 am     Reply with quote

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
   }
}
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