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

problem with comparator

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



Joined: 09 Apr 2006
Posts: 7

View user's profile Send private message

problem with comparator
PostPosted: Thu Apr 27, 2006 6:41 pm     Reply with quote

Hi
Im using a 16f873a's comparator to turn a 40khz sinusoidal signal with a 50 % duty cycle into a 40khz square wave signal. The problem is that when i check the comparator's output with an oscilloscope I get a 20kHz square wave signal with a 33% duty cycle. Here is the code I'm using to test the comparator

Code:
#include <16F873A.h>
#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7)

#BYTE CMCON = 0x9C

#int_COMP
COMP_isr() {
   byte b;
   b = CMCON;
   if(bit_test (b, 6))
   {
      output_high(PIN_B2);     
    }
   if(!bit_test (b, 6))
   {
      output_low(PIN_B2);     
   }
}

void main() {

   setup_comparator(A0_VR_A1_VR);
   setup_vref(VREF_HIGH|1);
   enable_interrupts(INT_COMP);
   enable_interrupts(GLOBAL);

   while(TRUE){
 
   }

}


Any suggestions or ideas?
Thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Apr 27, 2006 8:48 pm     Reply with quote

The problem is that it takes about 70 instruction cycles to handle the
interrupt. At 20 MHz, this is 14 us. Your input sinewave is 40 KHz,
which has a period of 25 us. Each half-cycle is 12.5 us. So you're
not able to handle an interrupt fast enough. You can't get out of the
first interrupt before the next transition has already passed by.

Besides looking at the .LST file, one way to test this is to poll the
comparator interrupt flag in main(), and then execute your isr, without
the PIC having to go through the CCS interrupt dispatcher. This will
save about 50 instructions, which is 10 us at 20 MHz. It should work
now. See the code below.

Also, your Vref level is only 1.40v for the comparator. Is that correct ?
(Assuming the PIC is running at 5v).

Code:

#include <16F873A.h>
#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7)

#BYTE CMCON = 0x9C
#byte PIR2 = 0x0D
#bit CMIF = PIR2.6

// #int_COMP   // Commented out this line.
COMP_isr() {
   byte b;
   b = CMCON;
   if(bit_test (b, 6))
   {
      output_high(PIN_B2);     
    }
   if(!bit_test (b, 6))
   {
      output_low(PIN_B2);     
   }
}

void main() {
char c;

   setup_comparator(A0_VR_A1_VR);
   setup_vref(VREF_HIGH|1);
//   enable_interrupts(INT_COMP);  // Commented out
//   enable_interrupts(GLOBAL);   // Commented out

c = CMCON;  // Clear "change" condition

CMIF = 0;  // Clear Comp. int. flag

while(1)
  {
   while(!CMIF); // Wait for Comp. interrupt
   
   COMP_isr();   // Handle it

   CMIF = 0;     // Clear Comp. interrupt flag   
  }
}
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Fri Apr 28, 2006 8:00 am     Reply with quote

If your input freq. is the same as what your producing, (40kHz) I would try an opamp and a cliper circuit. That would make the sin wave look like a square wave.
trojanman



Joined: 09 Apr 2006
Posts: 7

View user's profile Send private message

PostPosted: Fri Apr 28, 2006 5:53 pm     Reply with quote

Thanks for your answers.
The reason why I'm trying to turn the sine wave into a square wave is because I want to make the PIC count the number of 40 kHz pulses it received, so I tried using the comparator to achieve this, but i think that that is no the best aproach. Is it possible to do this with out adding any hardware?
cmdrdan



Joined: 08 Apr 2005
Posts: 25
Location: Washington

View user's profile Send private message

PostPosted: Fri Apr 28, 2006 6:48 pm     Reply with quote

With the code described by PCM, you don't need external hardware. All he said was that by using interrupts, you can't count fast enough for a 40 kHz signal. By polling, as he suggested, you may be able to do that -- just add code to increment a variable in your former comparator ISR routine, and you're all set. The only drawback to this is that it ties up your PIC for the time you're counting pulses, and perhaps that is okay; we don't know your requirements.

Another possibility is to use an external comparator as Treitmey suggested to square-up your sine wave. Perhaps then you could feed it into the timer0 input, with timer0 setup as a counter. I've never worked with the A-series parts, but with a cursory glance of the data sheet it doesn't seem capable to route the internal comparator's output to the timer0 input. Using timer0 as a counter should free up some processor time on your PIC, but at the cost of an external comparator....

Dan
Leef_me



Joined: 14 Mar 2006
Posts: 45

View user's profile Send private message

PostPosted: Fri Apr 28, 2006 6:56 pm     Reply with quote

