ELECTRONICA DIGITAL

PIC16F877A

LCD
DEL LIBRO: COMPILADOR C CCS Y SIMULADOR PROTEUS PARA MICROCONTROLADORES PIC EDUARDO GARCIA BREIJO

Comando: lcd_init();
Es la primera función que debe ser llamada.

Borra el LCD y lo configura en el formato de 4 bits, con dos líneas y con caracteres de 5x8 puntos, en modo encendido, cursor apagado y sin parpadeo.

Configura el LCD con un autoincremento del puntero de direcciones y sin desplazamiento del display real.

Comando: lcd_gotoxy(byte x, byte y);
Mueve el curso a la posición (x, y). Por ejemplo (5,1) indica la posición 5 en x (fila) y 1 en y (columna).

Comando: lcd_getc(byte x, byte y);
Lee el carácter de la posición (x,y).

Comando: lcd_putc (char s);
s es una variable de tipo char. Esta función escribe la variable en la posición correspondiente. Si, además, se indica:

/f: Se limpia el LCD.
/n: el cursor va a la posición (1,2).
/b: el cursor retrocede una posición.

El compilador de C ofrece una función más versátil para trabajar con el LCD.

printf(string);
printf(cstring,values...);
printf(fname,cstring,values...);

String es una cadena o un array de caracteres, values es una lista de variables separadas por comas y fname es una función..

El formato es %nt, donde n es opcional y puede ser:

1-9: Para especificar cuántos caracteres se deben especificar.
01-09: para indicar la cantidad de ceros a la izquierda.
1.1-9.9 para coma flotante.

t puede indicar:

c: Carácter.
s: Cadena o carácter.
u: Entero sin signo.
d: Entero con signo.
Lu: Entero largo sin signo.
Ld: Entero largo con signo.
x: Entero hexadecimal (minúsculas).
X: Entero hexadecimal (mayúsculas).
Lx: entero largo hexadecimal (minúsculas)
LX: Entero largo hexadecimal (mayúsculas).
f: Flotante con truncado.
g: Flotante con redondeo.
e: Flotante en formato exponencial.
w: Entero sin signo con decimales insertados. La primera cifra indica el total, la segunda el número de decimales.


Formato Valor = 0x12 Valor = 0xFE
%03u 018 254
%u 15 254
%2u 18 *
%5 18 254
%d 18 -2
%x 12 fe
%X 12 FE
%4X 0012 00FE
%3.1w 1.8 25.4

Ejemplo.
byte x,y,z;
printf("Hola");
printf("Valor => %2x\n\r", get_rtcc());
printf("%2u %X %4X\n\r", x, y, z);
printf(LCD_PUTC, "n = %u", n);


El driver <lcd.c> está pensado para trabajar con el PORTD o el PORTB. Por defecto, utiliza el PORTD a menos que le indiquemos lo contrario mediante:

Formato: #define use_portb_lcd TRUE

Por defecto, este drive usa siete terminales para la comunicación entre el LCD y el PIC. En la 

Ejercicio 1. Realizar un programa en C utilizando el PIC16F877A y la pantalla LCD 16x2 que simule una carga (Loading).

Solución. Componentes a utilizar:

- PIC16F877A
- LCD (LM016L).

El circuito en ISIS:



El código en CCS C Compiler:


#include <16F877A.h>
#fuses xt,nowdt
#use delay(clock=4000000)
#include <stdlib.h>

#include "lcd.c"  // Librería LCD.
void main() {
     lcd_init (); // Inicializa la librería para manejar el LCD.
     // Variable local
     int i; // Usada por el FOR.
     printf (LCD_PUTC, "\f"); //Borra o limpia la LCD
     while ( true )  {
           lcd_gotoxy(1,1);
           printf(LCD_PUTC, "Loading");
           for (i = 1; i <= 16; ++i) {
               lcd_gotoxy(i,2);
               printf(LCD_PUTC, "*");
               delay_ms( 500 );
           }
           printf(LCD_PUTC, "\f");
     }
}


Ejercicio 2. Realizar un programa en C utilizando el PIC16F877A y la pantalla LCD  16x2 que genere un asterisco y que gire alrededor en sentido horario.

