Estoy usando el pin analógico 5 en Arduino para detectar presiones de 6 botones. En la imagen, el botón superior derecho es el número 1 y luego, de derecha a izquierda, van como 2, 3, 4, 5, 6. El programa debe imprimir 0 cuando no se presiona ninguno de los botones y si se presiona uno de ellos, debería imprime su posición como mencioné antes. Actualmente, el problema es que si presiono el segundo botón, a veces (en lugar de solo una vez) imprimirá 2 un par de veces. Supongo que es por el "ruido" cuando se presiona el botón y que debe ser rebotado, pero no sé cómo rebotar el pin analógico.
Mi código:
int old_button = 0;
int button;
int pressed_button;
int z;
void setup () {
Serial.begin(9600);
pinMode(A5, INPUT);
}
void loop () {
z = analogRead(5);
if (z > 1021) button = 0;
else if (z > 511 && z < 514) button = 1;
else if (z > 680 && z < 684) button = 2;
else if (z > 766 && z < 770) button = 3;
else if (z > 817 && z < 822) button = 4;
else if (z > 851 && z < 856) button = 5;
else if (z > 875 && z < 880) button = 6;
else button = 0;
if (old_button == button) {
old_button = button;
pressed_button = 0;
}
else {
old_button = button;
pressed_button = button;
}
Serial.println(pressed_button);
}
Circuito (resistencias de 2200 ohmios):
Cuando detecte una diferencia significativa en la lectura de ADC, espere 20 milisegundos y luego promedie algunas lecturas y luego tome una decisión. Si una de las lecturas todavía se ve mal cuantificable, espere otro período corto de tiempo.
Sí, es ruido de rebote. Debe esperar un poco (digamos 50 ms) y leer la entrada analógica nuevamente. Si el resultado coincide, entonces el valor del botón puede considerarse válido. Algo como esto:
int old_button = 0;
int getButton()
{
int i, z, sum
int button;
sum = 0;
for (i=0; i < 4; i++)
{
sum += analogRead(5);
}
z = sum / 4;
if (z > 1021) button = 0;
else if (z > 511 && z < 514) button = 1;
else if (z > 680 && z < 684) button = 2;
else if (z > 766 && z < 770) button = 3;
else if (z > 817 && z < 822) button = 4;
else if (z > 851 && z < 856) button = 5;
else if (z > 875 && z < 880) button = 6;
else button = 0;
return button;
}
void loop ()
{
int button, button2, pressed_button;
button = getButton();
if (button != old_button)
{
delay(50); // debounce
button2 = getButton();
if (botton == button2)
{
old_button = button;
presed_button = button;
Serial.println(pressed_button);
}
}
}
Como Andy no quería proporcionar ningún código, agregué algunos promedios al tomar las lecturas de ADC. Entonces, el promedio dentro de getButton tiene en cuenta cualquier ruido que lea la línea analógica que ingresa al ADC, y el retraso de 50 ms se encarga de detectar el rebote del interruptor.
Muchos interruptores del estilo que está usando son difíciles de contrarrestar bien, y tratar de usar un multiplexor resistivo no lo hará más fácil. Aún así, si puede pagar dos pines de puerto (uno analógico), puedo ofrecerle una receta para el éxito que debería funcionar incluso si sus interruptores son bastante malos. Sugeriría mover la resistencia de la barra colectora (ignore la barra colectora inferior de la placa de pruebas) a la izquierda de la que está más a la izquierda y conectarla al pin del puerto no analógico. El cable común en la parte superior debe conectarse al pin del puerto analógico. El cable de la resistencia más a la derecha debe conectarse a tierra.
Cuando su unidad está "inactiva" [no cree que se presione ningún botón] configure la salida común en alto y haga flotar la otra. Se leerá bajo cuando no se presione ningún botón y se leerá cerca de VDD cuando se presione cualquier botón.
Para saber qué botón se presiona, haga flotar el cable común y lleve el cable del lado izquierdo hacia arriba. Configure brevemente el cable común alto o bajo (vea la nota) y hágalo flotar nuevamente, luego lea el voltaje en ese pin un poco más tarde (manteniendo alto el cable del lado izquierdo). Una vez que se ha tomado la lectura, si lo desea, puede apagar el cable del lado izquierdo (volver a encenderlo antes del siguiente ciclo de lectura).
Mientras se presiona un botón, el voltaje en el cable común debe ser una buena fracción de VDD (si hay seis botones y siete resistencias, los botones deben leer 1/7, 2/7, 3/7, etc. hasta 6 /7); el voltaje no debe verse demasiado afectado por si el pin común se pulsó brevemente hacia arriba o hacia abajo. Si no se presiona ningún botón, las lecturas después de que el pin haya sido pulsado alto serán mucho más altas que después de haber sido pulsado bajo. Esto indicará que se ha soltado el botón.
Una vez que se ha soltado el botón, puede volver a la configuración "inactiva". Cuando la resistencia izquierda se eleva, la cadena de resistencia consumirá corriente ya sea que se presione o no algún botón, pero cuando el pin izquierdo flota y el cable común está alto, no se extraerá corriente hasta que se presione un botón.
Para obtener buenos resultados con interruptores baratos, debe demorar lo suficiente después de cada pulso momentáneo de "tierra" o "VDD" en su cable común para que, si el interruptor hace algún contacto, produzca una buena lectura (intente colocar una resistencia de 100K en paralelo con un interruptor, y ajuste el retardo y la sensibilidad para que "apenas" registre que el interruptor se mantiene presionado). Los interruptores baratos tienen una resistencia de más de un mega cuando se sueltan por completo, y menos de 10 ohmios cuando se presionan por completo, pero su resistencia puede vagar por todos lados entre esos estados, y el tiempo de rebote convencional no ayudará. Lo que ayudará es tener un circuito que no detecte la pulsación de un botón hasta que la resistencia sea bastante baja, y considerará un botón como presionado a menos que su resistencia sea mucho mayor. Para el circuito que he descrito,
Recientemente comencé a trabajar con Arduino, y aunque esta es una vieja pregunta, encontré este hilo cuando intentaba ampliar la cantidad de botones que podía escuchar.
Trabajé a partir de la ilustración original de Fritzing y produje una ligera variante tanto en hardware como en software.
Modifiqué el conjunto de resistencias para usar diferentes valores para tratar de producir un paso más consistente entre los interruptores en lugar de los pasos logarítmicos producidos al usar las mismas resistencias en todo momento.
A partir de 5V, las resistencias son:
Esto produce pasos de alrededor de 0,5 V entre cada interruptor.
También construí un software básico que busca el mismo valor para 3 lecturas seguidas antes de reconocer un cambio en el voltaje. Esto elimina pequeñas variaciones en la lectura.
int sensorPin = A5; // The input port
int sensorValue; // Current reading
int outputValue; // The reported reading
int lastValues[3] = {0,0,0}; // The last 3 readings
void setup() {
Serial.begin(9600);
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
// Initialise variables for checks
int i;
int updateOutput = 1;
// Loop through previous readings
for( i = 0 ; i<3 ; i++ ){
// If this historic value doesn't match the current reading,
// we will not update the output value
if( lastValues[i] != sensorValue ){
updateOutput = 0;
}
// Shift the array elements to make room for new value
if( i>0 ){
lastValues[(i-1)] = lastValues[i];
}
}
// Update if needed
if( updateOutput == 1 ){
outputValue = sensorValue;
}
// Append the new value
lastValues[2] = sensorValue;
// Debugging output
Serial.print(sensorValue);
Serial.print(" ");
Serial.println(outputValue);
}
Obviamente, la lastValues
matriz podría tener la longitud que desee: cuanto más larga sea la matriz, más tiempo se debe presionar un interruptor para que se detecte.
En mis pruebas, los valores del sensor informados fueron:
(Probado según el diagrama.)
Mis cálculos aproximados sugieren que incluso podría extender esto a 8 botones, agregando las siguientes resistencias a continuación (que deberían hacer que el voltaje vuelva a caer en pasos de 0.5V):
Transeúnte
Nick Alexeev
bajo