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 CCS Technical Support

INT_RB problem [solved]

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



Joined: 15 May 2011
Posts: 6
Location: San José, CR

View user's profile Send private message MSN Messenger

INT_RB problem [solved]
PostPosted: Mon May 16, 2011 12:04 am     Reply with quote

Hi folks out there!

This is my first post. I've been reading lots of forums about the interrupt handling on PORTB with INT_EXT and INT_RB. I managed to make some code from everything I read and all the suggestions that were made.
For some reason the PIC is no getting into the RB interrupt routine (I checked that with the RS232 and printf). Here´s first some relevant information:

CCS PCM C Compiler, Version 4.108, 42649
Target MCU: PIC16F887
Input Voltage: 5V
Xtal Speed: 8MHz

I'm trying to implement some pushbuttons on PORTB to handle some LED's on and off (I know that's easy) and the use of a DS1631 Digital Thermometer (already working perfectly). The pushbuttons should be regularly at 0 and when pushed they set the port pin at 1 (I think this is better than going low from high for power saving reasons).

Here's the code I currently have:

Code:


#include <main.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lcd.c>

////////////////////////////////////////////////////////////////////////////////
//                     Defines Declaration                                    //
////////////////////////////////////////////////////////////////////////////////
#define LOWTOHIGH TRUE
#define HIGHTOLOW FALSE
#BYTE INTCON = 0xff2    //INTCON: INTERRUPT CONTROL REGISTER
#BYTE IOCB = 0xf7d      // interrupt on change bit  control
#byte ANSEL = 0xF7E
#byte ANSELH = 0xF7F
#use fast_io(B)
////////////////////////////////////////////////////////////////////////////////
//                     Variable Declaration                                   //
////////////////////////////////////////////////////////////////////////////////

int16 value; //Variable used for reading the ADC Port
int1 done;//Variable that controls the activity of the ADC Port
unsigned char Config; // Config. Reg. Data
int8 temp_H;//MSB del registro Temperature
int8 temp_L;//LSB del registro Temperature
unsigned char MSB; // temp byte MSB
unsigned char LSB; // temp byte LSB
float temp;//Read Temperature
float TH=40;
float TL=0;
int8 mensaje=0x42;
short int dbutton4, dbutton5, dbutton6, dbutton7;
int current;
static int last=0;

////////////////////////////////////////////////////////////////////////////////
//                     Interrupt Service Rutine Declaration                   //
////////////////////////////////////////////////////////////////////////////////
#INT_RB
void detect_rb_change(void)
{
   printf("Entering INT_RB\n\r");
   current=input_b();

   #if LOWTOHIGH
   if ((!bit_test(last,4))&&(bit_test(current,4)))
         dbutton4=1;
   if ((!bit_test(last,5))&&(bit_test(current,5)))
         dbutton5=1;
   if ((!bit_test(last,6))&&(bit_test(current,6)))
         dbutton6=1;
   if ((!bit_test(last,7))&&(bit_test(current,7)))
         dbutton7=1;
     
   #elif HIGHTOLOW
   if ((!bit_test(current,4))&&(bit_test(last,4)))
         dbutton4=1;
   if ((!bit_test(current,5))&&(bit_test(last,5)))
         dbutton5=1;
   if ((!bit_test(current,6))&&(bit_test(last,6)))
         dbutton6=1;
   if ((!bit_test(current,7))&&(bit_test(last,7)))
         dbutton7=1;
   #endif

   last=current;
   delay_ms(1);
}

////////////////////////////////////////////////////////////////////////////////
//                     Function Prototypes Definition                               //
////////////////////////////////////////////////////////////////////////////////

   //Config Reg writing routine
   void writeConfigReg (void)  {}
   
   //Config Reg reading routine 
   void readConfigReg (void) {}
       
   // TH & TL Reg writing routine
   void writeTHTLReg(void)   {}

   //Measure temperature and display value routine
   void measureTemp (void) {} 
     
   // This function reads Port B without changing the TRIS.
   int8 input_state_b(void)
   {
      #byte PortB = 6  // PortB address for 16F PICs   
      return(PortB);
   }
   
   void clear_reg(void)
   {
      dbutton4=0;
      dbutton5=0;
      dbutton6=0;
      dbutton7=0;
      current = input_state_b();
      last = current;
   }
   
////////////////////////////////////////////////////////////////////////////////
//                     Main Function                                                       //
////////////////////////////////////////////////////////////////////////////////

void main()
{
   setup_adc_ports(RA1);
   setup_adc(ADC_CLOCK_DIV_2);   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_comparator(NC_NC_NC_NC);
   disable_interrupts(INT_TIMER0);
   disable_interrupts(GLOBAL);
   
   //PortB interrupts set up
  port_b_pullups(TRUE);
   set_tris_b(0xF0);
   delay_us(10); //ensure line has time to settle
   clear_reg();
   IOCB = 0xF0;
   ANSEL = 0;
   ANSELH = 0;
   last=input_b();
   clear_interrupt(INT_RB);
   disable_interrupts(INT_EXT);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);

   output_high(pin_C3); //Led that indicates the PIC is on 
   
   //DS1631 set up
   writeConfigReg();
   readConfigReg();
   writeTHTLReg();     
             
      do
      {
         measureTemp();//Measures and display temperature every second
         delay_ms(500);
       
      printf("Entering DO\n\r");//This works as a "flag" on the RS232
      if(dbutton4)
      {
        dbutton4=FALSE;
        printf("dbuttom4\n\r");
      }
     
      if(dbutton5)
      {
        dbutton5=FALSE;
        printf("dbuttom5\n\r");
      }
     
      if(dbutton6)
      {
        dbutton6=FALSE;
        printf("dbuttom6\n\r");
      }
     
      if(dbutton7)
      {
        dbutton7=FALSE;
        printf("dbuttom7\n\r");
      }   
     
      printf("Getting out of DO\n\r");

      }while(1);
         

   while(1);
}



