Jugando con un LCD



1. Introducción:

 El lcd es un elemento que se usa como interface. En nuestro caso usaremos un lcd alfanumérico.

Cada lcd integra un controlador que es el encargado de "dibujar" la pantalla. Nosotros le indicaremos a este controlador lo que queremos presentar.

La mayoría de los LCD son compatibles con el HD44780 y en el datasheet encontraremos información sobre la secuencia para comunicarnos y los diferentes comandos.

  Algunas características:




2. Conexiones:

  Nosotros usaremos el lcd PC2004ARS que usa un bus paralelo de 4 u 8 bits y tiene 4 líneas de 20 caracteres cada una.




  Pines:


Nota: Cambian con respecto al esquema de la placa. Fijarse en la serigrafía.

Nota: El display que estoy usando no tiene retroiluminación.


3. Estructura del proyecto:

 Desde el Menú "File", vamos a crear un nuevo proyecto (seguimos los pasos descritos con anterioridad).


  Creamos el nuevo proyecto y añadimos los siguientes archivos:




4. Adaptando las liberías existentes:

 Nos basaremos en las librerías de muestra que tenemos en el siguiente directorio: C:\Program Files (x86)\Microchip\Mla\v2016_11_07\bsp\picdem_fs_usb. Modificaremos lcd.c; lcd.h se mantiene igual al original:





 La diferencia entre estas dos funciones, es el pin RS; para enviar datos lo ponemos a nivel alto y para enviar comandos lo ponemos a nivel bajo.

4.1. Ejemplo 1:

 En este sencillo ejemplo escribimos carácter a carácter, o enviamos una línea de texto.

Nota: Los pines de datos están compartidos con los led. Para deshabilitar los led, basta con eliminar el jumper "J9" que se encuentra junto a estos.


					
#include 
#include "config.h"
#include "typedefs.h"
#include "lcd.h"
#include "xc.h"

#define _XTAL_FREQ 48000000		

void delay_ms(uint16_t);

void main(void)
{
	LCD_Initialize();
	delay_ms(100);
	while (1)
		{
			LCD_ClearScreen();
			LCD_PutChar('H');
			LCD_PutChar('o');
			LCD_PutChar('l');
			LCD_PutChar('a');
			delay_ms(5000);
			LCD_ClearScreen();
			LCD_PutString("Hoy es Martes 11 de Julio de 2017. Hace buen tiempo para ir a la playa.", 70);
			delay_ms(5000);
		}
}		

void delay_ms(uint16_t i)
{
	for(uint16_t x=0; x < i; x++)
	{
	__delay_ms(1);
	}
}	
					
		



5. Ampliando las librerías:

  Buscamos alcanzar los siguientes objetivos (Nos ayudaremos del datasheet del display):


5.1. Adaptando Lcd.h:

/*******************************************************************************
 *                           LIBERERIA LCD MODIFICADA
 * 
 * - Asignación de pines independientes al puerto
 * - Funcionamiento en bus de 8 y 4 bits
 * - Definicion del numero de filas y columnas del display
 * - Algunas funciones como SCROLL
*******************************************************************************/

#include 
#include 
#include "config.h"     //Necesaria porque es donde esta definido el _XTAL_FREQ


////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE INICIALIZAR EL SISTEMA
//
//  Configura los pines como salida
//  Configura el display en el modo correcto
////////////////////////////////////////////////////////////////////////////////
void LCD_Initialize(void);


////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE HACER SCROLL DEL TEXTO
//
////////////////////////////////////////////////////////////////////////////////
void LCD_ScrollLeft (void);


