|
|
View previous topic :: View next topic |
Author |
Message |
Stormrider
Joined: 15 May 2011 Posts: 6 Location: San José, CR
|
INT_RB problem [solved] |
Posted: Mon May 16, 2011 12:04 am |
|
|
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
|
|
Posted: Mon May 16, 2011 12:54 pm |
|
|
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
|
|
Posted: Mon May 16, 2011 1:25 pm |
|
|
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
|
|
Posted: Mon May 16, 2011 1:34 pm |
|
|
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
|
|
Posted: Mon May 16, 2011 2:18 pm |
|
|
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
|
|
Posted: Mon May 16, 2011 2:53 pm |
|
|
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); |
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: 19552
|
|
Posted: Mon May 16, 2011 2:54 pm |
|
|
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
|
|
Posted: Mon May 16, 2011 4:51 pm |
|
|
@ 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. |
|
|
|
|
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
|