>>I'm trying to turn the sine wave into a square wave
>>I want to make the PIC count the number of 40 kHz pulses it received
>>Is it possible to do this with out adding any hardware?

trojanman,

Does a trace, or piece of wire count as 'hardware' ?

But seriously, how about the following idea?

If you can use Timer1, why not enable the comparator output to an external pin, wire that pin to the Timer1 external clock input, and use Timer1 as a synchronous counter. There is a capture register that can
hold the Timer1 value. Timer1 has on overflow interrupt available.

Some useful sections of the datasheet are:

6.3 Timer1 Operation in synchronized counter mode
8.1 Capture mode (and timer mode selection) this also talks about a
prescaler that allows for an interrupt based on 1, 4 or 16 rising edges,
so you could reduce the number of times you go through the ISR
The capture register value could be read when it is convenient to get an
exact count.
12.5 Comparator outputs

May I ask, what is the source of you 40khz?

Leef_me
trojanman



Joined: 09 Apr 2006
Posts: 7

View user's profile Send private message

PostPosted: Fri Apr 28, 2006 9:20 pm     Reply with quote

Leef_me wrote:
>>I'm trying to turn the sine wave into a square wave
>>I want to make the PIC count the number of 40 kHz pulses it received
>>Is it possible to do this with out adding any hardware?

trojanman,

Does a trace, or piece of wire count as 'hardware' ?

But seriously, how about the following idea?

If you can use Timer1, why not enable the comparator output to an external pin, wire that pin to the Timer1 external clock input, and use Timer1 as a synchronous counter. There is a capture register that can
hold the Timer1 value. Timer1 has on overflow interrupt available.

Some useful sections of the datasheet are:

6.3 Timer1 Operation in synchronized counter mode
8.1 Capture mode (and timer mode selection) this also talks about a
prescaler that allows for an interrupt based on 1, 4 or 16 rising edges,
so you could reduce the number of times you go through the ISR
The capture register value could be read when it is convenient to get an
exact count.
12.5 Comparator outputs

May I ask, what is the source of you 40khz?

Leef_me


I can't enable the comparator's output to an external pin since I'm using the internal vref. What would be the easiest way to implement an external vref if the pic's operating voltage is 5v?


Going to try PCM programmer's code to count pulses and see if it doesn't tie up the pic
Leef_me



Joined: 14 Mar 2006
Posts: 45

View user's profile Send private message

PostPosted: Sun Apr 30, 2006 9:27 pm     Reply with quote

>>I can't enable the comparator's output to an external pin since I'm >>using the internal vref. What would be the easiest way to implement >>an external vref if the pic's operating voltage is 5v?

Sorry, Embarassed
I missed that idiosyncrasy (from the latin word for STUPID) Mad


I have NOT tried this, I expect it to work based on the sections of the datasheet I have read.
http://ww1.microchip.com/downloads/en/DeviceDoc/39582b.pdf

13.0 Comparator voltage reference module
" the output of the refernce generator may be connectoed to the RA2/AN2/VREF-/CREF pin. This can be used as a simple D/A function by the user if a very high-impedance load is used. The primary purpose of this function is to provide a test path for testing the reference generator function. "

Also take a look at AN611
http://ww1.microchip.com/downloads/en/AppNotes/00611b.pdf
At the section "Using the Voltage Reference" on the page marked
"DS00611B-page 7" which has some details and cautions.


What is the source of your 40khz? Question

Can you tell I found the emoticons?


Leef_me
trojanman



Joined: 09 Apr 2006
Posts: 7

View user's profile Send private message

PostPosted: Mon May 01, 2006 12:07 am     Reply with quote

I used a voltage divider to get a voltage reference of 2.1V and connected it to pin A3 with mode 5 and that worked fine when checking pin A5 with an oscilloscope, although I couldn't get anything from pin A4, probably because of this:
"RA4 is an open collector I/O pin. When
used as an output, a pull-up resistor is
required."

How do I connect the reference generator to pin RA2/AN2/VREF-/CREF, I tried using the code below and checked pin A5 but it didn't work:

Code:
#include <16F873A.h>
#fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)

void main() {

   setup_comparator(A0_A3_A1_A2_OUT_ON_A4_A5);
   setup_vref(VREF_HIGH|10);

   while(1){
     
   }
}


the source of the 40 kHz is a transducer
trojanman



Joined: 09 Apr 2006
Posts: 7

View user's profile Send private message

PostPosted: Mon May 01, 2006 12:31 am     Reply with quote

If I'm going to use the external output of the comparator to connect it to Timer1 external clock input, and use Timer1 as a synchronous counter, do I have to poll the comparator's interrupt flag or can I use the comparator interrupt service routine?
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Mon May 01, 2006 7:16 am     Reply with quote