void LCD_ScrollRight (void);



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA PONER CURSOR EN UNA POSICION
//
////////////////////////////////////////////////////////////////////////////////
void LCD_SetCursor ( uint8_t linea, uint8_t columna );



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA PONER CURSOR EN UNA POSICION
//
////////////////////////////////////////////////////////////////////////////////
void LCD_SetCursor (uint8_t linea, uint8_t columna );



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ESCRIBIR UNA CADENA
//
////////////////////////////////////////////////////////////////////////////////
void LCD_PutString ( char* inputString , uint16_t length );



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ESCRIBIR CARACTERES
//
// Recibe caracteres y cambia de linea automaticamente
////////////////////////////////////////////////////////////////////////////////
void LCD_PutChar(char);



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE BORRAR DISPLAY
//
//  Borra display
//  Salta a la posicion inicial
////////////////////////////////////////////////////////////////////////////////
void LCD_ClearScreen(void);



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE HACER VISIBLE O NO EL CURSOR
//
////////////////////////////////////////////////////////////////////////////////
void LCD_CursorEnable(bool enable);



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ENVIAR DATOS AL DISPLAY
//
//  Segun el tipo de configuracion 4bits o 8bits
////////////////////////////////////////////////////////////////////////////////
static void LCD_SendData ( char data );



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ENVIAR COMANDOS AL DISPLAY
//
//  Segun el tipo de configuracion 4bits o 8bits
////////////////////////////////////////////////////////////////////////////////
static void LCD_SendCommand ( char command , unsigned int delay );



////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE HACER RETARDO uS
//
////////////////////////////////////////////////////////////////////////////////
static void LCD_Wait_us ( unsigned int delay );


5.2. Adaptando Lcd.c:

/*******************************************************************************
 *                           LIBERERIA LCD MODIFICADA
 * 
 * - Asignación de pines independientes al puerto
 * - Funcionamiento en bus de 8 y 4 bits
 * - Definicion del numero de filas y columnas del display
 * - Algunas funciones como SCROLL
*******************************************************************************/

#include 
#include "lcd.h"
#include 

//TIEMPOS DE RETARDO PARA EJECUCION SEGUN OPERACION
#define LCD_HS_OPERT        50      //Operacion rapida > 43uS
#define LCD_NS_INSTR        1400    //Operacion tipica > 1.35ms
#define LCD_INI_TIME        30000   //Operacion de arranque > 30ms


//INDICAMOS LOS CARACTERES POR LINEA QUE TIENE NUESTRO DISPLAY
#define LCD_MAX_COLUMN      20
//INDICAMOS LAS LINEAS QUE TIENE NUESTRO DISPLAY (Las direcciones están en el datasheet del lcd)
#define LCD_MAX_ROW      4
#define LCD_COMMAND_ROW_0_HOME          0x80
#define LCD_COMMAND_ROW_1_HOME          0xC0
#define LCD_COMMAND_ROW_2_HOME          0x94
#define LCD_COMMAND_ROW_3_HOME          0xD4 

//COMANDOS QUE ACEPTA EL CONTROLADOR HD44780
#define LCD_COMMAND_CLEAR_SCREEN        0x01    //Borra la pantalla. Tiempo ejecucion: 1.64ms
#define LCD_COMMAND_RETURN_HOME         0x02    //Coloca el cursor al inicio. Tiempo ejecucion: 1.64ms
#define LCD_COMMAND_ENTER_DATA_MODE     0x06    //Autoincremento a la derecha. Tiempo ejecucion: 40us
#define LCD_COMMAND_CURSOR_OFF          0x0C    //Cursor no visible. Tiempo ejecucion: 40us
#define LCD_COMMAND_CURSOR_ON           0x0F    //Cursor visible. Tiempo ejecucion: 40us
#define LCD_COMMAND_MOVE_CURSOR_LEFT    0x10    //Desplaza cursor a la izquierda. Tiempo ejecucion: 40us
#define LCD_COMMAND_MOVE_CURSOR_RIGHT   0x14    //Desplaza cursor a la derecha. Tiempo ejecucion: 40us
#define LCD_COMMAND_SET_MODE_8_BIT      0x38    //8 bits, 2 lineas. Tiempo ejecucion: 40us
#define LCD_COMMAND_SET_MODE_4_BIT      0x28    //4 bits, 2 lineas. Tiempo ejecucion: 40us


