# Menú y LCD 2 x 16 duda al implementarlo



## Moyano Jonathan (Feb 1, 2009)

Hola a todos.

Quería saber si me pueden ayudar a llegar a algo como esto:
YouTube - Menu LCD y PIC16F877A
Mi problema específicamente es el desplazamiento de las opciones a través del pulsador.

Cualquier idea o código que pueda orientarme es bienvenido


----------



## sangreaztk (Feb 1, 2009)

Para que son 4 botones?
Serian 2 de dirección (arriba-up- y abajo-down-) y 1 de confirmación-ok-? el otro que sería... un 'escape'-esc-?

Se me ocurre a base de un contador-registro, primero estaría en su valor inicial con cero, cuando se oprima down, el registro incrementa en uno, si se oprime up entonces el registro decrementa en uno.
Dependiendo del valor del registro se imprimiría la pantalla adecuada:


```
x = 0

--> Opción0x0
    Opción0x1
---------------
x = 1

    Opción0x0
--> Opción0x1
----------------
x = 2

--> Opción0x2
    Opción0x3
----------------
x = 3

    Opción0x2
--> Opción0x3
----------------
```

Aunque de esta forma no se ve tan "fluido" el cambio, para eso seria mejor abordar todas las posibles combinaciones, que serían 4C2=6. Pero para ello el registro lo dividiría en dos partes: dos bits para la posición absoluta y un bit para la posición relativa.
Al decir posición absoluta son las pantallas

Opción0
Opción1

Opción1
Opción2

Opcion2
Opcion3

Y la posición relativa sería la del cursor, en la linea superior o en la inferior:


```
Cursor en primer linea

--> Opción0x0
    Opción0x1
---------------
Cursor en segunda linea

    Opción0x0
--> Opción0x1
---------------
```

Esto es suponiendo un total de 4 opciones, pero puede extenderse a más.

Buena Vibra!


----------



## Moyano Jonathan (Feb 1, 2009)

La verdad no entendí del todo tu idea , tenés algun código o diagrama de flujo. Lo que pasa es que ando verdaderamente perdido con el tema y no se de donde empezar.

Agradesco tu ayuda.


----------



## luis_e (Feb 2, 2009)

Hola a todos!

He realizado unos cuantos menus con pantallas de 2x16, y creo que la mejor forma de hacerlo es la siguiente:

En la primer linea del LCD mostras un titulo del menu, o algun texto, por ejemplo: "Elija una opcion", y en la segunda linea, mostras la opcion. Con 2 teclas incrementas o decrementas un contador, y en funcion de ese contador mostras una opcion en la segunda linea del lcd.
Con otra tecla entras a la opcion, una vez dentro de la opcion (si tenes que mostrar mas opciones) haces lo mismo. Osea, en la primer linea mostras el nombre de la opcion a la que entraste, y en la segunda linea mostras las opciones disponibles en funcion de un contador.

Un menu de asi lo podes implementar asi:

Funcion mostrar_menu:

Escribo algo en la primer linea.
Pongo un contador a 0.

loop:
si tecla es +, incrementar contador
si tecla es - , decrementar contador
si tecla es enter {
si contador es 0, ejecutar la opcion 1
si contador es 1, ejecutar la opcion 2
si contador es 2, ejecutar la opcion 3
si contador es 3, ejecutar la opcion 4
si contador es 4, ejecutar la opcion 5
}

(de esta forma, cuando llegues a la ultima opcion, te quedaras en esa)
si contador es menor a 0, contador = a 0
si contador es mayor a numero de opciones, contador = a numero de opciones

(de esta forma, cuando llegues a la ultima opcion, iras a la primera) ( elije una sola)
si contador es menor a 0, contador = a numero de opciones
si contador es mayor a numero de opciones, contador = a 0

si contador es 0, mostrar en la linea 2 la opcion 1
si contador es 1, mostrar en la linea 2 la opcion 2
si contador es 2, mostrar en la linea 2 la opcion 3
si contador es 3, mostrar en la linea 2 la opcion 4
si contador es 4, mostrar en la linea 2 la opcion 5
....
esperar un tiempo cortito(unos 20 o 30 ms)
goto loop.

Espero haberte ayudado, cualquier cosa que no entiendas avisa.

Saludos


----------



## sangreaztk (Feb 2, 2009)

Moyano Jonathan dijo:
			
		

> La verdad no entendí del todo tu idea , tenés algun código o diagrama de flujo. Lo que pasa es que ando verdaderamente perdido con el tema y no se de donde empezar.
> 
> Agradesco tu ayuda.



