Llevo muchas horas peleando con el conversor ADC, googleando y probando sin ningún resultado.
La tarea es aparentemente simple: leer un teclado analógico de cinco teclas para un nuevo programador de riego.
Los voltajes que se envian desde el teclado a la entrada analógica son bastante estables para mis necesidades: 0.00, 0.15, 0.40, 0.80, 1.65 y sin pulsar 4.96v aprox., +/- 0.01v.
Es probable que el teclado esté preparado para soportar voltajes mayores de 5v. No me importa la diferencia de voltaje entre la última tecla y sin pulsar porque luego se convierte por soft en valores de 0 a 5.
El resultado que devuelve el ADC con la orden analogRead(A0) es siempre un valor aleatorio entre 0 y 1023, independiente incluso de las teclas pulsadas.
Creo que he probado casi de todo:
Alimentacion del teclado desde fuente independiente.
Varias fuentes, tanto para el teclado como para el micro.
Varios puertos de entrada.
Varios medios de salida, consola serial y LCD.
Varios componentes para estabilización de la señal, condensadores 100uF, 10uF, 100nF, resist. 100K
Varios micros, un Mega 2560 y un Nano, ambos compatibles.
Varias configuraciones para valores de referencia, tanto soft como hard en el pin AREF.
Mapeo con la funcion map().
Varios metodos de espera, con delay() y con millis(), también depurando rebotes y cálculo de promedios.
Algunos componenes para estabilización dejaban la señal de salida del ADC fija, a 0 ó a 1023.
En un primer momento pensé que el conversor ADC estaba averiado, pero quedé sorprendido cuando cambié de micro y vi los mismos resultados.
Este es uno de los muchos sketchs que he probado:
int adc_key_val[5] ={50, 200, 400, 600, 800 }; // valores provisionales
int NUM_KEYS = 5;
int adc_key_in;
int key=-1;
int oldkey=-1;
int analogPin = A0;
unsigned long TiempoRebote = 80;
void setup() {
Serial.begin(9600);
analogReference(DEFAULT);
}
void loop() {
adc_key_in = analogRead(analogPin);
ControlRebote();
key = get_key(adc_key_in);
if (key != oldkey) {
adc_key_in = analogRead(analogPin);
ControlRebote();
Serial.println("Lectura: " + String(adc_key_in));
key = get_key(adc_key_in);
if (key != oldkey) {
oldkey = key;
if (key >=0){
switch(key) {
case 0:Serial.println(String(adc_key_in)+" S1 OK"); break;
case 1:Serial.println(String(adc_key_in)+" S2 OK"); break;
case 2:Serial.println(String(adc_key_in)+" S3 OK"); break;
case 3:Serial.println(String(adc_key_in)+" S4 OK"); break;
case 4:Serial.println(String(adc_key_in)+" S5 OK"); break;
}
}
}
}
delay(100);
}
int get_key(unsigned int input) {
int k;
for (k = 0; k < NUM_KEYS; k++) {
if (input < adc_key_val[k]) {
return k;
}
}
if (k >= NUM_KEYS)k = -1;
return k;
}
void ControlRebote() {
unsigned long Temporizador = millis() + TiempoRebote;
while (Temporizador > millis()) { }
}
Adjunto una imagen con la salida de consola, sin pulsar ninguna tecla
Alguien puede decirme que es lo que estoy haciendo mal.
¿Podrías poner un esquema de como tienes conectado el keypad?
Y si además tuvieras el del keypad sería un golazo.
Por otro lado me he tomado el atrevimiento de modificar el código como a mi entender debería ser en base a como lo has planteado
// const int adc_key_val[5] ={50, 200, 400, 600, 800 }; // valores provisionales
// valores calculados de ADC segun voltajes declarados 0, 31, 82, 164, 338 entonces
const int adc_key_val[5] ={20, 50, 100, 180, 360}; // valores mas adecuados
const int NUM_KEYS = 5;
int adc_key_in;
int key=-1;
int oldkey=-1;
const int analogPin = A0;
const unsigned long TiempoRebote = 80;
void setup() {
Serial.begin(9600);
analogReference(DEFAULT);
}
void loop() {
adc_key_in = analogRead(analogPin);
ControlRebote(); // delay(TiempoRebote);
key = get_key(adc_key_in);
if (key != oldkey) {
// adc_key_in = analogRead(analogPin);
// ControlRebote();
Serial.println("Lectura: " + String(adc_key_in));
// key = get_key(adc_key_in);
// if (key != oldkey) {
oldkey = key;
// if (key >=0){
switch(key) {
case 0:Serial.println(String(adc_key_in)+" S1 OK"); break;
case 1:Serial.println(String(adc_key_in)+" S2 OK"); break;
case 2:Serial.println(String(adc_key_in)+" S3 OK"); break;
case 3:Serial.println(String(adc_key_in)+" S4 OK"); break;
case 4:Serial.println(String(adc_key_in)+" S5 OK"); break;
default:Serial.println(" NO KEY"); break;
}
// }
}
}
delay(100);
}
int get_key(unsigned int input) {
int k;
for (k = 0; k < NUM_KEYS; k++) {
if (input < adc_key_val[k]) {
return k;
}
}
if (k >= NUM_KEYS)k = -1;
return k;
}
void ControlRebote() {
unsigned long Temporizador = millis();
while (millis() - Temporizador < TiempoRebote) { }
}
Por la forma en que usas millis() en ControlRebote(), entra en un while hasta que se cumple el tiempo, da lo mismo usar directamente delay() y prescindir ControlRebote(), porque en ambos casos el micro no hace nada hasta que se cumple el tiempo.
De todos modos modifiqué la función porque como lo habías hecho, si el equipo está funcionando más de 49 días, te podía generar problemas cuando millis() se reinicia.
La lectura de teclas, como la planteaste no te iba a dar buenos resultados, por eso te lo modifique.
De todos modos en general está bien y te adelanto que funciona porque básicamente hice lo mismo para leer las teclas de los controles del volante de mi auto que también son resistivos.
Hi,
Haz verificado el voltaje con un voltimetro cuando selecionas una tecla. Si lee 1023 quire decir que estas leyendo un voltaje de 5 voltios por eso de leer el voltaje para saber con seguridad donde esta el problema.
A gatul: Lamentablemenete no tengo el esquema de teclado, por si aporta infomación es uno tipico de aliexpress con cinco botones amarillos, 4 en forma de rombo y uno separado a la derecha.
El esquema de conexión es muy elemental: VCCy GND a una fuente externa, con transformador de AC-DC 220 a 12v (probados de 1A y de 3A) y luego un conversor DC-DC a 5v,
Dependiendo del transformador y del conversor, la alimentación tiene un voltaje ligeramente por encima o por debajo de 5v. También probé con un cargador de móvil que daba algo mas de 5v, y con un conversor a 3.3v que daba otros voltajes mas pequeños en las pulsaciones de teclas.
Luego tengo el pin OUT conectado directo a A0, y probado en los pines A2, A3 y A8 en el Mega.
En algunas pruebas los componentes para estabilizar iban desde OUT a GND.
Gracias por tu atrevimiento de modificar el codigo. Los valores estaban pendientes de conseguir las lecturas correctas.
Ya conocia el problema de los millis(), lo tengo solucionado de forma similar en otro proyecto con un display TM1637, pero no lo habia copiado aquí todavía.
A tauro0221: Como dice gatul, una cosa son los voltajes y otra las lecturas que devuelve el conversor ADC. En este caso los 1023 es el resultado que devuelve la función analogRead(A0), que si no estoy equivocado deberian corresponder con un voltaje de 5v en A0. Ese es el problema, los valores que devueve la función no se corresponden con los voltajes de A0.
Hacé una prueba con un potenciómetro en lugar del keypad, eso no debería fallar.
Ya sabes, cursor a A0, extremos a 5V y GND respectivamente.
Si eso va bien el problema esta con algún detalle del keypad.
Si el keypad es como este la verdad no tiene ningún secreto.
Lo unico que se me ocurre es que pruebes poner una resistencia de 10k para fijar el estado alto cuando no hay tecla pulsada, aunque sea redundante (porque el modulo ya tiene una) con probar no pierdes nada.
En el supuesto que sea como el de la foto, encontré el esquema
Como dije, no hay secretos.
Lo que sí, con esos valores de resistencias, ni remotamente daría los valores que has medido, pero seguramente no tiene las mismas resistencias que el esquema.
Hi,
Si pero como sabes que estas leyendo correctamente el vltaje si no sabes que voltaje tiene el pin A0. Estas asuminedo el voltaje. Si lee 1023 quire decir que tienes 5 voltios de entrada. Ahora puedes haccer una prueba de conectar el A0 a los 3,3 y lee el voltaje. Asi sabras que esta pasando.
@tauro0221 sin pulsar nada está leyendo ruido, fijate la captura en el primer post.
Para mi tiene algo mal en la placa del teclado, aunque no tiene mucho misterio, tal vez mal soldada la resistencia pullup.
Con un tester se resuelve en 5 minutos, pero desde atrás de la pantalla es siempre fácil.
Hola,
La apariencia del teclado es la misma, aunque cambia algo la serigrafía. Coincide en el pinout y en el nombre de las teclas.
Probaré con un potenciómetro, aunque pienso que no aportará información, dado que el teclado es muy estable y siempre devuelve los mismos voltajes con las mismas teclas.
La problema principal es que la lectura del conversor ADC a través de la funcion analogRead(), muestra valores aleatorios sin importar los voltajes de la entrada.
Cabe la posibilidad que se haya dañado el conversor ADC por un sobrevoltaje?
A tauro0221: Si conozco el voltaje de las teclas, tengo el tester pinzando el OUT y el GND del teclado y los valores se repiten siempre de forma correcta.
Nabuky:
Cabe la posibilidad que se haya dañado el conversor ADC por un sobrevoltaje?
Es para descartar eso que te digo que pruebes con un potenciómetro.
Como alternativa prueba que conectando A0 a masa lea 0 y luego a 5V (o 3.3, segun sea la placa) lea 1023.
Ya si así lee mal es porque se malogró el ADC.
El problema estaba en la fuente externa, puede que fuera el ruido del conversor AC o puede que un voltaje erroneo.
Al conectar A0 con masa y luego con 5v, seguía dando lecturas aleatorias en ambos casos.
Se ha solucionado al tomar la alimentacion del teclado desde los pines del mico que se alimenta por USB.
Para continuar con el montaje, también he conectado un lcd 2004 a las mismas salidas 5V y GND del micro y de momento todo aguanta bien.
Era un AC 220V a DC 12V 1A, en vacio daba 12.33V en el tester y luego un DC 12V a DC 5V que daba 5.12V.
Alimentando el Mega directamente con 12.33V funciona bien, por lo que pienso que el otro DC-DC era de baja calidad.
Saludos.