// DEFINIMOS LOS PINES QUE USAREMOS PARA COMUNICARNOS CON EL DISPLAY
//////////PINES DE CONTROL
//EN: Al pasar de 1 a 0, el controlador lee el bus ya sea para control o datos
//RW: Cuando esta a 0 escribimos en el lcd. Cuando esta a 1 leemos del lcd. Si vamos a
// escribir siempre, podemos conectarla a gnd.
//RS: Cuando esta a 0 indica comando. Cuando esta a 1 indica texto
#define LCD_RS_pin  LATAbits.LATA5
#define LCD_RS_tris TRISAbits.TRISA5
#define LCD_RW_pin  LATAbits.LATA4
#define LCD_RW_tris TRISAbits.TRISA4
#define LCD_E_pin  LATAbits.LATA3
#define LCD_E_tris TRISAbits.TRISA3
//////////PINES DE DATOS
#define LCD_MODE_4  true    //Indica si usamos el modo 4 pines o 8 pines de datos
// En modo 4 bits usamos los pines de mayor peso (D4-D5-D6-D7))
// Para transferir los 8 bits usando un bus de 4 bits, primero transferimos los bits
// mas altos del dato (D4-D7) y luego los mas bajos (D0-D3). Hacemos dos envios de 4 bits.
#define LCD_D0_pin  LATDbits.LATD0
#define LCD_D0_tris TRISDbits.TRISD0
#define LCD_D1_pin  LATDbits.LATD1
#define LCD_D1_tris TRISDbits.TRISD1
#define LCD_D2_pin  LATDbits.LATD2
#define LCD_D2_tris TRISDbits.TRISD2
#define LCD_D3_pin  LATDbits.LATD3
#define LCD_D3_tris TRISDbits.TRISD3
#define LCD_D4_pin  LATDbits.LATD4
#define LCD_D4_tris TRISDbits.TRISD4
#define LCD_D5_pin  LATDbits.LATD5
#define LCD_D5_tris TRISDbits.TRISD5
#define LCD_D6_pin  LATDbits.LATD6
#define LCD_D6_tris TRISDbits.TRISD6
#define LCD_D7_pin  LATDbits.LATD7
#define LCD_D7_tris TRISDbits.TRISD7


/* Private variables ************************************************/
static uint8_t row ;
static uint8_t column ;


////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE INICIALIZAR EL SISTEMA
//
//  Configura los pines como salida
//  Configura el display en el modo correcto
////////////////////////////////////////////////////////////////////////////////
void LCD_Initialize(void)
{
    LCD_RS_tris = 0;    //Pines de control como salidas
    LCD_RW_tris = 0;
    LCD_E_tris = 0;

    LCD_RW_pin = 0;     //Inicializamos los pines de control
    LCD_RS_pin = 0;
    LCD_E_pin = 0;     
    
    
    if (!LCD_MODE_4)
    {
        LCD_D0_tris = 0;    //Configuramos los pines como salidas
        LCD_D1_tris = 0;
        LCD_D2_tris = 0;
        LCD_D3_tris = 0;
        LCD_D4_tris = 0;
        LCD_D5_tris = 0;
        LCD_D6_tris = 0;
        LCD_D7_tris = 0;
        
        LCD_D0_pin = 0;     //Ponemos los pines a nivel bajo
        LCD_D1_pin = 0;
        LCD_D2_pin = 0;
        LCD_D3_pin = 0;
        LCD_D4_pin = 0;
        LCD_D5_pin = 0;
        LCD_D6_pin = 0;
        LCD_D7_pin = 0;
        
    LCD_E_pin = 1;          //Inicializamos display en modo 8 bits
    LCD_Wait_us ( LCD_INI_TIME   ) ;

    LCD_SendCommand ( LCD_COMMAND_SET_MODE_8_BIT, LCD_HS_OPERT + LCD_INI_TIME   ) ;
    LCD_SendCommand ( LCD_COMMAND_CURSOR_OFF, LCD_HS_OPERT ) ;
    LCD_SendCommand ( LCD_COMMAND_ENTER_DATA_MODE, LCD_NS_INSTR ) ;
    }
    
    else
    {
        LCD_D4_tris = 0;    //Configuramos los pines como salidas
        LCD_D5_tris = 0;
        LCD_D6_tris = 0;
        LCD_D7_tris = 0;
        
        LCD_D4_pin = 0;     //Ponemos los pines a nivel bajo
        LCD_D5_pin = 0;
        LCD_D6_pin = 0;
        LCD_D7_pin = 0;  
        
    LCD_E_pin = 1;          //Inicializamos display en modo 4 bits
    LCD_Wait_us ( LCD_INI_TIME   ) ;
    
    LCD_D4_pin = 1;     
    LCD_D5_pin = 1;
    
    LCD_E_pin = 1;
    LCD_Wait_us ( 50 ) ;
    LCD_E_pin = 0;
    LCD_Wait_us ( 5000 ) ;
    
    LCD_E_pin = 1;
    LCD_Wait_us ( 50 ) ;
    LCD_E_pin = 0;
    LCD_Wait_us ( 100 );
    
    LCD_E_pin = 1;
    LCD_Wait_us ( 50 ) ;
    LCD_E_pin = 0;
    LCD_Wait_us ( 5000 ) ;
    
    LCD_D4_pin = 0;
    LCD_E_pin = 1;
    LCD_Wait_us ( 50 ) ;
    LCD_E_pin = 0;
    LCD_Wait_us ( 100 ) ;


    
    LCD_SendCommand ( LCD_COMMAND_SET_MODE_4_BIT, LCD_HS_OPERT);
    LCD_SendCommand ( 0x0C, LCD_HS_OPERT);
    LCD_SendCommand ( 0x01, LCD_HS_OPERT);
    LCD_SendCommand ( 0x07, LCD_HS_OPERT);
    }

    LCD_ClearScreen ( ) ;
}






