Find analog value based on number of led with shift register

Hello.

I have:

  • 2 shift registers with 16 LEDS with 220 ohms each (8 Red, 8 Green)
  • 3 buttons connected to ONE analog pin, with resistors (1k, 2.2k, 10k) and 100k direct to ground.
    Everything is working fine. When all LED are open. I can know all the values for the analog pin and know which button has been pressed.

Goal:
I can connect up to 8 servos to any digital pins. That I'll detect and light up the Red light for each servos connected. ( Red LED => 1 to 8)

My 3 buttons are:

  • 2 buttons to control ONLY one servo (Left, Right).
  • 1 button for selecting which servo to control. Based on how many servos are connected to digital pins.

So the Green LEDs will light up to 1 to 8, based on which servo i want to control.

My problem is:

  • My 8 Red LED, can be 1 to 8 open. (Depends on how many digital pin is connected).
  • My 8 Green LED, can be 1 to 8, depends on the button.

Each time a LED is open, the value of the analog pin is changing. So I can't find which button has been pressed.

I tried to find the voltage, and mapping from 0 to 1023. But the value is so small between each.

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

int btn_value = analogRead(A5);
float voltage = btn_value * (5.0 / 1023.0);
float mapping = mapfloat(voltage, 0.0, 5.0, 0.0, 1023.0);


RESULT:
NBLed: 1 Value: 608 Voltage: 2.97 Mapping: 608.00
NBLed: 2 Value: 606 Voltage: 2.96 Mapping: 606.00
NBLed: 3 Value: 605 Voltage: 2.96 Mapping: 605.00
NBLed: 4 Value: 602 Voltage: 2.94 Mapping: 602.00
NBLed: 5 Value: 601 Voltage: 2.94 Mapping: 601.00
NBLed: 6 Value: 600 Voltage: 2.93 Mapping: 600.00
NBLed: 7 Value: 596 Voltage: 2.91 Mapping: 596.00
NBLed: 8 Value: 597 Voltage: 2.92 Mapping: 597.00
NBLed: 9 Value: 595 Voltage: 2.91 Mapping: 595.00
NBLed: 10 Value: 594 Voltage: 2.90 Mapping: 594.00
NBLed: 11 Value: 592 Voltage: 2.89 Mapping: 592.00
NBLed: 12 Value: 591 Voltage: 2.89 Mapping: 591.00
NBLed: 13 Value: 590 Voltage: 2.88 Mapping: 590.00
NBLed: 14 Value: 588 Voltage: 2.87 Mapping: 588.00
NBLed: 15 Value: 587 Voltage: 2.87 Mapping: 587.00
NBLed: 1 Value: 608 Voltage: 2.97 Mapping: 608.00

NOTE: My voltage is low, because I added more resistor to the ground. (It was shifting without any button). The 100k was not enough.

  • I tried to add a tolerence between each value.
  • I tried to add a drop voltage, when X red LED and Y green LED, are high.

Can someone help me? Any one have a idea how to find the values?
Thanks
NLT

Why? This is a hack that just makes things harder, as you see.

If you have two more pins, woyncha just use three digital inputs? Most analog pins works as as digital inputs.

As an alternative, provide better power so the analog doesn't sag and confuse things.

How are you providing power to all the components in you project that require it?

Also, FWIW, I would illuminate just one LED to indicate which servo is to respond to the buttons.

First LED, first servo. second LED, second and so forth.

The LED indicating the controlled servo could be near that servo.

Just sayin'.

a7

no led, no shift register, no buttons have something to do with servos.
you want connect 8 servos, do it. so simple. connect them.

It would help if you posted your annotated schematic showing exactly how this is wired. Be sure to show power sources and grounds with notation on wire leads over 10"/25cm.

Sketch is incomplete and does not compile.

Have you tried:

if(servo1.attached())

?

How to you have the resistors and buttons wired?

You don't want to look for a specific voltage when a button is pressed, you need to look for approximately the mid-way point between one button and the next, that allows for some fluctuation of voltage. Also, no need to convert the analog reading to a voltage, or use map(), just use the analog reading value directly.

Thank you guys, for your help.

First of all, when I say everything is working fine, I meant, when all LED is High (Open), it's easy to find the value of the analog pin. Because the value is always the same. I just add some tolerance, +3, -3. and that's it.

But when you have multiple LED that is not High (Open), and you open them sometimes, the value change based on how many LED is Open. That's what I have to find.

Based on: Multiple Buttons on 1 analog pin

Second, I can't really connect them all at once. Because I'm doing a "fancy" Robot Arm. I can add layers to the arm. such as

  • servos (up, down).
  • servos (left, right).
  • linear actuator (high or low).
  • The hand, can be disconnected and replaced by anything, like a claw, a drill, etc...

When I'm connecting one of these "gadget", the Arduino will detect them and show a Red LED for each. (Max 8 "gadgets")
To select one of the "gadget", I press a button and the green light is shifting 1 to 8

That's why I use a shift register. It's easy and it take only 3 digital pins for X number of registers.

Third. For the test I'm using Arduino Uno/Mega, but to fit inside my robot arm, I'll use Arduino Nano or Micro. I don't have a lot of digital/analog. That's why I use 3 buttons with only one analog pin.

