tasa de muestreo digitalRead para Arduino Uno

Estoy intentando enviar un carácter a través del puerto serie cuando presiono un botón externo, el botón está conectado al pin 3 de E/S digital, utilicé el código del ejemplo SerialCallResponse y reemplacé el "sensor" que estaba haciendo en el principal bucle con lo siguiente:

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
    } 
  }
}

Sin embargo, me envían varias B, así que intenté poner un ciclo while en la sección if buttonState==HIGH para esperar hasta buttonState==LOW, sin embargo, si presiono el botón, luego lo suelto y luego lo vuelvo a presionar, no responde tan rápido como hubiera esperado parecía ser una respuesta de segundo a segundo y medio (aunque no cronometrada con precisión).

¿Hay una cierta cantidad de tiempo que tiene que pasar entre las lecturas digitales donde cambiará a otro valor? ¿Existe alguna forma de "antirrebote" interno de una señal en Digital IO?

Este es mi primer Arduino y lo obtuve hace dos días, ya está mucho más avanzado en mi proyecto de lo que pude obtener con mi Pic debido a la placa de desarrollo completa, afortunadamente.

EDITAR: Así que estaba buscando tutoriales de adafruits antes tratando de averiguar si ella menciona algo sobre lo que estoy viendo, probé este código como una prueba adicional:

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);
}

Presiono el botón, después de haberlo soltado, todavía aparecen aproximadamente 15 1, lo que me dice que incluso si llamo a digitalRead, en realidad solo está leyendo un búfer (o algo así) que muestra el puerto de E/S digital a algún ritmo, es esto esperado, ¿alguna idea de dónde puedo averiguar dónde está este número? ¿De dónde vino (como por qué ese número)?

¿Usar una interrupción tendría más sentido? De esta manera solo serías "notificado" cuando ocurra un nuevo evento.

EDIT #2: Así que decidí probar las interrupciones, cambié mi código a lo siguiente:

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
}

Este cambio ahora solo muestra algo en el puerto serie cuando se activa una interrupción. Presioné el botón y obtuve "Leer entrada del interruptor: 1", sin embargo, si presiono el botón en cualquier momento antes de que hayan transcurrido 30 segundos (conteo aproximado de 30) no parece activar la interrupción. Espero un conteo de 30 y recibo el mensaje "Leer entrada de interruptor: 1". Una vez más, esto continúa diciéndome que el IO digital no se sondea a un ritmo muy rápido, lo encuentro sorprendente, me he metido con Pics en el pasado y no he notado este problema, y ​​este es mi primer programa "real". con el Arduino, me pregunto si hay algo que deba configurar tal vez.

El problema sigue siendo y sigue siendo que me pregunto cuál es la velocidad con la que el arduino uno (y más exactamente el atmel atmega 328P) sondea los puertos IO digitales.

EDICIÓN #3 Para ser más específicos, son unos 12 segundos (utilicé un cronómetro en línea y lo controlé). Si presiono una segunda vez en 11 segundos, no se activa y todavía tengo que esperar otros 12 segundos desde la segunda presión.

¿Cuál es el propósito de envolverlo en un si serial.disponible()?
Estaba usando el programa de ejemplo, básicamente, el dispositivo externo debe responder una vez, para reconocer la existencia, luego el mcu transmitirá los datos cuando se presione un botón, no es crítico para el proyecto y es probable que se elimine eventualmente, ¿es posible que lea? está ralentizando las cosas.... ahora podría tener que intentarlo....
Lo descartaría por ahora, una cosa que se interpone en el camino. Mantenga el programa lo más simple posible para empezar.
@ onaclov2000: ¿cómo está exactamente conectado su botón? ¿Tienes una resistencia pullup o pulldown conectada?
Sin resistencia, pero puse una, ahora funciona como se esperaba.

Respuestas (2)

Tienes dos problemas en este momento que están separados el uno del otro.

1) Botón de rebote

2) Cableado de botón inadecuado

Primero, debe introducir un retraso en su función de interrupción para que no siga registrando cada subida y bajada del rebote como una pulsación de botón separada. Use "delayMicroseconds()" porque aparentemente no puede usar "delay()" normal dentro de las interrupciones. Sugeriría un retraso de 20.000 microsegundos.

En segundo lugar, debe colocar una resistencia desplegable en el pin digital que está muestreando.

El problema que tiene es que el pin está en modo de entrada y, por lo tanto, a alta impedancia (resistencia muy alta) y, por lo tanto, tiene una tenencia para "flotar". Si le pones voltaje, se carga como un capacitor y dado que el pin en sí tiene una resistencia a tierra muy alta, la carga tarda un tiempo en disiparse hasta el punto en que el Arduino registrará un BAJO nuevamente. Una resistencia de 10k del pin a tierra obligará al "condensador" a descargarse rápidamente después de que la corriente del botón haya dejado de fluir.

Finalmente, el Arduino es bastante rápido en sus operaciones de lectura/escritura (soy ingeniero mecánico, TODOS los componentes electrónicos suceden "rápidamente" en comparación con los sistemas mecánicos, por lo que supongo que es relativo). Aquí hay un enlace a algunos resultados de la prueba.

Versión TL;DR:

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
Eso lo haría, frustrado nuevamente por las resistencias pull up/down. Tuve un problema similar probablemente hace 2 años (la última vez que me metí con un botón, obviamente), no puedo creer que no lo reconocí.
No hay problema, en realidad tuve este problema la semana pasada...

La razón por la que obtiene múltiples B es porque la función "bucle" se llama en un bucle sin fin.

while (true) {
    loop();
}

Tal vez ayude ver su función de esta manera:

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

Tan pronto como la entrada en serie esté disponible, lee el estado del botón y envía una 'B' en caso de que se presione el botón. La entrada en serie nunca se consume, porque Serial.read() nunca se llama, por lo que en el próximo paso a través de su función de bucle, sucede lo mismo.

Si todo lo que desea es enviar una 'B' cuando se presiona el botón, entonces esto podría funcionar:

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");
            } 
        }
    }
}

A continuación hay un enlace a un tutorial bastante completo para manejar los botones. También explica la demora de 10 ms para dejar que el botón se asiente.

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

Entiendo que está enviando múltiples B debido al ciclo while, lo que no entiendo es por qué no está pasando de Alto a Bajo más o menos rápido... si eso tiene sentido.