If you want to debounce digital readings, you can compare the current value of the reading pin to its previous value, more or less like this
int button = digitalRead(buttonPin);
int oldButton;
if(button != oldButton){
execute your code here
}
oldButton = button;
This will execute the code inside the curly braces only when you push or release the button, and not constantly at baud rate, right?
Is there some similar technique for analog readings? I can't think of any code (that doesn't use delay) as analog readings always flicker slightly, and if you use something like this
it might work, but you'll always be getting jumps of two values, therefore reducing resolution to half. Does this all make sense?
I actually want something like this cause I'm using Arduino to control parameters in Pure Data, and I'd like Arduino to work as a MIDI controller, in the sense that it will output values only when something changes, so that Pure Data doesn't have to compute the incoming data constantly.
This will execute the code inside the curly braces only when you push or release the button, and not constantly at baud rate, right?
No. Since oldButton is (or appears to be) local to the function, it is NOT assigned an initial value and is not persisted across function calls.
I have no idea what you mean by "at baud rate".
I actually want something like this cause I'm using Arduino to control parameters in Pure Data, and I'd like Arduino to work as a MIDI controller, in the sense that it will output values only when something changes,
What is the difference between a change caused by a gross twist of a potentiometer and instability in the value returned by analogRead()? A change from one reading to the next is a change.
The threshold doesn't reduce resolution. Two successive readings might be 650 and 653. The delta will be three. Full resolution. If the successive readings are 650 and 651, the snippet you showed would ignore the second reading. But, if you save a value (as well as outputting it) only when the change is large enough, resolution isn't compromised. You'd ignore the 651. But, if the next value read was 652, you'd output and save that.
I would also like to add that your "debounce" code is not, in fact, debouncing code. The code you posted detects edges, which is a completely different thing. In order to software debounce a switch, you MUST use a time variable to make sure the switch state is stable for a certain amount before you register the state change. THEN you can run it through the edge detector. to detect a state change.
If you use your code as is, every press of the switch can still register multiple bounces of the switch, which will cause multiple edges and will trigger whatever routine you want to run multiple times. Hook a button up to pin 12 and run the following sketch:
#define pin_button 12
#define pin_led 13
long debounce_delay = 15;
long t_now;
long t_switch=0;
int b_prev;
int b_state;
int b_curr=HIGH;
bool b_edge = false;
int led_state=LOW;
long low_trigger;
int bounce_count;
void setup()
{
pinMode( pin_led, OUTPUT );
pinMode( pin_button, INPUT_PULLUP );
digitalWrite( pin_button, HIGH );
// initialize the button states to whatever the switch is when
// the controller starts.
b_state = digitalRead( pin_button );
b_prev = b_state;
bounce_count=0;
Serial.begin(9600);
}
void loop()
{
// get current time (ms) and state of button press.
t_now = millis();
b_curr = digitalRead( pin_button );
// edge trigger variable cleared.
b_edge = false;
if( b_curr!=b_prev )
{
t_switch = t_now;
bounce_count++;
}
// if a delay has passed without the switch timer being reset,
// button state is not bouncing.
if( t_now-t_switch > debounce_delay )
{
// if the new state is not the same as the old one,
// edge variable is set to true.
if( b_curr!=b_state )
b_edge = true;
b_state = b_curr;
}
b_prev = b_curr;
// if the button is high and the edge triggered
// toggle the led.
if( b_edge && b_state==LOW )
{
if( led_state==HIGH )
{
digitalWrite( pin_led, LOW );
led_state = LOW;
}
else
{
digitalWrite( pin_led, HIGH );
led_state = HIGH;
}
}
low_trigger++;
if( b_edge && b_state==LOW )
low_trigger = 0;
if( b_edge && b_state==HIGH )
{
Serial.print( low_trigger );
Serial.print(" ");
Serial.print(bounce_count/2);
Serial.print(" ");
Serial.println( led_state );
bounce_count=0;
}
}
This sketch shows a proper debounce routine with edge detector of a single button, hooked up to pin 12 with pullups enabled. Every time you release the button, 3 columns of data will be printed out to the serial monitor:
Relatively unimportant, it is the number of times the routine is cycled through while the button is low.
The one of interest, how many time the switch changed state before the timer expired. Anything greater than 1 indicates the switch bounced and would have detected multiple edges.
State of the LED on pin 13.
Different buttons may bounce more or less than others. Try out as many as you have.
I guess I didn't use the right term (debounce). I also guess that a potentiometer that flickers, will just flicker and there's no real solution for this?
The threshold doesn't reduce resolution. Two successive readings might be 650 and 653. The delta will be three. Full resolution. If the successive readings are 650 and 651, the snippet you showed would ignore the second reading. But, if you save a value (as well as outputting it) only when the change is large enough, resolution isn't compromised. You'd ignore the 651. But, if the next value read was 652, you'd output and save that.
What I mean by resolution reduction is that with the way I suggested I will be receiving only half of the values of the potentiometer. They will be in full range 0 -1023, but only every two values would be printed to the serial port.
What I'd like to achieve is make a controller that will print a value to the serial port only when that value changes, but if a potentiometer flickers then the analog reading changes, so...get better potentiometers?
I think what you are saying is that you want to eliminate track noise on the pot?
Try putting a 100nF capacitor between potentiometer wiper terminal and ground
(but near the relevant analog pin). This should eliminate track noise and greatly reduce any
electrical interference (such as picked up by the wiring to the pot).
You may also have to implement a little hysteresis on the input (also known as dead-banding)
to ignore changes in just the LSB.
Most analog measurement devises have some hysteresis. That means that even though whatever it's measuring is constant, the output coming from the device will float around in an uncertainty band. Lets say your ADC will read 0-1023 and the absolute value should be 900 counts. The hysteresis may cause you to read 900,903,897. If you make process adjustments to the output, you may introduce real fluctuations in whatever you're measuring. So now the readings are running 903, 890, 909, 885. Causing the system to become even more unstable. Instead one adds some dead band to the system. This dead band is like saying I'm not going to make a change in the output until I'm sure that the actual thing I'm trying to control needs adjusted.
Herbie56:
Most analog measurement devises have some hysteresis. That means that even though whatever it's measuring is constant, the output coming from the device will float around in an uncertainty band. Lets say your ADC will read 0-1023 and the absolute value should be 900 counts. The hysteresis may cause you to read 900,903,897. If you make process adjustments to the output, you may introduce real fluctuations in whatever you're measuring. So now the readings are running 903, 890, 909, 885. Causing the system to become even more unstable. Instead one adds some dead band to the system. This dead band is like saying I'm not going to make a change in the output until I'm sure that the actual thing I'm trying to control needs adjusted.
Hysteresis doesn't cause the measured value to float around, noise does. Hysteresis is one solution to the noise problem, the "dead band" solution you said.
Another way to stabilize the input is to keep the last X reads in a ring buffer and calculate a running average every time you take a sample. However, you'll still need some king of minimum threshold to trigger on. You won't want to change on each little digit change. How fast you sample, how much you average will depend on the speed of your analog signal and the amount of noise it has.
I'm afraid I don't know enough about your "MIDI controller" application to offer you better advice. What is the source of the signal you are sampling? Is it a sound sample, or something else?
I'm afraid I don't know enough about your "MIDI controller" application to offer you better advice. What is the source of the signal you are sampling? Is it a sound sample, or something else?
I'm only reading potentiometers and use them to control parameters of sound. All sound processing is being done in my laptop with Pure Data, but I want to build a custom made controller that fits my needs, so I thought of Arduino. The thing is that when Pure Data receives a value which controls, say the amplitude of sound, it will have to do quite some calculations, and if the values received from the potentiometer flicker, then Pure Data will have to do these calculations constantly, even if that's not necessary.
All I want is Arduino to output values only when I twist the potentiometers, but I see that this is quite hard to achieve...
BTW, in a wikipedia article it's mentioned that the 'dead band' is different from hysteresis..
Yes the term hysteresis has almost devolved into the realm of slang and I agree that noise is a better term in this application. Typically I'd look at hysteresis values when selecting a device that measures an analog condition but outputs a digital signal.
Herbie56:
the term hysteresis has almost devolved into the realm of slang
It's not slang, it's a well defined and widely understood term, it's just the wrong term for what you were describing.
A deadband algorithm makes the input 'notchy' since it ignores small variations. This may be desirable in some situations.
A running average algorithm would be more suitable if you want to be able to follow small slow variations but just want to eliminate higher frequency variations e.g. noise.
A running average algorithm would be more suitable if you want to be able to follow small slow variations but just want to eliminate higher frequency variations e.g. noise.
Would something like what MarkT suggested be an implementation of a running average algorithm?