1. This is a mixture of different codes I've seen but the PIC does not enter on INT_RB when a button is pushed over RB<7:4>.
2. What are the following lines for? I know that later on in the program IOCB = 0xF0 sets RB<7:4> as inputs.
Code:

#BYTE INTCON = 0xff2   
#BYTE IOCB = 0xf7d     
#byte ANSEL = 0xF7E
#byte ANSELH = 0xF7F


Thanks so much in advance if anyone has an idea of whats going on.


Last edited by Stormrider on Mon May 16, 2011 9:26 pm; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon May 16, 2011 12:54 pm     Reply with quote

Quote:

Target MCU: PIC16F887

What are the following lines for? I know that later on in the program
IOCB = 0xF0 sets RB<7:4> as inputs.

#BYTE INTCON = 0xff2
#BYTE IOCB = 0xf7d
#byte ANSEL = 0xF7E
#byte ANSELH = 0xF7F

Those are PIC register addresses, and they are incorrect for your PIC.

Download the 16F887 data sheet.
http://ww1.microchip.com/downloads/en/DeviceDoc/41291F.pdf
Look in this section (on page 27 in the Acrobat reader):
Quote:

FIGURE 2-6: PIC16F886/PIC16F887 SPECIAL FUNCTION REGISTERS

You will see the correct addresses for those registers. Edit those 4 lines
to fix the problem.
Stormrider



Joined: 15 May 2011
Posts: 6
Location: San José, CR

View user's profile Send private message MSN Messenger

PostPosted: Mon May 16, 2011 1:25 pm     Reply with quote

Thanks so much PCM Programmer, your advice did help.

Before you replied I was implementing INT_EXT successfully and was turning on/off an LED with the push button at B0 and changing respectively a inner variable that holds the state of the LED (will need fit urther on for taking some decisions).

After I changed the register addresses, INT_RB started triggering correctly and could determine which button<7:4> was pressed. The only strange thing is that now B0 is triggering INT_RB and INT_EXT seldomly (like 1 time every 20 pushes). Do you have an idea of why is B0 triggering INT_RB instead of INT_EXT??

Thanks so much again!

[edit]