////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE HACER SCROLL DEL TEXTO
//
////////////////////////////////////////////////////////////////////////////////
void LCD_ScrollLeft (void)
{
    LCD_SendCommand (0x10 | 0x08 | 0x00, LCD_HS_OPERT); 
}

void LCD_ScrollRight (void)
{
    LCD_SendCommand (0x10 | 0x08 | 0x04, LCD_HS_OPERT);      
}

////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA PONER CURSOR EN UNA POSICION
//
////////////////////////////////////////////////////////////////////////////////
void LCD_SetCursor (uint8_t linea, uint8_t columna )
{
    
    if (linea == 0)
        linea = LCD_COMMAND_ROW_0_HOME;
    else if (linea == 1)
        linea = LCD_COMMAND_ROW_1_HOME;
    else if (linea == 2)
        linea = LCD_COMMAND_ROW_2_HOME;
    else 
        linea = LCD_COMMAND_ROW_3_HOME;
    
    if (columna > LCD_MAX_COLUMN)
        columna = LCD_MAX_COLUMN;
    
    row = linea;
    column = columna;
    
    LCD_SendCommand (0x80 | (row+column), LCD_HS_OPERT);
    
    
}

////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ESCRIBIR UNA CADENA
//
////////////////////////////////////////////////////////////////////////////////
void LCD_PutString ( char* inputString , uint16_t length )
{
    while (length--)
    {
        switch (*inputString)
        {
            case 0x00:
                return ;

            default:
                LCD_PutChar ( *inputString++ ) ;
                break ;
        }

    }
}




////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ESCRIBIR CARACTERES
//
// Recibe caracteres y cambia de linea automaticamente
////////////////////////////////////////////////////////////////////////////////
void LCD_PutChar ( char inputCharacter )
{
    if (column == LCD_MAX_COLUMN)
    {
        column = 0 ;
        if (row == 0 && LCD_MAX_ROW > 1)
        {
            LCD_SendCommand ( LCD_COMMAND_ROW_1_HOME , LCD_NS_INSTR  ) ;
            row = 1 ;
        }
        else if (row == 1 && LCD_MAX_ROW > 2)
        {
            LCD_SendCommand ( LCD_COMMAND_ROW_2_HOME , LCD_NS_INSTR  ) ;
            row = 2 ;
        }
        else if (row == 2 && LCD_MAX_ROW > 3)
        {
            LCD_SendCommand ( LCD_COMMAND_ROW_3_HOME , LCD_NS_INSTR  ) ;
            row = 3 ;
        }
        else
        {
            LCD_SendCommand ( LCD_COMMAND_ROW_0_HOME , LCD_NS_INSTR  ) ;
            row = 0 ;
        }
    }        
            
    LCD_SendData ( inputCharacter ) ;
    column++ ;
}


