• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC18F analog comparator problem

Not open for further replies.


New Member
I'm writing for the first time on this kind of a forum. I've read many posts that helped me, so I decided to ask something. I saw that people here have the know how :)

I'm working at an interesting project, a data acquisition system, which acquires 32 analog lines when a trigger has been received, and calculates the time between the rising edge and falling edge of each analog line. So I decided to use PIC18F4550 because has built in analog comparators, 48MHz and USB communication (I'm using it to transmit acquired data to the PC).

As a short description of my hardware implementation, I used 2 analog multiplexer's (ADG406) each with 16 analog inputs and 1 analog output. I'm addressing the mux via PIC18F4550 through PORTB (RB5 -> enable Mux2, RB4 -> enable Mux1, RB3 -> RB0 selecting each line of Mux1 and Mux2). The analog output of Mux1 is connected to analog comparator1 input of uC (PORTA.RA0) and the Mux2 analog output is connected to analog comparator2 input of uC (PORTA.RA1).
I'm configuring the analog comparators to have a common internal reference.
I have the trigger connected to the RD4 pin.

I wrote the code for PIC18F4550 and in order to test it ( I don't have 32 analog lines) I build up another uC (PIC18F4620) to simulate the signals (but digital).
A short description of my code:
1. I'm waiting for the trigger (signal on PORTB.RB4, 200 ms duration)
2. If the trigger received, start timer0 to count 94us
3. I'm selecting each mux line
4. If RA0>Vref or RA1>Vref or RA0<Vref or RA1<Vref (any change of either comparator) and interrupt is generated
5. If comparator interrupt is generated, I'm checking all the comparators outputs to see any change and if so, I'm saving the current value of the tmr0Counter (one increment of tmr0Counter means 94us)
6. If 94us time has past the program enters in the timer0 interrupt routine and increments the tmr0Counter
7. The process starts all over again from step 3
Here is my source code:

/** V A R I A B L E S ********************************************************/
#pragma udata

unsigned int x;
unsigned int var;
char var1,var2;
unsigned int tmr0Counter=0;
unsigned char flag=0;
unsigned int i=1;
unsigned int tablouTimp [32][2];/*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};*/
unsigned int time[32];

/** P R I V A T E P R O T O T Y P E S ***************************************/
//static void InitializeSystem(void);
void BIOS(void); //function that initializes registers BAsic Input Ouput Settings
void USBTasks(void);
void _high_ISR(void);
void init_Timer(void);
void set_Timer(unsigned int);
void muxLineSelect(void);
void calculateTime(void);

/** V E C T O R R E M A P P I N G *******************************************/

extern void _startup (void); // See c018i.c in your C18 compiler dir
#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
void _reset (void)
_asm goto _startup _endasm
#pragma code

#pragma code _HIGH_INTERRUPT_VECTOR = 0x08
goto _high_ISR

#pragma code
#pragma interrupt _high_ISR
void _high_ISR(void) {

if (INTCONbits.TMR0IF==1) { // timer 0 interrupt has been received
INTCONbits.TMR0IE=0; // disable timer0 interrupts
// INTCONbits.PEIE=0; //disable peripheral interrupts
PIE2bits.CMIE=0; //disable analog comparators interrupts
INTCONbits.TMR0IF=0; //reset timer0 interrupt flag


INTCONbits.TMR0IE=1; //enable timer0 interrupts
PIE2bits.CMIE=1; //enable analog comparators interrupts
INTCONbits.PEIE=1; //enable peripheral interrupts
init_Timer(); //start timer0


if (PIR2bits.CMIF==1) { //comparator interrupt has been received

PIE2bits.CMIE=0; //disable analog comparators interrupts
PIR2bits.CMIF=0; //reset comparator interrupt flag

if (CMCONbits.C1OUT==1) { //comparator1's input (RA0)> Vref

tablouTimp[0]=tmr0Counter; //save the value in a array
if (CMCONbits.C1OUT==0) { //comparator1's input (RA0) <Vref

tablouTimp[1]=varx; //save the value in a array


if (CMCONbits.C2OUT==1) { //RA1 (comp2 input) > Vref

tablouTimp[i+16][0]=varx; //save the value in a array
if (CMCONbits.C2OUT==0) { //RA1<Vref
PORTCbits.RC1=1; //toggle this pin to see the behaviour on the osciloscope
tablouTimp[i+16][1]=varx; //save value in a array
PORTCbits.RC1=0; //toggle this pin to see the behaviour on the osciloscope

PIE2bits.CMIE=1; //enable comparator interrupts

}//end if interrupt comparator


#pragma code _LOW_INTERRUPT_VECTOR = 0x000818
void _low_ISR (void)
#pragma code

/** D E C L A R A T I O N S **************************************************/
#pragma code

* Function: void main(void)
* PreCondition: None
* Input: None
* Output: None
* Side Effects: None
* Overview: Main program entry point.
* Note: None
void main(void) {

BIOS(); //initializing uC
set_Timer(94);//setting timer to 94us

init_Timer(); //starting timer0
if (PORTDbits.RD4==1){ // if the trigger received via this pin
tmr0Counter=0; //reset the tmr0 counter

muxLineSelect(); //selecting the mux lines
while(flag==0); //waiting for timer0 to finish

if (tmr0Counter==4000) { //forced stop of the acquisition

CloseTimer0(); //stoping timer0
// Close_ancomp();
calculateTime(); //calculating the time

}//end while 1


void init_Timer(void) { //setting timer0 with interrupt enable, 16 bit resolution, with the prescaler 1:64
OpenTimer0(TIMER_INT_ON&T0_16BIT & T0_SOURCE_INT & T0_PS_1_64);
WriteTimer0(var); //writing var value in the TMR0 register

void set_Timer(unsigned int micro_sec){ //calculating the value for TMR0 register



void muxLineSelect(void) { //this function selects the mux lines by adressing each line of the mux via pins RD3->RD0
char mask;

mask=0b00110000; //enable both muxes (RD5 en mux2, RD4 en mux 1)

/*for (i=0;i<16;i++){
PORTB=PORTB|i; //selecting lines from 0-15

//************test code -> only 2 lines selected *************//
i=15; //line 15 select
i=16; // line 16 select



void BIOS(void) { //Basic Input Output Settings
int i;

INTCON = 0xE0; //init interrupt vector
TRISB=0; //setting port B as output
TRISC=0; //setting port C as output
TRISA=0b00000011; //setting RA0 and RA1 as inputs
//setting analog comparator register with 2 analog comparators, output inverted, comparator's have the same internal reference, and comp interrupt enable
CVRCON=0b11001000; //setting up comparator refference voltage 2.8125V

for (i=0;i<32;i++) { //initializing array with 0


void calculateTime(void) {
char k;

for (k=0;k<32;k++){ // calculates time


So, my big problem is : if I have more than one line selected at the from the multiplexor, the program saves the tmr0Counter value inapropriate. To debug this, I used only mux1 (clearing RB5 bit) which is connected to Comparator1 and selecting only 2 mux lines. I put a bit to toggle in comparator2 interrupt case (CMCONbits.C2OUT==0) and surprise, my bit is toggleing even if I don't have any significant signal to comparator2 input ( I checked with the osciloscope and I saw only a small noise). And even strange, the program enters the comparator2 interrupt routine every time I have a change in comparator1 output (on rising and on falling edge). And even more strange, if I use only 1 line from the Mux1, the program works very well, the signal comming to the comparator1 is sensed very precise and the tmr0Counter value is saved as expected.

Please help me with this problem.

Not open for further replies.

EE World Online Articles