Using ARD to output constant voltages

Hi everyone, I have a small project I need some guidance with please.

I have a multi-function knob with the following states:

N/O the signed wire sees 5v (4.9)
Position 1 - 0.0v
Position 2 - 3.3v
Postiion 3 - 1.8v

I am thinking of feeding this line into an analog input, and depending on the volt. have arduino send a signal equal to that voltage to an output pin (analog?)

Here is the challenge, the positions of the switch is no latching. Meaning the once I go to pos. 1 (0.0) it will go back to the rail voltage (5v).

What I want is for the ard. to keep or hold position 1, 2 or 3.

If its not P1, then it has to be P2 or P3. Meaning that the scrip will have to look up the last position it was in and hold it (millis? or while) it is not P2 or P3.

Not looking for a complete scrip, but I was to know if what I am asking for can be done and if I am on the right track.

Thanks.

You can find out when the voltage is close to one of the specified voltages - then you can assume that the switch is in the related position. All other voltages can be ignored.

An Arduino can not produce a constant voltage - analogWrite produces a PWM signal. You'll need an external DAC for that.

In your case you can also connect a resistor voltage divider to a digital pin, and produce a fixed voltage that way. This voltage in turn you may buffer using an OpAmp (unity gain) to get a stronger signal if needed.

Run PWM thru a lowpass RC filter, can make any level you want between 0 and 5V in 255/5V steps.
Here I used a 10K resistor and 4.7uF cap, with analogWrite at 0, 25, 50, 75, up to 250.

Looks nice.
You can clearly see the slow reaction on changes, which for OPs application should be no problem. But drawing any significant current from this circuit will be a problem.

Thank you guys for all the help, I did get any notification for your replies. BTW I had to also make a new account since my account from 2014 seems to have disappeared (weird).

Anyway, regarding the analog voltages, I am outputting to to a pin with marked with the "~" symbol and I seem to be getting variable voltages at least with my multimeter. could it have a low phase filter built it?

analogWrite(Var, 168);  // yields 3.3v

For some reason it seemed like this would be a project suited for some case statements, but the challenge that I am running into is this:

With the line, I am sort of arbitrarily mapping the input voltages into the 4 cases.
As I mentioned, I have 0V, 1.8V, 3.3V and 5V as possible inputs and would like to say that if there is 0v go do this.., if there is 1.8v go do that.. etc.

Maybe Cases is not the right approach? Can you guys please suggest a solution to this?
Thank you

const int sensorMin = 0; 
const int sensorMax = 1023;
int mode = map(InSignal, sensorMin, sensorMax, 0, 3);

.

crullier:
Anyway, regarding the analog voltages, I am outputting to to a pin with marked with the "~" symbol and I seem to be getting variable voltages at least with my multimeter. could it have a low phase filter built it?

Normally - yes. Or it averages the values. Or (for an analog one) it's the reaction time of the needle. Connect it to a scope and you'll see the block wave it really produces.

For some applications it'll have the same effect as a constant voltage, for other applications not.

As I mentioned, I have 0V, 1.8V, 3.3V and 5V as possible inputs and would like to say that if there is 0v go do this.., if there is 1.8v go do that.. etc.

I'd do it a little different.
First of all the ADC is not that precise, nor will be your input voltage. Some dirt on the contacts for example, or even a temperature difference, can change the ADC value a bit. So you have to use a range, and for that you'd normally take the mid point between the voltage values as threshold. So in your case:
ADC < 184 (0.9V): 0V
184 <= ADC < 522 (2.55V): 1.8V
522 <= ADC < 850 (4.15V): 3.3V
ADC >= 850: 5V

Or in code:

if (ADC < 184) {
  digitalWrite(output, LOW); // 0 V
}
else if (ADC < 522) {
  analogWrite(output, 369); // 1.8V
}
else if (ADC < 850) {
  analogWrite(output, 676); // 3.3V
}
else {
  digitalWrite(output, HIGH); // 5V
}

I have had good luck with external DAC chips. Specifically, the MCP4725. A simple little chip, but gave me solid voltages. Very easy to wire up, and incredibly easy to program.

could it have a low phase filter built it?

That would be a Low Pass Filter, not exactly but a multimeter might avrage a reading, it depends on the meter. Often they are not much good at fast signals.

This is what is going on http://www.thebox.myzen.co.uk/Tutorial/PWM.html

Guys, is there an advantage to using switch case vs if?

The problem I need to overcome, and maybe this if beyond the scope of this thread or definitely my skill, is that the input values are temporary.

When the knob is turned in position 1 - I need the voltage go from 5V to 0.0V and then back to 5V as soon as the knob it let go off.

The part I am suck on here is that I am not sure how to tell the arduino to ignore the 5V or preserve the condition and keep outputting what voltage or PWM that corresponds to that 0.0v input.

I realize this is a bit complicated.
Would a "do while" inside the IF or Switch help?

crullier:
Guys, is there an advantage to using switch case vs if?

Not that I'm aware of, beyond readability.

The problem I need to overcome, and maybe this if beyond the scope of this thread or definitely my skill, is that the input values are temporary.

When the knob is turned in position 1 - I need the voltage go from 5V to 0.0V and then back to 5V as soon as the knob it let go off.