////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE BORRAR DISPLAY
//
//  Borra display
//  Salta a la posicion inicial
////////////////////////////////////////////////////////////////////////////////
void LCD_ClearScreen ( void )
{
    LCD_SendCommand ( LCD_COMMAND_CLEAR_SCREEN , LCD_NS_INSTR  ) ;
    LCD_SendCommand ( LCD_COMMAND_RETURN_HOME ,  LCD_NS_INSTR  ) ;

    row = 0 ;
    column = 0 ;
}




////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE HACER VISIBLE O NO EL CURSOR
//
////////////////////////////////////////////////////////////////////////////////

void LCD_CursorEnable ( bool enable )
{
    if (enable == true)
    {
        LCD_SendCommand ( LCD_COMMAND_CURSOR_ON , LCD_NS_INSTR  ) ;
    }
    else
    {
        LCD_SendCommand ( LCD_COMMAND_CURSOR_OFF , LCD_NS_INSTR  ) ;
    }
}


////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ENVIAR DATOS AL DISPLAY
//
//  Segun el tipo de configuracion 4bits o 8bits
////////////////////////////////////////////////////////////////////////////////
static void LCD_SendData ( char data )
{
    LCD_RW_pin = 0;
    LCD_RS_pin = 1;
    
    //LATD = (LATD & 0xFF00) | data;
    
    if (!LCD_MODE_4)
    {
    LCD_D0_pin = 0x01 & data>>0;     //Vamos escribiendo en cada pin el valor de posicion que le corresponde
    LCD_D1_pin = 0x01 & data>>1;
    LCD_D2_pin = 0x01 & data>>2;
    LCD_D3_pin = 0x01 & data>>3;
    LCD_D4_pin = 0x01 & data>>4;
    LCD_D5_pin = 0x01 & data>>5;
    LCD_D6_pin = 0x01 & data>>6;
    LCD_D7_pin = 0x01 & data>>7;
    }
    else
    {
    LCD_D4_pin = 0x01 & data>>4;
    LCD_D5_pin = 0x01 & data>>5;
    LCD_D6_pin = 0x01 & data>>6;
    LCD_D7_pin = 0x01 & data>>7;
    
    LCD_E_pin = 1;
    LCD_Wait_us ( 50 ) ;
    LCD_E_pin = 0;

    LCD_D4_pin = 0x01 & data>>0;     //Vamos escribiendo en cada pin el valor de posicion que le corresponde
    LCD_D5_pin = 0x01 & data>>1;
    LCD_D6_pin = 0x01 & data>>2;
    LCD_D7_pin = 0x01 & data>>3;
    }
        


    LCD_E_pin = 1;
    Nop ( ) ;
    Nop ( ) ;
    Nop ( ) ;
    LCD_E_pin = 0;
    LCD_RS_pin = 0;
    LCD_Wait_us (LCD_HS_OPERT ) ;
}