Pss no tengo ningún código, de hecho nunca he armado algún programa de ese tipo, son las primeras ideas que se me ocurrieron al leer tu post. Mi idea es parecida a la de 'luis_e' solo que las opciones van "rotando" sobre el LCD, las dos lineas contienen opciones.
Y ahora que lo pienso bien, lo que nombre como 'posición relativa' sería más bien la 'absoluta' (primer linea o segunda linea) y lo contrario para la otra.

Buena Vibra!


----------



## Moyano Jonathan (Feb 2, 2009)

Bueno he terminado de pulir si se puede decir asi el código del LCD para mis requerimientos, gracias a la ayuda de ustedes.   

Lo que hace es primero me presenta todas las opciones del menu y luego con 3 botones up/down y OK me meto a las diferentes opciones.


----------



## Chico3001 (Feb 2, 2009)

Yo elaboro los menus con ayuda de una variable de conteo y muchas comparaciones


```
Si menu=00{
-escribir en linea 1 display (texto menu 0)
-escribir en linea 2 display (texto menu 0)
si tecla arriba menu=02 (numero del ultimo menu usado)
si tecla abajo menu=01 (siguiente menu)
si tecla enter ejecutar accion 0
}

Si menu=01{
-escribir en linea 1 display (texto menu 1)
-escribir en linea 2 display (texto menu 1)
si tecla arriba menu=00 (menu anterior)
si tecla abajo menu=02 (siguiente menu)
si tecla enter ejecutar accion 1
}

Si menu=02{
-escribir en linea 1 display (texto menu 2)
-escribir en linea 2 display (texto menu 2)
si tecla arriba menu=01 (menu anterior)
si tecla abajo menu=00 (siguiente menu)
si tecla enter ejecutar accion 1
}
```

En fin... la idea es esa, para submenus pongo variables de submenus y las comparo del mismo modo, o puedes incrementar la variable menu en pasos de 10 en 10 que te permitirian poner 9 submenus en cada menu


----------



## Moyano Jonathan (Feb 2, 2009)

gracias chico ya voy a ver que puedo hacer con la información que posteaste. Cualquier cosa te pregunto las dudas.

PD: Tenés algún código hecho como para guiarme?


----------



## Chico3001 (Feb 2, 2009)

en que lenguaje?


----------



## Chico3001 (Feb 2, 2009)

Haber... aqui hay un ejemplo que hice para un cliente, es un extracto de la subrituna de configuracion, por obvias razones no te puedo pasar el programa completo ni decir que hace, pero si te puedo explicar como funciona la subrutina

Para este caso el cliente no queria el uso de 3 botones (arriba, abajo y enter) queria que todo se hicera con un unico boton lo que me obligo a tener que detectar el tiempo que se mantiene presionado, ese tiempo lo comparo contra una constante (_toquel) para saber si se hizo un toque largo o corto y definir que se tiene que hacer a continuacion

Antes de entrar a la sub coloco la variable estado a 21 para mantener el programa dentro del loop principal de configuracion

Si te fijas cada loop es identico y solo cambia las acciones que debe ejecutar cada submenu:

1.-Se coloca un numero en el display que identifica el setpoint que se esta cambiando
2.-Se detiene momentaneamente el programa en lo que la persona suelta y vuelve a presionar el boton para poder contabilizar el tiempo de presionado
3.-Si el toque es corto se pasa al siguiente submenu
4.-Si el toque es largo se pone momentaneamente estado a 30 para editar la variable
5.-Se coloca el valor de la variable en el display
6.-Se vuelve a esperar a que se suelte y se presione el boton para medir de nuevo
7.-Si el toque es corto se incrementa la variable
8.-Si el toque es largo se sale del loop de incremento

Espero que este entendible...


----------



## Moyano Jonathan (Feb 3, 2009)

Muchas gracias chico, una pregunta el código es en C18, yo utlizo C de CCS pero el código que me pasaste es totalmente trasportable. De nuevo muchas gracias , en este momento ya tengo algo cocinado con interrupciones pero me parece que de la forma en que lo planteas vos es bastante interesante.

PD: tengo algunas dudas, por ejemplo:

- A que le llamas setpoint que está cambiando?
- TMR0 cuando termina de contar , lo verificas por interrupciones o lo haces mirando la bandera que lo indica?
- La variable que sube o baja segun el tiempo de pulsado cual es?

perdon por tantas pregutas , pero es para orientación nomás.