Maybe, I'll have the space for 3 digital pins.

Fourth, I was reading the analog value directly, I know it's the same as Map() or Voltage. But I was trying to find a better way to read the value, for the buttons pressed.

Here is the schematic. Hope it's fine :wink:

I don't really want to share the code, because there is a lot of files (c++ and headers).
The code is not the problem.
I though there was some calculus equation to find the analog value, based on how many led is High.

We differ on this. It's a very easy way to have many buttons on one Nano pin, for instance. No, I wouldn't do it in an industrial setting, but for a hobby board, what's the problem? Sure, it takes more-than-newb coding, but it's not rocket science, either.

However, for this OP, I suspect the problem is slightly different.

@nolimitech your technique will work. Ohm's law is the formula, you can calculate exactly what the divider output will be.

I do this same thing for > 20 "buttons on a string". In my case, only one button can be pressed at a time. However, I don't bother with a formula, due mostly to 5% tolerance resistors and ambient noise making it a bit 'fuzzy'. Rather, I simply wired up what I wanted, then wrote a routine that prints each analog value to Serial Monitor while I press buttons; picked a few nice values(well separated), then made a lookup table filled with the values halfway between the aforementioned readings. No reason you couldn't do the same with multiple buttons pressed, just makes it a bit more convoluted.
For example, if the button values are 0, 10, 20, 30 etc, my table has 5, 15, 25, 35, and the code simply does an analog read, then scans the LUT for the first value greater than the reading; the index of that value is the button number.

My pullup is 2.2k, my resistors could be(for example) 0, 100, 220, 330, 470, 680, 1k.
I put a 2.2nF capacitor from pullup to GND, though it probably isn't needed.

After that, it's just debouncing.
Works a charm, if you have a relatively noise-free environment and a stable VCC.

Well I asked why and wanting to conserve pins or having run out is reason enough.

I don't understand the sensitivity to Vcc sagging, is it established to be a/the problem?

I think that Vcc is the reference voltage unless you take steps away from letting that be, so the relative nature of the analog reading should mask that problem.

With only three buttons and using @camsysca's LUT scheme this should work well, with the entirely reasonable caveat that buttons will not work properly if more than one is pressed at a time.

I don't see a small capacitor in between the analog input pin and ground, 0.1 uF ceramic has been suggested elsewhere, or here for all I recall

All the handling of this should be done outside the main code, which should just be able to pick up state and transitions on three buttons.

So should it prove unsatisfactory, you can go back to digitalRead(). :wink:

But don't toss the idea until it is coded plausibly.

a7

Generally speaking, I think the problem comes when people calculate an ideal voltage, using a reference like 5V, then fail to account for differences when, for example, they use USB as the power source, and their USB output is 4.7V, for example. Leads to all sorts of headscratching. You're correct, as long as the sensing is done as a fraction of VCC, and VCC is the reference, if VCC drifts nothing changes.

Agreed, in the case of the OP's incomplete diagram.

However, I think their original question has been answered. What say you, @nolimitech, do you have further questions?

220 ohm for the LEDs is in theory a 116mA load for the 74HC595 when all LEDs are ON, which is a bit much for a chip with an absolute max of 70mA. 470 ohm or 1k would have been much nicer for the chip.

Where is VCC for the buttons coming from. The Arduino A/D returns a 1/1024 ratio of it's 5volt supply (forget about voltage), so ground and VCC for the buttons must come directly from a separate 5volt and ground pin of the Uno. If you share supply/ground with the 595 circuit, then expect instability.
Leo..

True, thanks.

@camsysca That was the idea. Right now, I did a table with 1 to 16 LED High (Open) and the values when I press each button.
It's correct, but I don't know it seem weirdo. I though there was a better way to find the values :slight_smile:

VCC => 5V from external source. I don't think it's a good idea to plug everything from the arduino :smiley:
Only the ground is connected to the Arduino.

The Arduino is connect via USB (for programmation only). But I'm from external 5V, in LIVE.

@Wawa I'll check about the mA load of the 74h595. Thank for that.

Thank you.
I guess there is no other way to do I what I need :smiley:
I'll continue with a table chart. 3 rows (buttons) and 16 columns (led) of each values.

Thanks again

Yeah I know. That was just for testing. Because the values is really close between each other. Whatever the source is used.
And I think it might change again, when I'll unplug the usb cable and keep the external source only.

Button A (select servo) => 915 to 850
Button B (right) => 296 to 263
Button C (left) => 166 to 160

When external 5V is connected and USB cable.

I just added more resistance to each button. it was too much close.

In general, no. But if your resistor hack draws little current (uses larger rather than smaller resistor) powering it from the same Vcc as the microprocessor enjoys would mean you would not need have a table 3 x 16 of empirically determined readings...

Or you could use a beefy 5 volt supply and power both the board and the resistor divider.

a7

True.
But I just realized that I mixed two ideas in the same project.
I wanted 8 servos with 2 buttons each (left, right or up, down). Needed 16 values + 16 LED. That's where I needed the values of each buttons, based on the LED. I had a table for each values.

But I changed the whole thing, because it was ridiculous.

Right now, with 3 buttons, I don't need it. Since the value of Button A is ~800, Button B ~300, Button C ~160. It's not enough close to make mistake. Even if I add more components to the project.