////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE ENVIAR COMANDOS AL DISPLAY
//
//  Segun el tipo de configuracion 4bits o 8bits
////////////////////////////////////////////////////////////////////////////////
static void LCD_SendCommand ( char command , unsigned int delay )
{
    
    LCD_RW_pin = 0;
    LCD_RS_pin = 0;
    
    //LATD = (LATD & 0xFF00) | command;
    
    if (!LCD_MODE_4)
    {
    LCD_D0_pin = 0x01 & command>>0;     //Vamos escribiendo en cada pin el valor de posicion que le corresponde
    LCD_D1_pin = 0x01 & command>>1;
    LCD_D2_pin = 0x01 & command>>2;
    LCD_D3_pin = 0x01 & command>>3;
    LCD_D4_pin = 0x01 & command>>4;
    LCD_D5_pin = 0x01 & command>>5;
    LCD_D6_pin = 0x01 & command>>6;
    LCD_D7_pin = 0x01 & command>>7;
    }
    else
    {
    LCD_D4_pin = 0x01 & command>>4;
    LCD_D5_pin = 0x01 & command>>5;
    LCD_D6_pin = 0x01 & command>>6;
    LCD_D7_pin = 0x01 & command>>7;
    
    LCD_E_pin = 1;
    LCD_Wait_us ( 50 ) ;
    LCD_E_pin = 0;

    LCD_D4_pin = 0x01 & command>>0;     //Vamos escribiendo en cada pin el valor de posicion que le corresponde
    LCD_D5_pin = 0x01 & command>>1;
    LCD_D6_pin = 0x01 & command>>2;
    LCD_D7_pin = 0x01 & command>>3;
    }
    
    
    LCD_E_pin = 1;
    Nop ( ) ;
    Nop ( ) ;
    Nop ( ) ;
    LCD_E_pin = 0;
    LCD_E_pin = 0;
    LCD_Wait_us ( delay ) ;
}


////////////////////////////////////////////////////////////////////////////////
//                  FUNCION ENCARGADA DE HACER RETARDO uS
//
////////////////////////////////////////////////////////////////////////////////
static void LCD_Wait_us ( unsigned int delay )
{
    for ( int x = 0; x < delay; x ++ ) 
    { 
    __delay_us(1); 
    }
}
				


5.3. Ejemplo 2: Usando las funciones avanzadas

 Este ejemplo, simplemente va escribiendo texto en el display y hace uso de algunas funciones como "LCD_SetCursor()":

				
/*
 * File:   main.c
 * Author: Eduardo
 *
 * Created on 11 de julio de 2017, 8:29
 */


#include 
#include "config.h"
#include "typedefs.h"
#include "lcd.h"
#include "xc.h"

//#define	_XTAL_FREQ	48000000		// se define la frecuencia FOSC -- Hay que tener en cuenta los preescalers usados

void delay_ms(uint16_t);

uint8_t a = 0;
uint8_t value = 0;
uint8_t numLed = 0;


void main(void) 
{
    LCD_Initialize();
    delay_ms(100);
    
    while (1)
    {
    LCD_ClearScreen();
    LCD_PutChar('H');
    LCD_PutChar('o');
    LCD_PutChar('l');
    LCD_PutChar('a');
    delay_ms(2000);
    
    LCD_SetCursor (0,0);
    
    LCD_PutChar('A');
    LCD_PutChar('d');
    LCD_PutChar('i');
    LCD_PutChar('o');
    LCD_PutChar('s');
    delay_ms(2000);
    
    LCD_ClearScreen();
    LCD_PutString("Martes 11 de Julio de 2017", 26);
    delay_ms(3000);
    //LCD_ClearScreen();
    LCD_SetCursor (1,0);
    LCD_PutString("Hoy es Martes 11 de Julio de 2017. Hace buen tiempo para ir a la playa", 70);
    delay_ms(3000);
    LCD_SetCursor (0,0);
    LCD_PutString("Hoy es Martes 11 de ", 20);
    LCD_SetCursor (1,0);
    LCD_PutString("Julio de 2017. Hace ", 20 );
    LCD_SetCursor (2,0);
    LCD_PutString("buen tiempo para ir ", 20 );
    LCD_SetCursor (3,0);
    LCD_PutString("a la playa", 10 );
    delay_ms(3000);
    
        
    while (true)
    {
    LCD_ScrollRight();
    delay_ms(500);
    }
    
    LCD_ClearScreen();
    }
    
}


void delay_ms(uint16_t i)
{
    for ( uint16_t x=0; x < i; x++ ) 
    { 
    __delay_ms(1); 
    }
}
				
				



- LCD funcionando:



6. Descargas:



www.microedu.es

Si chove, non orballa!