----------



## Chico3001 (Feb 3, 2009)

Nop... el codigo es para CCS pero el micro que programo es un AVR de Atmel, por eso ves diferencias, en cuanto a las preguntas aqui te van las respuestas:

- Cada setpoint (por que en el ejemplo son 4) es un valor de calibracion para la maquina que se realizo, el cliente entra a esa subrutina para modificar los rangos de operacion en los que trabaja el equipo, y con cada pulsacion se va incrementando ese valor en especial, cuando se excede de cierto nivel maximo lo reinicializo al valor minimo, esto es debido a que solo cuento con un boton,

- El TMR0 siempre esta corriendo y monitoreando el boton, cuando detecta que hubo un cambio de estado habilita una bandera (bbotone,btnconf) que avisa al programa que hubo una pulsacion y comienza a incrementar la variable contbtn en cada interrupcion subsecuente

- La variable de conteo de tiempo de pulsado es contbtn, pero recuerda que este ejemplo es mas complejo por que el cliente solo queria un boton, en tu caso puedes colocar 3 o mas botones que hacen que el programa sea menos complejo y podrias eliminar toda la parte de monitoreo de tiempo de pulsado

Deja hago un ejemplo similar para un caso de 3 botones (enter, arriba y abajo) y te lo subo para que lo veas, desafortunadamente no se programar para C18, pero al estar programando ambos en C la conversion AVR-PIC se puede hacer de manera mas simple


----------



## Moyano Jonathan (Feb 3, 2009)

Ok dale , igual voy a estudiar tu código para un botón que se ve bastante bueno para implementarlo.


----------



## Chico3001 (Feb 4, 2009)

Listo... aqui esta la rutina, solo nitas adaptarla a tu micro


----------



## Moyano Jonathan (Feb 4, 2009)

La verdad que muchas gracias te agradesco el esfuerzo.


----------



## luis_e (Feb 4, 2009)

Aca te dejo un pequeño programa de un menu con algunos submenus, y un archivo de proteus, para que veas como trabaja. Esta hecho en C18, para correr en un pic18f2550, a 40Mhz, pero se puede adaptar facilmente a la velocidad que necesitas.

Espero que te sirva, cualquier duda avisa.

Tambien hay una libreria para manejar lcds de 2x16 bastante completa, que fui armando en bastante tiempo.
En el archivo LCD.h estan los defines para indicar en los pines que va conectada. Si necesitas cambiar algo avisame, porque la hice para adaptarla sin modificar el codigo, aunque esto se va un poco del tema central.


----------



## Moyano Jonathan (Feb 4, 2009)

Gracias por ayuda, la voy a simular y luego contare las dudas que tenga.


----------



## basilinho (Feb 12, 2009)

Hola amigos que tal?, estoy haciendo un proyecto fin de curso con una lcd, pero no se ve nada , le he puesto algun progrma de inicializacion que ví ene ste mismo foro,  y lo introduzco en el pic 16f876 , y lo unico que sale son cuadrados negros y barras muy fina estilo codigo de barras y nada mas , si alguien pudueria ayudarme se lo agradeceria mucho.Gracias por adelantado


----------



## Moyano Jonathan (Feb 12, 2009)

Hace el programa que postee en la primera página de este hilo , los consejos de chico3001 soy muy útiles te pueden ayudar a hacer lo que necesitas.

Ahora si querés hacer "algo" con el LCD fijate en el foro hay muchos ejemplos.


----------



## cristian_elect (Feb 12, 2009)

Aqui tengo un ejemplo con atmega8 de un temporizador que activa una luz utilizando un reloj todo se configura en lcd , compilado en codevisionavr.
cambie de archivo.


----------



## Chico3001 (Feb 12, 2009)

y por cierto.. te funciono la rutina Moyano?


----------



## Moyano Jonathan (Feb 12, 2009)

me funciono pero me consumia mas recursos de la memoria y ram un 5% mas.


----------



## EDGAR KAMI (Jun 13, 2013)

Menu en lenguaje C usando 16F877A LCD 2X16 Y Keypad