By the way, the 16F887 datasheet states that INTCON has 4 different addresses (0x0B, 0x8B, 0x10B, 0x18B), I just chose 0x0B randomly because I couldn't find anything particular to which address to choose.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon May 16, 2011 1:34 pm     Reply with quote

I notice you have this line. It's for an older PIC, such as 16F877.
Quote:
port_b_pullups(TRUE);


But the 16F887 has more features. The pull-ups can now be turned on/off
for each pin. The data sheet says:
Quote:

3.4.2 WEAK PULL-UPS

Each of the PORTB pins has an individually configurable
internal weak pull-up. Control bits WPUB<7:0> enable or
disable each pull-up (see Register 3-7). Each weak
pull-up is automatically turned off when the port pin is
configured as an output. All pull-ups are disabled on a
Power-on Reset by the RBPU bit of the OPTION register.


To fix it, change that line of code to use a bitmask instead of True/False.
Stormrider



Joined: 15 May 2011
Posts: 6
Location: San José, CR

View user's profile Send private message MSN Messenger

PostPosted: Mon May 16, 2011 2:18 pm     Reply with quote

Yeah I changed that byte before implementing INT_EXT. As for this moment, PORTB<7:4> push buttons are working excellent and they keep record of their state (for further decisions). But still got the problem that B0 is triggering INT_RB.

Here´s my main up till now. I don't know if the problem could be at enable_interrupts(INT_EXT_H2L); or ext_int_edge(0,H_TO_L); .

Code:

void main()
{
   setup_adc_ports(RA1);
   setup_adc(ADC_CLOCK_DIV_2);   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_comparator(NC_NC_NC_NC);
   disable_interrupts(INT_TIMER0);
   disable_interrupts(GLOBAL);
   ext_int_edge(0,H_TO_L);
   //Sets LEDs at low initial state
   output_low(RC0);
   output_low(RC1);
   output_low(RC2);
   output_low(RC3);
   
   
   //PortB intertupts set up
   clear_reg();
   port_b_pullups(0xF1);
   set_tris_b(0xFF);
   delay_us(10); //ensure line has time to settle
   IOCB = 0xF1;
   ANSEL = 0;
   ANSELH = 0;
   last=input_b();
   clear_interrupt(INT_RB);
   clear_interrupt(INT_EXT);
   enable_interrupts(INT_EXT_H2L);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);
   
   //Welcoming message and LED blinking
   output_high(RE0); //On Led
   delay_ms(500);
   output_low(RE0); //Off Led
   delay_ms(500);
   output_high(RE0); //On Led
   delay_ms(500);
   output_low(RE0); //Off Led
   delay_ms(500);
   output_high(RE0); //On Led
   delay_ms(500);
   printf("Lab de Micros\n\r");
   delay_ms(500);
   printf("Sensor de Temperatura DS1631\n\r");
   delay_ms(500);

   //DS1631 set up
   writeConfigReg();
   readConfigReg();
   writeTHTLReg(); 
               
      do
      {
     
         last=input_b();
         clear_interrupt(INT_RB);
         clear_interrupt(INT_EXT);
         enable_interrupts(INT_EXT_H2L);
         enable_interrupts(INT_RB);
         
         /*measureTemp();
         delay_ms(200);*/ I'm just working on interrupts at this time
             
         if(dbutton0)
         {
           dbutton0=FALSE;
           output_toggle(RE2);
           printf("dbuttom0\n\r");
         }
         
         if(dbutton4)
         {
           dbutton4=FALSE;
           output_toggle(RC3);
           printf("dbuttom4\n\r");
         }
         
         if(dbutton5)
         {
           dbutton5=FALSE;
           output_toggle(RC2);
           printf("dbuttom5\n\r");
         }
         
         if(dbutton6)
         {
           dbutton6=FALSE;
           output_toggle(RC1);
           printf("dbuttom6\n\r");
         }
         
         if(dbutton7)
         {
           dbutton7=FALSE;
           output_toggle(RC0);
           printf("dbuttom7\n\r");
         }   
                 
      }while(1);
         
   while(1);
}


Thanks again!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon May 16, 2011 2:53 pm     Reply with quote

