Simple Arduino Math Question

Started by electrosonic, June 01, 2013, 02:44:02 PM

Previous topic - Next topic

electrosonic

I want to use an analogRead to tell if one or both switches are on, using something like this...



The point V is read by analogRead. Each of the four possible states should give a different voltage which I can use to figure out what is switched.

I can play with the values of the resistors and find workable readings, but I was wondering if anyone has any ideas how to optimize it. That is the most spread between the possible readings?

Thanks,
Andrew.

  • SUPPORTER

gtr2

Why not use digitalWrite with each switch on it's own input?  Then use a case statement for what it should do depending on each switches state (high or low).

Josh

electrosonic

The  plan is to  port a project from Arduino to a ATTiny85 chip and put it in a pedal. I only have one input to read two switches, so they are sharing an input.

Andrew.
  • SUPPORTER

artifus

#3
as far as analogread is concerned point v is a value between 0 and 1023.
so if v = 5v then analogread 1023, if v = 0v then analogread 0. if v = 2.5v analogread is 511ish.
is that what you mean by spread?

http://arduino.cc/en/Reference/analogRead
http://arduino.cc/en/Tutorial/ReadAnalogVoltage
http://arduino.cc/en/Tutorial/AnalogInput
http://www.arduino.cc/en/Tutorial/Potentiometer
http://www.electronics2000.co.uk/calc/potential-divider-calculator.php

*with that in mind - you could replace the three resistors and two switches with one pot to act as a 'rotary switch' of sorts, if that were to be cheaper?*

gcme93

#4
This seems like a fair solution, if you have R1=R2=2*R3

(note you can't have R2=R3 or you won't be able to tell which switch is on if only one is engaged).

I'm not the cleanest at writing Arduino code or anything, but do something like:

if (output > Va)             // Both switches are closed
.....

if (Va >= output > Vb)         // Switch 2 only
.....

if (Vb >= output > Vc)         // Switch 3 only
.......

if (Vc>= output)                  // Neither switch
.......

Where "....." is what you want to happen for each case

Then work out what Va, Vb, and Vc should roughly be for all the cases so that you're guaranteed to be in that range even if the exact voltages are a little bit off ideal values


George
Piss poor playing is why i make pedals.

slacker

#5
I was going to suggest the same as George, that should work fine.
There's a thread about the same thing here with some other ideas. http://www.diystompboxes.com/smfforum/index.php?topic=90775.0  
Here's the image that was in my post

A 2 bit version of that would give voltages for the different combinations of 0, 1.25, 2.5 and 3.75 Volts, which I think is the biggest spread you can get, probably not worth the extra resistors and board space needed over your idea though.

SISKO

Quote from: slacker on June 02, 2013, 12:44:55 PM
A 2 bit version of that would give voltages for the different combinations of 0, 1.25, 2.5 and 3.75 Volts, which I think is the biggest spread you can get

This
--Is there any body out there??--

electrosonic

Thanks for the pic and the link, just what I was looking for. I guess most things have been previously discussed here, I guess I didn't choose my search terms very well when I was looking.

I found another solution that uses SPDT switches, saves a few resistors if that is the switch you have on hand.

Something like this...



I get 0v, 1.25v, 2.5v or 3.75v depending on the switch position.