Tengo 5 programas en C y necesito ayuda para crear un menú usando el pic16f877a, lcd 16x2 y keypad 4x4. Las especificaciones son que el lcd muestre un mensaje al inicio (bienvenidos) y después de unos ms muestre seleccione una opción. Después de seleccionar una opción muestre (se está ejecutando :nombre) y aparte en los otros puertos se este ejecutando los programas que se verán con en un display doble y usando pulsadores.
Anexo los programas están para 16f84a pero como es lenguaje c se puede trasladar al 16f877a.
Se necesita un botón del keypad que nos lleve al inicio, como un reset.
En resumen el LCD muestra que opciones tenemos y cual se esta ejecutando , el keypad sirve para seleccionar la opción de 1 a 5 y tendrá un botón de reinicio y aparte las demás funciones se hacen con los pulsadores y el display doble.
Les agradezco su ayuda.


----------



## EDGAR KAMI (Oct 20, 2013)

Mi problema es realizar un menú usando *lenguaje C en Pic C Copiler.*
el hardware es un pic16f877a, lcd 16x2 y keypad 4x4abcd.
*LCD EN PUERTO D Y KEYPAD PUERTOB y el boton de salida A* 
Necesito estructurar el menú para 7 opciones y un botón que me regrese a un mensaje de inicio.

El primer mensaje tarda 1500ms después aparece el mensaje seleccione y aparecerán los números del 1 al 7 
después de seleccionar cualquiera de los 7 aparecerá un mensaje con el nombre de la opción y ahí se quedara hasta que oprimamos una tecla digamos A.

En cada opción pondré un programa diferente que ya realice pero *no logro hacer que salga con un botón* es decir, selecciono 1 y aparece selecciono semáforo y estará haciendo lo operación del semáforo todo el rato. ...


----------



## Chico3001 (Oct 20, 2013)

Por favor publica lo que llevas hecho hasta ahora... Gracias


----------



## EDGAR KAMI (Oct 21, 2013)

*Este es un ejemplo  es  LENGUAJE C y necesito como poner default para cuando no sea un numero del 1 al 7 y que regrese al mensaje de bienvenidos usando el botón A, cada opción sera una programación diferente que se estara ejecutando infinitamente *


```
void main ()
{
   
   set_tris_a (0b00011111);
   set_tris_b (0b11111111);
   set_tris_c (0b00000000);
   set_tris_d (0b00000000);
   Port_b_pullups (true);
   lcd_init ();
   kbd_init ();
   CHAR k;
   INT8 con, x, uni, dec;
   lcd_gotoxy (3, 1) ;
   printf (lcd_putc, "\nBienvenidos"); Delay_ms (1500);
   lcd_gotoxy (1, 1) ;
   printf (lcd_putc, "Seleccione\n") ;
   printf (lcd_putc, "1 2 3 4 5 6 7\r");

   WHILE (TRUE)
   {
      
      k = kbd_getc ();
      x = k - 48;
      
      IF (k !=  0)
      {
         IF (k == ' * ')
            lcd_putc ("\fpresiono") ;

         
         ELSE
         printf (lcd_putc, "\fpresiono: = % u", x);
      }

      SWITCH (x)
      {
         CASE 1:
         WHILE (true)
         {
            lcd_gotoxy (1, 2) ;
            printf (lcd_putc, "\r F (X) = 3X ^ 2 + 2Y\r");
         }

         CASE 2:
         WHILE (true)
         {
            lcd_gotoxy (1, 2) ;
            printf (lcd_putc, "\r F (X) = X^8 + 2\r");
         }

         CASE 3:
         WHILE (true)
         {
            lcd_gotoxy (1, 2) ;
            printf (lcd_putc, "\r F (X) = 3X ^ 2 + 2Y\r");
         }

      }
   }
}
```


----------



## Chico3001 (Oct 21, 2013)

```
switch (x)
  case 1:
  case 2:
  default:
    (codigo a ejecutar en caso de ser opcion 1, 2 o ninguna)

  case 3:
........
```

algunos compiladores soportan mutiples selecciones con un mismo codigo como:


```
switch (x)
  case 1:
    .....

  case 2:
    .....

........

  default:
    (codigo a ejecutar si no hubo alguna de las opciones anteriores
```


----------



## EDGAR KAMI (Oct 21, 2013)

*QUEDARÍA ENTONCES *

DEFAULT:
         {
            lcd_gotoxy (1, 2) ;
            printf (lcd_putc, "\r NO DISPONIBLE\r");
         }
*Y COMO HAGO PARA QUE REGRESE AL MENSAJE DE BIENVENIDA*


----------



## Chico3001 (Oct 22, 2013)

Si pones whiles infinitos no puedes regresar al mensaje de bienvenida.. necesitas cambiar completamente la estructura de tu programa


----------



## EDGAR KAMI (Oct 22, 2013)