What is the source of the sine wave? Do you need to use a comparator at all? Microchip application note AN521 is a classic piece on how to connect nasty real world signals to a digital PIC pin with almost no hardware.
_________________
The search for better is endless. Instead simply find very good and get the job done.
trojanman



Joined: 09 Apr 2006
Posts: 7

View user's profile Send private message

PostPosted: Mon May 01, 2006 9:47 am     Reply with quote

Going to take a look at the application note, though I've decided to go with the external comparator.
If I'm using Timer1's external input (pin C0?), how can I make timer1 give me its contents if after a specified amount of time it has stopped counting? Does any one have an example?
Is it by resetting timer1 using a ccp trigger output?
Leef_me



Joined: 14 Mar 2006
Posts: 45

View user's profile Send private message

PostPosted: Tue May 02, 2006 12:45 pm     Reply with quote

Uhh, what? Sorry, I got distracted looking at your code line:
setup_comparator(A0_A3_A1_A2_OUT_ON_A4_A5);

I have compiler version 3.180 and the project wizard thinks it's
"...OUT_ON_A3_A4" looks like I might need a compiler update.


>>how can I make timer1 give me its contents if after a specified amount of time it has stopped counting?

You can't using just Timer1 and the CCP registers.
A 'watchdog timer' idea comes to mind. One method is to use Timer0
and its overflow interrupt to signal when some time has elapsed after the last edge was detected.


Here is my attempt, this has not been compiled or tested


Code:

// Inserted into .c file before main():


int16 t_value;      // this is the count of 40khz pulses received.
int8 t_value_bad;    // a flag indicating status of measurement



#int_TIMER1
TIMER1_isr()    
{
   // timer overflowed, count of 40khz pulses is invalid

   t_value_bad=0xff;
   t_value=0;

}

#int_CCP1
CCP1_isr()    // 16 edges occurred, 40khz is still coming in
{
   set_timer0(0);  // reset the 'watchdog' timer (this timer does not reset the uC)

}


#int_TIMER0   // overflow in 819 us, which is greater than the time for 16 edges of 40khz
TIMER0_isr()
{

   // time has elapsed without more 40khz pulses; report contents of Timer1

   t_value=get_timer1();   
   t_value_bad=0x00;   // good result

}


// Inserted into .c file in main():

   setup_counters(RTCC_INTERNAL,RTCC_DIV_16);
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_EXTERNAL_SYNC);
   setup_timer_2(T2_DISABLED,0,1);

   setup_ccp1(CCP_CAPTURE_RE|CCP_CAPTURE_DIV_16);   // so the interrupt is called 1/16 of the time

   disable_interrupts(INT_TIMER1);
   disable_interrupts(INT_CCP1);
   disable_interrupts(INT_TIMER0);

   enable_interrupts(global);


*
*
*



//*******************************************************//
// Get ready to start a measurement
//*******************************************************//


   disable_interrupts(global);


   set_timer0(0);  // reset the 'watchdog' timer (this timer does not reset the uC)
   set_timer1(0);  // reset the 40khz pulse counter


// you need to make sure the interrupt flags associated with the interrupts below
//  are cleared before starting a measurement


   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_CCP1);
   enable_interrupts(INT_TIMER0);

   t_value_bad=0x01;   // measurement in progress

   enable_interrupts(global);



   While(t_value_bad==0x01)   // wait for a result
   ;


//*******************************************************//
// Measurement ended, restore normal operation
//*******************************************************//



   disable_interrupts(global);

   disable_interrupts(INT_TIMER1);
   disable_interrupts(INT_CCP1);
   disable_interrupts(INT_TIMER0);

   enable_interrupts(global);


   If (t_value_bad==0xff)   
   ; // bad result
   else
   ; //good result




I have also used Timer0 to set up a 'clock' with an interrupt that keeps several processes running. I use it to create a pseudo-realtime clock.
I can add a variable that is decremented at a desired rate, say 1ms
and then monitor that value from the code in 'main'. When the variable
hits zero, the main loop continues to the next step -- whatever that is.
It is similar to the delay_us() function, but other things can be happening; instead of the uC being stuck in a counter loop, doing nothing.



>>Is it by resetting timer1 using a ccp trigger output?
This will not give you any value. I have found the CCP trigger output
useful in starting a A/D conversion or aiding in generating a single or repetitive square-edged pulse with varing duty cycle. In the above code, I used the edge detection part of the CCP to delay having to go through the Timer1 interrupt for each edge of the 40khz pulse, but the CCP register values are not used.


Leef_me
trojanman



Joined: 09 Apr 2006
Posts: 7

View user's profile Send private message

PostPosted: Fri May 05, 2006 1:59 pm     Reply with quote

Thanks for the suggestion, going to try that code
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