Electronic – arduino – digitalRead sampling rate for Arduino Uno

arduinoatmegabutton

I am attempting to send a character across the serial port when I press an external button the button is attached to the digital IO pin 3, I used the code from the SerialCallResponse example, and replaced the "sensor" stuff it was doing in the main loop with the following:

void loop()
{
 // if we get a valid byte, read button in:
  if (Serial.available() > 0) {
   // read the state of the pushbutton value:
   buttonState = digitalRead(3);  
   if (buttonState == HIGH) {     
     // print B on serial port:    
      Serial.print('B', BYTE);   // send a T
    } 
  }
}

However I get multiple B's sent out, so I tried putting a while loop in the if buttonState==HIGH section to wait until buttonState==LOW, however if I press the button, and then release then press again, it doesn't respond as quickly as I would have expected seemed to be a second to a second and a half response (although not accurately timed).

Is there a certain amount of time that has to happen between the digitalRead's where it will changeover to another value? Is there a form of an internal "debouncing" of a signal on the Digital IO?

This is my first Arduino and I got it two days ago, it's already much further along in my project then I was able to get with my Pic due to the full dev board fortunately.

EDIT: So I was browsing adafruits tutorials earlier trying to figure out if she mentions anything about what I'm seeing, I tried this code as an additional test:

int switchPin = 3;              // Switch connected to digital pin 2

void setup()                    // run once, when the sketch starts
{
  Serial.begin(115200);           // set up Serial library at 9600 bps
  pinMode(switchPin, INPUT);    // sets the digital pin as input to read     switch
}


void loop()                     // run over and over again
{
  Serial.print("Read switch input: ");
  Serial.println(digitalRead(switchPin));    // Read the pin and display the value
  delay(300);
}

I press the button, after I have released it, roughly 15 1's came across still, which tells me that even if I call digitalRead it's really only reading a buffer (or something like this) that samples the digital IO port at some rate, is this expected, any ideas where I can figure out where this number is? Where it came from (as in why that number)?

Would using an interrupt would make more sense? This way you would only be "notified" of when a new event occurs.

EDIT #2: So I decided to try interrupts, I changed my code to the following:

int switchPin = 3;              // Switch connected to digital pin 2

void setup()                    // run once, when the sketch starts
{
  Serial.begin(115200);           // set up Serial library at 9600 bps
  pinMode(switchPin, INPUT);    // sets the digital pin as input to read switch
  attachInterrupt(1,handle_button,FALLING);
}

void loop()                     // run over and over again
{
}

void handle_button()
{
  Serial.print("Read switch input: ");
  Serial.println(digitalRead(switchPin));    // Read the pin and display the value
}

This change now only displays anything on the serial port when an interrupt is triggered. I pressed the button and got "Read switch input: 1", however if I press the button anytime before 30 seconds has elapsed (rough count to 30 that is) it doesn't seem to trigger the interrupt. I wait for a count of 30, and I get the "Read switch input: 1" message. Again this continues to tell me that the digital IO isn't polled at a very fast rate, I find this surprising, I have messed with Pics in the past and haven't noticed this problem, and this is my first "real" program with the Arduino, I'm wondering if there is something I need to setup maybe?

The problem still is and remains that I am wondering what the rate the arduino uno (and more exactly the atmel atmega 328P) polls the digital IO ports.

EDIT #3 To be more specific, it's about 12 seconds (used an online timer and kept an eye on it). If I press a second time in 11 seconds it doesn't trigger it and I still have to wait another 12 seconds from the second press.

Best Answer

You have two problems right now that are separate from each other.

1) Button bounce

2) Improper button wiring

First, you need to introduce a delay into your interrupt function so that it won't keep registering each rise and fall of the bounce as a separate button press. Use "delayMicroseconds()" because apparently you can't use regular "delay()" inside interrupts. Id suggest a 20,000 microsecond delay.

Second, you need to put a pull down resistor onto the digital pin that you are sampling.

The problem you are having is that the pin is in input mode and thus at high impedance (very high resistance) and thus has a tenancy to "float". If you put a voltage to it, it charges up like a capacitor and since the pin itself has very high resistance to ground, it takes a while for the charge to dissipate to the point where the Arduino will register a LOW again. A 10k resistor from the pin to ground will force the "capacitor" to discharge quickly after current from the button has stopped flowing.

Finally, the Arduino is pretty quick at it's read/write operations (I'm a mechanical engineer, ALL electronics happen "quickly" in comparison to mechanical systems, so it's relative I guess). Here's a link to some test results.

TL;DR verson:

What these values tell me, is that we can do about:

10 analog 10-bit readings per millisecond with analogRead()
128 pwm settings per millisecond with analogWrite()
220 pin reads per millisecond with digitalRead()
224 pin writes per millisecond with digitalWrite()
1056 pin reads per millisecond with direct port reads
1059 pin writes per millisecond with direct port writes