View previous topic :: View next topic |
Author |
Message |
dubinc
Joined: 04 Feb 2011 Posts: 9
|
Problem with INT_EXT (PIC16F877A) |
Posted: Fri Feb 04, 2011 8:14 am |
|
|
Hi all,
First I'm french so excuse me if I make faults in my explanation. So, I'm making a program and I use the interrupt of PB0 to increment a counter when I press a button. In function of this number, the program select the output and I want to view a message of a LCD display. I use too RB4 and RB5 with the interrupt "portB change". I have two other buttons, and when I press it I want to increment or decrement a counter and select a output. I make this code:
Code: |
#include <16F877A.h>
#device ICD=TRUE
#device adc=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES DEBUG //Debug mode for use with ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock=12000000)
#include <LCD.C>
#byte PORTA=5
#byte TRISA=0x85
#bit C1=PORTA.1
#bit C2=PORTA.2
#bit C3=PORTA.3
#bit C4=PORTA.4
#bit C5=PORTA.5
#byte PORTB=6
#byte TRISB=0x86
#bit up=PORTB.5
#bit down=PORTB.4
#byte PORTC=7
#byte TRISC=0x87
#bit C6=PORTC.0
#bit C7=PORTC.1
#bit C8=PORTC.3
#bit C9=PORTC.4
#bit C10=PORTC.5
#bit C11=PORTC.6
#bit C12=PORTC.7
#byte PORTE=9
#byte TRISE=0x89
#bit signal1=PORTE.0
#bit signal2=PORTE.1
int compteur_gamme=0;
int compteur_signal=0;
#int_RB // RB4 to RB7
RB_isr()
{
disable_interrupts(INT_EXT);
disable_interrupts(INT_RB);
if(up==0) // RB5
{
compteur_gamme++;
if(compteur_gamme==12)
compteur_gamme=0;
switch (compteur_gamme)
{
case 0:
TRISC=0b01111111;
TRISA=0b11111111;
C12=0;
break;
case 1:
TRISC=0b10111111;
TRISA=0b11111111;
C11=0;
break;
case 2:
TRISC=0b11011111;
TRISA=0b11111111;
C10=0;
break;
case 3:
TRISC=0b11101111;
TRISA=0b11111111;
C9=0;
break;
case 4:
TRISC=0b11110111;
TRISA=0b11111111;
C8=0;
break;
case 5:
TRISC=0b11111101;
TRISA=0b11111111;
C7=0;
break;
case 6:
TRISC=0b11111110;
TRISA=0b11111111;
C6=0;
break;
case 7:
TRISC=0b11111111;
TRISA=0b11011111;
C5=0;
break;
case 8:
TRISC=0b11111111;
TRISA=0b11101111;
C4=0;
break;
case 9:
TRISC=0b11111111;
TRISA=0b11110111;
C3=0;
break;
case 10:
TRISC=0b11111111;
TRISA=0b11111011;
C2=0;
break;
case 11:
TRISC=0b11111111;
TRISA=0b11111101;
C1=0;
break;
}
}
if(down==0) // RB4
{
compteur_gamme--;
if(compteur_gamme==-1)
compteur_gamme=11;
switch (compteur_gamme)
{
case 0:
TRISC=0b01111111;
TRISA=0b11111111;
C12=0;
break;
case 1:
TRISC=0b10111111;
TRISA=0b11111111;
C11=0;
break;
case 2:
TRISC=0b11011111;
TRISA=0b11111111;
C10=0;
break;
case 3:
TRISC=0b11101111;
TRISA=0b11111111;
C9=0;
break;
case 4:
TRISC=0b11110111;
TRISA=0b11111111;
C8=0;
break;
case 5:
TRISC=0b11111101;
TRISA=0b11111111;
C7=0;
break;
case 6:
TRISC=0b11111110;
TRISA=0b11111111;
C6=0;
break;
case 7:
TRISC=0b11111111;
TRISA=0b11011111;
C5=0;
break;
case 8:
TRISC=0b11111111;
TRISA=0b11101111;
C4=0;
break;
case 9:
TRISC=0b11111111;
TRISA=0b11110111;
C3=0;
break;
case 10:
TRISC=0b11111111;
TRISA=0b11111011;
C2=0;
break;
case 11:
TRISC=0b11111111;
TRISA=0b11111101;
C1=0;
break;
}
}
enable_interrupts(INT_EXT);
enable_interrupts(INT_RB);
}
#int_EXT
EXT_isr() // RB0
{
disable_interrupts(INT_EXT);
disable_interrupts(INT_RB);
compteur_signal++;
if(compteur_signal==3)
{
compteur_signal=0;
}
switch (compteur_signal)
{
case 0: // triangle
signal1=0;
signal2=1;
lcd_gotoxy(1,2);
printf(lcd_putc, "Triangle ");
break;
case 1: // sinus
signal1=1;
signal2=1;
lcd_gotoxy(1,2);
printf(lcd_putc, "Sinus ");
break;
case 2: // carré
signal1=0;
signal2=0;
lcd_gotoxy(1,2);
printf(lcd_putc, "Carre ");
break;
}
enable_interrupts(INT_EXT);
enable_interrupts(INT_RB);
}
#int_TIMER1 // debordement toute les 13.1ms
TIMER1_isr()
{
debordement=debordement++;
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); // externe ou interne ????
setup_timer_2(T2_DIV_BY_1,0,1);
setup_ccp1(CCP_CAPTURE_RE);
setup_ccp2(CCP_CAPTURE_RE);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
lcd_init();
enable_interrupts(INT_EXT);
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
TRISB=0b11111111;
do
{
lcd_gotoxy(1,1);
printf(lcd_putc, "Frequence");
}
while(1);
}
|
But when I try the program doesn't work !!! I have just the message "frequence" on my LCD.
Thanks a lot
Jeremy |
|
![](templates/subSilver/images/spacer.gif) |
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Fri Feb 04, 2011 10:40 am |
|
|
Hi,
This is what I understand:
1) you write to LCD on your main function inside a infinite loop.
2) you write new messages to the LCD inside your ISR. (you should only set flags inside the ISR as to get in and out fast).
3) when you press a button, your ISR fires.
4) ISR writes the new message to the LCD.
5) but as soon as you exit the ISR, your main function REwrites frequence to the LCD.... (this is your problem)
other things:
Also be advise that "interrupt on change" fires 2 times in a button press.
Once when you press the button and once you release the button... this happens because the pin changes twice: from high to low and from low to high. Also since you are using mechanical buttons you need to establish some form of debounce or you will get unpredictable results from a button press.
Furthermore it seems that what you are trying to do with TRIS is just to change the state the whole port, in other words output a byte to port of. There are specific functions for this.
hope that helps
Gabriel _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
![](templates/subSilver/images/spacer.gif) |
dubinc
Joined: 04 Feb 2011 Posts: 9
|
|
Posted: Fri Feb 04, 2011 11:17 am |
|
|
Thanks for your answer. I write to LCD with a infinite loop just to see if the program works. I try to remove the infinite loop and I insert a delay of 500ms after the message send to LCD in the ISR but it doesn't work.
I made several tests and sometimes (about 1 on 50) it works, but when I switch off/on the power, after it doesn't work anymore. I think it doesn't go in my interrupt and I don't know why. |
|
![](templates/subSilver/images/spacer.gif) |
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Fri Feb 04, 2011 12:54 pm |
|
|
Like I said, keep your ISR as short as possible.
only set flags inside your ISR. your taking too long inside your ISR.
Delays inside an IRS are a big NO-NO.
You need to compensate for the fact that you will fire the RB int twice.
Inside your ISR you should only have a small debounce loop that checks the state of the pin that triggered the input... if the state is the same for ~4 consecutive reads, the button is debounced...then increment a counter... when you release the button you pressed, the ISR will fire again... increments the counter which now has a value of 2 (ISR triggered twice) and when counter is 2, set a flag and reset counter.
In your main code the only infinite loop is one that checks the ISR flag...
when flag is set... it executes the desired command (out of the ISR).
G _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
![](templates/subSilver/images/spacer.gif) |
dubinc
Joined: 04 Feb 2011 Posts: 9
|
|
Posted: Sat Feb 05, 2011 5:13 am |
|
|
Ok I understand, but I'm not a very good programmer and I never use flag. Can you explain me quickly how I can use a flag. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Sat Feb 05, 2011 6:13 am |
|
|
Adding an other other thing. You don't have to disable interrupts in the handler. The chip's _hardware_ does this for you...
Now on interrupts:
Code: |
int8 seen_bits,old_bits,changed_bits;
int1 port_changed=FALSE;
#INT_RB
void changed_handler(void) {
seen_bits=input_b();
changed_bits=old_bits~seen_bits;
old_bits=seen_bits;
port_changed=TRUE;
}
//Then in main
if(port_changed) {
//coming here implies portB has changed
port_changed=FALSE;
Here look at the bits in 'changed_bits' to see what has changed
and then the bits in 'old_bits' to see which way the change was
}
|
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
dubinc
Joined: 04 Feb 2011 Posts: 9
|
|
Posted: Sat Feb 05, 2011 12:30 pm |
|
|
I understand the method but I have yet two questions:
-What is doing this line ?
changed_bits=old_bits~seen_bits;
more when I compile I have have a mistake with the "~"
- you say: "Here look at the bits in 'changed_bits' to see what has changed and then the bits in 'old_bits' to see which way the change was" but how ?? Just in reading the byte ?? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Sat Feb 05, 2011 4:05 pm |
|
|
'^', is the 'XOR' operator in C. It returns '1' for each bit that is _different_ in two binary values. It is really what the interrupt on change does internally, so allows you to find which bit has changed to trigger the interrupt.
Am typing from a Mac, and for some reason the posting showed '~' which is the 'ones complement' operator (inverts each bit).
Done this through the PC simulator, so should be right this time.....
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
|