How to "stabilize" analog read

Hi,

I'm fairly new into this so please excuse any dumb thing I may ask...

I'm building a small led strip controller. I've install those strips on my house and I'm planning to have different setup for Halloween, Christmas, St-Valentin...

I've program different routine for those events and I've install a rotary switch with 10 positions. There are 5 pins on that switch. I've been able to map the different position of the switch (like 0 = pin 1, 2 = pin 2, 3 = pin 1 and pin 2...) I've put 4 different resistors on 4 of the pin and connect the 5th pin to an analog pin of my Arduino Uno.

With some experimentation, when reading the analog pin, I've been able to come up with some range and can call the appropriate routine.

My problem is that those readings are inconsistent (depending on how many lights are ON of OFF) and the power supply I'm using.

Is there any way to "stabilize" those readings so they will always be the same. I'm not expecting to have an exact value and won't mind using a range but right now my ranges are not good enough.

Thanks

The best way to stabilize the readings is to use a separate power supply for the lights (be sure to connect the two power supply grounds together). If you can't do that, read up on "power supply decoupling" -- you need additional filtering on the Arduino power supply.

FYI - I hate the idea of using analog for something that's actually digital....

What are the readings from the ADC, and how much do they vary? It shouldn't be that hard to get 5 completely different readings.

Is your sketch looking for an exact reading, or for a range? I think it can work if you look for a range of values, or simply use greater-than or less-than. If you have values that go from 0 to 1023, the values should be distinctly different and far enough apart so this can work.

What is the OP actually trying to achieve?
Is it measuring the voltage across the load, or to identify which position a switch is in?

Sounds like you forgot the fifth resistor going to Vcc, given that the others go to ground.

Show your circuit.

I understand that he tries to identify the switch position :wink:

but I'm afraid we won't be helpful without a schematic . Maybe the power supply can't deliver enough current and the voltage drops when several strips are on

How about something like this?

[glow=teal,2,300]POS  VOLTS   ADC     DETECT[/glow]
  1      1   205    180-230
  2      2   410    385-435
  3      3   615    590-640
  4      4   820    795-845
  5      0     0      0-25

alnath:
I understand that he tries to identify the switch position :wink:

but I'm afraid we won't be helpful without a schematic . Maybe the power supply can't deliver enough current and the voltage drops when several strips are on

Ahh cheers :slight_smile:
An input for each switch position instead.
Detect which one is high, if none then it is off?

Note that he said "ten position" and "five pins".

Get it?

It's a BCD switch.

alnath:
Maybe the power supply can't deliver enough current and the voltage drops when several strips are on

Doesn't matter.

The ADC is ratiometric.

Paul__B:
Note that he said "ten position" and "five pins".

Get it?

It's a BCD switch.

Well spotted net sleuth!

I've program different routine for those events and I've install a rotary switch with 10 positions. There are 5 pins on that switch. I've been able to map the different position of the switch (like 0 = pin 1, 2 = pin 2, 3 = pin 1 and pin 2...) I've put 4 different resistors on 4 of the pin and connect the 5th pin to an analog pin of my Arduino Uno.

Alternate connections: An R2R ladder will give equal steps in voltage at it's output.

Here, the steps in VOUT are equal at 1/3 volt per step:

dlloyd:
Here, the steps in VOUT are equal at 1/3 volt per step:

I don't think so!

An R-2R ladder depends on negligible input impedance to the 2R sections. In this case however, you are switching not rail-to-rail, but between one rail and open, so that the impedance of the ladder varies with the number of resistors actually switched in. Let me examine the above. No switches on, output is zero. "1" on - output is 1/2 of 5V. "2" on - output is 3/5 of 5V. "1+2" - output is 3/4 of 5V, "4" on - output is 2/3 of 5V.

Did I miscalculate something there? Will check later.

Did I miscalculate something there? Will check later.

You're right ... was thinking active logic type, however opened contacts are high impedance. They should ideally be at GND potential.

If R=10K and 1K pull-down resistors added to 1,2,4,8, then it would work with 1/3V steps ±10%. Although easy to detect each step, we're now up to 12 resistors. However, through-hole 10K/20K R/2R network SIP resistors are available + another SIP for the pulldowns, bringing it to 2 additional external components.