Solución.  El circuito en ISIS:



Vamos a declarar que el puerto RC es el de salida:

El código en CCS C Compiler:

#include <16F877A.h>
#fuses xt, nowdt
#use delay(clock=4000000) 
#define LCD_RS_PIN PIN_C0
#define LCD_RW_PIN PIN_C1
#define LCD_ENABLE_PIN PIN_C2
#define LCD_DATA4 PIN_C4
#define LCD_DATA5 PIN_C5
#define LCD_DATA6 PIN_C6
#define LCD_DATA7 PIN_C7
#include "lcd.c"  // Librería LCD.
void main() {
     lcd_init (); // Inicializa la librería para manejar el LCD.
     // Variable local
     int i; // Usada por el FOR.
     printf (LCD_PUTC, "\f"); //Borra o limpia la LCD
     for (i = 1; i <= 16; i++) {
         lcd_gotoxy (i,1);
         printf (LCD_PUTC, "*");
         delay_ms (75);
         printf (LCD_PUTC, "\f");
     }
     for (i = 16; i >= 1; --i) {
         lcd_gotoxy (i,2);
         printf (LCD_PUTC, "*");
         delay_ms (75);
         printf (LCD_PUTC, "\f");
     }
     while ( true )  {
  }

}


Ejercicio 3. Se configuran los terminales RB1 como salida y el RB0 como entrada (con resistencia de pull-up). La salida debe tener el mismo valor que la entrada. Se utiliza un interruptor en la entrada y un LED en la salida.


Solución. El circuito en ISIS:



El código en CCS C Compiler:

#include <16F877A.h>
#fuses XT, NOWDT
#use delay (clock = 4M)                //Reloj de 4M.
#byte trisB = 0x86                     //trisB en 86h.
#byte portB = 0x06                     //portB en 06h.
#byte option_reg = 0x81                //option_reg en 81h.

void main () {
     bit_clear(option_reg,7);          //habilitación pull-up.
     bit_set(trisB,0);                 //B0 como entrada.
     bit_clear(trisB,1);               //B1 como salida.
     bit_clear(portB,1);               //Apaga el LED.
     while (true) {
           if (bit_test(portB,0) == 1) //Si RB0 es 1, apaga el LED.
              bit_clear(portB,1);
           else
              bit_set(portB,1);        //sI rb0 = 0, enciende el LED.
     }

}

Ejercicio 4. Diseñar un circuito contador del 0 al 9.

Solución. El circuito en ISIS:



El código en CCS C Compiler:

#include <16F877A.h>
#fuses hs, nowdt
#use delay(clock = 4M)

int unid[10] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 103};
int i;

void main() {
     set_tris_b(0b00000000);
     output_b(0b00000000);
     i = 0;
     while (true) {
           for (i = 0; i < 10; i++) {
               output_b(unid[i]);
               delay_ms(500);
           }
     }
}


Ejercicio 5. Diseñar un circuito contador del 0 al 99.

Solución. El circuito en ISIS:



El código en CCS C Compiler:

#include <16F877A.h>
#fuses hs, nowdt
#use delay(clock = 4M)

int unid[10] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 103};
int i,j;

void main() {
     set_tris_b(0b00000000);
     set_tris_c(0b00000000);
     output_b(0b00000000);
     output_c(0b00000000);
     while (true) {
           for (i = 0; i < 10; i++) {
               if (i == 0) {
                  output_b(0b00000000);
               }
               if (i > 0) {
                    output_b(unid[i]);
                 }
               for (j = 0; j < 10; j++) {
                   output_c(unid[j]);
                   delay_ms(500);
               }
           }
     }
}


Ejercicio 6. Diseñar un circuito contador del 0 al 999.

Solución. El circuito en ISIS:


El código en CCS C Compiler:

#include <16F877A.h>
#fuses hs, nowdt
#use delay(clock = 4M)

int unid[10] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 103};
int i, j, k;