(the idea is from this page http://www.skillbank.co.uk/SignalConversion/dac.htm)

I guess I should check in input impedance of analogRead() to see if I need to scale this.

Andrew.
  • SUPPORTER

g_u_e_s_t

if you have spdt switches, this would give you 0v, 1.7, 3.3, and 5.


g_u_e_s_t

ok, for some reason the picture didnt end up getting in there.  i will try again, but in case it doesnt work, here is the link:



http://wiki.openmusiclabs.com/wiki/OpenMusicLabsWiki?action=AttachFile&do=get&target=switch.png

its basically the same thing you have above, but with only the 100k resistors, except they arent 100k, they are 10k and 20k

Gurner

#10
Do you have sufficient capacity in your main loop to be polling this last pin frequently enough?

Whenever I've tried to squeeze the last drop of IO out of an under-pinned(?!) MCU by for example trying to get two switches on the one pin, it's never been a roaring success ...IMHO far better to have your switches on interrupts & leave your main loop to do the main thing it was intended for.

Failing that I'd be looking at if there's a comparator pin that can be pressed into service on the Arduino (I'm not familiar with them...I'm a PIC guy) & ensure either that either switch when pressed flips an internal comparator ...then use that comparator interrupt routine to do your voltage read.....at least this way, you remove the pin polling overhead (which to get a switch feeling zippy has to be polled rather frequently)

g_u_e_s_t

yarrr, this should do it.  computers really confound me sometimes.



at any rate, the adc should be able to be read in an interrupt, and therefore not take away too much from processing time.

electrosonic

That is just what I was looking for. Seems obvious enough after you have seen it.

Thanks,
Andrew.

  • SUPPORTER

cpm

Quote from: Gurner on June 03, 2013, 05:16:46 PM
Do you have sufficient capacity in your main loop to be polling this last pin frequently enough?

Whenever I've tried to squeeze the last drop of IO out of an under-pinned(?!) MCU by for example trying to get two switches on the one pin, it's never been a roaring success ...IMHO far better to have your switches on interrupts & leave your main loop to do the main thing it was intended for.

Failing that I'd be looking at if there's a comparator pin that can be pressed into service on the Arduino (I'm not familiar with them...I'm a PIC guy) & ensure either that either switch when pressed flips an internal comparator ...then use that comparator interrupt routine to do your voltage read.....at least this way, you remove the pin polling overhead (which to get a switch feeling zippy has to be polled rather frequently)

or just setup adc to start reading on a timer interrupt (save the previously read value), and use asynchronously that reading from your main program

something like this:
--> timer interrupt code:
save last_value in a global variable
signal start ADC
<--return from interrupt

the ADC keeps working on the background, it stops when finished, keeping the value on its registers, which will be saved to a variable on the next iteration. this way you have a ready value that refreshes every time the timer triggers.
If you have more that one analog input, just round-robin for a different input each time the timer interrupt is visited (keeping diferent stored readings as read_in1, read_in2, etc)

Actually its easier to get hold of when working o a more "classic" uC programming (i do PIC assembly).
On the arduino library the analogread() is a dedicated call which stalls the main program flow. Going the interrupt route means writing some hacks to get to low level registers and interrupt handling.



Gurner

Quote from: cpm on June 03, 2013, 05:41:17 PM


or just setup adc to start reading on a timer interrupt (save the previously read value), and use asynchronously that reading from your main program

something like this:
--> timer interrupt code:
save last_value in a global variable
signal start ADC
<--return from interrupt
the ADC keeps working on the background, it stops when finished, keeping the value on its registers, which will be saved to a variable on the next iteration. this way you have a ready value that refreshes every time the timer triggers.
If you have more that one analog input, just round-robin for a different input each time the timer interrupt is visited (keeping diferent stored readings as read_in1, read_in2, etc)


The problem with that method is you waste a timer (and I don't know if Arduinos are like PICs......I soon run out of timers!)...fine if you've a spare timer though!

That methodology is still just plain polling...in fact it might even be worse than just doing an ADC read in the main loop as inevitably there's an overhead entering/exiting the asscoiated interrupt routine...for hw switches, it's hard to beat a dedicated pin with interrupt routine, but I guess electrosonic doesn't have that luxury in this case...

cpm

Quote from: Gurner on June 03, 2013, 06:57:44 PM
The problem with that method is you waste a timer (and I don't know if Arduinos are like PICs......I soon run out of timers!)...fine if you've a spare timer though!

In that timer id put more code, like reading other inputs, or any other type of granularization for time slices. And dont do processing, just set some flags as fast as possible, and calculate later in the main program.
Or simpler enough, put that logic inside the main loop as long as you dont need guaranteed timing for input collection (or already have a precisely timed loop)

Quote
That methodology is still just plain polling...in fact it might even be worse than just doing an ADC read in the main loop as inevitably there's an overhead entering/exiting the asscoiated interrupt
routine...
Wrong! analog_read call is doing exactly that to start the ADC plus waiting for it to fill the latches one bit at a time. Indeed, the analogread routine will probably be compiled as a subroutine so still there are some jumps and rets behind the scenes.
Actually i was addressing your issue:
"Do you have sufficient capacity in your main loop to be polling this last pin frequently enough?" Thats where a stalling analog read ruins performance

Even more edgy, if you only need one analog input: setup the ADC_finished_interupt to start the ADC again, and get your value directly from the registers when you need it in the main program. No timer involved, just the ADC freewheeling on its own...


Quote
for hw switches, it's hard to beat a dedicated pin with interrupt routine, but I guess electrosonic doesn't have that luxury in this case...

right on digital pins... I dont know about the atmel chips, the more simple uCs usually dont have an interrupt on change for analog inputs.


g_u_e_s_t

setting the ADC to autotrigger and just grabbing the register is a great approach.

but, i dont think pin change interrupts are always the best way to go.  if your switch glitches (rotary encoders are notoriously bad here) then youll get that interrupt firing many times for a single change.  you can always add debouncing, but its more circuitry, and not always successful.  there is the fine line between averaging out the noise, and waiting too long for a response.  and pin change interrupts still have the interrupt overhead as polling might (although not neccessarily if done in main loop).  for the most part, interface buttons and such can usually be polled on such a low rate, that the overhead is negligible.  for things that require precision timing, like tap tempo buttons or sound triggers, pin change interrupts are a good way to go.

Gurner

#17
Quote from: cpm on June 03, 2013, 07:29:45 PM
Wrong! analog_read call is doing exactly that to start the ADC plus waiting for it to fill the latches one bit at a time. Indeed, the analogread routine will probably be compiled as a subroutine so still there are some jumps and rets behind the scenes.
Actually i was addressing your issue:

I wasn't referring to the bit about the analog_read call .......just simply outlining that if you're using a timer to generate an interrupt & then grabbing an ADC sample in the interrupt routine, then essentially you are using the timer to  check (poll) the pin's voltage to see if the value has changed. Whichever way you cut/dice it, having more than one switch off a single pin & then deriving which switch has been pressed solely via trapping a changed voltage (measured by ADC) must always involve polling ....as opposed to a far more preferable (& less cpu cycle intensive) bog standard pin generated interrupt.

Gurner


potul

I know you already got some answers on this, but I think a quite standard way to approach this is a R-2R resistor ladder. At the end, this is a DAC...

http://en.wikipedia.org/wiki/Resistor_ladder#R-2R_resistor_ladder_network_.28digital_to_analog_conversion.2C_or_DAC.29