TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Cryn en 27 de Noviembre de 2006, 17:47:45
-
Hola saludos he escrito el codigo para ingresar una clave y si es la correcta encender un led un corto tiempo, si es incorrecta encender el mismo led pero mas tiempo, hice la rutina de exploracion del teclado, y despues pregunto por cada tecla ingresada hasta que se digiten 5 teclas y fin de ingreso un '*', verifica y si es correcto debe hacer lo necesario, pero no me funciona, algo esta mal?? ayuda por favor, por que lo hago correr y me da problemas, porque no reconoce ninguna clave ingresada y parece que simepre dara error, esta muy raro, creo haber escrito correctamente el codigo, les dejo en el adjunto el hex y el dsn de proteus, muchas gracias; aca el codigo:
/*------------------------------------------------------------------------------------*/
/* Teclado matricial 4x4 4 filas x 4 columas, puede adaptarse fácilmente a uno 4x3 */
/* Diseñado Cryn ---- 2006 */
/* */
/* C1 C2 C3 C4 */
/* F1 1 2 3 C *=A */
/* F2 4 5 6 D #=B */
/* F3 7 8 9 E */
/* F4 * 0 # F */
/* La exploración del teclado lo que hace es verificar secuencialmente y en orden */
/* la situación de las columnas 1,2,3 y 4 enviando '0' por la columna que queremos */
/* analizar y '1' al resto, si se encontrara algún pulsador activado, el código */
/* recibido por las filas sería diferente a 1111 que es el valor de reposo */
/* */
/* 4 resistencias pull-up en las entradas RB4 a RB7 */
/*------------------------------------------------------------------------------------*/
#include<16F84A.h>
#FUSES XT,NOWDT,PUT,NOPROTECT
#use delay(clock=4000000)
#byte port_a=0x05
#byte port_b=0x06
#use fast_io(a)
#use fast_io(b)
unsigned char CONST clave[5]={'1','2','3','4','5'};
boolean var=0;
char c;
int limit;
int i=0;
int digitos=5;
void delay()
{
delay_ms(50);
}
char kbd_getc() // función que explora todo el teclado
{
port_b=0xfe; // verifica columna 1
if(bit_test(port_b,4)==0)
{delay();
return ('1');} // si se presiono el uno devuelve 1
if(bit_test(port_b,5)==0)
{delay();
return ('4');} // si se presiono el cuatro devuelve 4
if(bit_test(port_b,6)==0)
{delay();
return ('7');} // si se presiono el siete devuelve 7
if(bit_test(port_b,7)==0)
{delay();
return ('*'); } // si se presiono el * devuelve 10 = A
port_b=0xfc; // verifica columna 2
if(bit_test(port_b,4)==0)
{delay();
return ('2');} // si se presiono el dos devuelve 2
if(bit_test(port_b,5)==0)
{delay();
return ('5');} // si se presiono el cinco devuelve 5
if(bit_test(port_b,6)==0)
{delay();
return ('8');} // si se presiono el ocho devuelve 8
if(bit_test(port_b,7)==0)
{delay();
return ('0');} // si se presiono el cero devuelve 0
port_b=0xfb; // verifica columna 3
if(bit_test(port_b,4)==0)
{delay();
return ('3');} // si se presiono el tres devuelve 3
if(bit_test(port_b,5)==0)
{delay();
return ('6');} // si se presiono el seis devuelve 6
if(bit_test(port_b,6)==0)
{delay();
return ('9'); } // si se presiono el nueve devuelve 9
if(bit_test(port_b,7)==0)
{delay();
return '#'; } // si se presiono el # devuelve 11 = B
// si se tiene una matriz 4x3 no se usará el pin RB3
port_b=0xf7; // verifica columna 4
if(bit_test(port_b,4)==0)
{delay();
return ('C');} // si se presiono la C devuelve 12 = C
if(bit_test(port_b,5)==0)
{delay();
return ('D');} // si se presiono la D devuelve 13 = D
if(bit_test(port_b,6)==0)
{delay();
return ('E');} // si se presiono la E devuelve 14 = E
if(bit_test(port_b,7)==0)
{delay();
return ('F');} // si se presiono el F devuelve 15 = F
if(port_b==0xfb)
return (0); // devuelve 16 en caso de no haber presionado ningun pulsador
// podria colocarse otra alternativa en caso de que no se presione ningun pulsador
}
void main() // programa principal
{
set_tris_b(0xf0); // define RB0 a RB3 (columnas) como salidas y RB4 a RB7 (filas) como entradas
port_b=0; // inicializa puerto B
set_tris_a(0xfe); // define puerto A como todas entradas excepto RA0
port_a=0; // inicializa puerto A
port_b_pullups(TRUE); // activa pull up del puerto b, no hará falta conectar resistencias
while(true) // bucle de trabajo
{
while(1)
{
do
{
c=kbd_getc();
}while(c==0);
if(c==clave)
{
var=0;
i++;
}
else
{
var=1;
break;
}
if(i==digitos && c=='*')
break;
}
if(var==0){
output_high(PIN_A0);
delay_ms(500);
output_low(PIN_A0);}
else{
output_high(PIN_A0);
delay_ms(2000);
output_low(PIN_A0);
}
}
}
-
Hay ciertas cosas que mejoraria de tu programa... mejorar no, optimizar... pero lo que mas me llama la atencion es esto, en lo referente al funcionamiento:
do
{
c=kbd_getc();
}while(c==0);
if(c==clave)
{
var=0;
i++;
}
has definido "clave" como un array de 5 elementos, sin embargo no haces referencia a ninguno de ellos cuando comparas con "c". No conozco el comportamiento del compilador ante eso, pero podria ser que el compilador compare todo el rato con el mismo elemento...
Tal vez se te ha olvidado la i : if(c==clave)
No comprendo muy bien el final del programa (tengo bastante sueño jajaja, hago lo que puedo) pero yo lo conformaria con un bucle FOR(I=1;I==5;I++).
Aparte acabo de ver otro fallo...
do
{
c=kbd_getc();
}while(c==0);
Segun eso, saldra del bucle solo cuando no se pulse ninguna tecla... es decir... si alguna vez sale del bucle, saldra con el valor 0... por lo que es inutil compararlo con "clave", pues siempre saldra con 0.
Espero haberte aclarado el asunto un poco. Un saludete!
-
hola, saludos, gracias por la respuesta, mira, nose qeu paso al momento de copiarlo, pero si le puse la i para compilar:
if(c==clave)
{
var=0;
i++;
}
y weno, lo de:
do
{
c=kbd_getc();
}while(c==0);
creo que esta correcto, ya que kbd_getc() devuelve una cadena correspondinte a la tecla pulsada cuando se presiona uno de los pulsadores del teclado matricial, en caso de que no se presione nada, la funcion devuelve 0 (en valor, no es ascii):
if(port_b==0xfb)
return (0); // devuelve 16 en caso de no haber presionado ningun pulsador
// podria colocarse otra alternativa en caso de que no se presione ningun pulsador
por tanto el do se hara hasta que se presione una tecla; mientras no se presione nada el valor de c sera cero y se qeudara trabado ahi hasta qeu se presione una tecla que hará que cambie el valor de c y hara salir del bucle do
y si probe tb con un for y no daba, e intente cambiar por este metodo, y tampoco dio, talvez haya otro erro que no tome en cuenta, por favor, ayudita, gracias adios.
pd. si los comentarios no estan como deberian, es porque he modificado tantas veces el programa que moficar comentarios mas, a acada rato, me haria perder mas tiempo.
gracias
-
Hola Cryn.
Hace unas semanas programé un algoritmo en CCS para leer el teclado y que devuelva un array con los pulsadores presionados(hasta 16) y una variable que indica la cantidad de pulsadores presionados(para poder saber hasta donde leer el array).
http://www.todopic.com.ar/foros/index.php?topic=14585.msg90970#msg90970
por ahi podes rescatar algo.
Saludos.
-
Primero: coincido con manex_1987 con lo del array. Tenés que ponerle un subíndice como ser if(c==clave[ i ]) y eso dentro del for que dice o algo similar.
Segundo: NO COINCIDO con manex_1987 con lo de:
do {
c=kbd_getc();
}while(c==0);
Eso está bien. La lógica es: se repite mientras c==0. y sólo sale cuando c tomó un valor.
Tercero: Pusiste:
port_b=0xfe; // verifica columna 1
...
port_b=0xfc; // verifica columna 2
...
port_b=0xfb; // verifica columna 3
...
port_b=0xf7; // verifica columna 4
según esto, estarias enviando
1111 1110
1111 1100 // error
1111 1011
1111 0111
Al mandar el cero del final te toma nuevamente lo del bloque anterior, cualquier 1, 4, 7 o * será reemplazado por 2, 5, 8 o 0. y es como si desconectaras de teclado la primer columna
Debería ser port_b=0xfd
Espero que sea eso nomás. Un saludo.
Me olvidaba.
Cuarto: Como evitás que cuando aprientes la primera tecla no te tome todas iguales??? Ten en cuenta que no hay nada que detenga el programa cuando lee una tecla hasta que lee de nuevo y seguramente la tecla permanece apretada mucho más tiempo del que demora el pic en ejecutar el bucle principal al menos decenas de veces...
La solución: volver a preguntar por el teclado ni bien se ingresó una tecla, pero salir del do while cuando c sea 0.
algo así:
do {
c=kbd_getc();
}while(c==0); // hasta que no presiones no sale
do {
c2=kbd_getc();
}while(c2!=0); //c2 es otra variable, ya que si usas c de nuevo perderías el valor de la tecla
// de acá no sale hasta que no sueltes la tecla
if(c==clave[ i ]) // acordate de inicializar i=0; dentro del bucle principal, xq no está
{
var=0;
i++;
}
else
{
var=1;
break;
}
Quinto: con el ingreso del * i toma el valor 6
if(i==digitos+1 && c=='*')
break;
-
Cuando usamos corchetes y le ponemos una i dentro = [ i ] ocurre algo muy curioso.
Mr. Foro lo toma como una directiva de cursiva e inclina todo el resto de la línea. Fíjense que en los dos mensajes de Cryn el último paréntesis aparece cursivo.
if(c==clave) ==> if(c==clave[ i ])
Yo tampoco me daba cuenta. Ahora te creo Cryn. Un saludo nuevamente para la gente de bolivia y después contame como como anda el teclado.
:-/
-
:D :D :D es que el [ i ] es un TAG del SMF(del foro) y lo asume como cursiva.
Saludos.
-
ya no se que hacer, estoy volviendome loco, y tengo sueño!!!, hice todas las correcciones que me dijeron y nada, lo curios es que una vez hice la prueba con pulsar solamente una tecla y dar respuesta y daba perfectamente, y le puse dos y ya no dio ni con tres ni con cuatro ni nada, bueno asi quedo, no hay error de definiciones de variables, o alguna cosa oculta que yo no veo?:
#include<16F84A.h>
#FUSES XT,NOWDT,PUT,NOPROTECT
#use delay(clock=4000000)
#byte port_a=0x05
#byte port_b=0x06
#use fast_io(a)
#use fast_io(b)
unsigned char CONST clave[5]={'1','2','3','4','5'};
int1 var=0;
char c,c2;
int limit,i,digitos=6;
void delay()
{
delay_ms(50);
}
char kbd_getc() // función que explora todo el teclado
{
port_b=0xfe; // verifica columna 1
if(bit_test(port_b,4)==0)
{delay(); // antirrebotes
return ('1');} // si se presiono el uno devuelve codigo ASCII de 1
if(bit_test(port_b,5)==0)
{delay();
return ('4');} // si se presiono el cuatro devuelve codigo ASCII de 4
if(bit_test(port_b,6)==0)
{delay();
return ('7');} // si se presiono el siete devuelve codigo ASCII de 7
if(bit_test(port_b,7)==0)
{delay();
return ('*'); } // si se presiono el * devuelve codigo ASCII de *
port_b=0xfd; // verifica columna 2
if(bit_test(port_b,4)==0)
{delay();
return ('2');} // si se presiono el dos devuelve codigo ASCII de 2
if(bit_test(port_b,5)==0)
{delay();
return ('5');} // si se presiono el cinco devuelve codigo ASCII de 5
if(bit_test(port_b,6)==0)
{delay();
return ('8');} // si se presiono el ocho devuelve codigo ASCII de 8
if(bit_test(port_b,7)==0)
{delay();
return ('0');} // si se presiono el cero devuelve codigo ASCII de 0
port_b=0xfb; // verifica columna 3
if(bit_test(port_b,4)==0)
{delay();
return ('3');} // si se presiono el tres devuelve codigo ASCII de 3
if(bit_test(port_b,5)==0)
{delay();
return ('6');} // si se presiono el seis devuelve codigo ASCII de 6
if(bit_test(port_b,6)==0)
{delay();
return ('9'); } // si se presiono el nueve devuelve codigo ASCII de 9
if(bit_test(port_b,7)==0)
{delay();
return '#'; } // si se presiono el # devuelve codigo ASCII de #
// si se tiene una matriz 4x3 no se usará el pin RB3
port_b=0xf7; // verifica columna 4
if(bit_test(port_b,4)==0)
{delay();
return ('C');} // si se presiono la C devuelve codigo ASCII de C
if(bit_test(port_b,5)==0)
{delay();
return ('D');} // si se presiono la D devuelve codigo ASCII de D
if(bit_test(port_b,6)==0)
{delay();
return ('E');} // si se presiono la devuelve codigo ASCII de E
if(bit_test(port_b,7)==0)
{delay();
return ('F');} // si se presiono la F devuelve codigo ASCII de F
if(port_b==0xfb)
return (0); // devuelve 0 en caso de no haber presionado ningun pulsador
// podria colocarse otra alternativa en caso de que no se presione ningun pulsador
}
void main() // programa principal
{
set_tris_b(0xf0); // define RB0 a RB3 (columnas) como salidas y RB4 a RB7 (filas) como entradas
port_b=0; // inicializa puerto B
set_tris_a(0xfe); // define puerto A como todas entradas excepto RA0
port_a=0; // inicializa puerto A
port_b_pullups(TRUE); // activa pull up del puerto b, no hará falta conectar resistencias
while(true) // bucle de trabajo
{
i=0;
while(1)
{
do
{
c=kbd_getc();
}while(c==0);
do
{
c2=kbd_getc();
}while(c2!=0); //c2 es otra variable, ya que si usas c de nuevo perderías el valor de la tecla
// de acá no sale hasta que no sueltes la tecla
if(clave[ i ]==c)
{
var=0;
i++;
}
else
{
var=1;
break;
}
if(i==digitos && c=='*')
break;
}
if(var==0){
output_high(PIN_A0);
delay_ms(500);
output_low(PIN_A0);}
else{
output_high(PIN_A0);
delay_ms(2000);
output_low(PIN_A0);
}
}
}
muchas garcais por los saludos, saludos para todos tb, y muchas gracias por toda la ayuda, ustedes me dan esperanzas!!! gracias y aguante el foro PIC!!!!!!!!!!!!!!!!
-
Creo (con temor a equivocarme), que si utilizas un array por ejemplo cadena[5]="12345" y al usarla en alguna función como cadena , o sea sin el corchete, el compilador tomará todo el contenido del array para lo que estas haciendo, debes revisar si ese es el caso tuyo.
Salu2
-
Me tuve que hacer el proteus, ya que tengo otra versión...
Copialo que anda...
#include<16F84A.h>
#FUSES XT,NOWDT,PUT,NOPROTECT
#use delay(clock=4000000)
#byte port_a=0x05
#byte port_b=0x06
#use fast_io(a)
#use fast_io(b)
unsigned char CONST clave[5]={'1','2','3','4','5'};
int1 var=0;
char c,c2;
int limit,i,digitos=5; // vuelve a ser 5
void delay()
{
delay_ms(50);
}
char kbd_getc() // función que explora todo el teclado
{
port_b=0xfe; // verifica columna 1
if(bit_test(port_b,4)==0)
{delay(); // antirrebotes
return ('1');} // si se presiono el uno devuelve codigo ASCII de 1
if(bit_test(port_b,5)==0)
{delay();
return ('4');} // si se presiono el cuatro devuelve codigo ASCII de 4
if(bit_test(port_b,6)==0)
{delay();
return ('7');} // si se presiono el siete devuelve codigo ASCII de 7
if(bit_test(port_b,7)==0)
{delay();
return ('*'); } // si se presiono el * devuelve codigo ASCII de *
port_b=0xfd; // verifica columna 2
if(bit_test(port_b,4)==0)
{delay();
return ('2');} // si se presiono el dos devuelve codigo ASCII de 2
if(bit_test(port_b,5)==0)
{delay();
return ('5');} // si se presiono el cinco devuelve codigo ASCII de 5
if(bit_test(port_b,6)==0)
{delay();
return ('8');} // si se presiono el ocho devuelve codigo ASCII de 8
if(bit_test(port_b,7)==0)
{delay();
return ('0');} // si se presiono el cero devuelve codigo ASCII de 0
port_b=0xfb; // verifica columna 3
if(bit_test(port_b,4)==0)
{delay();
return ('3');} // si se presiono el tres devuelve codigo ASCII de 3
if(bit_test(port_b,5)==0)
{delay();
return ('6');} // si se presiono el seis devuelve codigo ASCII de 6
if(bit_test(port_b,6)==0)
{delay();
return ('9'); } // si se presiono el nueve devuelve codigo ASCII de 9
if(bit_test(port_b,7)==0)
{delay();
return '#'; } // si se presiono el # devuelve codigo ASCII de #
// si se tiene una matriz 4x3 no se usará el pin RB3
port_b=0xf7; // verifica columna 4
if(bit_test(port_b,4)==0)
{delay();
return ('C');} // si se presiono la C devuelve codigo ASCII de C
if(bit_test(port_b,5)==0)
{delay();
return ('D');} // si se presiono la D devuelve codigo ASCII de D
if(bit_test(port_b,6)==0)
{delay();
return ('E');} // si se presiono la devuelve codigo ASCII de E
if(bit_test(port_b,7)==0)
{delay();
return ('F');} // si se presiono la F devuelve codigo ASCII de F
return(0); // solo retorna 0 si no retornó nada antes
}
void main() // programa principal
{
set_tris_b(0xf0); // define RB0 a RB3 (columnas) como salidas y RB4 a RB7 (filas) como entradas
port_b=0; // inicializa puerto B
set_tris_a(0xfe); // define puerto A como todas entradas excepto RA0
port_a=0; // inicializa puerto A
port_b_pullups(TRUE); // activa pull up del puerto b, no hará falta conectar resistencias
while(true) // bucle de trabajo
{
i=0;
while(1)
{
do
{
c=kbd_getc();
}while(c==0);
do
{
c2=kbd_getc();
}while(c2!=0); // ya que si usas c de nuevo perderías el valor de la tecla
// de acá no sale hasta que no sueltes la tecla
if(c=='*') // esto va antes, me parece mejor y dígitos ahora es 5 again
break;
if(clave[ i ]==c)
{
var=0;
i++;
}
else
{
var=1; // saque el break ya que si está y ponés un numero mal
// te salta y prende el led y así sabés cuando te equivocas
// por lo que es mas facil adivinar el código
// en 50 intentos lo sacas! Eso no es nada seguro
}
}
if(i==digitos && var==0) //acá pregunto por los dígitos. Las dos opciones son redundantes, pero *
{
output_high(PIN_A0);
delay_ms(400);
output_low(PIN_A0);}
else{
output_high(PIN_A0);
delay_ms(3000);
output_low(PIN_A0);
}
}
}
* Por ejemplo, no necesitas usar la varible var, ya que con i alcanza, si ingresaste i digitos correctos antes de * ya está y donde asignas var=1 pondrías i=0; para volver a empezar cuando se erra un dígito. Pero el usuario no se entere...
de todas formas modifiqué solo lo necesario para que afuncione, ya que no todos programamos igual, yo lo hubiese hecho diferente, hay varias formas y aunque unas mejores que otras es importante respetar el estilo de programación de cada uno, creo que este programa te sirve más así que si te paso uno que yo hubiera empezado de cero. Cada uno debe evolucionar a una mejor programación por su propio camino, eso pienso yo al menos.
-
Hola, saludos, muchas gracias compañero :cry: eres mi idolo!!, mira que de esos errores no me daba cuenta nunca, deberas que hay que mirarlo todo, pucha, siempre se me pasan cosillas y no me funciona bien; muchas gracias por haberte instalado porteus y ayudarme, de verdad, me ahorraste unos dias mas de preocupacion y bronca, jeje; y muchas gracias a todos los que me ayudaron, ahora a terminar el trabajo, que todavia falta, jeeje, weno, hay nos vemos Adios, y si volvemos a los ciclos For?? qeu le cambio??
:-/ :-/ :-/ :-/
-
Hace 4 semanas que estoy en el foro y sos al primero que ayudo bien. :D Eso está muy, muy bueno.
Ahora que ya tenés TU código funcionando me tomo el atrevimiento de modificártelo, :D
Son solo giladas, los delay antirebotes me parecen que no son necesarios ahí donde están. Yo le pondría solo uno por columna revisada, es decir despues de verifica columna y no dentro de cada if, pero eso es solo una sugerencia. También pondría tiempos de 10 ms, creo que con eso ya tiene. Ademas, si cambias esto te quedan solo 4 delays y creo que no se justifica una subrutina para eso. yo pondria delay_ms(10); derecho.
En fin lo retoqué y de paso se ahorran: ROM:2%, RAM:4% y fundamentalmente 58 líneas de C que lo hacen mucho más legible. (Amontoné un poco, es verdad)
Lo adjunto para no estirar tanto...
-
Hola
No he tenido mas tiempo de responder. Menta, tienes razon... no se en que estaba pensando entonces, pero lo que he escrito es un error GARRAFAL... nada, se me ha ido la olla. Sera por el examen que tenia hoy. Sorry por el tiempo que os pudiera haber hecho perder por mi despiste!
-
pos, que ams que agradecerles nuevamente, seguire todos sus consejos, y no hay problema, somos humanos siempre podemos equivocarnos, no pasa nada!!, jeeje; bueno saludos a todos y gracias de verdad!!!