Autor Tema: código para lcd 2x16 - controlador HD44780- con timer  (Leído 1919 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado LucasBols

  • PIC16
  • ***
  • Mensajes: 129
    • Desarrollos y Servicios Digitales
código para lcd 2x16 - controlador HD44780- con timer
« en: 12 de Junio de 2016, 19:34:37 »
hola, buenas tardes,

cuando necesito verificar la presión de un botón utilizo un delay para el anti-rebote, lo mismo para controlar la inicialización y escritura de los mensajes en un lcd, porque incluir un _delay_ms() es más fácil y rápido que usar un timer, y por supuesto, utilizo menos flash, reconozco que una buena práctica casi obligatoria es programar con timers, pero bueno, es demasiado engorroso

ahora estoy haciendo una insoladora porque le tengo un odio enfermizo a la plancha, así que para la insoladora uso un teclado matricial de los genéricos, un lcd 2x16 azul y un 18F46K22 que es una bestialidad pero tengo unos 30 en mi casa de un proyecto anterior y no quiero comprar otro más chico

a la insoladora le agregué tres memorias, en cada memoria se puede almacenar un tiempo presionando la tecla de la mem durante un segundo, y si la tecla de la mem se presiona durante menos de un segundo, se carga el tiempo almacenado

el problema surgía cuando debía recibir el evento del flanco descendente de la tecla de mem para calcular el tiempo que estuvo presionada, si estaba mandando algo al display, los delays me bloqueaban la int, así que me puse a escribir un código para manejar el lcd con el timer

les comparto el código por si a alguien le interesa usarlo o por si quieren indicarme algún error o mejora

el controlador utiliza solamente el nibble alto del lcd (d4~d7) para ahorrar pines,
se utilizan cuatro funciones:

    void LCD_Inicializar(void);
    inicializa el display con delays

la inicialización del display la hice con delays para ocupar menos flash y simplificar el código, la ejecuto antes de la activación de las int y no uso timers porque no me preocupa que el pic se tome un par de segundos para estar listo en su arranque

    void LCD_EscribeLinea( char nroLinea, const unsigned char *cadena,
                                              unsigned char lngCadena, unsigned long num );

    escribe una línea en el display

    void LCD_ProcesarColaMensajes(void);
    procesa la cola de tareas pendientes del lcd, es conveniente llamarla desde el while de main

    void LCD_EjecutarTareasTimer(void);
    ejecuta las tareas que necesitan temporización, debe ser ejecutada en la int del timer, los valores de temporización los establece el controlador previo al reinicio del temporizador

la freq del pic es de 16mhz, el timer es de 16 bits y el presc 1:8, si utilizan una config diferente, deberán recalcular los valores del timer en la cabecera, en la parte de Retardos para el pasaje de datos al LCD

la cabecera del controlador:
Código: C
  1. /*
  2.  * File:   lcd_HD44780.h
  3.  * Author: Darío
  4.  *
  5.  * Created on 9 de junio de 2016, 12:04
  6.  */
  7.  
  8. #ifndef LCD_HD44780_H
  9. #define LCD_HD44780_H
  10.  
  11. //------------------------------------------------------------------------------
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stdbool.h>
  16.  
  17. // descartar si no se usa el MPLAB Code Configurator
  18. #include "mcc_generated_files/mcc.h"
  19. #include "mcc_generated_files/pin_manager.h"
  20.  
  21. //******************************************************************************
  22.  
  23. /*******************************************************************
  24.  * Modificar las asignaciones de los puertos conectados al display *
  25.  *******************************************************************/
  26.  
  27. #define LCD_RS_PORT     PORTCbits.RC5 // aviso de envio de comando
  28. #define LCD_E_PORT      PORTCbits.RC4 // deshabilita la comunicacion
  29.  
  30. #define LCD_D4_PORT     PORTDbits.RD4 // bus de 4 bits
  31. #define LCD_D5_PORT     PORTDbits.RD5
  32. #define LCD_D6_PORT     PORTDbits.RD6
  33. #define LCD_D7_PORT     PORTDbits.RD7
  34.  
  35. //------------------------------------------------------------------------------
  36.  
  37. /***************************************************************
  38.  * Modificar los procedimientos para iniciar, detener el timer *
  39.  * y para cambiar el tiempo                                    *
  40.  ***************************************************************/
  41.  
  42. #define IniciarTimer()              TMR1_StartTimer()
  43. #define DetenerTimer()              TMR1_StopTimer()
  44. #define CambiarTiempoTimer(val)     TMR1_WriteTimer(val)
  45.  
  46. //------------------------------------------------------------------------------
  47. //------------------ Retardos para el pasaje de datos al LCD -------------------
  48. //------------------------------------------------------------------------------
  49.  
  50. #define LCD_TMR0_VAL_AVISO_ENV_BYTE                 64286   // 2,5 ms
  51. #define LCD_TMR0_VAL_HABIL_COMUNIC_ENV_MSB          64286   // 2,5 ms
  52. #define LCD_TMR0_VAL_DESHAB_COMUNIC_PROCES_MSB      63036   // 5 ms
  53. #define LCD_TMR0_VAL_HABIL_COMUNIC_ENV_LSB          64286   // 2,5 ms
  54.  
  55. //##############################################################################
  56. //##############################################################################
  57. //##########                                                             #######
  58. //##########   A   P A R T I R   D E   A C A   N O   M O D I F I C A R   #######
  59. //##########                                                             #######
  60. //##############################################################################
  61. //##############################################################################
  62.  
  63. #define _LCD_LIMPIAR_PANTALLA_      0b00000001
  64.  
  65. #define _LCD_VUELVE_AL_INICIO_      0b00000010
  66. #define _LCD_CURSOR_IZQUIERDA_      0b00010000
  67. #define _LCD_CURSOR_DERECHA_        0b00010100
  68.  
  69. #define _LCD_PANTALLA_IZQUIERDA_    0b00011000
  70. #define _LCD_PANTALLA_DERECHA_      0b00011100
  71.  
  72. //******************************************************************************
  73.  
  74. /* posiciones del display */
  75. /*
  76.  *  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
  77.  * 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  1º linea
  78.  * 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F  2º linea
  79.  *
  80.  * En HEX con 0b1 como comando -------------------
  81.  *  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
  82.  * 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
  83.  * C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
  84.  */
  85.  
  86. #define _LCD_L1_C_01_     0b10000000
  87. #define _LCD_L1_C_02_     0b10000001
  88. #define _LCD_L1_C_03_     0b10000010
  89. #define _LCD_L1_C_04_     0b10000011
  90. #define _LCD_L1_C_05_     0b10000100
  91. #define _LCD_L1_C_06_     0b10000101
  92. #define _LCD_L1_C_07_     0b10000110
  93. #define _LCD_L1_C_08_     0b10000111
  94. #define _LCD_L1_C_09_     0b10001000
  95. #define _LCD_L1_C_10_     0b10001001
  96. #define _LCD_L1_C_11_     0b10001010
  97. #define _LCD_L1_C_12_     0b10001011
  98. #define _LCD_L1_C_13_     0b10001100
  99. #define _LCD_L1_C_14_     0b10001101
  100. #define _LCD_L1_C_15_     0b10001110
  101. #define _LCD_L1_C_16_     0b10001111
  102.  
  103. #define _LCD_L2_C_01_     0b11000000
  104. #define _LCD_L2_C_02_     0b11000001
  105. #define _LCD_L2_C_03_     0b11000010
  106. #define _LCD_L2_C_04_     0b11000011
  107. #define _LCD_L2_C_05_     0b11000100
  108. #define _LCD_L2_C_06_     0b11000101
  109. #define _LCD_L2_C_07_     0b11000110
  110. #define _LCD_L2_C_08_     0b11000111
  111. #define _LCD_L2_C_09_     0b11001000
  112. #define _LCD_L2_C_10_     0b11001001
  113. #define _LCD_L2_C_11_     0b11001010
  114. #define _LCD_L2_C_12_     0b11001011
  115. #define _LCD_L2_C_13_     0b11001100
  116. #define _LCD_L2_C_14_     0b11001101
  117. #define _LCD_L2_C_15_     0b11001110
  118. #define _LCD_L2_C_16_     0b11001111
  119.  
  120. //******************************************************************************
  121.  
  122. #define LNG_COLA_BUFFER_LCD         8
  123. #define LNG_COLA_TBYTE_LCD          32
  124.  
  125. //------------------------------------------------------------------------------
  126.  
  127. #ifndef TYPEDEF_UNION_T_BYTE
  128. #define TYPEDEF_UNION_T_BYTE
  129.  
  130. typedef union
  131. {
  132.     unsigned char byte;
  133.  
  134.     struct
  135.     {
  136.         unsigned b0 : 1, b1 : 1, b2 : 1, b3 : 1, b4 : 1, b5 : 1, b6 : 1, b7 : 1;
  137.     };
  138. } t_byte;
  139.  
  140. typedef struct ColaDeByte
  141. {
  142.     t_byte tByte;
  143.     bool comando;
  144. } ColaByte;
  145.  
  146. ColaByte buffer_t_byte[LNG_COLA_TBYTE_LCD];
  147.  
  148. ColaByte caracterActual;
  149.  
  150. #endif /* TYPEDEF_UNION_T_BYTE */
  151.  
  152. //------------------------------------------------------------------------------
  153.  
  154. typedef struct bufferMensajesLCD
  155. {
  156.     char            lineaUno;
  157.     unsigned char   mensaje[LNG_COLA_TBYTE_LCD];
  158.     unsigned char   lngMensaje;
  159.     unsigned long   valorParam;
  160. } bufferMsgLCD;
  161.  
  162. bufferMsgLCD bufMsgLCD[LNG_COLA_BUFFER_LCD];
  163.  
  164. //------------------------------------------------------------------------------
  165.  
  166. typedef enum
  167. {
  168.     E_TAREALCD_LIBRE,
  169.  
  170.     E_TAREALCD_ENV_BYTE_LCD_P1,
  171.     E_TAREALCD_ENV_BYTE_LCD_P2,
  172.     E_TAREALCD_ENV_BYTE_LCD_P3,
  173.     E_TAREALCD_ENV_BYTE_LCD_P4
  174. } estadoTareasLCD;
  175.  
  176. estadoTareasLCD estadoActualTareaLCD = E_TAREALCD_LIBRE;
  177.  
  178. //------------------------------------------------------------------------------
  179.  
  180. bool TMR_Libre = true;
  181.  
  182. bufferMsgLCD LCDmensajeActual;
  183.  
  184. //------------------------------------------------------------------------------
  185. //----------------   T A R E A S   A U T O M A T I Z A D A S   -----------------
  186. //------------------------------------------------------------------------------
  187.  
  188. /**
  189.   @Summary
  190.     Procesa los mensajes pendientes a mostrar en el LCD
  191.  
  192.   @Description
  193.     Esta funcion utiliza el Timer1 y es ejecutada en el while de main
  194.  
  195.   @Example
  196.     <code>
  197.     void main(void)<br>
  198.     &nbsp;{<br>
  199.         &nbsp;&nbsp;&nbsp;while(1)<br>
  200.         &nbsp;&nbsp;&nbsp;{<br>
  201.         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCD_ProcesarColaMensajes();<br>
  202.         &nbsp;&nbsp;&nbsp;}<br>
  203.     &nbsp;}<br>
  204.     </code>
  205. */
  206. void LCD_ProcesarColaMensajes(void);
  207.  
  208. /**
  209.   @Summary
  210.  Ejecuta las tareas pendientes del LCD desde el timer
  211.  
  212.   @Description
  213.  Esta funcion la ejecuta el timer y contiene las tareas que se deberan ejecutar
  214.  periodicamente para la escritura de los mensajes en el lcd.<br>
  215.  Por omision se utiliza el Timer1
  216.  
  217.   @Example
  218.     <code>
  219.  #define LINEA_1&nbsp;&nbsp;&nbsp;&nbsp;0<br>
  220.  &nbsp;#define LINEA_2&nbsp;&nbsp;&nbsp;&nbsp;1<br><br>
  221.  &nbsp;LCD_EscribeLinea( LINEA_1, "Mensaje", 7, 0 );<br><br>
  222.  &nbsp;//imprime Numero 32<br>
  223.  &nbsp;LCD_EscribeLinea( LINEA_2, "Numero %", 8, 32 );<br><br>
  224.  &nbsp;// imprime Hora 1:15:25 (4525 segundos)<br>
  225.  &nbsp;LCD_EscribeLinea( LINEA_2, "Hora &", 6, 4525 );<br>
  226.     </code>
  227. */
  228. void LCD_EjecutarTareasTimer(void);
  229.  
  230. //------------------------------------------------------------------------------
  231. //---------------------   T A R E A S   M A N U A L E S   ----------------------
  232. //------------------------------------------------------------------------------
  233.  
  234. /**
  235.   @Summary
  236.     Inicializa el LCD de 2x16 basado en el controlador HD44780
  237.  
  238.   @Description
  239.     Inicializa el LCD de 2 lineas y 16 caracteres.<br>
  240.     Utiliza un bus de datos de 4 bits (D4 - D7).<br>
  241.     Los puertos que se utilizan deben definirse en el archivo
  242.  <b>lcd_HD44780.h.</b><br>
  243.     <code><br>
  244.         #define LCD_RS_PORT&nbsp;&nbsp;PORTCbits.RC5<br>
  245.         #define LCD_E_PORT&nbsp;&nbsp;&nbsp;PORTCbits.RC4<br><br>
  246.         #define LCD_D4_PORT&nbsp;&nbsp;PORTDbits.RD4<br>
  247.         #define LCD_D5_PORT&nbsp;&nbsp;PORTDbits.RD5<br>
  248.         #define LCD_D6_PORT&nbsp;&nbsp;PORTDbits.RD6<br>
  249.         #define LCD_D7_PORT&nbsp;&nbsp;PORTDbits.RD7<br>
  250.     </code><br>
  251.     Esta funcion debe llamarse antes de cualquier otra función del LCD
  252.     durante la inicializacion del sistema<br>
  253.  
  254.   @Example
  255.     <code>
  256.  void main(void)<br>
  257.     &nbsp;{<br>
  258.         &nbsp;&nbsp;&nbsp;LCD_Inicializar();<br>
  259.     &nbsp;}
  260.     </code>
  261. */
  262. void LCD_Inicializar(void);
  263.  
  264. /**
  265.   @Summary
  266.  Imprime un mensaje
  267.  
  268.   @Description
  269.  Imprime un mensaje en el LCD en la linea especificada
  270.  
  271.  @param <b>char nroLinea</b><br0 para que se imprima la línea superior<br>
  272.  1 para que se imprima la linea inferior
  273.  
  274.  @param <b>const unsigned char *cadena</b><br>
  275.  la cadena a imprimir, si la cadena contiene:<br>
  276.  &nbsp;% imprime números<br>
  277.  &nbsp;& imprime h.hhh.hhh:mm:ss
  278.  
  279.  @param <b>unsigned char lngCadena</b><br>longitud de la cadena
  280.  
  281.  @param <b>unsigned long num</b><br>valor que reemplaza a % o a &
  282.  
  283.   @Example
  284.     <code>
  285.  #define LINEA_1&nbsp;&nbsp;&nbsp;&nbsp;0<br>
  286.  &nbsp;#define LINEA_2&nbsp;&nbsp;&nbsp;&nbsp;1<br><br>
  287.  &nbsp;LCD_EscribeLinea( LINEA_1, "Mensaje", 7, 0 );<br><br>
  288.  &nbsp;//imprime Numero 32<br>
  289.  &nbsp;LCD_EscribeLinea( LINEA_2, "Numero %", 8, 32 );<br><br>
  290.  &nbsp;// imprime Hora 1:15:25 (4525 segundos)<br>
  291.  &nbsp;LCD_EscribeLinea( LINEA_2, "Hora &", 6, 4525 );<br>
  292.     </code>
  293. */
  294. void LCD_EscribeLinea( char nroLinea, const unsigned char *cadena,
  295.                          unsigned char lngCadena, unsigned long num );
  296.  
  297. //------------------------------------------------------------------------------
  298.  
  299. #endif  /* LCD_HD44780_H */

las definiciones IniciarTimer(), DetenerTimer() y CambiarTiempoTimer(val) permiten especificar el timer a utilizar

obviamente deben cambiar las definiciones de los puertos

el código:
Código: C
  1. /*
  2.  * File:   lcd_HD44780.h
  3.  * Author: Darío
  4.  *
  5.  * Created on 9 de junio de 2016, 12:04
  6.  */
  7.  
  8. //------------------------------------------------------------------------------
  9.  
  10. #include "lcd_HD44780.h"
  11.  
  12. //------------------------------------------------------------------------------
  13.  
  14. void inicializarDatosLCD(void);
  15.  
  16. //##############################################################################
  17. //###   I n i c i a l i z a c i o n   d e l   L C D   c o n   d e l a y s   ####
  18. //##############################################################################
  19. /*
  20.  * La inicializacion del LCD se hace con delays para poder ejecutarla antes de
  21.  * activar las interrupciones y los timers.
  22.  */
  23. void LCDpasajeDatos(void)
  24. {
  25.     LCD_E_PORT   = 1; // habilita la comunicacion para que procese el nibble
  26.     __delay_us( 20 ); // delay para garantizar el pasaje de datos al lcd
  27.     LCD_E_PORT   = 0; // deshabilita la comunicacion
  28. }
  29.  
  30. //------------------------------------------------------------------------------
  31.  
  32. void LCDenviaByte( t_byte dato )
  33. {
  34.     // transmite el nibble alto al lcd
  35.     LCD_D7_PORT  = dato.b7;
  36.     LCD_D6_PORT  = dato.b6;
  37.     LCD_D5_PORT  = dato.b5;
  38.     LCD_D4_PORT  = dato.b4;
  39.  
  40.     LCDpasajeDatos(); // envia los datos al lcd
  41.  
  42.     __delay_us( 10 );
  43.  
  44.     // transmite el nibble bajo al lcd
  45.     LCD_D7_PORT  = dato.b3;
  46.     LCD_D6_PORT  = dato.b2;
  47.     LCD_D5_PORT  = dato.b1;
  48.     LCD_D4_PORT  = dato.b0;
  49.  
  50.     LCDpasajeDatos();
  51.  
  52.     __delay_ms(10);
  53. }
  54.  
  55. //------------------------------------------------------------------------------
  56.  
  57. void LCDenviaComando( t_byte comando )
  58. {
  59.     LCD_RS_PORT = 0; // aviso de envio de comando
  60.     __delay_us( 10 );
  61.     LCDenviaByte( comando );
  62. }
  63.  
  64. //------------------------------------------------------------------------------
  65.  
  66. void LCD_Inicializar(void)
  67. {
  68.     DetenerTimer();
  69.     inicializarDatosLCD();
  70.  
  71.     t_byte dato[7];
  72.  
  73.     // configura el lcd
  74.     dato[0].byte = 3;
  75.     dato[1].byte = 2;
  76.     dato[2].byte = 0x28;
  77.     dato[3].byte = 0xC;
  78.     dato[4].byte = 1;
  79.     dato[5].byte = 6;
  80.     dato[6].byte = _LCD_LIMPIAR_PANTALLA_;
  81.  
  82.     for ( int i=0; i<100; i++ )
  83.         __delay_ms( 25 ); // espera a que el voltaje se estabilice
  84.  
  85.     LCD_RS_PORT  = 0; // aviso de envio de comando
  86.  
  87.     LCD_E_PORT   = 0; // deshabilita la comunicacion
  88.  
  89.     LCD_D7_PORT = 0;
  90.     LCD_D6_PORT = 0;
  91.     LCD_D5_PORT = 1; // modo seteo
  92.     LCD_D4_PORT = 1; // bus de 4 bits
  93.  
  94.     __delay_ms( 15 );
  95.  
  96.     LCD_E_PORT  = 1; // habilita la comunicacion
  97.  
  98.     __delay_ms( 15 );
  99.  
  100.     LCD_E_PORT   = 0; // deshabilita la comunicacion
  101.  
  102.     __delay_ms( 15 );
  103.  
  104.     //----------------------------------
  105.     for ( int i=0; i<7; i++ )
  106.         LCDenviaByte( dato[i] );
  107.  
  108.     for ( int i=0; i<20; i++ )
  109.         __delay_ms( 20 );
  110.  
  111.     dato[6].byte = _LCD_LIMPIAR_PANTALLA_;
  112.     LCDenviaComando( dato[6] );
  113. }
  114.  
  115. //##############################################################################
  116. //#########   M a n e j o   d e l   L C D   c o n   e l   T i m e r   ##########
  117. //##############################################################################
  118.  
  119. void reiniciarTimerConPeriodo(uint16_t periodo)
  120. {
  121.     DetenerTimer();
  122.     CambiarTiempoTimer( periodo );
  123.     TMR_Libre = false;
  124.     IniciarTimer();
  125. }
  126.  
  127. //******************************************************************************
  128.  
  129. void agregarMensajeColaBuffer(char nroLinea, const unsigned char *cadena,
  130.                          unsigned char lngCadena, unsigned long num)
  131. {
  132.     // busca el primer espacio libre para agregar el mensaje
  133.     for( unsigned char i=0; i<LNG_COLA_BUFFER_LCD; i++ )
  134.     {
  135.         if( bufMsgLCD[i].lngMensaje == 0 )
  136.         {
  137.             // si el mensaje pasado es mayor que el permitido, lo descarta
  138.             if ( lngCadena <= LNG_COLA_TBYTE_LCD )
  139.             {
  140.                 bufMsgLCD[i].lineaUno   = nroLinea;
  141.                 bufMsgLCD[i].lngMensaje = lngCadena;
  142.                 bufMsgLCD[i].valorParam = num;
  143.                 for( unsigned char j=0; j<lngCadena; j++ )
  144.                     bufMsgLCD[i].mensaje[j] = cadena[j];
  145.             }
  146.            
  147.             i = LNG_COLA_BUFFER_LCD;
  148.         }
  149.     }
  150. }
  151.  
  152. bufferMsgLCD obtenerMensajeColaBuffer(void)
  153. {
  154.     // extrae el fifo mensaje del bufer
  155.     bufferMsgLCD bufMsg = bufMsgLCD[0];
  156.  
  157.     // corre los mensajes del bufer hacia adelante
  158.     for( unsigned char i=1; i<LNG_COLA_BUFFER_LCD; i++ )
  159.         bufMsgLCD[i-1] = bufMsgLCD[i];
  160.  
  161.     // vacia el ultimo mensaje del bufer
  162.     for( unsigned char i=0; i<LNG_COLA_TBYTE_LCD; i++ )
  163.             bufMsgLCD[LNG_COLA_BUFFER_LCD-1].mensaje[i] = 0;
  164.  
  165.     bufMsgLCD[LNG_COLA_BUFFER_LCD-1].lineaUno   = false;
  166.     bufMsgLCD[LNG_COLA_BUFFER_LCD-1].lngMensaje = 0;
  167.     bufMsgLCD[LNG_COLA_BUFFER_LCD-1].valorParam = 0;
  168.    
  169.     return bufMsg;
  170. }
  171.  
  172. //------------------------------------------------------------------------------
  173.  
  174. void agregarCaracterColaBuffer(unsigned char iniIdx, unsigned char byte,
  175.         bool comando)
  176. {
  177.     static unsigned char idxLinea=0;
  178.  
  179.     if ( iniIdx == false )
  180.     {
  181.         buffer_t_byte[idxLinea].tByte.byte = byte;
  182.         buffer_t_byte[idxLinea].comando    = comando;
  183.         idxLinea++;
  184.     }
  185.     else
  186.         idxLinea=0;
  187. }
  188.  
  189. //------------------------------------------------------------------------------
  190.  
  191. void inicializarDatosLCD(void)
  192. {
  193.     for( unsigned char i=0; i<LNG_COLA_BUFFER_LCD; i++ )
  194.     {
  195.         for( unsigned char j=0; j<16; j++ )
  196.             bufMsgLCD[i].mensaje[j] = 0;
  197.  
  198.         bufMsgLCD[i].lineaUno   = 0;
  199.         bufMsgLCD[i].lngMensaje = 0;
  200.         bufMsgLCD[i].valorParam = 0;
  201.     }
  202.    
  203.     for( unsigned char i=0; i<16; i++ )
  204.         buffer_t_byte[i].tByte.byte = 0;
  205.  
  206.     TMR_Libre = true;
  207.  
  208.     caracterActual.comando    = false;
  209.     caracterActual.tByte.byte = 0;
  210. }
  211.  
  212. //------------------------------------------------------------------------------
  213.  
  214. bool convertirValorCaracterColaBufer( unsigned char valor, bool imprimir )
  215. {
  216.     unsigned char caracter;
  217.  
  218.     if ( (valor > 0) || (imprimir == true) )
  219.     {
  220.         caracter = valor + 48;
  221.         agregarCaracterColaBuffer( false, caracter, false );
  222.  
  223.         return true;
  224.     }
  225.     else
  226.         return imprimir;
  227. }
  228.  
  229. //------------------------------------------------------------------------------
  230.  
  231. /*
  232.  * % imprime números
  233.  * & imprime h.hhh.hhh:mm:ss
  234.  */
  235. void escribirLinea( char nroLinea, const unsigned char *cadena,
  236.                          unsigned char lngCadena, unsigned long num )
  237. {
  238.     unsigned char caracter;
  239.  
  240.     if ( nroLinea == 0 )
  241.     {
  242.         caracter = _LCD_LIMPIAR_PANTALLA_; // limpia la pantalla
  243.         agregarCaracterColaBuffer( false, caracter, true );
  244.         // mueve el cursor al primer caracter de la primer linea
  245.         caracter = _LCD_L1_C_01_;
  246.         agregarCaracterColaBuffer( false, caracter, true );
  247.     }
  248.     else
  249.     {
  250.         // mueve el cursor al primer caracter de la segunda linea
  251.         caracter = _LCD_L2_C_01_;
  252.         agregarCaracterColaBuffer( false, caracter, true );
  253.     }
  254.  
  255.     // procesa cada caracter de la cadena
  256.     for ( int i=0; i<lngCadena; i++ )
  257.     {
  258.         // si el caracter es comodin de numero o de hora
  259.         if ( *cadena == '%' || *cadena == '&' )
  260.         {   // crea un array para almacenar el pre procesamiento de los datos
  261.             unsigned long nums[3];
  262.  
  263.             if ( *cadena == '%' ) // si es comodin de numeros
  264.             {
  265.                 nums[0] = num; // almacena el numero en el primer char
  266.                 nums[1] = 0;   // del array y deja vacios el resto
  267.                 nums[2] = 0;
  268.             }
  269.             else if ( *cadena == '&' ) // si es comodin de hora
  270.             {   // extrae las horas
  271.                 nums[0] = ((num / 60) / 60);
  272.                 // extrae los minutos
  273.                 nums[1] = ((num - ((nums[0] * 60) * 60)) / 60);
  274.                 // extrae los segundos
  275.                 nums[2] = (num - (((nums[0] * 60) * 60) + (nums[1] * 60)));
  276.             }
  277.  
  278.             for ( char i=0; i<3; i++) // procesa los elementos del array
  279.             {
  280.                 unsigned char valimp;
  281.                 bool imp = false;
  282.  
  283.                 // imprime números hasta un máximo de 9 billones
  284.                 for ( unsigned long j=0, divs=1000000000; j<10; j++, divs = divs/10 )
  285.                 {
  286.                     valimp = (nums[i] / divs) % 10;
  287.                      // imprime el número
  288.                     imp = convertirValorCaracterColaBufer( valimp, imp );
  289.                     if ( ((j==0) || (j==3) || (j==6)) && (imp == true) )
  290.                     {
  291.                         caracter = 46; // imprime el punto separador
  292.                         agregarCaracterColaBuffer( false, caracter, false );
  293.                     }
  294.                 }
  295.  
  296.                 // si es número y su valor es cero, imprime un cero
  297.                 if ( (*cadena == '%') && (nums[0] == 0) && (i == 2) )
  298.                     convertirValorCaracterColaBufer( 0, true );
  299.  
  300.                 // si es hora
  301.                 if ( *cadena == '&' )
  302.                 {   // si el valor es cero
  303.                     if ( (nums[i] == 0) )
  304.                         convertirValorCaracterColaBufer( 0, true );
  305.  
  306.                     if ( i == 0 )
  307.                     {
  308.                         caracter = 'h';
  309.                         agregarCaracterColaBuffer( false, caracter, false );
  310.                         caracter = ' ';
  311.                         agregarCaracterColaBuffer( false, caracter, false );
  312.                     }
  313.                     else if ( i == 1 )
  314.                     {
  315.                         caracter = 'm';
  316.                         agregarCaracterColaBuffer( false, caracter, false );
  317.                         caracter = ' ';
  318.                         agregarCaracterColaBuffer( false, caracter, false );
  319.                     }
  320.                     else if ( i == 2 )
  321.                     {
  322.                         caracter = 's';
  323.                         agregarCaracterColaBuffer( false, caracter, false );
  324.                     }
  325.                 }
  326.             }
  327.         }
  328.         else
  329.         {
  330.             caracter = *cadena;
  331.             agregarCaracterColaBuffer( false, caracter, false );
  332.         }
  333.  
  334.         *cadena++;
  335.     }
  336.     agregarCaracterColaBuffer( true, caracter, false );
  337. }
  338.  
  339. //------------------------------------------------------------------------------
  340.  
  341. void detener_Timer(void)
  342. {
  343.     DetenerTimer();
  344.     TMR_Libre = true;
  345.  
  346.     estadoActualTareaLCD = E_TAREALCD_LIBRE;
  347.  
  348.     caracterActual.comando    = false;
  349.     caracterActual.tByte.byte = 0;
  350. }
  351.  
  352. //------------------------------------------------------------------------------
  353.  
  354. void enviarCaracterLCD(void)
  355. {
  356.     static unsigned char idx=0;
  357.  
  358.     // si hay un caracter para imprimir
  359.     if ( buffer_t_byte[idx].tByte.byte > 0 )
  360.     {
  361.         caracterActual = buffer_t_byte[idx];
  362.         idx++;
  363.  
  364.         if (caracterActual.comando)
  365.             LCD_RS_PORT = 0; // aviso de envio de comando
  366.         else
  367.             LCD_RS_PORT = 1; // aviso de envio de datos
  368.  
  369.         estadoActualTareaLCD = E_TAREALCD_ENV_BYTE_LCD_P1;
  370.  
  371.         reiniciarTimerConPeriodo( LCD_TMR0_VAL_AVISO_ENV_BYTE ); // 5 ms
  372.     }
  373.     else
  374.     {
  375.         for( unsigned char i=1; i<LNG_COLA_TBYTE_LCD; i++ )
  376.         {
  377.             buffer_t_byte[i].comando    = false;
  378.             buffer_t_byte[i].tByte.byte = 0;
  379.         }
  380.         idx = 0;
  381.         detener_Timer();
  382.     }
  383. }
  384.  
  385. //------------------------------------------------------------------------------
  386.  
  387. void LCD_EjecutarTareasTimer(void)
  388. {
  389.     switch( estadoActualTareaLCD )
  390.     {
  391.         case E_TAREALCD_ENV_BYTE_LCD_P1: //*************************************
  392.  
  393.             // transmite el nibble alto al lcd
  394.             LCD_D7_PORT = caracterActual.tByte.b7;
  395.             LCD_D6_PORT = caracterActual.tByte.b6;
  396.             LCD_D5_PORT = caracterActual.tByte.b5;
  397.             LCD_D4_PORT = caracterActual.tByte.b4;
  398.  
  399.             LCD_E_PORT = 1; // habilita la comunicacion para que procese el nibble
  400.  
  401.             estadoActualTareaLCD = E_TAREALCD_ENV_BYTE_LCD_P2;
  402.  
  403.             reiniciarTimerConPeriodo( LCD_TMR0_VAL_HABIL_COMUNIC_ENV_MSB );
  404.  
  405.             break;
  406.  
  407.         case E_TAREALCD_ENV_BYTE_LCD_P2: //*************************************
  408.  
  409.             LCD_E_PORT   = 0; // deshabilita la comunicacion
  410.  
  411.             estadoActualTareaLCD = E_TAREALCD_ENV_BYTE_LCD_P3;
  412.  
  413.             reiniciarTimerConPeriodo( LCD_TMR0_VAL_DESHAB_COMUNIC_PROCES_MSB );
  414.  
  415.             break;
  416.  
  417.         case E_TAREALCD_ENV_BYTE_LCD_P3: //*************************************
  418.  
  419.             // transmite el nibble bajo al lcd
  420.             LCD_D7_PORT = caracterActual.tByte.b3;
  421.             LCD_D6_PORT = caracterActual.tByte.b2;
  422.             LCD_D5_PORT = caracterActual.tByte.b1;
  423.             LCD_D4_PORT = caracterActual.tByte.b0;
  424.  
  425.             LCD_E_PORT = 1; // habilita la comunicacion para que procese el nibble
  426.  
  427.             estadoActualTareaLCD = E_TAREALCD_ENV_BYTE_LCD_P4;
  428.  
  429.             reiniciarTimerConPeriodo( LCD_TMR0_VAL_HABIL_COMUNIC_ENV_LSB );
  430.  
  431.             break;
  432.  
  433.         case E_TAREALCD_ENV_BYTE_LCD_P4: //*************************************
  434.  
  435.             LCD_E_PORT   = 0; // deshabilita la comunicacion
  436.  
  437.             if ( buffer_t_byte[0].tByte.byte > 0 )
  438.                 enviarCaracterLCD();
  439.             else
  440.                 detener_Timer();
  441.  
  442.             break;
  443.     }
  444. }
  445.  
  446. //------------------------------------------------------------------------------
  447.  
  448. void LCD_ProcesarColaMensajes(void)
  449. {
  450.     /*
  451.      * si en el bufer hay datos para imprimir y el timer esta libre
  452.      */
  453.     if( (bufMsgLCD[0].lngMensaje > 0) && (TMR_Libre) )
  454.     {
  455.         // obtiene el primer mensaje del bufer
  456.         LCDmensajeActual = obtenerMensajeColaBuffer();
  457.        
  458.         /*
  459.          * formatea el primer mensaje de la cola de mensajes para mostrar
  460.          * y queda listo para enviar al display con el protocolo de transmision
  461.          */
  462.         escribirLinea(LCDmensajeActual.lineaUno, &(LCDmensajeActual.mensaje),
  463.                 LCDmensajeActual.lngMensaje, LCDmensajeActual.valorParam);
  464.  
  465.         /*
  466.          * comienza la impresion del mensaje
  467.          */
  468.         enviarCaracterLCD();
  469.     }
  470. }
  471.  
  472. //------------------------------------------------------------------------------
  473.  
  474. void LCD_EscribeLinea( char nroLinea, const unsigned char *cadena,
  475.                          unsigned char lngCadena, unsigned long num )
  476. {
  477.     agregarMensajeColaBuffer( nroLinea, cadena, lngCadena, num );
  478. }
  479.  
  480. //------------------------------------------------------------------------------

una utilización de ejemplo del controlador sería algo así

Código: C
  1. void TMR1_ISR(void)
  2. {
  3.     // Clear the TMR1 interrupt flag
  4.     PIR1bits.TMR1IF = 0;
  5.    
  6.     // Write to the Timer1 register
  7.     TMR1H = (timer1ReloadVal >> 8);
  8.     TMR1L = (uint8_t) timer1ReloadVal;
  9.  
  10.     // Add your TMR1 interrupt custom code
  11.  
  12.     LCD_EjecutarTareasTimer();
  13. }
  14.  
  15. //------------------------------------------------------------------------------
  16.  
  17. void main(void)
  18. {
  19.     SYSTEM_Initialize();
  20.  
  21.     INTERRUPT_GlobalInterruptEnable();
  22.  
  23.     INTERRUPT_PeripheralInterruptEnable();
  24.  
  25.     TMR1_StopTimer();
  26.    
  27.     LCD_Inicializar();
  28.  
  29.     LCD_EscribeLinea( 0, "PIC", 3, 0 );
  30.     LCD_EscribeLinea( 1, "Inicializado", 12, 0 );
  31.  
  32.    
  33.     while (1)
  34.     {
  35.         LCD_ProcesarColaMensajes();
  36.     }
  37. }

una de las tareas pendientes es reducir los retardos de la inicializacion -LCD_Inicializar()- es ridículo que se tome aprox 3 segundos, esto está desde cuando compré unos lcd azules de cuarta

otra de las tareas es ajustar reduciendo los retardos para el pasaje de datos al lcd sin que saturen el stack cuando saltan otras ints, aunque los retardos se pueden reemplazar utilizando el D7 para leer el busy del lcd, eso podría ir en el timer con un retardo de 1ms o menos, o en void LCD_ProcesarColaMensajes(void), pero en este caso me parece que ocuparía innecesariamente al micro

lo del busy en el D7 sería más o menos algo así

Código: C
  1. LCD_RS_PORT = 0 // pone RS a 0 (registro de instrucciones)
  2.  
  3. LCD_RW_PORT = 1 // pone R/W a 1 (registro de lectura)
  4.  
  5. LCD_E_PORT = 1 // habilita la comunicacion con el display
  6.  
  7. if ( LCD_D7_PORT == 0 )
  8.         // display libre, pasa a la tarea siguiente
  9.  
  10. LCD_E_PORT = 0 // deshabilita la comunicacion con el display

adjunto el .c y el .h del controlador
* controlador.zip
(20.13 kB - descargado 172 veces)
y un ejemplo de uso para el XC8 con el 16F46K22,
* ejemplo.zip
(29.69 kB - descargado 154 veces)


saludos,
Un experto es alguien que te explica algo sencillo de forma confusa de tal manera que te hace pensar que la confusión sea culpa tuya.

DSD http://www.dysd.com.ar/