unstable analogRead() result from a pot

I’m trying to read the value of a pot on each cycle a 2-row RGB LED array is updated. The value read from the pot is to be used to fade the color of the array from blue to red and vice versa. I’ll have 2 pots being read each cycle (one to control the fading of each row), but right now I just have one pot, so I take it’s reading twice essentially. Therefore, both rows fade from red to blue at the same time.

The problem is, I think the analogRead() function is returning unstable values, therefore the intensity of the row of LEDs jumps around a little on each cycle. This is especially noticeable when both red and blue are slightly lit at the same time (approx. mid point of the pot sweep).

In the following code I’ve inserted a Serial.println() just to see what values are returned by the analogRead() function. The refresh rate is way too slow with the Serial.println inserted, however. If I remove it I get around a 75Hz refresh rate and a duty cycle of over 40%.

DELAY_HIGH = 6000
DELAY_LOW = 100

The pot is a 500K (I know it’s a little high) audio taper.

Any clue to how to get this analogRead() function to behave itself (if that’s even the problem) would be MOST helpful!

Thanks,
lqbert

void state(){
  float b;
  float n;
  int temp_time;
     
  while(1){
      
    digitalWrite(R2, LOW);   
    
    b = ((float)(potRead(POT_SOURCE, B_POT_PIN)-b_pot_min)/b_pot_range);
    for (int i = start_pos; i <= start_pos+3; i++){
      Serial.println((int)((1-b)*MAX_INTENSITY));
      setLED(0, i, RED, (int)((1-b)*MAX_INTENSITY));
      setLED(0, i, BLUE, (int)((b)*MAX_INTENSITY)); 
    }   
         
    Tlc.update();
    delayMicroseconds(DELAY_LOW);
    digitalWrite(R1, HIGH); 
    delayMicroseconds(DELAY_HIGH); // Delay 1
    digitalWrite(R1, LOW);

    n = (((float)potRead(POT_SOURCE, N_POT_PIN)-n_pot_min)/n_pot_range);  
    for (int i = start_pos; i <= start_pos+3; i++){
      setLED(0, i, RED, (int)((1-n)*MAX_INTENSITY));
      setLED(0, i, BLUE, (int)((n)*MAX_INTENSITY)); 
    }
  
    Tlc.update();
    delayMicroseconds(DELAY_LOW);
    digitalWrite(R2, HIGH);
    delayMicroseconds(DELAY_HIGH);
      
  }

  
}


/**********************************************************************************  
 * potRead() -- Function to return an ADC value from a potentiometer... values    *
 * passed to it are a digital pin number acting as the 5VDC source and an analog  * 
 * pin number to take the reading from                                            *
 **********************************************************************************/

int potRead(int source_pin, int read_pin){
  digitalWrite(source_pin, HIGH);
  int x = analogRead(read_pin);    // read the value from the pot and store in 'n'
  digitalWrite(source_pin, LOW);
  return x;
}


/************************************************************************* 
 * setLED() -- This is a wrapper function that turns on the LED          *
 * cooresponding to row #, column #, color, and intensity (0 - 4095)     *
 * sent to the function                                                  *
 *                                                                       *
 * Blue   -- Channels 0-7                                                *
 * Green  -- Channels 8-15                                               *
 * Red    -- Channels 16-23                                              *
 *************************************************************************/

int setLED(int row, int column, int color, int intensity) {           
  TLC_CHANNEL_TYPE channel;
 // if (intensity > 0 && intensity < 5) intensity = 3;
  if (intensity < 0) intensity = 0;
  if (intensity > 4095) intensity = 4095;

  if(column > NUM_COLUMNS || column < 1){
    return 1;  // to be used for debugging
  }
  else{  
    // This statement calculates and sets the TLC Channel value
    channel = color*NUM_COLUMNS-(NUM_COLUMNS-column)-1;

    // Set the proper LED to the called for intensity
    Tlc.set(channel, intensity);  
  }
  return 0;
}

You're counting on a digital output being a rock-steady 5V reference for your (admittedly large) pot value, but it's not. You're also starting an A/D conversion immediately after changing the value that you're trying to measure.

As a simple change, try delaying a few microseconds from the time you set source_pin high to the time you start your analogRead.

Any chance you can keep the pot at a steady 5V rather than driving it from a port pin?

While I would agree with everything above.

The pot is a 500K (I know it's a little high) audio taper.

I think that is your problem, it is too high an impedance to override all the noise. It needs to be about 10K.

Awesome responses... I'll try to implement those ideas. Maybe I can program it to run a couple few cycles before reading from the pot.

I was looking for ways to save power... that's why I initially chose not to leave the pot source at 5v all the time.

I was planning on using a 250k pot in the final design... here's the reason: this pot has to be stacked (dual concentric) on a pot that is used in an electric guitar. The adjoining pot of the stack is going to be 500k. I've heard that you can take apart CTS pots and put them back together with difference disks. I can't find anything less than a 250k pot to use the disk from (for the A/D portion of the LED circuit).

So, if anyone has a source for a 10k dissectable pot that is the size of a guitar pot, please let me know... other than that, I'm gonna have to hope adjusting the code as you guys described is enough to do the trick.

Thanks again for the quick responses... keep them coming if you have any new revelations... :)

lqbert

So I added a 1ms delay after setting the pot source pin to HIGH and before taking my reading from the pot... this did the trick. Now there is no perceivable flicker during the fade from one color to the other... awesome!!!

Thanks for the love, folks!

lqbert