void main() {
     set_tris_b(0b00000000); //Inicializa el puerto b como salida.
     set_tris_c(0b00000000); //Inicializa el puerto c como salida.
     set_tris_d(0b00000000); //Inicializa el puerto d como salida.
     output_b(0b00000000);   //Inicializa el puerto b en cero.
     output_c(0b00000000);   //Inicializa el puerto c en cero.
     output_d(0b00000000);   //Inicializa el puerto d en cero.
     while (true) {
           for (i = 0; i < 10; i++) {
               if (i == 0) {
                  output_d(0b00000000);
               } else {
                    output_d(unid[i]);
                 }
               for (j = 0; j < 10; j++) {
                   if (i == 0 && j == 0) {
                      output_c(0b00000000);
                   } else {
                      output_c(unid[j]);
                   }
                   for (k = 0; k < 10; k++) {
                       output_b(unid[k]);
                       delay_ms(300);
                   }
               }
           }
     }
}

Ejercicio 7. Desarrollar un programa que permita realizar el conteo de pelotas que pasa por un ducto, el cual debe ser visualizado en un display de 7 segmentos. El contador solo contará hasta 9 pelotas..

Solución. El circuito EN ISIS:



El código en CCS C Compiler:

#include <16F877A.h>
#fuses xt, nowdt
#use delay(clock=4M)
#use standard_io(A)

int unid[10] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 103};
int i=0;
#int_ext
void int_rb0() {
     i = i + 1;
     if (i > 9)  {
        output_c(0b00000000);
        i = 0;
     }
     if (i > 0) {
        output_c(unid[i]);
     }
}

void main () {
     set_tris_b(0b00000001);
     output_c(0b00000000);
     port_b_pullups(true);
     enable_interrupts(int_ext);
     ext_int_edge(h_to_l);
     enable_interrupts(global);
     while(true) {
     }
}

El mismo problema pero utilizando un LCD.

El circuito en ISIS:


El código en CCS C COMPILER:

#include <16F877A.h>
#fuses xt,nowdt
#use delay(clock=4000000)
#include <stdlib.h>
#include <lcd.c>
int i = 0;
float j;
#int_ext

void int_rb0() {
      i = i + 1;
     if (i >= 0) {
        j = (float)(i);
        lcd_gotoxy(1,1);
     printf (LCD_PUTC, "\f");     
        printf(LCD_PUTC,"%f",j);
     }
     if (i > 9) {
        i = 0;
        j = (float)(i);
        printf (LCD_PUTC, "\f");        
        printf(LCD_PUTC,"%f",j);
     }          
}
void main() {
     lcd_init ();
     set_tris_b(0b00000001);
     port_b_pullups(true);
     enable_interrupts(int_ext);
     ext_int_edge(h_to_l);
     enable_interrupts(global);

     while (true) {}

}

Ejercicio 8. Encender y apagar, consecutivamente, un LED en la patilla RB7 cuando se produzca un cambio de nivel en la patilla RB0. 

Solución. El circuito en ISIS:



El código en CCS C Compiler:

#include <16F877A.h>
#fuses xt, nowdt
#use delay(clock=4M)

#int_ext

void int_rb0() {
   output_toggle(PIN_B7);
}

void main () {
     set_tris_b(0b00000001);
     output_low(PIN_B7);
     port_b_pullups(true);
     enable_interrupts(int_ext);
     ext_int_edge(h_to_l);
     enable_interrupts(global);
     while(true) {
     }
}

El resultado en video:



Ejercicio 9. Generar una señal cuadrada de 1KHz utilizando la interrupción del TIMER0.

Solución. Para generar una señal de 1 KHz se necesita un semiperíodo de 500 s. Según la ecuación de desbordamiento del K, utilizando un cristal de 4 MHz y un prescaler de 2:

Sustituyendo los valores:

resolviendo la ecuación  , es decir, se debe cargar el TIMER0 con el valor 6. Pero esta relación sólo se cumple si se trabaja en ensamblador. Al trabajar en C, el compilador genera líneas de código que aumentan el tiempo de ejecución del programa y, por ello, es necesario ajustar el valor final. En este caso se ha utilizado un valor de carga de 29 (0x1D).

Ejercicio 10. Utilizando el microcontrolador PIC16F877A con una frecuencia de reloj de 4 MHz, el cual controla un par de semáforos en una avenida como se muestra en la figura.