Si puedes difundir este Tema Chico3001 (¿Moderador?) por que no me eres de mucha ayuda sin ofender.


----------



## Chico3001 (Oct 22, 2013)

Tu problema es que el programa esta pobremente estructurado.... estas usando whiles infinitos dentro de la sentencia SWITCH - CASE obligando al programa a permanecer atorado una vez que alguien realizo una accion, lo que tienes que hacer es identificar la pulsacion del boton y en base a eso mostrar las acciones


```
while (1) {

  if (boton_presionado) {
    switch (x) {

      case 1:
        (acciones de display para caso 1)
        break;

      case 2:
        (acciones de display para caso 1)
        break;

      case 3:
        (acciones de display para caso 3)
        break;

      default:
        (acciones de display para caso otro)
        break;

    }
  } else {
    (mas acciones si no se ha presionado boton)
  }
}
```


----------



## EDGAR KAMI (Oct 22, 2013)

Ya veo, si pero es porque se necesitan así por ejemplo para el semáforo, el contador, las compuertas lógicas y los otros 4 por que si no solo harían su acción  una ves y ya y ese no es el caso.

Necesito que al sumir un botón me regrese al inicio con mis variables a cero otra ves.


----------



## Chico3001 (Oct 22, 2013)

No puedes salir de un loop infinito sin violar los principios de la programacion estructurada... necesitas volver a hacerlo desde el principio.. pensando como reorganizar las rutinas y convertirlas en funciones.. para que asi puedas llamarlas dentro de un unico loop infinito... y no varios como tienes ahorita...


----------



## EDGAR KAMI (Nov 21, 2013)

Sabes algo de las interrupciones?, según es posible usandolas


----------



## Chico3001 (Nov 22, 2013)

claro que es posible.. el menu corre en el loop principal... y las interrupciones solo interrumpen al loop principal por momentos y lo que hacen es alterar banderas y variables globales que el loop principal constantemente esta revisando..


----------



## BELTRANCESAR (May 13, 2016)

Buenas tardes, hestoy tratando de hacer un menu con LCD 2x16 y un PIC 16F877A, hasta el momento puedo desplazarme entre las 4 paginas del menu y entrar a cada una de ellas, mediante 4 pulsadores  que estan conectadas al AN0, la forma que se utiliza para saber cual boton se oprimió es por variacion de tension.  el problema que presento es que al pulsar la tecla 'L' que tengo definida para devolverme al menu principal (estando dentro de alguna de las 4 opciones)  no se sale, se queda infinitamente en cada una de las funciones. Agradezco de antemano la ayuda que me puedan brindar, ya que estoy haciendo una de las partes para un robot sumo. 
Adjunto el codigo del programa.

Muchas Gracias ...


----------



## DJ T3 (May 13, 2016)

Principalmente el problema es que no volves a comprovar si "btn_push" cambia de estado: solo haciendo "while(btn_push != 'L')", siempre te dara true, ya que nunca cambia el valor de btn_push.
Hace una funcion especifica que identifique si algun boton es presionado, y devolve ese valor, luego lo aplicas al while.
Mete en la funcion, lo que hay en el main desde el "medicion = readadc()", y el if que asigna el valor a btn_push, y devolve ese valor.

Otra cosa, no es necesario hacer esto:
"lcd_putc(".       ");
lcd_gotoxy(1,1);"
Con solo poner printf(lcd_putc, "\fAca elbtexto de arriba\bY este de abajo");
Ya esta, con el "\f", borras toda la pantalla, y con el "\b", vas a la segunda fila...


----------



## BELTRANCESAR (May 14, 2016)

Hola Amigo Muchas gracias por tu ayuda, voy a hacer las modificaciones a ver como me va.
Gracias


----------



## D@rkbytes (May 14, 2016)

¿Es necesario que leas las teclas de forma análoga?
¿Lo haces por cuestión de ahorrar pines?
Ya que también puedes usar la técnica de poleo para leer un teclado matricial.

Sin embargo, este ejemplo te puede servir de base para leer una matriz análoga de pulsadores.
*Teclado Analógico*


----------



## yorsk2004 (May 14, 2016)

Yo lo haría así:


```
/*Aquí va todo tu código antes del menú*/

byte flag=0;

while (flag == 0)
{
    if (tecla_que_define_la_funcion_salir == Aqui_la_condicion_que_tu_definiste)
    {
         flag=1;  /*Con lo cual saldría del while*/
    }
    /*Aquí va todo tu código del menú*/
}
```


----------