Oh well, the idea is to get equal steps in VOUT ... but not sure how practical or economical the solution is.

EDIT: Non-overlapping steps seems the best that can be achieved without use of an op-amp.

Well, the OP seems to have deserted us - not an uncommon event - and I stick to my original reply that we need to know his actual circuit arrangement and whether he had the necessary pull-up resistor to start with, in the absence of which performance would be very unstable.

With that resistor, it is not particularly difficult to have four resistors, one to each switch pole, with binary progressive values. Unless you provide a constant-current source, the voltage steps will not be linear, but if the pull-up is significantly higher than the largest "binary" resistance value, it may be practical for a direct division/ shift operation to scale the result into a value from 0 to 15 suitable for a "case" routine.

In fact, the internal pull-up probably behaves in a somewhat constant-current mode and would be the best choice.

Hi,

sorry for the long delay... my life is not as quiet these days as I'd like it to be... here are some clarifications.

  • I'm using an old computer power supply to feed the 12v and 5v.
  • I've connected 4 different resistors to 4 of the rotary pins (910k, 250k, 820k and 220k) and a 100k to the ground and analog pin5

To experiment with the button, I first built a small prototype with only the button and I was sending the values to the serial output. Then I've test twice with my full project (including a LCD screen to be able see the actual values used when trying to balance the LED): all LED off and then all LED on. This is what each position of the switch was reading:

Res = Resistors combinations
Test1 = Rotary button only
Test2 = Rotary button, all LED off
Test3 = Rotary button, all LED on

As you can see, once the LED are turn on, there is a big difference and the readings will vary from everything off to everything on...