Como se puede ver en la figura el semáforo tiene una avenida y una calle que pasa la avenida perpendicularmente, y una calle que ingresa a la avenida. La secuencia entre la avenida y la calle perpendicular se muestra en la siguiente figura. La duración de la secuencia es de 30 s, 15 s de rojo en alto y 15 s de rojo en bajo.


Cuando el sensor 1 detecta un vehículo inicia la siguiente secuencia por 15 segundos.


Solución. El circuito en ISIS:


El código en CCS C COMPILER:

#include <16f877a.h>
#fuses xt, nowdt
#use delay(clock=4M)              //Reloj de 4 mhz
#use standard_io(b)
#use standard_io(c)

#int_ext

void int_rb0() {
           output_low(pin_b1);
           output_high(pin_b2);
           output_low(pin_b3);
           output_low(pin_b4);
           output_high(pin_b5);
           output_low(pin_b6);
           output_low(pin_b7);
           output_high(pin_c0);
           output_low(pin_c1);
           output_high(pin_c2);
           output_low(pin_c3);
           output_low(pin_c4);           
           delay_ms(3000);
           output_high(pin_b1);
           output_low(pin_b2);
           output_low(pin_b3);
           output_high(pin_b4);
           output_low(pin_b5);
           output_low(pin_b6);
           output_low(pin_b7);
           output_low(pin_c0);
           output_high(pin_c1);
           output_low(pin_c2);
           output_low(pin_c3);
           output_high(pin_c4); 
           delay_ms(6000);
           output_high(pin_b1);
           output_low(pin_b2);
           output_low(pin_b3);
           output_high(pin_b4);
           output_low(pin_b5);
           output_low(pin_b6);
           output_low(pin_b7);
           output_low(pin_c0);
           output_high(pin_c1);
           output_low(pin_c2);
           output_high(pin_c3);
           output_low(pin_c4); 
           delay_ms(3000);
           output_high(pin_b1);
           output_low(pin_b2);
           output_low(pin_b3);
           output_high(pin_b4);
           output_low(pin_b5);
           output_low(pin_b6);
           output_low(pin_b7);
           output_high(pin_c0);
           output_low(pin_c1);
           output_low(pin_c2);
           output_high(pin_c3);
           output_low(pin_c4); 
           delay_ms(3000);
}
void main () {
     set_tris_b(0b00000001);
     port_b_pullups(true);
     enable_interrupts(int_ext);
     ext_int_edge(l_to_h);
     enable_interrupts(global);
     output_low(pin_b1);
     output_low(pin_b2);
     output_low(pin_b3);
     output_low(pin_b4);
     output_low(pin_b5);
     output_low(pin_b6);
     output_low(pin_b7);
     output_low(pin_c0);
     output_low(pin_c1);
     output_low(pin_c2);
     output_low(pin_c3);
     output_low(pin_c4);     
     while (true) {
           output_high(pin_b1);
           output_low(pin_b2);
           output_low(pin_b3);
           output_low(pin_b4);
           output_low(pin_b5);
           output_high(pin_b6);
           output_low(pin_b7);
           output_low(pin_c0);
           output_high(pin_c1);
           output_high(pin_c2);
           output_low(pin_c3);
           output_low(pin_c4);           
           delay_ms(10000);
           output_high(pin_b1);
           output_low(pin_b2);
           output_low(pin_b3);
           output_low(pin_b4);
           output_high(pin_b5);
           output_low(pin_b6);
           output_low(pin_b7);
           output_high(pin_c0);
           output_low(pin_c1);
           output_high(pin_c2);
           output_low(pin_c3);
           output_low(pin_c4); 
           delay_ms(5000);
           output_low(pin_b1);
           output_low(pin_b2);
           output_high(pin_b3);
           output_high(pin_b4);
           output_low(pin_b5);
           output_low(pin_b6);
           output_high(pin_b7);
           output_low(pin_c0);
           output_low(pin_c1);
           output_high(pin_c2);
           output_low(pin_c3);
           output_low(pin_c4); 
           delay_ms(10000);
           output_low(pin_b1);
           output_high(pin_b2);
           output_low(pin_b3);
           output_high(pin_b4);
           output_low(pin_b5);
           output_low(pin_b6);
           output_high(pin_b7);
           output_low(pin_c0);
           output_low(pin_c1);
           output_high(pin_c2);
           output_low(pin_c3);
           output_low(pin_c4); 
           delay_ms(5000);
     }
}

