Connect with us

Modulating ADC channels?

Discussion in 'Microcontrollers, Programming and IoT' started by chopnhack, Sep 2, 2016.

Scroll to continue with content
  1. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Hello all, I added in the code for monitoring both ADC inputs (pic12f675) to my ongoing project, but its not working. I need some help getting the code to function properly. I am not sure of how to alternate between ADC inputs.

    When I set the ADCON0.bits for voltage and right justification outside of the loop at the start of the program, is that assumed by the program to be the universal setting? (see first ADC setup)
    I have highlighted the new sections of code with *** - the highlight feature does not work inside of code brackets.
    Thanks!

    Code:
    int main(void)
    
    {
      // Variable Declaration
      int AN3_AD_IN_110 = 0;                        // variable to hold value of A/D input from U2 Allegro chip, 110v line.
      int AN2_AD_IN_220 = 0;                        // " from U3 Allegro chip, 220v line.
                                                    // This signal is baseline of 2.5VDC with a 0-2.5VAC signal riding on top.
      int max = 511, min = 511,  
              max1 = 511, min1 = 511;               // variables for min/max comparisons on both channels 110/220
      int temp_value = 0, temp_value1= 0,
             temp_peak = 0, temp_peak1 = 0;         // Hold temp values to compare ADC against
      int count = 0;
     
      //ADC Setup
      ADCON0bits.ADFM = 1;                          // Right justified A/D results
      ADCON0bits.VCFG = 0;                          // Voltage reference set to Vdd
      TRISIO = 0b101000;                            // AN2 and AN3/MCLR are inputs all else outputs.
      GPIO = 0b000000;                              // Turn off all outputs initially
      //Analog Select Register Setup
      ANSELbits.ADCS = 0b101;                       // Clock derived from internal osc - max of 500kHz - problem with 4MHz xtal freg??
      ANSELbits.ANS2 = 1;                           // Sets AN2 as analog input (page 46 of pic675 manual states this and trisio need to be set)
      ANSELbits.ANS3 = 1;                           // Sets AN3 as analog input
         
    while(1)
    {
        while (count < 128)                              // set counter to prevent infinite loop
         
         {
            // ADC Setup
            ADCON0bits.CHS = 11;                          // Channel select register set to 11 to select AN3
            ADCON0bits.ADON = 1;                          // Turn A/D converter on
            __delay_us(15);
         
             // Start A/D conversion process
            ADCON0bits.GO = 1;
            __delay_us(15);
         
            while (ADCON0bits.nDONE){}                  // Wait for conversion to be done
             //
            AN3_AD_IN_110 = ADRESL + (ADRESH << 8);     // 1024 bit resolution 5v/1023 = 4.88mV per bit
     
              if (AN3_AD_IN_110 >= max)                 // check for 511 (1/2 Vcc) or greater
                {
                  max = AN3_AD_IN_110;                  // set variable max to 511 or greater
                }
     
              if (AN3_AD_IN_110 <= min)                 // check variable min for 511 or less
                {
                  min = AN3_AD_IN_110;                  // set var. min to 511 or less
                }
          // ***
            // ADC Setup
            ADCON0bits.CHS = 10;                        // Channel select register set to 11 to select AN2
            ADCON0bits.ADON = 1;                        // Turn A/D converter on
            __delay_us(15);
             // Start A/D conversion process
            ADCON0bits.GO = 1;
            __delay_us(15);
            while (ADCON0bits.nDONE){}                  // Wait for conversion to be done
             //
            AN2_AD_IN_220 = ADRESL + (ADRESH << 8);     // 1024 bit resolution 5v/1023 = 4.88mV per bit
     
              if (AN2_AD_IN_220 >= max1)                // check for 511 (1/2 Vcc) or greater
                {
                  max1 = AN2_AD_IN_220;                 // set variable max to 511 or greater
                }
     
              if (AN2_AD_IN_220 <= min1)                // check variable min for 511 or less
                {
                  min1 = AN2_AD_IN_220;                 // set var. min to 511 or less
                }
          // ***
            count = count + 1;                          // incrementing counter
            if (count == 128)
            {
             GPIO4 = 1;                                 //    write a =! GPIO statement to turn led GP4 on and off every 128 cycles
             __delay_ms(50);
             GPIO4 = 0;
            }
         }
           
         temp_peak = max - min;                     // temporary peak value established and used to compare later
         min = 511;                                 // reset variable
         max = 511;                                
      // ***
         temp_peak1 = max1 - min1;                  // same as above on other channel
         min1 = 511;                                // reset variable
         max1 = 511;                              
      // ***  
         if ((temp_peak >= 80)||(temp_peak1 >= 80)) // control statement - if peak value is above threshold
                                                    // and if 0.354V above and below Vcc - (110v threshold) then proceed
            {
              __delay_ms(2000);                     // 2 second delay before turning on
              //GPIO = 0b000001;                    // set GP0 high to turn on relay
              GPIO5 = 1;  //REMOVE ONLY FOR TESTING // this is to check code on dev. board - GP5 outermost LED to corner should light
              //ADCON0bits.GO_DONE = 1;             // do A/D measurement          
            }
             
          if ((temp_peak <= 60)||(temp_peak1 >= 60))
               
            {
              __delay_ms(3000);
              GPIO5 = 0;
            }
             
          count = 0;                           // reset count variable to zero for next go around
        }
    }
    
     
  2. NorthGuy

    NorthGuy

    53
    16
    Mar 24, 2016
    If you want GP5 to turn on when both channels are present you need:
    Code:
    if ((temp_peak >= 80)&&(temp_peak1 >= 80)) // both are on
    ...
    if ((temp_peak <= 60)||(temp_peak1 <= 60)) // at least one is off
    
    If you want GP5 to turn on when either of the two channels is present you need:
    Code:
    if ((temp_peak >= 80)||(temp_peak1 >= 80)) // at least one is on
    ...
    if ((temp_peak <= 60)&&(temp_peak1 <= 60)) //  both are off
    
    Right now you have "||" in both places and also ">= 60" typo.

    Also, instead of copying and pasting, you could have a function:
    Code:
    int ReadADC(char channel) {
      ADCON0bits.CHS = channel;
      // do reading here
      return ADRESL + (ADRESH << 8);
    }
    
    You can then call it two times with different channel numbers. This way, if you want to change something, such as delay, you don't need to do it twice.
     
    hevans1944 and chopnhack like this.
  3. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Thank you NorthGuy - I didn't spot the typo and you're correct, that was from cut and pasting! I didn't understand your logic for AND'ing the off condition, but once I thought it through, I got it. The AND means both have to be off to go low and that makes sense as if any which one is high, it can't go low.
    Functions are far more efficient, agreed - I just have a hard time writing them, I am very novice in C having only written less than a handful of anything more than trivial programs.

    I will try to get the code to work first with your suggestions and then try to tidy it up using a function, thanks!!. :)
     
  4. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Ok, implemented your suggestions and fixed the logic error. QHB mentioned that I was calling some of the bits using decimal numbers instead of binary and I corrected that as well. I am still stumped as to why the code is not functioning as intended. The program still cycles through and lights GP4 each time around the loop, but when current is introduced, GP5 does not light. This led me back to my original question of whether the location of those adcon0.bits sfr's mattered. I tried to add them to the loop as well as reiterate them lower in the loop to make sure that the second ADC channel got formatted. In either experiment, the code still did not execute properly. Where am I going wrong?

    Code:
    int main(void)
    
    {
      // Variable Declaration
      int AN3_AD_IN_110 = 0;                        // variable to hold value of A/D input from U2 Allegro chip, 110v line.
      int AN2_AD_IN_220 = 0;                        // " from U3 Allegro chip, 220v line.
                                                    // This signal is baseline of 2.5VDC with a 0-2.5VAC signal riding on top.  
      int max = 511, min = 511,    
              max1 = 511, min1 = 511;               // variables for min/max comparisons on both channels 110/220 
             temp_peak = 0, temp_peak1 = 0;         // Hold temp values to compare ADC against
      int count = 0;
       
      //ADC Setup
      ADCON0bits.ADFM = 1;                          // Right justified A/D results
      ADCON0bits.VCFG = 0;                          // Voltage reference set to Vdd
      TRISIO = 0b101000;                            // AN2 and AN3/MCLR are inputs all else outputs.
      GPIO = 0b000000;                              // Turn off all outputs initially
      //Analog Select Register Setup
      ANSELbits.ADCS = 0b101;                       // Clock derived from internal osc - max of 500kHz - problem with 4MHz xtal freg??
      ANSELbits.ANS2 = 1;                           // Sets AN2 as analog input (page 46 of pic675 manual states this and trisio need to be set)
      ANSELbits.ANS3 = 1;                           // Sets AN3 as analog input
           
     while(1) 
     {  
        while (count < 128)                              // set counter to prevent infinite loop
           
         {
            // ADC Setup
            ADCON0bits.CHS = 0b11;                          // Channel select register set to 11 to select AN3
            ADCON0bits.ADON = 1;                          // Turn A/D converter on
            __delay_us(15);
           
             // Start A/D conversion process
            ADCON0bits.GO = 1;  
            __delay_us(15); 
           
            while (ADCON0bits.nDONE){}                  // Wait for conversion to be done
             //
            AN3_AD_IN_110 = ADRESL + (ADRESH << 8);     // 1024 bit resolution 5v/1023 = 4.88mV per bit
       
              if (AN3_AD_IN_110 >= max)                 // check for 511 (1/2 Vcc) or greater
                { 
                  max = AN3_AD_IN_110;                  // set variable max to 511 or greater
                }
       
              if (AN3_AD_IN_110 <= min)                 // check variable min for 511 or less
                { 
                  min = AN3_AD_IN_110;                  // set var. min to 511 or less
                }
           
            // ADC Setup
            ADCON0bits.CHS = 0b10;                        // Channel select register set to 11 to select AN2
            ADCON0bits.ADON = 1;                        // Turn A/D converter on
            __delay_us(15);
             // Start A/D conversion process
            ADCON0bits.GO = 1;  
            __delay_us(15); 
            while (ADCON0bits.nDONE){}                  // Wait for conversion to be done
             //
            AN2_AD_IN_220 = ADRESL + (ADRESH << 8);     // 1024 bit resolution 5v/1023 = 4.88mV per bit
       
              if (AN2_AD_IN_220 >= max1)                // check for 511 (1/2 Vcc) or greater
                { 
                  max1 = AN2_AD_IN_220;                 // set variable max to 511 or greater
                }
       
              if (AN2_AD_IN_220 <= min1)                // check variable min for 511 or less
                { 
                  min1 = AN2_AD_IN_220;                 // set var. min to 511 or less
                }  
           
            count = count + 1;                          // incrementing counter 
            if (count == 128)
            {
             GPIO4 = 1;                                 //    write a =! GPIO statement to turn led GP4 on and off every 128 cycles
             __delay_ms(50);
             GPIO4 = 0;
            }
         } 
             
         temp_peak = max - min;                     // temporary peak value established and used to compare later  
         min = 511;                                 // reset variable 
         max = 511;                                  
       
         temp_peak1 = max1 - min1;                  // same as above on other channel  
         min1 = 511;                                // reset variable 
         max1 = 511;                                
         
         if ((temp_peak >= 80)||(temp_peak1 >= 80)) // control statement - if peak value is above threshold 
                                                    // and if 0.354V above and below Vcc - (110v threshold) then proceed
            { 
              __delay_ms(2000);                     // 2 second delay before turning on
              //GPIO = 0b000001;                    // set GP0 high to turn on relay
              GPIO5 = 1;  //REMOVE ONLY FOR TESTING // this is to check code on dev. board - GP5 outermost LED to corner should light
              //ADCON0bits.GO_DONE = 1;             // do A/D measurement            
            }  
               
          if ((temp_peak <= 60)&&(temp_peak1 <= 60))  
                 
            {
              __delay_ms(3000);
              GPIO5 = 0;
            }
               
          count = 0;                           // reset count variable to zero for next go around
        }
    }
    
     
  5. NorthGuy

    NorthGuy

    53
    16
    Mar 24, 2016
    In your past code, it worked with AN1 (GP1). This code uses AN2 (GP2) and AN3 (GP4, the one you're blinking). Have you moved your connections?
     
  6. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Yes, I made double sure. I changed the ports to reflect what the project board will use.
     
  7. NorthGuy

    NorthGuy

    53
    16
    Mar 24, 2016
    I usually do one small change at a time. Then, if something breaks, I know that this was my last change which caused this and nothing else. If you do three or four changes, then it's getting hard to guess which change caused the problem.

    So, I would go back to the connection and program which is working and I would start modifications from there. For example, as a first step, I would add the second channel in the code (without changing anything else or connecting anything new), then I would run it and test if the first channel is still working. Then I would disconnect the first channel, connect the known good signal from the first channel to where the second channel is going to be and then I would run it and test it. And so on, one little change at a time until both channels are working, then until they're moved to the correct pins etc.

    It's like picking a safe. If you have 10 digit code, it's awfully hard to find a correct combination, but I you are allowed to do it one digit at a time, it's a piece of cake.
     
    chopnhack likes this.
  8. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    I am back, I followed your advice and iterated through many changes. I ended up with this final code that works. The funny thing about it is that it's giving me some false lighting conditions on AN2 channel - at least what I thought were false lightings. It turns out that the input to that channel was at 5v under no load conditions, when it should be at 1/2 Vcc or 2.5V, so it was triggering the GP5 high!!! By manually cycling the input pin I was able to verify operation of the program, thanks!

    This appears to happen only when I have voltage present through U3 Allegro chip so I am looking at troubleshooting a hardware issue :mad:
    Again thanks for your assistance on the code :D:D

    Code:
    void main()
    
    {
      // Variable Declaration
      int AN3_AD_IN_110 = 0;                        // variable to hold value of A/D input from U2 Allegro chip, 110v line.
      int AN2_AD_IN_220 = 0;                        // " from U3 Allegro chip, 220v line.
                                                    // This signal is baseline of 2.5VDC with a 0-2.5VAC signal riding on top.  
      int max = 511, min = 511,    
              max1 = 511, min1 = 511;               // variables for min/max comparisons on both channels 110/220 
      int temp_peak = 0, temp_peak1 = 0;            // Hold temp values to compare ADC against
      int count = 0;
      CMCONbits.CM = 0b111;                         // Turn comparator off
      //ADC Setup
      ADCON0bits.ADFM = 1;                          // Right justified A/D results
      ADCON0bits.VCFG = 0;                          // Voltage reference set to Vdd  
      ADCON0bits.ADON = 1;                          // Turn A/D converter on
      __delay_us(15);
      TRISIO = 0b010100;                            // Only AN2 and AN3/MCLR are inputs all else outputs.
      GPIObits.GP1 = 0;                             // Turn off GP1 output initially
      GPIObits.GP5 = 0;                             // Turn off GP5 output initially
      //Analog Select Register Setup
      ANSELbits.ADCS = 0b101;                       // Clock derived from internal osc - max of 500kHz - problem with 4MHz xtal freg??
      ANSELbits.ANS2 = 1;                           // Sets AN2 as analog input (page 46 of pic675 manual states this and trisio need to be set)
      ANSELbits.ANS3 = 1;                           // Sets AN3 as analog input
           
     while(1) 
     {  
        while (count < 128)                            // set counter to prevent infinite loop
           
         {
           ADCON0bits.CHS = 0b11;                      // Channel select register set to 0b11 to select AN3
           __delay_us(15);
           // Start A/D conversion process
           ADCON0bits.GO = 1;  
           __delay_us(15); 
            while (ADCON0bits.nDONE){}                  // Wait for conversion to be done
             //
            AN3_AD_IN_110 = ADRESL + (ADRESH << 8);     // 1024 bit resolution 5v/1023 = 4.88mV per bit
           
           // ADC Setup
           ADCON0bits.CHS = 0b10;                       // Channel select register set to 0b10 to select AN2
           __delay_us(15);
            // Start A/D conversion process
           ADCON0bits.GO = 1;  
           __delay_us(15); 
            while (ADCON0bits.nDONE){}                  // Wait for conversion to be done
             //
            AN2_AD_IN_220 = ADRESL + (ADRESH << 8);     // 1024 bit resolution 5v/1023 = 4.88mV per bit
       
              if (AN3_AD_IN_110 >= max)                 // check for 511 (1/2 Vcc) or greater
                { 
                  max = AN3_AD_IN_110;                  // set variable max to 511 or greater
                }
       
              if (AN3_AD_IN_110 <= min)                 // check variable min for 511 or less
                { 
                  min = AN3_AD_IN_110;                  // set var. min to 511 or less
                }
               
              if (AN2_AD_IN_220 >= max1)                // check for 511 (1/2 Vcc) or greater
                { 
                  max1 = AN2_AD_IN_220;                 // set variable max to 511 or greater
                }
       
              if (AN2_AD_IN_220 <= min1)                // check variable min for 511 or less
                { 
                  min1 = AN2_AD_IN_220;                 // set var. min to 511 or less
                }  
           
           
           count = count + 1;                          // incrementing counter 
           if (count == 128)
            {                                           // REMOVE from final - only for testing on dev.board
             GPIO1 = 1;                                 //    write a =! GPIO statement to turn led GP1 on and off every 128 cycles
             __delay_ms(50);
             GPIO1 = 0;
            }
         } 
             
         temp_peak = max - min;                     // temporary peak value established and used to compare later
         temp_peak1 = max1 - min1;
         min = 511;                                 // reset variable 
         max = 511;                                 // reset variable 
         min1 = 511;
         max1 = 511;
         
         if ((temp_peak >= 80)||(temp_peak1 >= 80)) // control statement - if peak value is above threshold 
                                                    // and if 0.354V above and below Vcc - (110v threshold) then proceed
            { 
              __delay_ms(2000);                     // 2 second delay before turning on
              //GPIO = 0b000001;                    // set GP0 high to turn on relay
              GPIO5 = 1;  //REMOVE ONLY FOR TESTING // this is to check code on dev. board - GP5 outermost LED to corner should light
             
            }  
       
         if ((temp_peak <= 60)&&(temp_peak1 <= 60))  
            {
              __delay_ms(3000);
              GPIO5 = 0;          
            }
           
          count = 0;                               // reset count variable to zero for next go around
        }
    } 
    
    
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-