You have to give a much more detailed explanation of what's going on there, as this just doesn't make sense (the sentence being not grammatically correct doesn't help, of course).

I just re-read my sentence and I don't even know what I was trying to say. =)

I have a 3 position on latching knob.
normally open which is the resting state the signal wire I am tapping into sees 5v.
when I move it to position 1 - the wire sees 1.9V but returns to 5V as soon as take my hand off.

Ideally I would replace the knob to be latched but this is not possible.

So what I need to do to is:

Original Signal in at 1.9 v => outputs a message and message remains despite the original signal going back to 5v.

If Signal in then is 3.3 v => outputs another message and message remains despite the original signal going back to 5v.

Using an Arduino this is easy to do. Connect to an analog pin, sample this pin all the time, the moment you see 1.9V on the pin switch on one output, when you see 3.3V switch on another output. Don't change states when the pin sees another voltage.

But how are you going to unlatch the signal, assuming you will want to do this?

Will the 1.9V be seen on the way to the 3.3V (or the other way around)? That would make it more complex as you have to start ignoring states for a certain time or so.

Eventually a library for a resistor ladder button can be used for the input part. If the knob is turned it has the same effect as if a button is pressed. A changed input voltage is accepted only after the voltage stays in a specified range for some time (debouncing).

Since you only have a few voltages that you need to generate, this could actually be done with a couple of resistor dividers on the output pins. You could use two output pins, and two resistors, with values 3.3K and 1.8K (or any other values with those ratios).

When both output pins are low, the output voltage is 0. When pinA is high and pinB is low, the output voltage is 1.8 volts. When pinA is low and pinB is high, the output voltage is 3.3 volts. And when both pins are high, output is 5 volts.

ResistorOutput.png

ResistorOutput.png

the problem is not generating the voltages. That is already happening / existing.
Here is the challenge, the 3.3V will become 5V as soon as I release the button or knob.

Let me see if I can out in to words how I think or image this should work, and then you guys can tell me if its even possible and give me a clue:

When the board's Pin A1 sees 5V is should do nothing. We are ignoring 5V.

The moment A1 sees 1.9v is should DO "ABC" and should remain in that state until is sees either 0V or 3.3V.
The moment A1 sees 3.3v is should DO "DEF" and should remain in that state until is sees either 1.9V or 3.3V.
The moment A1 sees 0v is should DO "GHI" and should remain in that state until is sees either 0V or 1.9V.

Okay guys, I am not giving up yet and I learning a bit more every time.
Here is the new code that addressed the voltages, just a quick bench test.

question: with Switch case, am I only limited to the range mix and max, unlie isolating specific ranges like I am able to do with the IF?

So with the code below I am getting consistent input results. What I need now is to figure out how to tell the arduino that once it identifies a voltage, to keep running the code in the IF unless the voltage changes to 0v 1.9v or 3.3v in other word just latch on.

int inSignal = analogRead(A1);  //Read input voltage into variable
float Vin = inSignal * (5.0/1023.0);  //Converts raw value into voltage 0-5v

int outPin = 9;

//0.0V Input
if (Vin <= 0.5)
{ 
  analogWrite(outPin, 127.5);
  Serial.println (Vin);
  Serial.println("MODE i");
  delay(1000);
}
//3.3V Input
if ((Vin >=3.0)&&(Vin <= 3.3))
{ 
  analogWrite(outPin, 127.5);
  Serial.println (Vin);
  Serial.println("MODE S");
  delay(1000);
}

}

A few things about that code.

The full range of the ADC is 1024, not 1023 (it goes from 0 to 1023, for a total of 1024 points).

It's often easier to use ADC figures rather than calculating voltage.

To detect 3.3V you should do 3.0-3.6 range, or even greater. As your next step is 1.7 I'd take the middle of the two. So 2.5-4.2V for the 3.3V point, and 0.8-2.5V for the 1.7V point.

analogWrite() only takes ints, not floats.

to work with states, use a state machine, like this:

#define STATE_ABC 1
#define STATE_DEF 2
#define STATE_GHI 3
byte state = STATE_ABC; // Start-up state. Set to 0 for no state.

void setup() {
  // Do setup.
}

void loop() {
  int adc = analogRead(A1);
  if (adc < 164) state = STATE_ABC; // 0V reading.
  else if (adc < 512) state = STATE_DEF; // 1.7V reading.
  else if (adc < 860) state = STATE_GHI; // 3.3V reading.

  switch (state) {
    case STATE_ABC:
      doABC();
      break;
    case STATE_DEF:
      doDEF();
      break;
    case STATE_GHI:
      doGHI();
      break;
  }
}

The suggested state machine can be replaced by:
if (adc < 164) doABC(); // 0V reading.
else if ...
what reveals that it does not implement a state machine.

A state machine in a certain state does only what is defined for that state, and also changes its state only according to the defined transitions for that state. In the concrete project the output does not necessarily change immediately when the input changes, instead the automaton can wait for some additional condition (debounce interval...) before changing its state and output.

Depends: if it's a one-off run of that function, then yes.

However OP stated that the input will go back up to 5V all the time, but the state has to be retained while the input is at 5V. That's why this slightly more complex solution.