I'm just going to go through your code and post anything that looks wrong.

Quote:
setup_adc_ports(RA1);

That's not a valid parameter for that function. Look in the .h file for your
PIC to see the list of valid parameters.


Quote:
setup_adc(ADC_CLOCK_DIV_2);

That's not the correct divisor. Look in the 16F887 data sheet, at this table:
Quote:
TABLE 9-1: ADC CLOCK PERIOD (TAD) VS. DEVICE OPERATING FREQUENCIES (VDD > 3.0V)

It says to use Fosc/32 for an 8 MHz crystal.
Code:
 setup_adc(ADC_CLOCK_DIV_32);   



Quote:
IOCB = 0xF1;

You're enable interrupt-on-change for pins B7-B4, and also pin B0.
That's certainly the cause of your problem.

Quote:
enable_interrupts(INT_RB);

If you had a modern version of the compiler, this line would cause a
problem. That's because it writes 0xFF to the IOCB register. It would
enable all bits on port B0 for interrupt-on-change. But your version has
a bug, and instead of writing to register address 0x96, it writes to 0x116,
which is in RAM bank 2.

Quote:

output_low(RC0);
output_low(RC1);
output_low(RC2);
output_low(RC3);
output_high(RE0);
output_low(RE0);

Why use a different constant than the CCS constants, which are PIN_C0,
PIN_C1, etc. ? It adds the possibility for errors to get into the code.
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Mon May 16, 2011 2:54 pm     Reply with quote

Key is that on the chip you have, INT_RB, is available on all eight pins of PORTB, not just the high four pins. The reference in the manual does tell you that extra features are available on some chips, and to check the .h file for your chip.

Code:

   clear_interrupt(INT_RB);
   clear_interrupt(INT_EXT);
   enable_interrupts(INT_EXT_H2L);
   //enable_interrupts(INT_RB); This would turn on _all_ RB interrupts
   enable_interrupts(INT_RB4|INT_RB5|INT_RB6|INT_RB7);
   //Turn on INT_RB for the high four pins only - unlike other interrupt
   //enables, these can be 'ored' together
   enable_interrupts(GLOBAL);


The reason for INT_RB, having priority over INT_EXT, would be down to the order the two routines are declared, and that INT_RB will remain triggered unless the port is read (level triggered), while INT_EXT, is an edge triggered routine.

Best Wishes
Stormrider



Joined: 15 May 2011
Posts: 6
Location: San José, CR

View user's profile Send private message MSN Messenger

PostPosted: Mon May 16, 2011 4:51 pm     Reply with quote

@ PCM Programmer

Thanks again for scanning the code thoroughly, I have some comments to say:
1. The ADC at this time is not crucial, it was meant for interfacing the LM35 (analog thermometer) but found out the digital DS1631 is far better. The ADC as it is works fine, only from 0 to 10V with an error of 0.1V (way to high for the LM35), to fix this I know I have to change the REF it uses, but is not important at this moment.
2. I'm not including the .h from my project, it has the fuses and some defines, like

Code:
#define RE0 PIN_E0
#define RE1 PIN_E1
#define RE2 PIN_E2


which makes more easy just to write RE0 and so on.

3. By changing IOCB=0xF0 the problem of B0 triggering INT_RB was solved, and this leads me to a new conclusion:

4. My only interest is to implement push buttons on port B (IOC and not necessarily flank detection), I was just playing with INT_EXT while the problem of INT_RB was solved (the wrong address registers you suggested). At this moment I'm just planning of deleting INT_EXT and using the whole INT_RB interruption.

@Ttelmah

5. I did read the 16F887.h and noticed there were INT_RB, INT_EXT, INT_RB0,..., INT_RB7, but tried to implement the ISR as INT_RB7 and the compiler complaint about it, I didn't know it had to be like this:
Code:
enable_interrupts(INT_RB4|INT_RB5|INT_RB6|INT_RB7);

At this time I just blew out the INT_EXT and I'm currently working with just EXT_RB managing all the pins.

Anyhow, my deepest thanks to both of you, I just finished this routine successfully.
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