State change detection with analog input?

Dear all,
some months ago, with your help I create a “speedometer” using arduino and communicating them with the laptop on an excel sheet using netcomm.
My schema is an inductive gauge (proximity sensor) who closes a magnetic switch when a magnet fixed on a wheel passes close to the sensor.
This is supposed to be a button switch

On arduino board I used the “State change detection” code , with a debounce filter who eliminates the flickering.(see below).That seems to work correctly.

But I noticed some troubles because of 2 kind of noises:

  • When I go to my brother’s house, who lives close to some big TV/phone antennas the counter increments automatically at as would it be crazy.
    What is exactly happening? How can I resolve it? ( I thought to insulate the arduino box with aluminium foil . Maybe I have to weld some extra resistance or filter…)

-Sometimes, when I connect my laptop to an external power source ( it doesn’t matter if it’s AC power or 12 DC power), some “extra” pulses will be count, specially just when I connect the plug. Rarely, but also sometimes the counter increments crazily as fast as it can.

Trying to find out the way to resolve definitively this problem I tthink I have maybe to redo the code and to don’t consider my inductive switch as an Digital Input and it would work better if I considere it as an analog Input. If this would be a good solution how would be the part of the code for transform the read voltage to a pulse?

every help would be welcome because I couldn’t find the way to solve this.

Thank you very much !!!

/*
  State change detection (edge detection)
    
    
 The circuit:

 * Arduino UNO rev3
 * inductive switch attached to pin 2 from +5V
 * 10K resistor attached to pin 2 from ground
 * LED attached from pin 13 to ground 

Other hardware:

* inductive sensor (proximity gauge) ataches to pin2 & to the 10K resistor.
 
    
 http://arduino.cc/en/Tutorial/ButtonStateChange
 
 */  State change detection (edge detection)

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastEvent = 0;  // the last time the output pin was toggled
long interval = 20;    // the debounce time; increase if the output flickers

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(19200);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  
// compare the buttonState to its previous state
 if (buttonState != lastButtonState)
 {
 // if the state has changed, increment the counter
 if (buttonState == HIGH && millis() - lastEvent > interval) // <-- Ignore this press if it is too close to the last one
 {
 lastEvent = millis(); // <-- record when the last good event occurred
  
      buttonPushCounter++;
      // Serial.println("on");
      // Serial.print("nr pulses:  ");
      Serial.println(buttonPushCounter);
    } 
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      // Serial.println("off"); 
    }
  }
  // save the current state as the last state, 
  //for next time through the loop
  lastButtonState = buttonState;
  
  // turns on the LED every four button pushes by 
  // checking the modulo of the button push counter.
  // the modulo function gives you the remainder of 
  // the division of two numbers:
  if (buttonPushCounter % 4 == 0) {
    digitalWrite(ledPin, HIGH);
  } else {
   digitalWrite(ledPin, LOW);
  }  
}

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

If you try to read an analog (slowly varying voltage (*)) with a digital input you risk false triggering. You can either use a low-pass-filter and schmitt-trigger (ie hysteresis) to clean up the input signal, or use analogRead () and do that the equivalent in software (but this limits your bandwidth to 5kHz or so)

(*) slowly varying means less than a few million volts per second or so! The problem is that noise on the signal will take it above and below the switching threshold of the input gate as the voltage "gradually" passes the threshold. The 328 has a little hysteresis on input pins to reduce this problem, but it sounds like the RFI near the transmitter is exceeding this. You would do well to filter out RF frequencies with an RC filter anyway, this might be enough to fix your problem.

Thanks Mark so you mind the preferred option would be to use digital inputs using a low -pass-filter and schmitt trigger. I never used low- pass-filter ...can you please explain shortly how to connect it? the schmitt trigger code I'll try to find it searching i nthe forum, but if you also can help me...

Thanks.

deikoalita:
Thanks Mark
so you mind the preferred option would be to use digital inputs using a low -pass-filter and schmitt trigger.
I never used low- pass-filter …can you please explain shortly how to connect it?
the schmitt trigger code I’ll try to find it searching i nthe forum, but if you also can help me…

Thanks.

I would suggest a digital low pass filter. Read the analog input “X” times, add the results together in an accumulator, then divide the final result by “X”.

example:

/*
unsigned int x;
unsigned int samples = 1000;
unsigned long int accumulator = 0; // initialize accumulator
for (x = 0; x < samples; x++) {
accumulator += analogRead(channel);
}
return accumulator / samples;
*/

Any random noise on the analog input will be averaged out and return you a clean reading.

Change the constant “1000” to whatever you like (larger == more smoothing but slower response, smaller == less smoothing but faster response).

Note that the “accumulator” variable must be large enough to hold (1023 * number_of_samples).

Hope this helps.

– Roger

deikoalita: Thanks Mark so you mind the preferred option would be to use digital inputs using a low -pass-filter and schmitt trigger. I never used low- pass-filter ...can you please explain shortly how to connect it? the schmitt trigger code I'll try to find it searching i nthe forum, but if you also can help me...

Thanks.

A VERY SIMPLE low pass filter is nothing more than a resistor and capacitor:

resistor input >----/\/\/\/----#-----------> output |


___ capacitor | com >---------------#----------->

The R and C values of course are determined by the frequency you want the filter to work at.

The digital filter works much better and is simpler (needs no parts!) :)

Well, I'll try to buid my first low-cut filter. :fearful: Because it is my first time I would be very grateful if someone could help me to calculate C and R.

These are my values:

digital in ( 0-5 V) (Low/High) pulses (between 0 and 30 per second...)

I suppose I have to connectthis RC filter to the input pin (pin2 ) isnt'it?

About the suggestion of the digital low pass filter I can see how it really works...becasue I want to count pulses not voltage...so I don't know how to implemnt this in my code.

tahnks again for your support...

I would very appreciate if anyone would help me to find out the values of R &C for bulding my low pass filter. The working values are given in my previous comment. thanks again a lot!

    unsigned int x;
    unsigned int samples = 1000;
    unsigned long int accumulator = 0; // initialize accumulator
    for (x = 0; x < samples; x++) {
        accumulator += analogRead(channel);
    }
    return accumulator / samples;

It is faster to use a power of 2 e.g. 512 or 1024 iso 1000 as the compiler can optimize this to a shift instruction which is faster.

In my experience 16/32/64 samples are often enough to have a stable read. More reads will take more time which can cause the
signal to drift as time goes by.

for (x = 0; x < samples; x++) {
accumulator += analogRead(channel);
// (1)
}

Is a small delay (some us) required in (1) ?

a small delay can be done but it will extend the time it take to make the measurements (1000 delays of 1 ms => 1 second) and chance of drift as explained above will increase.

Often you just need to do some (or many) experiments to find the best timing params.

You can implement a digital low-pass filter easily.

Your issue is likely caused by interference - high input impedance on the input pin. One way to fix that is to lower its input impedance, by grounding that pin with a small resistor (<47k).

robtillaart: a small delay can be done but it will extend the time it take to make the measurements (1000 delays of 1 ms => 1 second) and chance of drift as explained above will increase.

Often you just need to do some (or many) experiments to find the best timing params.

I was thinking about the A/D stuff requiring a minimum time between two consecutive reads. Something like 50 microseconds, not one ms.