2
\$\begingroup\$

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.

\$\endgroup\$
5
  • \$\begingroup\$ What is the purpose of wrapping it in an if serial.available()? \$\endgroup\$
    – Majenko
    Commented Oct 16, 2011 at 8:05
  • \$\begingroup\$ I was using the example program, basically the external device must respond once, to acknowledge existence, then the mcu will transmit the data when a button press occurs, its not critical to the project and will likely be removed eventually, is it possible that read is slowing things down....now I might have to try.... \$\endgroup\$ Commented Oct 16, 2011 at 13:51
  • \$\begingroup\$ I would scrap it for now - one thing that's just getting in the way. Keep the program as simple as possible to start with. \$\endgroup\$
    – Majenko
    Commented Oct 16, 2011 at 14:03
  • \$\begingroup\$ @onaclov2000 - how exactly is your button connected? Do you have a pullup or pulldown resistor attached? \$\endgroup\$
    – Oli Glaser
    Commented Oct 16, 2011 at 21:16
  • \$\begingroup\$ No resistor, but did put one in, now it works as expected. \$\endgroup\$ Commented Oct 18, 2011 at 1:58

2 Answers 2

3
\$\begingroup\$

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
\$\endgroup\$
2
  • \$\begingroup\$ That would do it, foiled again by pull up/down resistors. I had a similar problem probably 2 years ago (last time I messed with a button obviously), can't believe I didn't recognize it. \$\endgroup\$ Commented Oct 18, 2011 at 1:58
  • \$\begingroup\$ No problem, actually I just had this issue myself last week... \$\endgroup\$
    – Faken
    Commented Oct 18, 2011 at 2:17
1
\$\begingroup\$

The reason you get multiple B's is because the the "loop" function is called in an endless loop.

while (true) {
    loop();
}

Perhaps it helps to look at your function like this:

while (true) {
    if (Serial.available() > 0) {
        buttonState = digitalRead(3);  
        if (buttonState == HIGH) {     
            Serial.print('B', BYTE);   // send a T
        } 
    }
}

As soon as serial input is available, you read the state of the button and send a 'B' in case the button is pressed. The serial input is never consumed, because Serial.read() is never called, so in the next pass through your loop function, the same thing happens.

If all you want is sending a 'B' when the button is pressed, then this might do:

int buttonState = LOW;
int button0, button1;

void setup()
{
    Serial.begin(9600);
    pinMode(3, INPUT);
}

void loop()
{
    button0 = digitalRead(3);
    delay(10);
    button1 = digitalRead(3); // de-bounce

    if (button0 == button1) {
        if (button0 != buttonState) {
            buttonState = button0;
            if (buttonState == HIGH) {     
            Serial.println("B");
            } 
        }
    }
}

Below is a link to a pretty thorough tutorial for dealing with buttons. It also explains the 10ms delay to let the button settle.

http://www.ladyada.net/learn/arduino/lesson5.html

\$\endgroup\$
1
  • \$\begingroup\$ I understand that it is sending multiple B's because of the while loop, what I am not understanding is why it is not transitioning from High to Low more or less quickly...if that makes sense. \$\endgroup\$ Commented Oct 16, 2011 at 19:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.