Maker Pro
Maker Pro

Modulating ADC channels?

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
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
    }
}
 

NorthGuy

Mar 24, 2016
53
Joined
Mar 24, 2016
Messages
53
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.
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
Right now you have "||" in both places and also ">= 60" typo.
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.
Also, instead of copying and pasting, you could have a function:
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!!. :)
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
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
    }
}
 

NorthGuy

Mar 24, 2016
53
Joined
Mar 24, 2016
Messages
53
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?
 

NorthGuy

Mar 24, 2016
53
Joined
Mar 24, 2016
Messages
53
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

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
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
    }
}
 
Top