PIC18F analog comparator problem

Discussion in 'Embedded Systems and Microcontrollers' started by david.silaghi, May 1, 2009.

  1. david.silaghi

    Thread Starter New Member

    May 1, 2009
    1
    0
    Hello
    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:

    #include<p18f4550.h>
    #include<timers.h>
    #include<stdio.h>
    #include<ancomp.h>
    /** 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
    void _HIGH_INTERRUPT_VECTOR (void)
    {
    _asm
    goto _high_ISR
    _endasm
    }

    #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

    flag=1;
    tmr0Counter++;

    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
    flag=1;

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



    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


    x=micro_sec/6;
    var=65536-x;


    //var1=var>>8;
    //var2=var;

    }
    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)
    PORTB=mask;

    /*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
    PORTB=mask|15;
    i=16; // line 16 select
    PORTB=mask|16

    flag=0;


    }

    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
    TRISD=0b00010000;
    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
    Open_ancomp(COMP_1_2_OP_INV& COMP_INT_REF_SAME_IP & COMP_INT_EN);
    CVRCON=0b11001000; //setting up comparator refference voltage 2.8125V

    for (i=0;i<32;i++) { //initializing array with 0
    tablouTimp[0]=0;
    tablouTimp[1]=0;
    }

    }

    void calculateTime(void) {
    char k;

    for (k=0;k<32;k++){ // calculates time
    time[k]=(tablouTimp[k][1]-tablouTimp[k][0])*0.094;
    }
    varx=0;

    }
    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.

    David
     
  2. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    When you set or clear a bit, the state of all bits may be modified due to read-modify-write method of PIC Architecture.

    The Datasheet for your PIC will show an example of the setup, and what steps are required to set/clear a single bit without affecting others

     
Loading...