|
|
View previous topic :: View next topic |
Author |
Message |
Salenko
Joined: 08 Sep 2008 Posts: 84
|
Comparator interruption for 16F877A [solved] |
Posted: Sun May 24, 2009 12:48 pm |
|
|
Hi,
I wrote a code using comparator interruption in 16f628 PICmicro which worked without problem. then I modified this code (you can find it here :http://www.ccsinfo.com/forum/viewtopic.php?t=38989) to run it in 16F877A,
for that I made the following changes:
- #byte CMCON = 0x9C ( value taken from the datasheet)
- I replaced C2OUT with C1OUT
- setup_comparator(A0_A3_A1_A2); // I'm using A0 and A3 as comparator inputs.
and I left the rest without change.
In the main
Code: |
if (C1OUT)
output_high(led);
else output_low(led);
|
The LED is blinking periodically, which means that the comparator is working correctly. But program never executes the Comparator interruption routine though there is:
Code: |
byte b;
b = CMCON; //to clear mismatch condition
|
in the interruption routine and before the setup_comparator() directive.
I'm blocked here since 10 hours now , can anybody help me to solve this problem ?
thanks in advance.
Last edited by Salenko on Sat May 30, 2009 1:24 am; edited 1 time in total |
|
|
apcaye
Joined: 22 May 2009 Posts: 29 Location: Brazil
|
|
Posted: Mon May 25, 2009 8:23 am |
|
|
I have no experience with the comparator, but I suggest you simulate your code to check that the pin directions (TRIS register) and all the registers related with the comparator are configured correctly. Also check that the comparator interrupt enable bit, the global interrupt enable bit and the peripheral interrupt enable bit are all set.
Regards,
Adriano. |
|
|
Ttelmah Guest
|
|
Posted: Mon May 25, 2009 8:45 am |
|
|
Your comparator setup, enables both comparators. The interrupt potentially could be triggered by either. You need A0_A3_NC_NC to have the same effect as the original setup, but moved onto the A0/A3 pins.
You _must_ have a pull up resistor on RA4.
You also speak about an LED. Beware. remember that the input threshold for the C1OUT signal (when read), is 4v. With the LED conneted, will your pull up, take thepin to this level?.
Best Wishes |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Mon May 25, 2009 10:44 am |
|
|
Hi apcaye and Ttelmah, thank you for your help.
apcaye wrote: | I have no experience with the comparator, but I suggest you simulate your code to check that the pin directions (TRIS register) and all the registers related with the comparator are configured correctly. Also check that the comparator interrupt enable bit, the global interrupt enable bit and the peripheral interrupt enable bit are all set.
Regards,
Adriano. |
As I know, TRIS register is automatically set by the compiler. concerning the comparator register (CMPON) and the different interrupts enable bits, I'll check them with MPLAB SIM.
Ttelmah wrote: | Your comparator setup, enables both comparators. The interrupt potentially could be triggered by either. You need A0_A3_NC_NC to have the same effect as the original setup, but moved onto the A0/A3 pins.
You _must_ have a pull up resistor on RA4.
You also speak about an LED. Beware. remember that the input threshold for the C1OUT signal (when read), is 4v. With the LED conneted, will your pull up, take thepin to this level?.
Best Wishes |
As the code shows below, A0_A3_NC_NC does not exist in the 16F877A.h file, I changed it to A0_A3_NC_NC_OUT_ON_A4 and added a pull-up resistance in RA4 this is always working (the RA4 pin changes status periodically) . the LED am talking about is connected to another pin (RB0) and always blinks when a drop passes with short latency, its voltage when blinking is about 4.7V.
Code: | ////////////////////////////////////////////////////////////////// COMP
// Comparator Variables: C1OUT, C2OUT
// Constants used in setup_comparator() are:
#define A0_A3_A1_A3 0xfff04
#define A0_A3_A1_A2_OUT_ON_A4_A5 0xfcf03
#define A0_A3_A1_A3_OUT_ON_A4_A5 0xbcf05
#define NC_NC_NC_NC 0x0ff07
#define A0_A3_A1_A2 0xfff02
#define A0_A3_NC_NC_OUT_ON_A4 0x9ef01
#define A0_VR_A1_VR 0x3ff06
#define A3_VR_A2_VR 0xcff0e
#define CP1_INVERT 0x0000010
#define CP2_INVERT 0x0000020
#bit C1OUT = 0x9c.6
#bit C2OUT = 0x9c.7
|
here is the portion of code that controlls the LED (it's in the main) and works as I said:
Code: | if (C1OUT)
output_high(led);
else output_low(led); |
it's obvious that the problem comes from the comparator interruption routine, probably the compiler has a different address for CMCON than the one of the datasheet :
|
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Tue May 26, 2009 8:57 am |
|
|
Hi, it's me again,
apcaye wrote: | I have no experience with the comparator, but I suggest you simulate your code to check that the pin directions (TRIS register) and all the registers related with the comparator are configured correctly. Also check that the comparator interrupt enable bit, the global interrupt enable bit and the peripheral interrupt enable bit are all set.
Regards,
Adriano. |
I read the datasheet and I found that paragraph and the Table below (page 68) talks about the comparator interrupts.
Quote: | 12.6 Comparator Interrupts
The comparator interrupt flag is set whenever there is
a change in the output value of either comparator.
Software will need to maintain information about the
status of the output bits, as read from CMCON<7:6>, to
determine the actual change that occurred. The CMIF
bit (PIR registers) is the Comparator Interrupt Flag. The
CMIF bit must be reset by clearing it (‘0’). Since it is
also possible to write a ‘1’ to this register, a simulated
interrupt may be initiated.
The CMIE bit (PIE registers) and the PEIE bit (INTCON
register) must be set to enable the interrupt. In addition,
the GIE bit must also be set. If any of these bits are
clear, the interrupt is not enabled, though the CMIF bit
will still be set if an interrupt condition occurs.
The user, in the Interrupt Service Routine, can clear the
interrupt in the following manner:
a) Any read or write of CMCON will end the
mismatch condition.
b) Clear flag bit CMIF.
A mismatch condition will continue to set flag bit CMIF.
Reading CMCON will end the mismatch condition and
allow flag bit CMIF to be cleared.
Note: If a change in the CMCON register
(C1OUT or C2OUT) should occur when a
read operation is being executed (start of
the Q2 cycle), then the CMIF (PIR
registers) interrupt flag may not get set.
|
I used MPLAB SIM and took three screen captures of the registers, first one at the start of the code, second: at the comparator enable directive and the last one in the main program.
As you can see, CMIF (Comparator interrupt Flag) and CMIE (Comparator interrupt Enble ) never take "1".
here is my entire code (which worked with 16F628) :
Code: | #include <16F877A.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 10000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include <input.c>
#byte CMCON = 0x9C // from datasheet
#define SysClock 10000000
#define led PIN_B0
//========Variables=======
int1 start_drop=0, next_drop=0, mes=0;
unsigned long overflowing_t1 ;
long Long mesure ;
//=============interruptions routines=================
//==========Comparator==============
#INT_COMP
void COMP_isr()
{
byte b;
b = CMCON; // to clear mismatch condition
printf("\n\rINT comparator") ;
if (C1OUT && !next_drop)
{
start_drop=1;
enable_interrupts(INT_TIMER0); // first drop
}
if (C1OUT && next_drop) // second drop
{
next_drop=0;
mes=1;
disable_interrupts(INT_TIMER1);
}
}
//==========Timers==============
#int_timer0 // overflows every 102us
void timer0_isr ( )
{
if (C1OUT && start_drop)
{
disable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
start_drop=0;
next_drop=1;
}
}
#int_timer1 // overflows every 26.2ms
void timer1_isr ( )
{
++ overflowing_t1 ;
}
//--------------------------the main program-----------------------------
void main()
{
byte b_comp ;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
b_comp = CMCON ; // Read the comparator register to clear mismatch condition
setup_comparator(A0_A3_NC_NC_OUT_ON_A4); // CM2:CM0 = 001 , CMCON=0000 0001
enable_interrupts(INT_COMP);
enable_interrupts(GLOBAL);
while(1)
{
if (C1OUT)
output_high(led);
else output_low(led);
if (mes)
{
mesure = overflowing_t1 * 26.2 ;
printf("overflowing_t1 = %Lu, duration = %ld ms\n\r",overflowing_t1, mesure) ;
mes=0;
overflowing_t1=0;
}
}
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Tue May 26, 2009 9:43 am |
|
|
What compiler version?.
Best Wishes |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Tue May 26, 2009 10:05 am |
|
|
Hi Ttelmah,
PCW 4.057 |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Tue May 26, 2009 3:34 pm |
|
|
is there a problem with this version ? |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Wed May 27, 2009 2:31 am |
|
|
Please can you tell me if the problem is with my code or with my compiler's version ?
much thanks. |
|
|
apcaye
Joined: 22 May 2009 Posts: 29 Location: Brazil
|
|
Posted: Wed May 27, 2009 7:05 am |
|
|
The compiler should have turned on the CMIE bit in the PIE1 register, this is why the comparator interrupt is not happening. You could try to set this bit yourself, writing directly to this register in the beginning of your code.
Regards,
Adriano. |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Wed May 27, 2009 8:36 am |
|
|
Hi apcaye, thank you for your help,
apcaye wrote: | The compiler should have turned on the CMIE bit in the PIE1 register, this is why the comparator interrupt is not happening. You could try to set this bit yourself, writing directly to this register in the beginning of your code.
Regards,
Adriano. |
I turned it on with this directive :
Code: |
#byte PIR1 = 0x0C
bit_set(PIR1,6); // I put this in the main() before the loop (while(1))
|
but nothing happened
According to 12.6 Comparator Interrupts of the datasheet, the CMIF bit should be also cleared, but I don't know "where" !!? , also CMIE should be set (I tried also to set it using #byte PIE1 = 0x8C ; bit_set(PIE1,6); but the MPLAB SIM stopped in the directive even when I commented it.
Quote: | 12.6 Comparator Interrupts
The comparator interrupt flag is set whenever there is
a change in the output value of either comparator.
Software will need to maintain information about the
status of the output bits, as read from CMCON<7:6>, to
determine the actual change that occurred. The CMIF
bit (PIR registers) is the Comparator Interrupt Flag. The
CMIF bit must be reset by clearing it (‘0’). Since it is
also possible to write a ‘1’ to this register, a simulated
interrupt may be initiated.
The CMIE bit (PIE registers) and the PEIE bit (INTCON
register) must be set to enable the interrupt. In addition,
the GIE bit must also be set. If any of these bits are
clear, the interrupt is not enabled, though the CMIF bit
will still be set if an interrupt condition occurs.
The user, in the Interrupt Service Routine, can clear the
interrupt in the following manner:
a) Any read or write of CMCON will end the
mismatch condition.
b) Clear flag bit CMIF.
A mismatch condition will continue to set flag bit CMIF.
Reading CMCON will end the mismatch condition and
allow flag bit CMIF to be cleared.
Note: If a change in the CMCON register
(C1OUT or C2OUT) should occur when a
read operation is being executed (start of
the Q2 cycle), then the CMIF (PIR
registers) interrupt flag may not get set. |
|
|
|
Ttelmah Guest
|
|
Posted: Wed May 27, 2009 8:49 am |
|
|
I have just stuck 4.057, back onto a system.
Code: |
.................... enable_interrupts(INT_COMP);
011B: BSF 03.5
011C: BSF 0D.6
|
It correctly sets CMIE.
The first instruction, selects the second page of memory 0x8?, and then it sets bit 6, at address 0x8D, which is the CMIE bit.
I'd suggest you start by printing out the listing of the enable interrupt instruction on your system, and seeing if it does what it should.
The CMIF, is automatically cleared for you at the end of the COMP interrupt.
One possibility (reinstall the compiler), is that part of the device database file is corrupted on your copy. Though this shouldn't prevent you from setting CMIE yourself. However you have the address wrong. It is 0x8D, not 8C. Bit 6, of 8C, is the ADC interrupt enable...
Best Wishes |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Wed May 27, 2009 11:44 am |
|
|
Mr Ttelmah,
as always, your help is valuable.
in fact, the table I posted concerns 16F628 PICmicro, the correct address for PIR2 register is 0x0D.
here is the correct table:
I enabled the Comparator interruption bit_set(PIR2,6); in the while (1) loop, this gave me false measure (duration = 26ms instead of 707 ms) , I reinstalled the compiler but nothing has changed.
Quote: |
I'd suggest you start by printing out the listing of the enable interrupt instruction on your system, and seeing if it does what it should.
|
All the interrupts below seems to be enabled correctly.
Code: |
.................... byte b_comp ;
....................
.................... setup_adc_ports(NO_ANALOGS);
*
02A0: BSF 03.5
02A1: BSF 1F.0
02A2: BSF 1F.1
02A3: BSF 1F.2
02A4: BCF 1F.3
.................... setup_adc(ADC_OFF);
02A5: BCF 03.5
02A6: BCF 1F.0
.................... setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
02A7: BSF 03.5
02A8: MOVF 01,W
02A9: ANDLW C7
02AA: IORLW 08
02AB: MOVWF 01
.................... setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
02AC: MOVLW 85
02AD: BCF 03.5
02AE: MOVWF 10
....................
.................... b_comp = CMCON ; // Read the comparator register to clear mismatch condition
02AF: BSF 03.5
02B0: MOVF 1C,W
02B1: BCF 03.5
02B2: MOVWF 2F
....................
.................... setup_comparator(A0_A3_NC_NC_OUT_ON_A4); // CMCON=0000 0001
02B3: MOVLW 01
02B4: BSF 03.5
02B5: MOVWF 1C
02B6: MOVF 05,W
02B7: IORLW 09
02B8: ANDLW EF
02B9: MOVWF 05
02BA: MOVLW 08
02BB: MOVWF 77
02BC: DECFSZ 77,F
02BD: GOTO 2BC
02BE: MOVF 1C,W
02BF: BCF 03.5
02C0: BCF 0D.6
.................... enable_interrupts(INT_COMP);
02C1: BSF 03.5
02C2: BSF 0D.6
.................... enable_interrupts(GLOBAL);
02C3: MOVLW C0
02C4: BCF 03.5
02C5: IORWF 0B,F
|
Code: | .................... enable_interrupts(INT_TIMER1);
009B: BSF 03.5
009C: BSF 0C.0 |
Code: | .................... enable_interrupts(INT_TIMER0); // first drop
0080: BSF 0B.5
0081: BSF 03.5 |
It is really strange, the comparator interruption works perfectly for a 16F628 and not for a 16F877A (or only when the CMIF is set "manually").
Salenko. |
|
|
apcaye
Joined: 22 May 2009 Posts: 29 Location: Brazil
|
|
Posted: Wed May 27, 2009 12:21 pm |
|
|
Just a detail, Salenko: the bit you should set is in the PIE2 register, not in the PIR2. So, the instruction that enable the comparator interrupt should be:
bit_set(PIE2,6);
Just change one letter in your code. The CMIF bit should be set/reset automatically.
Regards,
Adriano. |
|
|
Salenko
Joined: 08 Sep 2008 Posts: 84
|
|
Posted: Wed May 27, 2009 2:01 pm |
|
|
apcaye wrote: | Just a detail, Salenko: the bit you should set is in the PIE2 register, not in the PIR2. So, the instruction that enable the comparator interrupt should be:
bit_set(PIE2,6);
Just change one letter in your code. The CMIF bit should be set/reset automatically.
Regards,
Adriano. |
Hi Adriano, thank you again,
Yes, you're right, but strangely, setting CMIF (bit_set(PIR2,6); 0x0D ) in the while loop enabled the interruption (despite of the false measure) and though it is a repetition of
Code: | .................... enable_interrupts(INT_COMP);
02C1: BSF 03.5
02C2: BSF 0D.6 |
while setting CMIE (bit_set(PIE2,6); 0x8D ) has no effect in the PICmicro.
Salenko. |
|
|
|
|
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
|