Ejercicio 11. Desarrollar un sistema con el microcontrolador PIC16F877A el cual debe generar una señal de onda cuadrada con una frecuencia de 500Hz.

Solución. El tiempo de desbordamiento del timer1 se calcula según la siguiente ecuación:


Para nuestro ejercicios los datos son:

 s

Para el Prescaler hay que proba con 2, 4, 8; para nuestro ejercicio se usa 8, sustituyendo:


Resolviendo esta ecuación:


El circuito simulado en ISIS:


El código en CCS C Compiler:

#include <16F877A.h>
#fuses XT, NOWDT
#use delay (clock = 4M)

#int_timer1
void mi_interrupcion () {
     output_toggle(pin_b0);
     set_timer1(3036);
}
void main () {
     set_tris_b(0b0);    //Configuramos el puerto B como salida. 
     output_b(0b0);       //Inicializamos en cero.
     setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); //Configuramos el timer1 con reloj interno y el escaler 8.
     set_timer1(3036);   //Cargamos el valor del registro.
     enable_interrupts(int_timer1);  //Habilitamos la interrupción.
     enable_interrupts(global);      //De forma global.
     while (true) {
     }
}

Ejercicio 12. Utilizando el TIMER1 como contador crear un programa para desplegar por LCD un contador.

Solución. El circuito en ISIS:


El código en CCS C Compiler:

#include <16F877A.h>
#fuses XT, PUT, NOWDT
#use delay(clock = 4M)
#include <lcd.c>
long pulsos;

void main () {
     lcd_init();
     setup_timer_1(T1_EXTERNAL | RTCC_EXT_L_TO_H | RTCC_DIV_1);
     set_timer1(0);
     
     while (true) {
           pulsos = get_timer1();
           lcd_gotoxy(6,1);
           printf(lcd_putc, "PULSOS: %lu", pulsos);
           if (pulsos >= 65535) {
              pulsos = 0;
              set_timer1(0);
           }
     }
}

Ejercicio 13. Realizar un programa que simule un reloj digital con el PIC16F877A.

Solución. Material a utilizar:


  • PIC16F877A.
  • LM016L.
  • OSCILADOR.
  • DCLOCK
El DCLOCK debe tener una frecuencia de 5 Hz.


El circuito en ISIS:


El código en CCS C Compiler:


#include <16F877A.h>
#fuses XT, NOWDT, PUT
#use delay (clock = 4M)
#include <lcd.c>
long segundos = 0;
long minutos = 0;
long horas = 0;

void main () {
     lcd_init ();
     setup_timer_1(T1_EXTERNAL |RTCC_EXT_L_TO_H | RTCC_DIV_1); //Configuramos el timer1 con reloj interno y el escaler 8.
     set_timer1(0);   //Cargamos el valor del registro.
     while (true) {
           segundos= get_timer1();
           lcd_gotoxy(1,1);
           printf(lcd_putc, "HORA: %02lu" ":" "%02lu" ":" "%02lu", horas, minutos, segundos);
           if (segundos >= 60) {
              segundos = 0;
              set_timer1(0);
              minutos = minutos + 1;
              if (minutos >= 60) {
                 minutos = 0;
                 horas = horas + 1;
              }
           }     
     }
}


Ejercicio 14. Crear un programa que controle un servomotor con el PIC16F877A el sentido de giro.
Solución. El circuito en ISIS:


El código en CCS C Compiler:

#include <16f877a.h>
#fuses xt, nowdt, protect
#use delay(clock = 4M)

#use standard_io(B)
void main () {
   long i;
   while (true) {
         for (i = 950; i < 2000; i+=2) {
             output_high(pin_b1);
             delay_us(i);
             output_low(pin_b1);
             delay_ms(20);
         }
         for (i = 2000; i > 950; i-=2) {
             output_high(pin_b1);
             delay_us(i);
             output_low(pin_b1);
             delay_ms(20);
         }
   }
}

No hay comentarios:

Publicar un comentario