LCD AVR PANTALLA LCD 2×16 CON EL AVR
Una de las aplicaciones de las entradas salidas digitales AVR viene a ser el uso de las pantallas LCD, estas pantallas LCD son muy útiles para obtener información sobre lo que va ocurriendo en los registros, en las variables o como se van actualizando los datos que se este utilizando mientras se utiliza el microcontrolador AVR.La pantalla LCD que se comentará y que será la que se utilice en los ejemplos con los microcontroladores AVR será la de 2 filas por 16 columnas, que es la que aparece en la imagen, esta se alimenta a 5VCC, como se ve consta de 16 pines, el pin 1 es el negativo de la alimentación, el pin 2 es el positivo de la alimentación, y el pin 3 es para el contraste de los caracteres que se visualizan.
Los pines 4, 5 y 6 son para el control de la pantalla LCD, los pines 7 al 14 son utilizados para el envió y recepción de datos en un grupo de 8 bits, pero resulta que se le puede hacer trabajar con solo 4 pines, de este modo se ahorran pines del microcontrolador.
Los pines 15 y 16 son para unos leds de fondo de pantalla, esto es para iluminar la pantalla si así se desea, algunas pantallas LCD no cuentan con estos pines.
Se encuentra una guía sobre como utilizar la pantalla LCD en este enlace.
El siguiente es el vídeo publicado por MrElberni sobre el uso de las pantallas LCD.
En este caso se ha preparado un código para hacer trabajar la pantalla LCD con el Microcontrolador AVR utilizando el XC8, se necesitarán un total de 7 pines del microcontrolador, son muchos pero para hacer pruebas de visualización por ahora vale la pena.
Para tener un orden al programar se recomienda que el siguiente código para el manejo del LCD AVR sea incluida en un archivo de cabecera dentro del mismo proyecto en el que se esté trabajando, para ello en el MPLABX, en la pestaña del proyecto se hará click derecho sobre Header Files -> new -> C Header File, poner como nombre lcd, esto creará el archivo de cabecera lcd.h, como se muestra en la imagen.
Para el ejemplo el proyecto se ha llamado lcd1, el programa principal que está en Suorce Files se llamo ejemplolcd.c y el archivo creado en Header Files será lcd.h, es el mostrado en la imagen, en este archivo en la parte resaltada se colocará el código siguiente para el uso de la pantalla LCD con el microcontrolador AVR, este lcd.h luego será incluido en el programa principal.
El código a utilizar es el siguiente:
#define middr DDRD //se usará el puerto D
#define mipuerto PORTD //si se quiere otro puero se puede cambiar
#define rs 0 //Pin rs al pin PD0 del AVR
#define ddr_rs 0
#define rw 1 //Pin rw al pin PD1 del AVR
#define ddr_rw 1
#define e 2 //Pin e al pin PD2 del AVR
#define ddr_e 2
#define db4 4 //Pin data4 al pin PD4 del AVR
#define ddr_db4 4
#define db5 5 //Pin data5 al pin PD5 del AVR
#define ddr_db5 5
#define db6 6 //Pin data6 al pin PD6 del AVR
#define ddr_db6 6
#define db7 7 //Pin data7 al pin PD7 del AVR
#define ddr_db7 7
void lcd_inicia();
void lcd_pulso();
void lcd_orden(uint8_t);
void lcd_caracter(uint8_t);
void lcd_mensaje(const char*);
void lcd_limpiar();
void lcd_acasa();
void lcd_ubicate(uint8_t,uint8_t);
void lcd_inicia(){
//los pines a utilizar como salidas digitales
middr|=(1<<ddr_rs);
middr|=(1<<ddr_rw);
middr|=(1<<ddr_e);
middr|=(1<<ddr_db4);
middr|=(1<<ddr_db5);
middr|=(1<<ddr_db6);
middr|=(1<<ddr_db7);
//las salidas se inician a 0
mipuerto&=~(1<<rs);//rs=0;
mipuerto&=~(1<<rw);//rw=0;
mipuerto&=~(1<<e);//e=0;
mipuerto&=~(1<<db4);//db4=0;
mipuerto&=~(1<<db5);//db5=0;
mipuerto&=~(1<<db6);//db6=0;
mipuerto&=~(1<<db7);//db7=0;
_delay_ms(20); //secuencia de inicio
mipuerto=0X03<<4;
lcd_pulso();
_delay_us(4100);
mipuerto=0X03<<4;
lcd_pulso();
_delay_us(4100);
mipuerto=0X03<<4;
lcd_pulso();
_delay_us(150);
mipuerto=0X02<<4;//a 4 bits
lcd_pulso();
lcd_orden(0x28);//a 4 bits,2 lineas, 5×7 puntos
_delay_us(80);
lcd_orden(0x0c);//display encendido,no muestra cursor,sin parpadeo
_delay_us(80);
lcd_orden(0x01);//Limpia pantalla;
_delay_ms(2);
lcd_orden(0x06);//incremento a la derecha, sin desplazamiento de display
_delay_us(80);
}
void lcd_pulso(){ //función para habilitar el LCD
mipuerto|=(1<<e);//e=1
_delay_us(40);
mipuerto&=~(1<<e);//e=0
_delay_us(40);
}
void lcd_orden(uint8_t orden){ //Función para enviar ordenes al LCD
mipuerto&=~(1<<rs);//rs=0
mipuerto=(((((mipuerto>>4&0x0f)|0x0f)&(orden>>4&0x0f))<<4)|(mipuerto&0x0f));
lcd_pulso();
mipuerto=(((((mipuerto>>4&0x0f)|0x0f)&(orden&0x0f))<<4)|(mipuerto&0x0f));
lcd_pulso();
}
void lcd_caracter(uint8_t caracter){ //Función para enviar caracteres al LCD
mipuerto|=(1<<rs);//rs=1
mipuerto=(((((mipuerto>>4&0x0f)|0x0f)&(caracter>>4&0x0f))<<4)|(mipuerto&0x0f));
lcd_pulso();
mipuerto=(((((mipuerto>>4&0x0f)|0x0f)&(caracter&0x0f))<<4)|(mipuerto&0x0f));
lcd_pulso();
mipuerto&=~(1<<rs);//rs=0
}
void lcd_mensaje(const char* cadena){ //Función para enviar cadenas de caracteres al LCD
while(*cadena != 0x00){
lcd_caracter(*cadena);
cadena++;
}
}
void lcd_limpiar(){ //Función para limpiar la pantalla LCD
lcd_orden(0x01);
_delay_ms(2);
}
void lcd_acasa(){ //Función par enviar el cursor al inicio de la pantalla
lcd_orden(0x02);
_delay_ms(2);
}
void lcd_ubicate(uint8_t linea,uint8_t columna){ //Función para ubicar el cursor
lcd_acasa(); //en cualquier ubicación del LCD
if (linea==1){
for(uint8_t i=1; i<columna; i++){
lcd_orden(0x14);
}
}
if(linea==2){
for (uint8_t i=1;i<(columna+40);i++){
lcd_orden(0x14);
}
}
}
Una vez pegado el código en la parte indicada, estará listo para utilizarse, en la siguiente imagen se muestra parte de como se verá.
PANTALLA LCD AVR EJEMPLO DE USO 1
El código está preparado para utilizarse con el puerto D, pero puede cambiarse al B por ejemplo con solo cambiar en la línea que se indica la D por B, el microcontrolador a utilizar será el ATMEGA88, en la siguiente imagen se indica como tendrán que ser las conexiones:
Las funciones existentes para el manejo de la pantalla lcd son:
void lcd_inicia(); //se usará siempre par inicializar el LCD
void lcd_pulso();//se usa internamente en el código
void lcd_orden(uint8_t);//se usa internamente en el código
void lcd_caracter(uint8_t);//para enviar caracteres a la pantalla LCD
void lcd_mensaje(const char*);//para enviar texto a la pantalla LCD
void lcd_limpiar();//para limpiar la pantalla
void lcd_acasa();//Función par enviar el cursor al inicio de la pantalla
void lcd_ubicate(uint8_t,uint8_t);//para ubicar el cursor fila, columna
La función lcd_inicia() siempre será necesaria para poder utilizar la pantalla LCD AVR, de las demás se usará l a función lcd_ubicate(fila,columna), donde fila solo puede tomar valores de 1 o 2 ya que solo se tendrán 2 filas, mientras columna puede tomar valores de 1 a 40, normalmente se usara de 1 a 16.
La otra función a utilizar normalmente será lcd_caracter(carcter) para enviar caracteres individuales a pantalla, la función mas utilizada será lcd_mensaje(texto), esta permitirá enviar cadena de texto a la pantalla LCD AVR.
En el ejemplo se enviará por pantalla en la primera fila el texto "MrElberni", y en la segunda fila "Suscríbete".
El código realizado en el MPLABX con el XC8, donde se incluye el archivo de cabecera lcd.h es el siguiente
#define F_CPU 20000000UL //velocidad del oscilador 20MHz
#include <avr/io.h>//necesario para las definciones de los registros
//y pines del AVR
#include <util/delay.h>//necesario para poder hacer pausas con delay
#include "lcd.h" //archivo de cabecera creado necesario
int main(void) {
DDRB|=(1<<1);//pin PB1 como salida digital
DDRB|=(1<<2);//pin PB2 como salida digital
PORTB&=~(1<<1);//pin PB1 inicia led apagado
PORTB|=(1<<2);//pin PB2 inicia led encendido
lcd_inicia();//se inicializa la pantalla lcd AVR
while (1) {//ciclo principal del programa
lcd_ubicate(1,1);//ubica el cursor en la fila 1 columna 1
lcd_mensaje("MrElberni");//mensaje primera fila
lcd_ubicate(2,1);//ubica el curso en la fila 2 columna 1
lcd_mensaje("Suscribete");//mesaje segunda fila
PORTB^=(1<<1);//pin PB1 cambia de estado
PORTB^=(1<<2);//pin PB2 cambia de estado
_delay_ms(200);//para ver el parpadeo de los leds
}
}
La siguiente es la imagen del resultado obtenido con el ATMEGA88 utilizando una pantalla LCD AVR
PANTALLA LCD AVR EJEMPLO DE USO 2
Se seguirá utilizando el mismo circuito utilizado para el ejemplo1, es decir el LCD AVR conectado al puerto D del ATmega88, en este caso se quieren ver datos numéricos en el LCD, pero resulta que a la pantalla LCD AVR solo se le pueden enviar caracteres y no valores numéricos, por lo tanto se tiene que convertir el valor numérico que se desea visualizar en el LCD AVR en una cadena de caracteres, para esto será necesario incluir el archivo de cabecera:
#include <stdio.h>
Esta librería contiene una función llamada sprintf cuya sintaxis es la siguiente:
sprintf(arreglo,”cadena a almacenar en arreglo %(especificador)”,dato);
Donde arreglo es un array de tipo char de una longitud adecuada, donde se guardará todo lo que aparece entre comillas en forma de cadena de caracteres, especificador es para indicar de que tipo es dato, %d para tipo entero, %f para tipo real, %s para tipo cadena, %c para tipo carácter, hay mas pero para el uso del LCD AVR son suficientes.
Por ejemplo si se tiene un numero real con un valor de 7.93 y se quiere visualizar en el LCD AVR, utilizando la función sprintf para ver en la pantalla LCD AVR el mensaje “Num real = 3.27”, entonces se crea un arreglo de una longitud de 16, será suficiente para almacenar la cantidad de caracteres del mensaje, y como el número es real entonces el especificador tiene que ser %f, luego
char cadena[16];//arreglo para almacenar el mensaje
sprintf(cadena,”Num real = %f”,7.93);//se almacena en el arreglo cadena el mensaje
lcd_mensaje(cadena);//para ver en la pantalla LCD AVR lo guardado en cadena
El siguiente es un código preparado en el XC8 para la visualización de un número entero de 8 bits en la segunda fila de la pantalla LCD AVR, este número irá cambiando su valor en cada ciclo de programa:
#define F_CPU 20000000UL //velocidad del oscilador 20MHz
#include <avr/io.h>//necesario para las definciones de los registros
//y pines del AVR
#include <util/delay.h>//necesario para poder hacer pausas con delay
#include <stdio.h> //para poder convertir numero a cadenas
#include "lcd.h" //archivo de cabecera creado necesario
char numcad[5];//arreglo donde se guarda el numero entero convertido a cadena
uint8_t numero=0;//numero de 8 bits a ser visto en el LCD inicia a 0
int main(void) {
DDRB|=(1<<1);//pin PB1 como salida digital
DDRB|=(1<<2);//pin PB2 como salida digital
PORTB&=~(1<<1);//pin PB1 inicia led apagado
PORTB|=(1<<2);//pin PB2 inicia led encendido
lcd_inicia();//se inicializa la pantalla lcd AVR
while (1) {//ciclo principal del programa
lcd_ubicate(1,1);//ubica el cursor en la fila 1 columna 1
lcd_mensaje("MrElberni AVR");//mensaje primera fila
sprintf(numcad,"%d",numero);
lcd_ubicate(2,1);//ubica el curso en la fila 2 columna 1
lcd_mensaje(numcad);//mesaje segunda fila
PORTB^=(1<<1);//pin PB1 cambia de estado
PORTB^=(1<<2);//pin PB2 cambia de estado
numero++;
if(numero>255){
numero=0;
}
_delay_ms(200);//para ver el parpadeo de los leds
}
}
PANTALLA LCD AVR EJEMPLO DE USO 3
Se seguirá utilizando el mismo circuito utilizado para el ejemplo1, es decir el LCD AVR conectado al puerto D del ATmega88, en este caso se quieren ver datos numéricos reales en el LCD, pero resulta que a la pantalla LCD AVR solo se le pueden enviar caracteres y no valores numéricos, por lo tanto se tiene que convertir el valor numérico que se desea visualizar en el LCD AVR en una cadena de caracteres.
En este caso para el ATMEGA88 el XC8 al utilizar la función sprintf no nos deja manipular números reales, tampoco encontramos la función itoa que es para convertir números enteros a cadenas, por lo que nos la tenemos que crear, en este ejemplo se ve la manera de crearse la función itoa, para luego utilizarla para poder visualizar números reales en la pantalla LCD AVR
El código utilizado es el siguiente:
#define F_CPU 20000000UL //velocidad del oscilador 20MHz
#include <avr/io.h>//necesario para las definciones de los registros
//y pines del AVR
#include <util/delay.h>//necesario para poder hacer pausas con delay
//#include <stdio.h> //para poder convertir numero a cadenas
#include "lcd.h" //archivo de cabecera creado necesario
char numcad[10];//arreglo donde se guarda la parte entera convertido a cadena
char numcad2[10];//arreglo donde se guarda la parte decimal convertido a cadena
uint16_t numero=1;//será el que cambie, se usará para ser multiplicado por un float
float miflo=1.1;//será el que se multiplique con número
float mirar=1;//será el número a ser visto en el LCD
uint16_t entero=0;//para obtener la parte entera de mirar
uint16_t decimal=0;//para obtener la parte decimal de mirar
void itoa(uint16_t , char *);//función para convertir un número en cadena
int main(void) {
DDRB|=(1<<1);//pin PB1 como salida digital
DDRB|=(1<<2);//pin PB2 como salida digital
PORTB&=~(1<<1);//pin PB1 inicia led apagado
PORTB|=(1<<2);//pin PB2 inicia led encendido
lcd_inicia();//se inicializa la pantalla lcd AVR
while (1) {//ciclo principal del programa
lcd_ubicate(1,1);//ubica el cursor en la fila 1 columna 1
lcd_mensaje("MrElberni AVR");//mensaje primera fila
// sprintf(numcad,"%d",numero);//guarda numero en numcad
itoa(entero,numcad);//parte entera se guarda en numcad
itoa(decimal,numcad2);//parte decimal se guarda en mumcad2
lcd_ubicate(2,1);//ubica el curso en la fila 2 columna 1
lcd_mensaje(numcad);//para ver la parte entera de mirar
lcd_mensaje(",");//para separar la parte entera de la decimal
lcd_mensaje(numcad2);//para ver la parte entera de mirar
lcd_mensaje(" ");//para borrar caracteres finales innecesarios
PORTB^=(1<<1);//pin PB1 cambia de estado
PORTB^=(1<<2);//pin PB2 cambia de estado
//En lo que sigue se cambia el valor de mirar en cada ciclo del programa
mirar=numero*miflo;//cambia el valor de mirar
entero=(uint16_t)mirar;//se obtiene la parte entera de mirar
decimal=(uint16_t)(mirar*100)%100;//se obtiene la parte decimal de mirar
numero++;//para cambiar mirar se cambia el valor de número en cada ciclo
if(numero>100){//cuando numero llega a 100
numero=1;//se reinicia a 1
}
_delay_ms(1000);//para ver mirar en el LCD
}
}
void itoa(uint16_t num, char guardacad[]){//función para convertir un número en cadena
char digitos[]="0123456789";//arreglo para obtener los digitos
if(num<0){ //si el número es negativo
*guardacad++ = '-';//en guardacad[1] se pone un -
num *= -1;//el número se hace positivo
}
int valor = num;//se usará para recorrer los digitos del número
do{ //este ciclo se realizará mientras el número de digitos de valor sea diferente de 0
++guardacad;//se avanza una ubicación en guardacadena
valor = valor/10;//valor se reduce en un digito
}while(valor);//mienras el número de digitos de valor sea diferente de 0
//Se han recorrido todos los digitos del número mas una ubicación
*guardacad = '\0';//en C siempre se agrega al final de una cadena
do{//para colocar los digitos del número en el arreglo guardacad
*--guardacad = digitos[num%10];//ahora se retrocede en el arreglo donde se coloca
//el digito que le corresponde del arreglo digitos
//de acuerdo a lo que se obtenga de num%10
num = num/10;//el número se reduce en un digito
}while(num);//mientras el número sea diferente de 0
//al final el número ha sido convertido en cadena y guardado en el arreglo guardacad
}
La imagen del resultado es la siguiente:
Esperamos de todo corazón ser de vuestra ayuda, no olviden suscribirse al canal de mrelberni, darle me gusta a los vídeos, compartirlos, que de esa manera nos ayudan a continuar, desde ya muchas gracias.
Publicar un comentario