Here is a diagram of my controller (I was not able to find an actual rotary switch so I've used the 1st object I could find with 5 pins and the LED are on a strip, not just 3 single LED...)

and just in case here is the diagram of my LCD module:

and here is a simplified version of the the source code (I've put the button identification in comment because I can't used it anymore, too much variation...)

#define SHIFTPWM_USE_TIMER2  // for Arduino Uno and earlier (Atmega328)
const int ShiftPWM_latchPin=8;
const bool ShiftPWM_invertOutputs = false;
const bool ShiftPWM_balanceLoad = false;

#include <ShiftPWM.h>   // include ShiftPWM.h after setting the pins!

unsigned char maxBrightness = 255;
unsigned char pwmFrequency = 75;
unsigned int numRegisters = 2;
unsigned int numOutputs = 9; //numRegisters*8;
unsigned int numRGBLeds = 3; //numRegisters*8/3;
unsigned int fadingMode = 0; //start with all LED's off.

unsigned long startTime = 0; // start time for the chosen fading mode

int pot1Pin = 1;
int pot2Pin = 2;
int pot3Pin = 3;
int buttonPin = 5;
int calibPin = 4;

#include <ShiftLCD.h>

ShiftLCD lcd(2, 4, 3); // orange - yellow- green
int reading, oldButton;
char *fonction[10] = {
  "Test HVS",    // 0
  "Test RGB",    // 1
  "Halloween",   // 2
  "Noel",        // 3
  "St-Valentin", // 4
  "Menu 5",      // 5
  "Menu 6",      // 6
  "Menu 7",      // 7
  "Menu 8",      // 8
  "Menu 9"       // 9
};

char *label[2][3] ={
  {"Hue:","Saturation:","Brigthness:"},
  {"Red:","Green:","Blue:"},
};

int myButton;
int pot1Value, pot2Value, pot3Value;

void setup(){
  Serial.begin(9600);
    
  lcd.begin(20, 3); // set up the LCD's number of rows and columns: 
  
  // Sets the number of 8-bit registers that are used.
  ShiftPWM.SetAmountOfRegisters(numRegisters);

  // SetPinGrouping allows flexibility in LED setup. 
  // If your LED's are connected like this: RRRRGGGGBBBBRRRRGGGGBBBB, use SetPinGrouping(4).
  ShiftPWM.SetPinGrouping(1); //This is the default, but I added here to demonstrate how to use the funtion
  
  ShiftPWM.Start(pwmFrequency,maxBrightness);
  checkButton(0);
  ShiftPWM.SetAllHSV(0,0,0);

}

void loop()
{ 

checkButton(1);
 TestColor(1);
}
void TestColor(int labelNumber){
  
  pot2Value = analogRead(pot2Pin)/4;
  delay(100);
  pot3Value = analogRead(pot3Pin)/4;
  delay(100);
  
  if(myButton==0){
    pot1Value = constrain(analogRead(pot1Pin)/2.8,0,360);
    
    ShiftPWM.SetAllHSV(pot1Value,pot2Value,pot3Value);
  } else{
      pot1Value = analogRead(pot1Pin)/4;
      ShiftPWM.SetAllRGB(pot1Value,pot2Value,pot3Value);
  }
  delay(100); 
}

void checkButton(int labelNumber){
  
  // 910k
  // 250k
  // 820k
  // 220k
  
  reading = analogRead(buttonPin); 
  Serial.println(reading);
  delay(500);
/*   
  if(reading >= 0 && reading <= 25){  // 0
      myButton = 0;
  }else if(reading >= 140 && reading <= 155){  // 1
    myButton = 1;
   }else if(reading >= 405 && reading <= 420){  // 2
    myButton = 2;
   }else if(reading >= 445 && reading <= 465){  // 3
    myButton = 3;
   }else if(reading >= 170 && reading <= 185){  // 4
    myButton = 4;
   }else if(reading >= 255 && reading <= 265){  // 5
    myButton = 5;
   }else if(reading >= 472 && reading <= 490){  // 6
    myButton = 6;
   }else if(reading >= 500 && reading <= 520){  // 7
    myButton = 7;
   }else if(reading >= 95 && reading <= 115){  // 8
    myButton = 8;
   }else if(reading >= 196 && reading <= 206){  // 9
    myButton = 9;
   }

  if (myButton != oldButton){
    lcd.clear();
    oldButton = myButton;  
  }
*/   
 DisplayLCD(labelNumber);

}

void DisplayLCD(int labelNo){
  lcd.clear();
  lcd.setCursor(1,0); lcd.print("Reading");lcd.setCursor(15,0);lcd.print(reading);
  lcd.setCursor(1,1); lcd.print(label[labelNo][0]); lcd.setCursor(15,1); lcd.print(pot1Value);
  lcd.setCursor(1,2); lcd.print(label[labelNo][1]); lcd.setCursor(15,2); lcd.print(pot2Value);
  lcd.setCursor(1,3); lcd.print(label[labelNo][2]); lcd.setCursor(15,3); lcd.print(pot3Value);
  
}

During all that testing, I kept the USB cable connected to the computer, so the board was receiving power from the USB port and the power supply. When I unplug the USB and only look at the results on the LCD screen, it is even worst. The LCD goes from very bright to very dim.

This is the info about the power supply:

+5v - 22A
+12v - 16A
250w

Thanks for your help.

My problem is that those readings are inconsistent (depending on how many lights are ON of OFF) and the power supply I'm using.

In the past better reading stability has been achieved by reading the input twice instead of just once, and using the second read as the input. Maybe something like below

pot2Value = analogRead(pot2Pin);
pot2Value = analogRead(pot2Pin)/4;

Your diagram shows no connection between GND on the Arduino, and what you have (inappropriately) described as "-12V" from the computer power supply.

That would be a big problem.

The values you show for the BCD switch are way too high
to expect stable signals.

If you had a few 10K and 20K resistors available plus
one 2.4K, you could configure them to get something
like this.

I'm sure this would be much more stable and would
have improved Vout steps in voltage:

Yes, clearly those original values were silly, not just because they were too high in value (which probably does not matter so much) but because they were not sufficiently scaled.

For practical resistor values, let's say you use a 10k for the ground resistor (which sets the impedance into the analog input, 10k is fine), then a 22k for the "8", 47k for the "4", 100k for the "2" and 220k for the "1".

Note - the lack of a ground connection is more likely the real problem here.