Microcontroladores PIC

Los microcontroladores PIC (conocidos simplemente como PIC) son circuitos integrados que pueden ser programados para ejecutar una secuencia de instrucciones automáticamente. El programa se escribe en un computador en un ambiente de programación adecuado (por ejemplo en lenguaje C) y luego se transfiere como código binario a la memoria de programa del microcontrolador para su ejecución en el momento de encendido del dispositivo. Los microcontroladores PIC son fabricados por la empresa Microchip y constan básicamente de una CPU, espacios de memoria para el programa y los datos, y varios periféricos para la interacción con el mundo externo, todo esto encapsulado dentro de un solo chip de silicio.

En este tutorial encontrarás conceptos básicos, medios y avanzados acerca de la arquitectura y programación de los microcontroladores PIC. Esta página está dirigida a todas las personas que se han preguntado alguna vez qué es un PIC, para qué sirve y cómo puede ser utilizado en la vida real. Con los conceptos aquí presentados estarás en capacidad de convertirte en un gran programador y diseñar tus propios proyectos para aplicarlos en la solución de problemas prácticos.

Microcontroladores PIC en PDF: Curso completo

Por qué iniciar nuestro aprendizaje con el PIC16F88, el PIC16F628A y el PIC16F877A? Estos PIC pertenecen a la gama media y pueden ser aplicados en circuitos electrónicos de propósito general. Actualmente son utilizados como modelos en la enseñanza de programación de microcontroladores en las Universidades de todo el mundo. Como ventajas relevantes se pueden destacar las siguientes: bajo precio, gran capacidad de memoria de programa y datos, gran disponibilidad de pines E/S (entrada/salida), oscilador interno (PIC16F88 y PIC16F628A), convertidor A/D (PIC16F88 y PIC16F877A), módulos de comunicación serie y tres temporizadores. Todas estas características los hacen completamente superiores al popular PIC16F84A, y por estas razones fueron seleccionados como modelos para el presente texto. Estos microcontroladores PIC constituyen un grupo muy completo, con características novedosas que los convierten en dispositivos apropiados para multitud de proyectos desde los más simples hasta los de mediana y alta complejidad. Cuando se emplea el oscilador interno el usuario tiene a su disposición dos pines más para utilizarlos como entrada/salida de propósito general. El oscilador interno significa un gran ahorro de recursos y puede ser configurado por el usuario de acuerdo a su conveniencia. La memoria de programa se puede grabar y borrar unas 100.000 veces, la memoria de datos EEPROM 1.000.000 de veces y sus datos permanecen almacenados por más de 40 años. Otras características son la Programación en Serie en el Circuito (ICSP) que requiere un total de 5 pines, acceso del procesador a la memoria de programa, programación en bajo voltaje, depuración en el circuito por medio de 2 pines, perro guardián (WDT) y un rango amplio de voltaje de operación. En la siguiente tabla tenemos un resumen de las principales caracteristicas de estos microcontroladores:

características-de-los-microcontroladores-pic

El lenguaje C es universalmente conocido debido a su gran versatilidad para el desarrollo de aplicaciones y se lo enseña como lenguaje básico de programación en muchas universidades e institutos educativos. En la actualidad es casi un estándar de facto a la hora de enseñar a programar computadoras. Es un lenguaje de alto nivel, lo que lo hace sumamente potente con respecto al popular (y difícil) lenguaje ensamblador. Además, el ambiente de desarrollo mikroC   tiene todas las herramientas (en librerías de funciones) y facilidades necesarias para una rápida y efectiva programación de los microcontroladores PIC.

Qué es un programador (grabador o quemador) de PIC? En el contexto del hardware, es una tarjeta electrónica en la cual se inserta el microcontrolador PIC con el propósito de transferir el código del programa (en formato binario) desde el computador del usuario y grabarlo en la memoria interna del microcontrolador. Esta tarjeta se conecta a un puerto (LPT1, USB, etc.) del computador y por medio del software de control se realiza la transferencia (programación) del código ejecutable *.hex de una determinada aplicación hacia el PIC. Programador también es el nombre que se le da a la persona encargada de escribir un programa en un lenguaje de programación con el fin de dar solución a un determinado problema. El resultado del proceso de programación es una aplicación.

Cuánto tiempo me tomará aprender a programar los PIC? Por supuesto no hay una respuesta exacta, lo que sí se puede afirmar es que mientras más perseverancia y dedicación se pongan de parte del lector, el tiempo necesario para el aprendizaje se reducirá.  Si se dedican unas 2 horas al día el avance será vertiginoso y en unas 4 semanas ya tendrá un dominio aceptable de la programación de PIC en lenguaje C.

Cuáles son los pasos a seguir para realizar una aplicación real con un PIC?

  1. Construir o comprar un programador de PIC compatible con los dispositivos a programar y con el sistema operativo disponible.
  2. Descargar el software de control (software de programación) del programador e instalarlo: por ejemplo PICkit2 v2.61, etc.
  3. Descargar e instalar el ambiente de desarrollo de programación de PIC en lenguaje C (mikroC).
  4. Seguir las indicaciones del libro para crear un nuevo proyecto, configurarlo, escribir el código fuente en lenguaje C y compilarlo para obtener el ejecutable *.hex (aplicación).
  5. Descargar el fichero ejecutable al PIC por medio del software de programación y del programador conectado a la computadora personal.
  6. Retirar el PIC del programador y colocarlo en el circuito de aplicación y, ¡a disfrutar con los maravillosos resultados!. La siguiente figura muestra la secuencia de programación:


secuencia-de-programacion-con-mikroc

Microchip® (empresa fabricante de los microcontroladores PIC) ofrece una gran variedad de microcontroladores de 8, 16 y 32 bits, de bajo costo, con una arquitectura potente, varias tecnologías de memoria, herramientas de desarrollo fáciles de usar, documentación técnica completa y una red de ventas y distribución global. Estas son las principales ventajas del uso de microcontroladores PIC:

  • Fácil migración y actualizacion de diseños
  • Amplio rango de velocidad de operación para satisfacer las múltiples necesidades de las aplicaciones
  • Dispositivos con memoria de programa desde 384B a 512 KB para cumplir los requerimientos de código
  • Arquitecturas compatibles para preservar la inversión económica en el desarrollo de códigos
  • Compatibilidad Pin a Pin en múltiples encapsulados, facilitando así el remplazo
  • Menor coste total del sistema con Perifericos Integrados
  • Comunicaciones: SPI, I2C ™, UART, CAN, USB, Ethernet, IrDA®, LIN
  • Control: captura / comparación, contadores, reloj en tiempo real y PWM
  • Módulos Analógicos: Convertidores A / D, comparadores, amplificadores operacionales, Convertidores D / A

Microcontroladores PIC

mikroC PRO para PIC es un compilador con todas las funciones ANSI C para dispositivos PIC de Microchip®. Es la mejor solución para el desarrollo de código para dispositivos PIC. Cuenta con IDE intuitivo, potente compilador con optimizaciones avanzadas, muchas bibliotecas de hardware y software, y herramientas adicionales que le ayudarán en su trabajo. Este Compilador viene con archivos de ayuda integrada y un montón de ejemplos listos para usar, diseñados para que pueda empezar en cualquier momento, sus principales caracteristicas son las siguientes:

  • Compilador inteligente y eficiente
  • Cuenta con cuatro niveles de optimizacion que pueden reducir el tamaño de su código hasta en un 20%
  • Uno de los mejores IDE (Entorno de Desarrollo Integrado) disponibles en la actualidad: intuitivo, rápido y rico en características. Te sentirás muy cómodo durante el trabajo.
  • Más de 500 funciones de librerias lo que se traduce en un enorme ahorro de esfuerzo y tiempo

Requisitos

Para aprender con rapidez y facilidad los conceptos de la programacion de microcontroladores PIC se requieren conocimientos basicos de:

  • Electronica digital
  • Computacion basica

Si usted carece de los requisitos nombrados no es aconsejable que siga adelante en la lectura de este documento pues se le dificultara notablemente entender los conceptos explicados.

El software necesario para ejecutar todas las tareas de programación es el siguiente:

  • mikroC PRO para PIC: ambiente de desarrollo de programación de microcontroladores PIC en lenguaje C. En este link puedes descargar la version demo 4.1 (te servirá para escribir los ejemplos durante la fase de aprendizaje).
  • Proteus-ISIS (opcional): simulador de aplicaciones con microcontroladores PIC
  • PICkit2 v2.61: lo puedes descargar desde esta pagina.

Para los primeros pasos en el estudio de la programación de microcontroladores se necesita el siguiente hardware básico:

  • Computador con puerto USB y sistema operativo Windows (recomendamos desde Windows XP hasta Windows 8.1)
  • Fuente de corriente directa de 5V
  • Microcontrolador PIC
  • Programador PICkit2 u otro programador compatible con el PIC que va a ser utilizado
  • Elementos electronicos varios que dependen del circuito de aplicacion del microcontrolador PIC

A continuación presentamos una introducción a los principales temas acerca de la programación de microcontroladores PIC en lenguaje C, con el compilador mikroC PRO; los ejemplos propuestos se pueden desarrollar con microcontroladores PIC y dispositivos electrónicos de propósito general disponibles actualmente y de fácil acceso. Los temas que se describen cubren múltiples áreas de aplicación y están organizados de menor a mayor complejidad. Se utiliza el lenguaje C (sintaxis de mikroC PRO for PIC) para la programación y se han añadido los ejemplos necesarios que permitirán al lector comprender rápidamente el uso de los diferentes módulos internos y externos de los microcontroladores PIC. Con los conceptos aquí expuestos, el lector estará en capacidad de emprender el diseño y construcción de sus propios proyectos en diversos campos de aplicación.

Un microcontrolador (abreviado μC, UC o MCU) es un circuito integrado fabricado de Silicio que puede programarse para realizar tareas (ejecutar instrucciones) de forma automática al conectarlo a una fuente de energia. Las instrucciones se almacenan en un espacio de memoria especificamente destinada a ese propósito. En la siguiente imagen se aprecia el patillaje o pinout del popular PIC16F628A:

Un microcontrolador está compuesto de varios bloques funcionales, los cuales cumplen una tarea específica; un microcontrolador incluye en su interior las tres principales unidades funcionales de una computadora:

  • Unidad central de procesamiento (CPU): se encarga de ejecutar las instrucciones y realizar las operaciones con los datos.
  • Memorias: FLASH para las instrucciones del programa, EEPROM (de almacenamiento permanente)  para datos y RAM (de almacenamiento temporal) para datos.
  • Periféricos de entrada/salida: permiten la comunicación del microcontrolador con su entorno físico recibiendo y entregando datos en forma de señales electricas. La conexion a los perifericos se realiza por medio de las patillas (alfileres o pines) del circuito integrado que conforma el microcontrolador.

Adicionalmente existe otra terminología que conviene conocer y entender ya que se emplea con mucha frecuencia en el mundo de la programación de microcontroladores: 

  • Compilador: Software que se encarga de convertir el codigo escrito en lenguaje C (lenguaje humano) a codigo de maquina (lenguaje de maquina). El codigo en lenguaje C se conoce como codigo fuente mientras que el codigo de maquina se conoce como codigo ejecutable.
  • IDE (Integrated Development Environment) Ambiente de desarrollo Integrado: software de computador que sirve para el desarrollo de programas para microcontroladores PIC. mikroC PRO for PIC es un IDE. Basicamente un IDE está conformado por dos partes: a) Un editor de texto para escribir el codigo fuente y b) Un compilador.
  • Programador: es un dispositivo de hardware electronico diseñado para transferir el codigo ejecutable (codigo de maquina) desde el computador hacia la memoria de programa del microcontrolador PIC. La conexion entre el computador y el programador se realiza por medio del puerto USB; el proceso se conoce como programacion, grabación o quemado (por esta razon el programador tambien se suele llamar grabador o quemador). También recibe el nombre de programador la persona que se encarga de escribir programas para microcontroladores.
  • Pin: cada una de las patillas o alfileres del microcontrolador. Por ejemplo el PIC16F628A tiene 18 pines (encapsulado DIP18).
  • Sintaxis: Conjunto de reglas definidas para escribir correctamente un lenguaje de programacion. mikroC PRO para PIC tiene su propia sintaxis que es muy similar a la sintaxis del lenguaje C de computadoras (ANSI C). 
  • Programa: Es una secuencia de instrucciones, escritas en un determinado lenguaje de programacion para realizar una tarea específica en un microcontrolador. En este curso se escribiran los programas de acuerdo a la sintaxis propia de mikroC PRO for PIC.

Primer proyecto

Este es el primer ejemplo de como crear un proyecto practico y funcional desde el principio. El proposito es hacer un contador de pulsos desde 0 hasta 9. Se utillizará el popular PIC16F628A, un boton pulsador normalmente abierto para generar los pulsos manualmente y un display de 7 segmentos para mostrar el conteo. Los pasos indicados son los que se deben seguir normalmente para crear otros nuevos proyectos:

  1. Iniciar el programa mikroC PRO for PIC (utilizamos la version 4.1 que puedes descargar más arriba en esta misma pagina) y crear un nuevo proyecto: Project > New Project. Clic en Next
  2. Seleccionar el PIC16F628A en el campo Device Name. Clic en Next
  3. Establecer la frecuencia de trabajo del microcontrolador en Device Clock. Se suele trabajar con una frecuencia de 4MHz y ese es el valor que  usaremos. Clic en Next
  4. Crear una carpeta (folder) para el nuevo proyecto; para ello hacer clic en el simbolo al final del campo Project File Name, esto abrirá la ventana New Project Location. Crear una carpeta en una determinada ubicación de su elección haciendo clic en New Folder, la carpeta deberá tener un nombre relacionado con la aplicación que vamos a crear; la llamaremos Contador. Luego de crear la carpeta Contador hacemos doble clic en ella para ubicarnos dentro de la misma y en el campo File Name creamos un nuevo archivo de proyecto, lo llamaremos tambien Contador (la extension propia del archivo de proyecto es .mcppi en mikroC PRO para PIC, no hace falta escribirla porque el sistema la añade automaticamente). Clic en Save y luego en Next.
  5. En el siguiente paso solo hacemos clic en Next
  6. Aunque en este ejemplo no vamos a emplear ninguna de las librerias de funciones de mikroC PRO, dejamos seleccionada la opcion Include All (por defecto). Clic en Next
  7. Un paso absolutamente necesario e imprescindible es establecer los bits de configuracion del microcontrolador PIC. Por lo tanto en este paso seleccionamos el checkbox Open Edit Project Window to set Configuration Bits. Clic en Finish.
  8. En la ventana Edit Project establecemos los bits de configuracion de la siguiente manera y hacemos clic en OK:
    Oscillator:    INTOSC: I/O on RA6/OSC2, I/O on RA7/OSC1
    Watchdog Timer: Off
    Power Up Timer: Enabled
    Master Clear Enable: Disabled
    Brown Out Detect: Enabled
    Low Voltage Program: Disabled
    Data EE Read Protect: Disabled
    Code Protect: Off
    Uno de los puntos mas importantes a tener en cuenta es la configuracion del oscilador que es un subsistema encargado de generar la base de tiempo (reloj) para la ejecucion de las instrucciones; con una frecuencia de 4MHz la base de tiempo (llamada ciclo de instruccion) es de 1us. Algunas instrucciones se ejecutan en un ciclo de instruccion, es decir que el microcontrolador se demora  1us en realizar la instruccion; por tanto, la ejecucion de las instrucciones se realiza a alta velocidad. El PIC16F628A incluye un oscilador interno de 4MHz que es utilizado al seleccionar INTOSC: I/O on RA6/OSC2, I/O on RA7/OSC1 para el bit Oscillator; el uso del oscilador interno es recomendable ya que facilita armar el circuito electrico y libera dos pines del microcontrolador, de lo contrario seria necesario agregar un cristal oscilador externo con sus elementos asociados.
    El significado y funcion de los demas bits se irá aclarando a medida que profundice en su estudio de la programacion de microcontroladores PIC.
  9. Aparece la ventana del editor de texto, donde escribiremos el codigo fuente de nuestro proyecto:
    //Contador.c
    //Macros (simbolos equivalentes)
    #define BOTON RA4_bit  //BOTON es equivalente a RA4_bit
    #define PRESIONADO 0   //PRESIONADO es equivalente a 0
    
    //Función para convertir de Binario a 7 segmentos
    char Bin2_7seg(char digit){
    	switch (digit){ 
    		case 0: return 0x3F;   //0x3F es el código 7-segmentos del 0.
    		case 1: return 0x06;   //0x06 es el código 7-segmentos del 1.
    		case 2: return 0x5B;
    		case 3: return 0x4F;
    		case 4: return 0x66;
    		case 5: return 0x6D;
    		case 6: return 0x7D;
    		case 7: return 0x07;
    		case 8: return 0x7F;
    		case 9: return 0x67;
    	}
    }
    
    //Declaracion de variables
    char contador=0;  //La variable contador es de tipo char y tiene valor inicial de 0.
    
    //Función principal
    void main(){
    	PORTB=0x00;  //Estado inicial del puerto B.
    	CMCON=0x07;  //Pines RA<3:0> como E/S digital.
    	TRISB=0x00;  //Puerto B como salida.
    	while (1){
    		if (BOTON==PRESIONADO){          //Si se pulsa,
    			Delay_ms(10);                   //esperar 10ms,
    			if (BOTON==PRESIONADO){         //revisar si el boton sigue pulsado,
    				while (BOTON==PRESIONADO);     //y esperar mientras siga presionado.
    				contador++;                    //Al soltar incrementar el contador,
    				if (contador>9) contador=0; //y reiniciarlo a 0 si supera el valor de 9.
    			}
    		}
    		PORTB=Bin2_7seg(contador);  //Convertir y enviar al puerto B el valor
    		//presente en la variable contador.
    	}
    }//Fin de la función principal
    
  10. Una vez terminada la escritura procedemos con la compilación (la traducción del codigo anterior a codigo de máquina). Este proceso es transparente para nosotros (lo único que observaremos serán unos mensajes durante esta fase en la parte inferior del IDE). Para compilar debemos seleccionar el comando Build > Build. El codigo de máquina o codigo ejecutable (se identifica como Contador.hex) se guarda automaticamente en un archivo en la carpeta Contador que creamos en el paso 4. 

    El codigo anterior es un ejemplo que se puede tomar como plantilla para la escritura de otros proyectos. El microcontrolador PIC ejecuta las instrucciones que se encuentran dentro de la función principal void main(){//Instrucciones...}, las partes restantes sirven como codigo complementario para la ejecución correcta de dichas instrucciones. Los Macros tienen el proposito de facilitar el mantenimiento y comprension del codigo; por ejemplo si se quiere emplear el pin RA7 en lugar del pin RA4 simplemente se tiene que escribir #define BOTON RA7_bit; también es mucho más comprensible BOTON==PRESIONADO que RA4_bit==0.

    Una funcion es una agrupacion de instrucciones que luego se tratan como una nueva instruccion dentro de la funcion principal; así Bin2_7seg(contador); es considerada como una instruccion más y ejecutada de acuerdo a su definicion.

    En mikroC PRO for PIC (así como en otros lenguajes de programación) es obligatorio declarar las variables que se usan en la funcion principal, indicando su tipo y de forma opcional su valor inicial; así char contador=0; es la declaracion de la variable contador como una variable de tipo caracter (puede tomar valores entre 0 y 255) y tiene en este caso un valor inicial de 0.

  11. El codigo de maquina Contador.hex tiene que ser grabado en la memoria de programa del microcontrolador PIC de tal forma que al encenderlo ejecute las instrucciones indicadas en dicho codigo, de no ser asi el microcontrolador PIC seria un dispositivo que no serviria para nada ya que su memoria de programa se encuentra en blanco cuando sale de fabrica. El proceso de grabado se realiza por medio de un programador tal como el PICkit2 (todos los detalles los puede encontrar en el articulo Pickit2 Clone: Guia de Usuario).
  12. El último paso es armar el circuito electrico del contador, teniendo en cuenta que la fuente de alimentacion debe ser de 5V (este voltaje se puede obtener fácilmente a partir de un regulador 7805).

  13. Como recomendacion importante se sugiere agregar un condensador ceramico de 0.1uF entre los pines de alimentacion del PIC, lo cual ayudara a eliminar posibles problemas ocasionados por las fluctuaciones rapidas de la fuente de alimentacion. Además, notese que la conexion al display es directa (sin resistencias de por medio), lo que es posible debido a que los microcontroladores PIC están diseñados para suministrar una corriente máxima de 25mA en cada uno de sus pines. Al encender el circuito se observará que el display muestra el numero 0 ya que asi fue programado el PIC. Si se presiona (y se libera) el pulsador el conteo se incrementará en una unidad hasta una cuenta máxima de 9, en la siguiente pulsacion el conteo regresa a 0.

Para profundizar en el aprendizaje de la programación de microcontroladores PIC le recomendamos leer nuestra serie de articulos a continuación, donde se explican los conceptos basicos acompañados con ejemplos practicos y faciles de probar. También puede adquirir el ebook que contiene el fundamento teorico mas detallado y muchos ejemplos reales minuciosamente explicados, asi como las simulaciones en Proteus-ISIS para que pueda verificar su funcionamiento de forma rapida y efectiva.

Los bits de configuración (Device Configuration Bits) tienen importancia capital en la operación de un proyecto. Sin la configuración adecuada el diseño jamás funcionará. Muchos diseñadores se esmeran por escribir un código fuente con las mejores características técnicas y estéticas, dedican largas horas al diseño del esquema eléctrico, del circuito impreso y multitud de detalles, pero suelen pasar por alto uno de los puntos de mayor significado: la selección de los bits de configuración. La omisión de este detalle les acarrea muchos dolores de cabeza, intentando hallar alguna falla en el lugar equivocado; es por eso que recomendamos que como paso previo a la escritura del código fuente, primero se configuren los bits del dispositivo para establecer el modo correcto de funcionamiento..

A continuación se detalla la configuración básica de los microcontroladores PIC16F84A, 16F628A, 16F88, 16F877A, 16F887, 18F2550 y 18F4550 tal como se realiza en el compilador mikroC PRO for PIC. Estas configuraciones garantizan el funcionamiento correcto cuando se trabaja con los puertos digitales. Como se puede ver, a medida que se incrementan las prestaciones de los microcontroladores PIC, también se incrementa el número de bits de configuración, y para su establecimiento correcto es imprescindible el estudio detallado de la hoja de especificaciones (datasheet). La importancia de los bits de configuración es vital, pues el proyecto jamás entrará en funcionamiento si se pasa por alto este requisito. Este artículo tiene el propósito de servir como guía para aquellas personas que están comenzando sus estudios y prácticas con los microcontroladores PIC, y no pretende hacer un estudio pormenorizado de cada uno de los bits de configuración. Si el usuario desea realizar otra configuración para el trabajo con los módulos internos del PIC, deberá revisar la hoja de especificaciones correspondiente. La configuración está realizada para que los microcontroladores PIC trabajen con su oscilador interno en caso de que venga incorporado (se exceptúa el PIC18F2550/4550 que aunque incluye oscilador interno se ha configurado para el oscilador externo).

Se indica el valor hexadecimal resultante que deben tener las palabras de configuración para que el usuario pueda verificar sus configuraciones en otros compiladores donde el formato puede ser diferente. También se añade un ejemplo para el encendido intermitente de un LED. Debe observarse que la configuración de los puertos de los microcontroladores PIC tiene que completarse con la programación de uno o varios registros adicionales para hacer que ciertos pines trabajen como E/S (Entrada/Salida) digital (resaltado en amarillo) ya que inicialmente esos pines cumplen otras funciones. Adicionalmente se ha puesto un enlace para la descarga del código de máquina (hex) de cada ejemplo, obtenido con el compilador mikroC PRO for PIC con la configuración indicada. El lector puede emplear este código ejecutable para comprobar el funcionamiento del PIC respectivo.

Bits de Configuración del PIC16F84A (no incluye oscilador interno)

Oscilador externo 4MHz
CONFIG1: 0x3FF2
--------------------------------------------------------------------------------------
Oscillator: HS
Watchdog Timer: Off
Power Up Timer: On
Code Protect: Off

//EncenderLED.c
    void main() {
    TRISB1_bit=0;     //RB1 como salida.
    while(1){        //Lazo infinito (repite continuamente).
    RB1_bit=1;      //RB1 encendido.
    Delay_ms(500);  //Pausa de 500ms.
    RB1_bit=0;      //RB1 apagado.
    Delay_ms(500);  //Pausa de 500ms.
  }
}

Código hex

Bits de Configuración del PIC16F628A

Oscilador interno 4MHz (por defecto)
CONFIG1: 0x2150
--------------------------------------------------------------------------------------
Oscillator:    INTOSC: I/O on RA6/OSC2, I/O on RA7/OSC1
Watchdog Timer: Off
Power Up Timer: Enabled
Master Clear Enable: Disabled
Brown Out Detect: Enabled
Low Voltage Program: Disabled
Data EE Read Protect: Disabled
Code Protect: Off

//EncenderLED.c
    void main(){
    CMCON=0x07;  //Pines RA<3:0> como E/S digital.
    PORTA=0x00;  //Estado inicial del puerto A (ejemplo).
    TRISA=0x00;  //Puerto A como salida.
    while (1)
    {
      RA0_bit=1;  //Encender LED conectado en RA0.
      Delay_ms(500);
      RA0_bit=0;  //Apagar LED conectado en RA0.
      Delay_ms(500);
    }
  }

Código hex

Bits de Configuración del PIC16F88

Oscilador interno 4MHz
CONFIG1: 0x3F50
CONFIG2: 0x3FFC
--------------------------------------------------------------------------------------
Oscillator: INTRC-OSC2 as RA6
Watchdog Timer: Off
Power Up Timer: Enabled
RA5/MCLR Pin Function Select: RA5
Brown Out Detect: Enabled
Low Voltage Program: Disabled
Data EE Read Protect: Disabled
Flash Program Write: Write Protect Off
Background Debug: Disabled
CCP1 Mux: RB0
Code Protect: Off
Fail-Safe Clock Monitor: Disabled
Internal External Switch Over: Disabled

//EncenderLED.c
      void main(){
      OSCCON=0x60; //Oscilador interno a 4MHz (ejemplo).
      ANSEL=0x00;  //Pines AN<6:0> como E/S digital.
      PORTA=0x00;  //Estado inicial del puerto A (ejemplo).
      TRISA=0x00;  //Puerto A como salida.
      while (1)
      {
        RA0_bit=1;  //Encender LED conectado en RA0.
        Delay_ms(500);
        RA0_bit=0;  //Apagar LED conectado en RA0.
        Delay_ms(500);
      }
    }

Código hex

Bits de Configuración del PIC16F877A (no incluye oscilador interno)

Oscilador externo 4MHz
CONFIG1: 0x2F42
--------------------------------------------------------------------------------------
Oscillator: HS
Watchdog Timer: Off
Power Up Timer: On
Brown Out Detect: On
Low Voltage Program: Disabled
Data EE Read Protect: Off
Flash Program Write: Write Protect Off
Background Debug: Disabled
Code Protect: Off

//EncenderLED.c
        void main(){
        ADCON1=0x06; //Pines RA<5:0> y RE<2:0> como E/S digital.
        PORTA=0x00;  //Estado inicial del puerto A (ejemplo).
        TRISA=0x00;  //Puerto A como salida.
        while (1)
        {
          RA0_bit=1;  //Encender LED conectado en RA0.
          Delay_ms(500);
          RA0_bit=0;  //Apagar LED conectado en RA0.
          Delay_ms(500);
        }
      }

Código hex

Bits de Configuración del PIC16F887

Oscilador interno 4MHz (por defecto)
CONFIG1: 0x23C4
CONFIG2: 0x0700
--------------------------------------------------------------------------------------
Oscillator: INTOSCIO: I/O on RA6/OSC2 and RA7/OSC1
Watchdog Timer: Disabled
Power Up Timer: Enabled
Master Clear Enable: RE3/MCLR is digital input, MCLR internally tied to VDD
Code Protect: Off
Data EE Read Protect: Disabled
Brown Out Reset Selection: Bor enabled
Internal External Switch Over: Disabled
Monitor Clock Fail-Safe: Disabled
Low Voltage Program: RB3 is digital I/O, HV on MCLR must be used for programming
Background Debug: In-Circuit Debugger disabled, RB6 and RB7 are general purpose I/O pins.
Brown Out Reset Selection Bit: Brown Out Reset set to 4.0V
Flash Program Self Write: Write Protect Off

//EncenderLED.c
          void main(){
          SCS_bit=1;                  //Usar el oscilador interno.
          ANSEL=0x00;                 //Pines AN<4:0> como E/S digital.
          ANSELH=0x00;                //Pines AN<13:8> como E/S digital.
          PORTA=0b01111100;           //Inicialización del puerto A (ejemplo).
          TRISA=0b01111100;           //Pines RA7 y RA<1,0> como salidas (ejemplo)

          while (1){
          RA0_bit=1;  //Encender LED conectado en RA0.
          Delay_ms(500);
          RA0_bit=0;  //Apagar LED conectado en RA0.
          Delay_ms(500);
        }
      }
    }

Código hex

Bits de Configuración del PIC18F2550-4550

(incluye oscilador interno, configurado para el oscilador externo)
Oscilador externo 8MHz
CONFIG1L: 0x0000
CONFIG1H: 0x000E
CONFIG2L: 0x001F
CONFIG2H: 0x001E
CONFIG3H: 0x0001
CONFIG4L: 0x0081
CONFIG5L: 0x000F
CONFIG5H: 0x00C0
CONFIG6L: 0x000F
CONFIG6H: 0x00E0
CONFIG7L: 0x000F
CONFIG7H: 0x0040
--------------------------------------------------------------------------------------
96MHz PLL Prescaler: Divide by 2 (8MHz input)
CPU System Clock Postscaler:  [OSC1/OSC2 Src:/1][96MHz PLL Src:/2]
Full Speed USB Clock Source Selection: Clock src from 96MHz PLL/2
Oscillator: HS:HS+PLL, USB-HS
Fail-Safe Clock Monitor Enable: Disabled
Internal External Switch Over: Disabled
Power Up Timer: Enabled
Brown Out Detect: Enabled in hardware, SBOREN disabled
Brown Out Voltage: 4.2V
USB Voltage Regulator: Enabled
Watchdog Timer: Disabled-Controlled by SWDTEN bit
Watchdog Postscaler: 1:32768
CCP2 Mux: RC1
PortB A/D Enable: PORTB <4:0> configured as digital I/O on reset
Low Power Timer1 Osc Enable: Disabled
Master Clear Enable: MCLR disabled, RE3 enabled
Stack Overflow Reset: Enabled

(El resto de opciones se deja Disabled)

//EncenderLED.c
        void main(){
        PORTB=0x00;           //Estado inicial del puerto B (ejemplo).
        TRISB=0x00;           //Puerto B como salida.
        while (1){
        RB0_bit=1;  //Encender LED conectado en RB0.
        Delay_ms(500);
        RB0_bit=0;  //Apagar LED conectado en RB0.
        Delay_ms(500);
      }
    }

Código hex (PIC18F2550)

El lenguaje C de mikroC PRO para programación de microcontroladores PIC está basaso en el lenguaje C estándar empleado en la programación de computadoras, por lo tanto se encontrará que hay sólo unas pequeñas diferencias propias de la aplicación en el campo de los microcontroladores. Para aprender lenguaje C lo más recomendable es conocer los elementos básicos de la programación, los cuales se emplean en la solución de la gran mayoría de problemas de programación.

A continuación se presentan los conceptos fundamentales más importantes, necesarios para emprender exitosamente el aprendizaje de programación de microcontroladores PIC en C, utilizando el conocido compilador mikroC PRO.

La programación en el compilador mikroC PRO se basa en PROYECTOS. Cada proyecto está conformado por un conjunto de archivos interrelacionados entre sí. Para crear un programa primero se debe crear un Proyecto (básicamente se debe seleccionar el microcontrolador, la frecuencia de operación y establecer los bits de configuración); a continuación se procede a escribir las instrucciones del programa en lenguaje C (código fuente); y por último se genera el código de máquina .HEX (código ejecutable) que será almacenado en la memoria de programa del microcontrolador.

En este artículo se explican los detalles de la programación de microcontroladores PIC en lenguaje C, es decir la sintaxis (cómo se deben escribir las instrucciones) y el uso de las instrucciones con ejemplos prácticos. Se recomienda al lector que estudie y repase estas líneas con paciencia y dedicación ya que constituyen la piedra angular sobre la cual descansa la programación de microcontroladores; el dominio de estos conceptos le permitirán a usted convertirse en un experto en la programación de microcontroladores PIC.

Estructura básica de un programa en mikroC PRO (sin funciones)

Todos los programas (código fuente) de microcontroladores PIC en C tienen una estructura básica, a partir de la cual se desarrolla cualquier aplicación del usuario:

//Nombre_de_programa.c
  //Descripción del programa. 
  //Autor: Ing. Penagos R.
  //Declaración de variables
  ...
  //Función principal
  void main( ){
  //Instrucciones del programa.
  ...
}

En el código anterior se debe entender lo siguiente:

  • Las líneas que comienzan con el doble slash // son sólo comentarios que no son necesarios pero sí son muy importantes para documentar (informar) acerca del significado de este código.
  • La declaración de variables se hace donde aparecen los puntos suspensivos ... (normalmente la mayoría de programas que son de alguna utilidad práctica tienen variables, por lo tanto se debe hacer la declaración correspondiente).
  • Las instrucciones del programa (las instrucciones que va a ejecutar o realizar el microcontrolador) se colocan donde van los puntos suspensivos ... (dentro de la función main)

Los 7 elementos básicos de la programación de PIC en C

La programación de PIC en C se puede comprender mejor si se estudian sus elementos básicos; una vez que se dominen estos elementos se podrá dar solución a la gran mayoría de problemas de programación. El propósito de la mayoría de los programas es resolver un problema. Los programas resuelven los problemas por medio de la manipulación de información o datos. Normalmente los programas se caracterizan por permitir el ingreso de información, tener uno o varios lugares de almacenamiento de dicha información, contar con las instrucciones para manipular estos datos y obtener algún resultado del programa que sea útil para el usuario. También, las instrucciones se pueden organizar de tal forma que algunas de ellas se ejecuten sólo cuando una condición específica (o conjunto de condiciones) sea verdadera, otras instrucciones se repitan un cierto número de veces y otras pueden ser agrupadas en bloques que se ejecutan en diferentes partes de un programa.
Lo anterior constituye una breve descripción de los siete elementos básicos de la programación: entrada de datos, tipos de datos, operaciones, salida, ejecución condicional, lazos y funciones. Una vez que se dominan estos elementos se puede afirmar que se conocen los fundamentos de la programación, con lo cual ya es posible desarrollar una gran cantidad de aplicaciones de diversa índole.

Instrucciones básicas de PIC en C

1.- Instrucción de asignación (=)
Permite asignar a una variable un valor constante, el contenido de otra variable o el resultado de una expresión matemática. La asignación va de derecha a izquierda. Por ejemplo,

suma=0; //El valor 0 se almacena en la variable suma.
    x0=x1; //El contenido de la variable x1 se almacena en la variable x0.
    dx=(b-a)/n; //El resultado de la expresión matemática se almacena en la variable dx.
  

2.- Instrucción de entrada de datos (variable=PORTx)
Permite el ingreso de uno o más datos a través de los pines del microcontrolador y almacenarlos en una o más variables. Por ejemplo,

variable=PORTA; //Los bits del puerto A se almacenan en la variable.
  

El siguiente es un caso especial utilizado en la programación de microcontroladores PIC en C:

PORTB=PORTA; //Los bits del puerto A se envían hacia los pines del puerto B.

También se puede leer el estado individual de cada bit de un puerto:

variable=RB3_bit; //Lee el estado del pin RB3 y lo guarda en la variable.
  

3.- Instrucción de salida de datos (PORTx=dato)
Permite el envío de datos, el contenido de una variable o el resultado de una expresión matemática hacia los pines de un puerto. Por ejemplo,

PORTA=0x00; //Todos los pines del puerto A se ponen en 0.
    PORTB=variable; Los bits de la variable son enviados hacia los pines del puerto B.
    PORTB=PORTA+65; //El valor del puerto A más 65 se envía hacia el puerto B.
  

Como caso especial, se pueden enviar bits individuales a cada uno de los pines de un puerto:

RB0_bit=0; //El pin RB0 se pone en 0.

4.- Instrucción de decisión (if...else)
Permite la ejecución de las instrucciones1 si la condición es verdadera, de lo contrario se ejecutan las instrucciones2. Las llaves { } no son necesarias cuando hay una sola instrucción.

if (condición){
     instrucciones1;
   }
   else{
   instrucciones2;
 }

Ejemplo 1:
Si el contenido de la variable codigo es igual al contenido de la variable clave, se ejecutan las primeras cuatro instrucciones; de lo contrario se ejecutan únicamente los dos últimas instrucciones.

if (codigo==clave){
   intentos=0;
   RA7_bit=1;
   Delay_1sec( );
   RA7_bit=0;
 }
 else{
 intentos++;
 Delay_ms(200);
}

Ejemplo 2:
Instrucción de decisión sin else. Esta es una variante muy utilizada cuando se desea condicionar la ejecución de un grupo de instrucciones.
Las dos instrucciones se ejecutarán únicamente si la variable contador es igual a 2, de lo contrario la ejecución continúa a partir de la línea //Aquí.

if (contador==2){
   RB6_bit=~RB6_bit;
   contador=0;
 }
 //Aquí.

Ejemplo 3:
Similar al caso anterior pero con una sola instrucción. Si la variable horas es igual a 24 se reinicia esta variable con un valor de cero.

if (horas==24) horas=0;
  

Nota 1: Las condiciones se obtienen por medio de los operadores de relación y los operadores lógicos.

Nota 2: Operadores de relación:

>    Mayor que
>=   Mayor o igual que
<    Menor que
<=   Menor o igual que
==   Igual a (nótese la diferencia con el operador de asignación =)
!=   No es igual a

Nota 3: Operadores lógicos:

&&   Y
||   O

5.- Instrucción de ciclo controlado por una variable (for)
Permite ejecutar un grupo de instrucciones de manera repetitiva, una determinada cantidad de veces.

for (número de veces){
   instrucciones;
 }

Ejemplo 1:
La variable i tiene un valor inicial de 7 (i=7) y un valor final de 1 (i>=1). Esta variable va disminuyendo de 1 en 1 (i--). Por lo tanto las dos instrucciones se ejecutarán en 7 ocasiones. La primera vez cuando i=7, la segunda cuando i=6, la tercera cuando i=5 y así sucesivamente hasta la séptima vez cuando i=1. Luego la ejecución continúa a partir de la línea //Aquí.

for (i=7; i>=1; i--){
   PORTB=PORTB<<1;
   Delay_ms(500);
 }
 //Aquí.

Ejemplo 2:
El valor inicial de la variable es 1 y su valor final es 3. La variable i se va incrementando de 1 en 1 (i++). Por lo tanto la instrucción se ejecuta tres veces, lo que da como resultado un retardo de 3 segundos. Luego la ejecución continúa a partir de la línea //Aquí.

for (i=1; i<=3; i++)
   Delay_1sec( );
   //Aquí.
 

6.- Instrucción iterativa condicional (while)
Permite ejecutar un grupo de instrucciones de manera repetitiva, mientras una condición sea verdadera. Primero se revisa la condición para determinar su valor de verdad (verdadero o falso) y luego se ejecutan las instrucciones.

while (condición){
   instrucciones;
 }

Ejemplo 1:
La ejecución del programa permanece indefinidamente en esta línea mientras el bit IOFS del registro OSCCON sea igual a cero. Como caso particular no se ejecuta ninguna instrucción (la cual debería estar antes del punto y coma).

while (OSSCON.IOFS==0) ;
  

Ejemplo 2:
Ejemplo de un lazo infinito. En mikroC PRO, cualquier valor numérico diferente a cero se considera VERDADERO, y un valor numérico igual a cero se considera FALSO.
Al valor numérico del puerto A se le suma el valor 65, el resultado se envía hacia los pines del puerto B. Este proceso se repite continua e indefinidamente, debido a que la condición siempre es verdadera (1).

while (1)
   PORTB=PORTA+65;
 

Ejemplo 3:
Las cuatro instrucciones encerradas por { } se ejecutarán indefinidamente mientras el valor del bit RB0 sea igual a 0.

while (RB0_bit==0){
   RB1_bit=1;
   Delay_ms(500);
   RB1_bit=0;
   Delay_ms(200);
 }

7.- Instrucción hacer-mientras (do...while)
Permite ejecutar un grupo de instrucciones de manera repetitiva, mientras una condición sea verdadera. Es similar a la instrucción while, con la diferencia de que primero se ejecutan las instrucciones y luego se revisa la condición.

do{
   instrucciones;
 }
 while (condición);

Ejemplo 1:
La variable kp tiene un valor inicial de cero. La instrucción kp=Keypad_Key_Click( ); se ejecuta y luego se revisa la condición (!kp).Mientras kp sea igual a cero (FALSO) la condición será VERDADERA (!kp), debido al operador de negación ! que cambia el valor de verdad a su estado contrario. Como resultado se tendrá un lazo infinito mientras la variable kp siga en cero. Cuando la variable kp cambie de valor como consecuencia de la pulsación de una tecla, la condición será FALSA y la ejecución continuará en la línea //Aquí.

kp=0;
    do
    kp=Keypad_Key_Click( );
    while (!kp);
    //Aquí.
  

Ejemplo 2:
Las cuatro instrucciones dentro de { } se ejecutarán indefinidamente mientras la variable tecla sea diferente a 1.

do{
     ingreso( );
     raiz( );
     pn_1( );
     seg_grado( );
   }
   while (tecla != 1);
 

Nota: A diferencia de la instrucción while, en la instrucción do...while las instrucciones se ejecutan por lo menos una vez.

8.- Instrucción de selección múltiple (switch)
Permite la ejecución de un grupo de instrucciones de varios grupos posibles, dependiendo del valor de una variable.

switch (variable){
   case 1: instrucciones1;
   break;

   case 2: instrucciones2;
   break;

   case 3: instrucciones3;
   break;

   …

   default: instrucciones;
 }

Si la variable es igual a 1 se ejecutan únicamente las instrucciones1, si es igual a 2 se ejecutan únicamente las instrucciones2 y así sucesivamente. Si la variable no es igual a ninguno de los casos (case) se ejecutan las instrucciones por defecto (default).

Ejemplo 1:
Esta es una función numérica que da como resultado un número hexadecimal dependiendo del valor que tenga la variable digit. Si digit es igual a 0 la función devuelve (return) el valor 0x3F. Si digit es igual a 1, la función devuelve el valor 0x06, y así sucesivamente. Este ejemplo es una variante de la instrucción switch, donde no aparece el elemento default.

char Bin2_7seg(char digit){
   switch (digit){
   case 0: return 0x3F; 
   case 1: return 0x06; 
   case 2: return 0x5B;
   case 3: return 0x4F;
   case 4: return 0x66;
 }
}

Funciones
Una función es una agrupación de instrucciones para formar una nueva instrucción creada por el programador (usuario). Empleando funciones, la solución total de un determinado problema se divide en varios subproblemas, cada uno de los cuales es resuelto por medio de una función particular, aplicando de esta manera la conocida máximaDivide y vencerás.
Las funciones constituyen una de las características fundamentales de mikroC PRO, pues todo programa bien escrito hace uso de ellas. Para poder utilizar una función se deben cumplir los dos siguientes pasos:

1.-Declaración de la función.- Consiste en indicar el tipo, nombre y parámetros de la función:

tipo nombre ( parámetro1, parámetro2, ...);

2.-Definición de la función.- Consiste en indicar las instrucciones que forman parte de dicha función:

tipo nombre ( parámetro1, parámetro2, ...){
 instrucciones;
}

Estructura básica de un programa en mikroC PRO (con funciones)
Todos los programas (código fuente) en mikroC PRO tienen una estructura básica, a partir de la cual se desarrolla cualquier aplicación del usuario:

//Nombre_de_programa.c
  //Descripción del programa. 
  //Autor: Ing. Penagos R.
  //***************************Declaración de funciones (prototipos)**************************
  ...
  //******************************Fin de declaración de funciones*****************************

  //==================================Declaración de variables================================ 
  ...
  //===============================Fin de declaración de variables============================

  //**********************************Función principal******************************** 
  void main( ){
  //Instrucciones del programa.
  ...
}
//********************************Fin de función principal***************************

//================================Definición de funciones============================ 

función1{ 
instrucciones1;
}

función2{ 
instrucciones2;
}
//============================Fin de definición de funciones==========================

Nota 1: Los tipos de funciones más empleadas son numéricas char y nulas void. Las primeras retornan return o devuelven como resultado un número, mientras que las segundas simplemente ejecutan un grupo de instrucciones.

Ejemplo 1:
En este ejemplo la función es numérica tipo char, su nombre es Bin2_7seg y tiene un parámetro digit de tipo char.
La función se utiliza como si fuera una instrucción cualquiera, tomando en cuenta el tipo de función y su(s) parámetro(s). En este ejemplo se tiene PORTB=Bin2_7seg(PORTA). Esto significa que la variable PORTA remplaza a la variable digit. Por lo tanto si PORTA es igual a 0, la función devuelve el valor 0x3F que será enviado al puerto B. Si PORTA es igual a 1, la función devuelve 0x06 que será enviado al puerto B, y así sucesivamente.

//7seg1.c
    //Se utiliza la función Bin2_7seg que transforma un número binario a su
    //equivalente en 7 segmentos.

    char Bin2_7seg(char digit); //Prototipo de la función. 

    void main(){ 
    OSCCON=0x40; //Oscilador interno a 1MHz.
    while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
    PORTA=0x00;  //Inicialización.
    PORTB=0x00;
    ANSEL=0x00;  //Pines AN<6:0> como E/S digital.
    TRISB=0x00;  //Puerto B como salida.
    while (1) PORTB=Bin2_7seg(PORTA);
  }

  char Bin2_7seg(char digit){  //Definición de la función. 
  switch (digit){
  case 0: return 0x3F;  //0x3F es el código 7-segmentos del 0.
  case 1: return 0x06;  //0x06 es el código 7-segmentos del 1.
  case 2: return 0x5B;
  case 3: return 0x4F;
  case 4: return 0x66;
  case 5: return 0x6D;
  case 6: return 0x7D;
  case 7: return 0x07;
  case 8: return 0x7F;
  case 9: return 0x67;
}
}

Ejemplo 2: Trabajo simplificado con funciones.

Variante del ejemplo anterior, en el que se hace únicamente la definición de la función (sin declaración). Se debe hacer antes de la función principal, de lo contrario se producirán errores de compilación por tratar de usar una función desconocida. Este método de uso de funciones es muy popular ya que simplifica notablemente la escritura de los programas asi como su mantenimiento.

//7seg1.c
  //Se utiliza la función Bin2_7seg que transforma un número binario a su
  //equivalente en 7 segmentos.

  char Bin2_7seg(char digit){  //Definición de la función. 
  switch (digit){
  case 0: return 0x3F;  //0x3F es el código 7-segmentos del 0.
  case 1: return 0x06;  //0x06 es el código 7-segmentos del 1.
  case 2: return 0x5B;
  case 3: return 0x4F;
  case 4: return 0x66;
  case 5: return 0x6D;
  case 6: return 0x7D;
  case 7: return 0x07;
  case 8: return 0x7F;
  case 9: return 0x67;
}
}

void main(){ 
OSCCON=0x40; //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
PORTA=0x00;  //Inicialización.
PORTB=0x00;
ANSEL=0x00;  //Pines AN<6:0> como E/S digital.
TRISB=0x00;  //Puerto B como salida.
while (1) PORTB=Bin2_7seg(PORTA);
}

Detalles importantes de mikroC PRO para tener en cuenta
En la programación de PIC en C existen pequeños detalles que se deben tener muy en cuenta y que permitirán que los programas realizados cumplan las tareas para los cuales fueron diseñados. Con respecto a los comentarios, se puede decir que son importantes aunque no son necesarios. Su importancia radica en que ofrecen una mayor facilidad para entender el código y realizar su mantenimiento (esto es especialmente cierto cuando ha pasado el tiempo y necesitamos realizar alguna modificación).

  • Los comentarios se inician con la doble barra diagonal //.
  • Los signos de agrupación siempre deben estar en pareja, es decir si hay tres llaves de apertura {{{, deben haber tres llaves de cierre correspondientes }}}. Lo mismo con los paréntesis ( ).
  • Los números hexadecimales se escriben comenzando siempre con 0x, por ejemplo 0x0A, 0x16, 0xFD, etc.
  • Los números binarios se escriben comenzando siempre con 0b, por ejemplo 0b001110, 0b11101111, etc.
  • Los números decimales se escriben de la forma común y corriente, por ejemplo 64, 126, 12.75, etc.
  • No se debe confundir el operador de asignación = con el operador de comparación == igual a.
  • El punto y coma ; indica el final de una instrucción, por lo tanto hay que tener mucho cuidado para colocarlo en el lugar apropiado.
  • Las llaves { } no son necesarias en aquellos casos en los que únicamente se va a ejecutar una instrucción (ver los ejemplos a lo largo de este apartado).
  • Todo programa en mikroC PRO debe tener una función principal main, y su nombre no debe ser cambiado.

Los tipos de datos más utilizados se muestran en la siguiente tabla.

Programación de pic en c: Tipos de datos en mikroc pro


El tipo float es para números con punto decimal, mientras que los demás tipos son para números enteros.
La EJECUCIÓN DE UNA INSTRUCCIÓN consiste en la realización de las operaciones especificadas en esa instrucción. De la ejecución se encarga la CPU (unidad central de proceso) del microcontrolador PIC.

ISIS es uno de los componentes del sistema PROTEUS de la empresa Labcenter Electronics. ISIS permite crear esquemas electrónicos empleando una amplia variedad de dispositivos de todos los fabricantes de renombre mundial. Los circuitos electrónicos con microcontroladores pueden ser simulados por medio del simulador incorporado PROTEUS VSM. También existe la posibilidad de diseñar circuitos impresos con el el programa ARES que es otro de los componentes del sistema PROTEUS.

Este tutorial describe el simulador Proteus ISIS, que es uno de los componentes del sistema de diseño Proteus, desarrollado por la empresa Labcenter Electronics. El simulador Proteus ISIS permite la elaboración de esquemas electrónicos empleando una amplia variedad de dispositivos de todos los fabricantes de renombre a nivel mundial. Estos circuitos electrónicos pueden ser simulados a través del simulador incorporado Proteus VSM. Además es posible diseñar circuitos impresos por medio del programa ARES, otro de los elementos integrantes de Proteus.

El propósito de este tutorial es describir el proceso básico de construcción y simulación de circuitos con microcontroladores PIC y otros componentes electrónicos, a partir del ejemplo EncenderLED.c empleando el PIC16F628A.

Comandos principales del simulador Proteus

A continuacion se muestran los principales comandos de este simulador usados durante la fase de diseño (armado y puesta a punto del circuito) y la fase de ejecucion (simulacion):

Comandos en tiempo de diseño:

Comandos en tiempo de ejecucion:

Construcción del esquema eléctrico

Para comenzar el tutorial se explicará cómo colocar y conectar los componentes electrónicos. Una vez que ha iniciado el simulador Proteus ISIS deberá tener una pantalla como la siguiente:

Tutorial simulador proteus isis con PIC16F628A. Fig.1

Al hacer clic en la letra P usted tendrá la oportunidad de seleccionar y reunir los elementos electrónicos con los cuales construirá su circuito:

Tutorial simulador proteus isis con PIC16F628A. Fig.2

En el campo Keywords puede empezar a teclear las primeras letras de uno de los componentes, por ejemplo PIC16F6, y automáticamente aparecerá una lista de los resultados relacionados; mientras más letras usted escriba, la lista se irá haciendo más corta y la búsqueda se irá enfocando en unos pocos elementos:

Tutorial simulador proteus isis con PIC16F628A. Fig.3

Ahora haga doble clic en el dispositivo PIC16F628A para que aparezca en el campo del selector de dispositivos:

Tutorial simulador proteus isis con PIC16F628A. Fig.4

Ahora se va a seleccionar un LED, para lo cual se deja en blanco el campo Keywords. En Category hacer clic en Optoelectronics y en Sub-category hacer clic en LEDs. En la lista de resultados hacer doble clic en LED-GREEN para añadirlo al selector de dispositivos:

Tutorial simulador proteus isis con PIC16F628A. Fig.5

Una vez que se han seleccionado todos los elementos se hace clic en OK. Se procede ahora a la construcción del esquema eléctrico. Hacer clic en el elemento PIC16F628A del selector de dispositivos, mover el cursor hacia la ventana de edición (el cursor debe adoptar la figura de un lápiz) y hacer clic (ahora se ve la silueta del PIC16F628A en color lila), ubicarla en cualquier parte de la ventana de edición y hacer clic una vez más (ahora aparece el símbolo completo del PIC16F628A). Hacer clic en el elemento LED-GREEN del selector de dispositivos y seguir el mismo procedimiento para ubicarlo en la ventana de edición a una altura adecuada para conectarlo al pin RA0:

Tutorial simulador proteus isis con PIC16F628A. Fig.6

Para colocar una referencia (GND) se hace clic en el icono Terminals Mode, hacer clic en el elemento GROUND y seguir el procedimiento descrito previamente:

Tutorial simulador proteus isis con PIC16F628A. Fig.7

Para realizar las conexiones se ubica el cursor en el pin RA0, de modo que aparezca un pequeño cuadro rojo y se hace clic; mover el cursor hasta el ánodo del LED para que aparezca un cuadro rojo y hacer clic nuevamente. Repetir el procedimiento para conectar el cátodo a la referencia (GND). Para borrar una conexión se debe hacer doble clic derecho sobre ella. La polarización del microcontrolador PIC se encuentra conectada inicialmente por defecto, por esta razón no aparecen los pines VSS y VDD en el símbolo:

Tutorial simulador proteus isis con PIC16F628A. Fig.8

Proceso de Simulación

El siguiente paso en este tutorial es la explicación de cómo realizar la simulación propiamente dicha. Para ello, lo siguiente es cargar el código ejecutable (EncenderLED.hex) en el PIC16F628A y configurar la frecuencia de operación. Hacer doble clic sobre el símbolo del PIC, esto abre la ventana Edit Component. En esta ventana se puede buscar el código ejecutable haciendo clic en la carpeta  del campo Program File. La frecuencia de operación (4MHz) se ingresa en el campo Processor Clock Frequency. Hacer clic en OK:

Tutorial simulador proteus isis con PIC16F628A. Fig.9

Para iniciar la simulación hacer clic en el botón Play, luego de unos segundos se podrá observar cómo el LED empieza a parpadear. Para detener la simulación hacer clic en el botón Stop. Si desea puede guardar este esquema con el comando File ->Save Design As.

Tutorial simulador proteus isis con PIC16F628A. Fig.10

Lo que se ha explicado constituye una introducción al simulador Proteus ISIS. Es posible emplear instrumentos tales como el osciloscopio, el voltímetro, el amperímetro y otros más; y una gran variedad de elementos animados: pulsadores, interruptores, motores, LEDs, etc. que usted irá conociendo a medida que profundice en el estudio de la programación de microcontroladores.

Sobrecarga del computador

Algunas simulaciones en el simulador Proteus ISIS pueden ocasionar la sobrecarga del microprocesador del computador, debido a la inmensa cantidad de cálculos que éste debe realizar en períodos muy cortos de tiempo; de ser así, el simulador Proteus ISIS hará una llamada de atención como la siguiente :

Tutorial simulador proteus isis con PIC16F628A. Fig.11

Al hacer clic en el símbolo de admiración se verá el siguiente mensaje de advertencia: Simulation is not running in real time due to excessive CPU load. En algunos casos puede corregirse este inconveniente reduciendo la frecuencia del oscilador, para lo cual se hace clic derecho sobre el microcontrolador y se selecciona el comando Edit Properties, que abre la ventana Edit Component; allí será posible cambiar la frecuencia en la casilla Processor Clock Frequency. Otra opción es excluir de la simulación algunos de los componentes del circuito (obviamente no será posible ver el resultado completo de la simulación); para ello, se debe hacer clic derecho sobre el componente que se desea excluir y seleccionar el comando Edit Properties, que abre la ventana Edit Component; marcar la opción Exclude from Simulation. La idea al hacer esto es utilizar un instrumento, por ejemplo el osciloscopio, para ver algunas formas de onda de relevancia que nos brinden información fundamental acerca del funcionamiento del circuito en cuestión. Como ejemplo puede tomarse el problema resuelto PWM_1.dsn que produce la sobrecarga del ordenador. Allí es posible excluir de la simulación los componentes 4N25, IRFZ44N y el motor DC. A continuación se puede conectar el osciloscopio en el pin CCP1 y observar la forma de onda PWM de salida, actuando sobre el pulsador.

Módulo USART  en el Simulador Proteus ISIS

Para  simular la comunicación con el ordenador a través del módulo USART del microcontrolador, ISIS dispone de un instrumento excepcional llamado Virtual Terminal. Para emplearlo se lo debe seleccionar de la lista de instrumentos haciendo clic en el icono de instrumentos virtuales. A continuación conectar los terminales RXD <-> T2OUT y TXD <-> R2IN (T2OUT y R2IN son pines del MAX232). Por último, hacer doble clic sobre el Virtual Terminal y constatar que esté configurado de acuerdo a los datos de la siguiente figura:

Tutorial simulador proteus isis con PIC16F628A. Fig.12

Al ejecutar la simulación se podrá ver una ventana similar a la que se muestra en la siguiente figura, que representa la pantalla del ordenador. Para ingresar texto a través del teclado del ordenador se debe hacer clic en esta ventana para que aparezca el cursor parpadeante. Lo explicado se puede verificar fácilmente con el problema resuelto USART_01.dsn.

Tutorial simulador proteus isis con PIC16F628A. Fig.13

El PICkit 2 es un programador de microcontroladores PIC, memorias EEPROM y otros dispositivos de Microchip (conocido también como grabador o quemador) que se basa en el original PICkit2 y trabaja con el software PICkit2 v2.61 de Microchip. Este programador está diseñado para el puerto USB que se encuentra actualmente en la gran mayoría de computadoras personales. Puede operar correctamente desde Windows XP hasta Windows 10.

Solución de Problemas con los microcontroladores PIC (fallas, errores, bloqueos). Las condiciones de funcionamiento en un ambiente real (no simulado) suelen ocasionar problemas inesperados, fundamentalmente debido al ruido eléctrico y algunos errores en el uso de los microcontroladores PIC; estas dificultades pueden convertirse en autenticos quebraderos de cabeza ocasionando pérdidas de recursos y valioso tiempo.

Las condiciones de funcionamiento en un ambiente real (no simulado) pueden ocasionar problemas inesperados, incontables dolores de cabeza y pérdida de tiempo valioso, fundamentalmente debido al ruido eléctrico y algunos errores en el uso de los microcontroladores PIC.

Con el fin de disminuir al mínimo estos problemas se sugiere tomar muy en cuenta las siguientes recomendaciones y aplicarlas desde el principio en el diseño de circuitos prácticos:

Pines no utilizados

Los pines de los microcontroladores PIC que no sean utillizados no se los debe tratar a la ligera, ya que pueden ocasionar graves problemas de funcionamiento. Se tienen las dos siguientes opciones para el tratamiento de estos pines:

  • Si se deja un pin sin utilizar puede dejarse desconectado pero obligatoriamente debe estar configurado como SALIDA y programado en cualquier estado (ALTO o BAJO).
  • Puede configurarse como ENTRADA y debe tener necesariamente un resistor externo de 10k a VDD o VSS.

Las dos opciones permitirán que el pin sea empleado en lo posterior ya sea como entrada o salida sin realizar modificaciones importantes en el hardware.

Reset maestro MCLR

La hoja de especificaciones de los PICs 16F88, 16F628A y 16F877A muestra que el reset MCLR se producirá siempre y cuando se aplique un pulso negativo que tenga una duración mínima de 2us en este pin (TMCL).

Problemas y errores con los microcontroladores PIC. Fig. 1
 

Debido a que este tiempo es muy corto, es muy probable que se produzcan reseteos o reinicios indeseados y aleatorios debido al ruido eléctrico (EMI, ESD o picos de voltaje) en el pin MCLR. Para evitar este problema, que suele presentarse en ambientes industriales contaminados eléctricamente, el fabricante sugiere emplear una red RCR, la cual puede tener los siguientes valores: R1=10k, R2=1,5k y C1=0,1 uF. El pin RA5/MCLR debe estar configurado como MCLR y no como E/S digital. Estos elementos se deben conectar lo más cerca que sea posible al pin MCLR (el fabricante recomienda que la longitud del conductor entre el pin y los elementos de protección sea máximo de 6 mm).

Problemas y errores con los microcontroladores PIC. Fig. 2
 

Brown Out Reset (reset por caida de voltaje)

Nota: Si se sospecha que el Brown Out Reset sigue ocasionando reseteos indeseados, incluso cuando se hayan implementado las medidas sugeridas a continuación, lo que se debe hacer es deshabilitarlo permanentemente por medio de los Bits de Configuracion.

Para tener la posibilidad de habilitar y deshabilitar el Brown-out Reset BOR a voluntad, se debe conectar siempre un capacitor de desacoplo de 100 nF (0.1 uF) lo más cerca posible de los pines de alimentación del microcontrolador PIC (entre VDD y VSS), para evitar que se produzca un reset BOR indeseado (si está habilitado) cuando cualquiera de las salidas del microcontrolador cambia de estado.
El uso de condensadores de desacoplamiento (decoupling capacitors) en los pines de alimentación es absolutamente necesario. Se deben tener en cuenta los siguientes criterios:

  • Valor y tipo de condensador: Se recomienda un valor de 0,1uF (100nF)/ 10-50V. Los más recomendados son los cerámicos.
  • Ubicación en el circuito impreso: Se deben colocar lo más cerca que sea posible a los pines de alimentación en la misma cara donde se ubica el microcontrolador (el fabricante recomienda que la longitud del conductor entre el pin y los elementos de protección sea máximo de 6 mm).
  • Manejo del ruido de alta frecuencia: Si el circuito está siendo afectado por el ruido de alta frecuencia (por encima de decenas de MHz), se debe añadir un segundo condensador cerámico en paralelo con el condensador señalado anteriormente. El rango del segundo condensador puede ir desde 0,01 a 0,001uF y se debe ubicar junto al primer condensador. En circuitos de alta velocidad se debe adicionar el par 0,1uF//0,001uF en los pines de alimentación (// indica conexión en paralelo).
  • Maximización del desempeño: En el diseño del circuito impreso, a partir del circuito de alimentación trazar primero las pistas hacia los condensadores de desacoplamiento y luego hacia los pines del microcontrolador. Esto asegura que los condensadores se encuentren en primer lugar en la cadena de alimentación del PIC. Igualmente importante es mantener al mínimo la longitud de las pistas entre los condensadores de desacoplamiento y los pines de los microcontroladores PIC, reduciendo de esta forma la inductancia de la pista (track inductance).
  • Condensador mayor: Se recomienda el empleo de un condensador mayor para mejorar la estabilidad de la fuente de alimentación. Los valores típicos van desde 4,7uF hasta 47uF y se debe colocar lo más cerca posible de los pines de alimentación del microcontrolador, en paralelo con los condensadores cerámicos nombrados anteriormente.

Problemas y errores con los microcontroladores PIC. Fig. 3

Relés (relays)

Para evitar que los microcontroladores PIC operen de manera inesperada (por ejemplo RESET indeseado o ejecución incorrecta del programa) se tiene que colocar una red snubber entre los contactos de los relés electromecánicos y de estado sólido (TRIAC), esto ayuda a atenuar los transitorios que se producen en el momento de la conexión y desconexión del relé, especialmente cuando hay cargas inductivas (motores, solenoides). El snubber está formado por una conexión RC en serie, que puede ser C=0,1uF(100nF)/250V (el capacitor debe ser de alto voltaje ya que soportará los picos de voltaje de la corriente alterna CA) y R=100ohm/0,5W. Uno de los errores más comunes es pasar por alto la implementación de esta red lo que ocasionará problemas inesperados.
Originalmente el snubber recomendado es de 100nF/100ohm (esto es aplicable a las cargas que trabajan con altas corrientes), pero si la carga trabaja con muy baja corriente permanecerá encendida todo el tiempo debido al paso de corriente a través de la red snubber. En estos casos se pueden probar varias alternativas de resistencia y capacidad hasta lograr eliminar los transitorios sin que la carga se encienda permanentemente. Por ejemplo puede probarse con 100nF y valores consecutivos de resistencia de 100ohm, 1k, 10k, 33k, 56k y 100k. Otra opción es 10nF y valores de resistencia de 100ohm, 1k, 10k, 33k, 56k y 100k, hasta lograr el resultado deseado. Como se puede concluir, la eliminación de los efectos nocivos producidos por el ruido eléctrico y la interferencia puede llegar a ser un proceso largo, basado en ensayo y error, pero debido a las particularidades de cada ambiente de trabajo esta es la única forma de lograr que el sistema opere correctamente.

Problemas y errores con los microcontroladores PIC. Fig. 4

Fuentes de alimentación de los microcontroladores PIC

Uno de los errores frecuentes que produce problemas con los microcontroladores es la regulación deficiente o baja calidad de las fuentes de alimentación, tanto del PIC como de los demás elementos. La regulación correcta de las fuentes a la hora de construir una aplicación real puede ahorrar incontables quebraderos de cabeza; para esto una opción recomendable es el uso de los reguladores de voltaje 7812 y 7805 con sus elementos asociados de acuerdo a las recomendaciones del fabricante.

Problemas y errores con los microcontroladores PIC. Fig. 5

LCD alfanumérico (con el controlador HD44780 o compatible)

Este LCD posee un terminal para el control de contraste (VLC) por medio de un potenciómetro, y dos terminales adicionales correspondientes al ánodo (A) y cátodo (K) de un diodo emisor de luz (LED) que se utiliza para el alumbrado de fondo del módulo LCD. El LED se polariza por medio de un resistor de 50 ohm / 0,25 W, lo que da como resultado una corriente de 25 mA aproximadamente. El siguiente esquema indica la conexión correcta del LCD 16x2 o 20x4:

Problemas y errores con los microcontroladores PIC. Fig. 6



Conexión de un relé electromecánico al PIC

Los relés electromecánicos (de contactos metálicos)  son muy útiles para el control de un sinnúmero de cargas eléctricas, tanto de CA como de CD. Son ampliamente utilizados por sus prestaciones y bajo costo. Se pueden conectar a un  microcontrolador por medio de un transistor de propósito general operando como interruptor de estado sólido y que actúa como amplificador de corriente.
Nota: Los valores indicados de la red snubber R3/C3 son únicamente referenciales (leer el apartado acerca del funcionamiento errático del PIC que aparece más arriba en esta página).

Problemas y errores con los microcontroladores PIC. Fig. 7

Pines del oscilador externo

El circuito del oscilador se debe situar en la misma cara del PCB en la que está el microcontrolador. Como se ha recomendado previamente para otros elementos, el circuito del oscilador tiene que estar lo más cerca posible a los pines del PIC, se debe hacer el diseño de forma que la longitud de las pistas de conexión no sea superior a 12mm. Igualmente, los condensadores que acompañan al cristal se deben ubicar en la misma cara y tan cerca como sea posible al mismo. Se debe usar un anillo de blindaje a tierra (GND) diseñado en el mismo circuito impreso, alrededor del oscilador para aislarlo de los demás circuitos. Este blindaje se tiene que conectar directamente al pin GND del microcontrolador, y se debe evitar que existan pistas de otras señales dentro de este anillo. Adicionalmente, si el circuito es de doble o múltiples caras se tiene que evitar la presencia de pistas de otras señales bajo el lugar de ubicación del oscilador externo.

Problemas y errores con los microcontroladores PIC. Fig. 8

Las pantallas de cristal líquido LCD 16x2 (display LCD 2x16) se han popularizado mucho en los últimos años, debido a su gran versatilidad para presentar mensajes de texto (fijos y en movimiento), valores numéricos y símbolos especiales, su precio reducido, su bajo consumo de potencia, el requerimiento de solo 6 pines del PIC para su conexión y su facilidad de programación en lenguajes de alto nivel (por ejemplo, lenguaje C). Desde todo punto de vista el empleo del display LCD 16x2 (LCD 2x16) debería considerarse como la primera opción a la hora de decidir por un dispositivo de presentación alfanumérica, excepto cuando las condiciones de iluminación ambiental no sean las más favorables. En este último caso se debería pensar en el empleo de displays de 7 segmentos, que aunque no tienen la misma versatilidad tienen la ventaja innegable de sus mejores características de visibilidad aún en los ambientes más desfavorables. En la actualidad existen diversos modelos de display LCD, aunque los más comunes son los LCD 16x2 (16 caracteres x 2 filas), gobernados por el controlador Hitachi HD44780, que se ha convertido en el estándar de facto para las aplicaciones con microcontroladores PIC; este articulo hace referencia a ese tipo de LCD. Existen LCD 16x2 con diferentes combinaciones de colores de fondo y texto.

Pinout (patillaje) del LCD 16x2

El LCD 16x2 tiene en total 16 pines (tome en cuenta que la posición correcta del display es con los pines en la parte superior, aunque existen modelos en los que la posición correcta es con los pines en la parte inferior) . La datasheet (pdf) muestra 14 pines, los dos pines adicionales son el ánodo (15) y el cátodo (16) del LED de fondo. Debe notarse que el controlador Hitachi HD44780 se encuentra incorporado al circuito impreso del módulo LCD y sirve de interfaz entre la propia pantalla LCD (donde se muestran los caracteres) y el microcontrolador PIC. Por lo tanto, de todos los pines del HD44780 únicamente se tiene acceso a aquellos necesarios para la conexión al PIC y para el control de contraste. 

Pinout del Display lcd 16x2 (lcd 2x16) con HD44780
Pinout Display lcd 16x2 (lcd 2x16) con HD44780
La polarización del LED de fondo se logra conectando una resistencia externa de 50 ohm-1/4 W con lo que se asegura el correcto encendido sin una corriente excesiva. El control de contraste se consigue con un potenciómetro de 10 k con el cual se ajusta el nivel de voltaje en el pin 3 (Vee ó VLC).
Conexión del Display lcd 16x2 (lcd 2x16) con HD44780

Conexión del LCD 16x2 al PIC

La conexión más recomendable del display LCD 16x2 requiere 4 pines para los datos (D7:D4), 1 pin para habilitar/deshabilitar el display (E) y 1 pin para los modos comando/carácter (RS). En la figura siguiente se indica la forma de conectar el display al PIC16F88 y al PIC16F628A.

Circuito con Display lcd 16x2 (lcd 2x16) con HD44780 y PIC

Librería LCD de mikroC PRO

mikroC PRO for PIC tiene una librería para comunicación con LCDs basados en el controlador HD44780 o compatibles, a través de un interfaz de 4 bits para datos. Para el trabajo con el módulo LCD se debe añadir la librería Lcd, que contiene las funciones listadas en la tabla 3.1. Para poder utilizar estas funciones se debe declarar previamente un total de 12 variables: 6 que definen los pines del PIC y otras 6 que permiten programar el sentido de circulación de datos (se detallarán en los ejemplos de este capítulo).

mikroC PRO para Display lcd 16x2 (lcd 2x16) con HD44780

Ejemplo en mikroC PRO con el PIC16F88

En el siguiente ejemplo se emplea la función ByteToStr de la librería Conversions de mikroC PRO, para convertir el contenido de la variable contador (un byte) en una cadena de caracteres (string) y así poderlo visualizar en el display con la función Lcd_Out.

Ejemplo-LCD1.c: Cada vez que presiona el pulsador conectado en RA4 se incrementa un contador que se visualiza en el centro de la segunda línea de la pantalla. Si la cuenta supera 100, el conteo se reinicia desde 0. En el centro de la primera línea se muestra la palabra Conteo:

//LCD1.c
//Declaración de las 12 variables necesarias para la conexión del LCD 2x16.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Fin de declaración de variables de conexión.

char contador=0,estado=1,texto1[]="Conteo:", texto2[4];

void main(){
OSCCON=0x40; //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
ANSEL=0x00;  //Pines AN6:AN0 como E/S digital.
Lcd_Init();                //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR);       //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);  //Apaga el cursor.
Lcd_Out(1,6,texto1);       //Escribe el texto1.
while (1)
{
  if (Button(&PORTA,4,1,0)) estado=0;    //Si se pulsa.
  if (estado==0 && Button(&PORTA,4,1,1)) //Si se pulsa y se libera.
  {
    contador++;  //"contador" contiene el número de pulsaciones.
    if (contador>100) contador=0;
    estado=1;
  }
  ByteToStr(contador,texto2); //Convierte a texto el contenido de la variable contador
  //y lo guarda en texto2.
  Lcd_Out(2,6,texto2);        //Muestra el texto2.
}
}

La memoria EEPROM interna (memoria no volátil de datos) de los microcontroladores PIC tiene la capacidad para ser programada y reprogramada por la CPU del PIC, para asegurar que en caso de una falla o desconexión de la energía los valores o variables críticas se puedan mantener en una memoria no volátil, es decir que los datos se mantienen grabados incluso al apagar el microcontrolador y estarán disponibles para su uso al encenderlo nuevamente.

La memoria EEPROM es muy útil en procesos que deben continuar a partir del último dato obtenido cuando se ha producido una interrupción en la energía. mikroC PRO incluye una librería con funciones que facilitan enormemente el trabajo de programación de esta memoria.

Librería EEPROM de mikroC PRO

En la tabla 4.1 se describen las funciones que permiten la lectura y escritura en la memoria EEPROM.
Funciones de mikroC PRO para la memoria eeprom de los microcontroladores pic
Tabla 4.1 Funciones de mikroC PRO
Ambas funciones soportan microcontroladores PIC inclusive con más de 256 bytes (recuerde que los microcontroladores PIC16F88 y 16F877A tienen 256 bytes, mientras que el 16F628A tiene 128 bytes). Todas las interrupciones deben estar deshabilitadas durante la ejecución de la función EEPROM_Write (el bit GIE del registro INTCON debe ser igual a cero). Al finalizar la ejecución, la función restaura el estado previo de este bit. Se debe asegurar un retardo mínimo de 20 ms entre el uso sucesivo de las funciones EEPROM_Write y EEPROM_Read; de lo contrario, aunque el PIC escribirá el valor correcto, la lectura con EEPROM_Read puede dar un resultado indefinido. Para tener a disposición estas funciones se debe añadir la librería EEPROM.

Ejemplo en mikroC PRO con el PIC16F88

En el ejemplo debe observarse que las 2 instrucciones resaltadas sólo deben ejecutarse en una ocasión (la primera vez que se enciende el PIC), con el propósito de colocar un valor inicial (0) en la primera dirección (0x00); por lo tanto este programa debe compilarse en dos ocasiones y el PIC debe ser programado igualmente en dos ocasiones: la primera con las 2 instrucciones activadas (no comentadas), y la segunda con las dos instrucciones desactivadas (comentadas). El conteo empieza la segunda vez que se enciende el PIC.

Ejemplo-EEPROM1.c: Cada vez que el PIC es reiniciado se incrementa un contador que se guarda en la primera posición de la memoria EEPROM y es visualizado en el LCD.

//EEPROM1.c
//Declaración de las 12 variables necesarias para la conexión del LCD.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit; 
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Fin de declaración de variables de conexión.

char contador, texto[4]; 

void main(){ 
OSCCON=0x40; //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
ANSEL=0x00;  //Pines AN6:AN0 como E/S digital.
Lcd_Init();                //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR);       //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);  //Apaga el cursor.
//EEPROM_Write(0x00,0);      //Valor inicial(sólo la 1era vez) .
//Delay_ms(20);              //Sólo la 1era vez.
contador=EEPROM_Read(0x00);
ByteToStr(contador, texto);
Lcd_Out(1,1,texto);
contador++;
EEPROM_Write(0x00,contador);
}

Circuito electrico

El Timer 0 del microcontrolador PIC se utiliza cuando el sistema necesita un control estricto del tiempo. Normalmente esto se suele realizar empleando código que genera retardos de tiempo, pero la manera más óptima y precisa de hacerlo es por medio de la programación del Timer 0 del PIC.

El Timer0 del PIC tiene las siguientes características:

  • Temporizador - contador de 8 bits.
  • Se puede leer y escribir.
  • Prescaler programable de 8 bits.
  • Selección de reloj interno o externo.
  • Genera una interrupción al desbordarse desde 0xFF a 0x00.
  • Selección de flanco del reloj externo.

La operación del Timer0 se controla a través del registro OPTION_REG (figura 5.1). En el modo temporizador (T0CS=0), se produce un incremento del registro TMR0 cada ciclo de instrucción (prescaler asignado al perro guardián WDT). Si se escribe en el registro TMR0, no se produce el incremento durante los dos siguientes ciclos de instrucción; este hecho debe tenerse muy en cuenta por parte del usuario y, de ser necesario, ajustar el valor escrito en TMR0.

Registro de control del Timer 0 (Timer0, TMR0) del PIC


En el modo contador (T0CS=1), se produce un incremento por cada transición ascendente (T0SE=0) o descendente (T0SE=1) en el pin RA4 del Timer0.
 

Prescaler

Un prescaler es un circuito que reduce la frecuencia que ingresa a un temporizador-contador dividiéndola para un determinado valor (figura 5.2). Por ejemplo, si la relación es 1:8, el prescaler entrega una frecuencia igual a la octava parte de la frecuencia del oscilador.

Prescaler  

El prescaler es compartido entre el Timer0 y el watchdog timer (WDT) del PIC, y no se puede leer ni escribir. Cuando se asigna el prescaler al Timer0 no puede ser utilizado por el WDT al mismo tiempo, y viceversa.

Los bits PSA y PS<2:0> determinan la asignación y la relación de división del prescaler. Cuando se asigna al Timer0, todas las instrucciones de escritura en el registro TMR0 reinician el prescaler. Cuando se asigna al WDT, una instrucción CLRWDT reinicia el prescaler y también el WDT.

Ejemplo en mikroC PRO con el PIC16F88

Ejemplo-Timer0_1.c: Cada vez que se actúe sobre el pulsador conectado en el pin RA4se incrementa un contador que se visualiza en el LCD.

//Timer0_1.c
//El registro OPTION_REG tiene todos sus bits en 1 después del encendido
//por lo tanto el Timer0 actúa como contador, incrementa en transición
//descendente y el prescaler está asignado al WDT.
//Declaración de las 12 variables necesarias para la conexión del LCD.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit; 
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Fin de declaración de variables de conexión.
char texto[4];

void main(){ 
OSCCON=0x40; //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
ANSEL=0x00;  //Pines AN<6:0> como E/S digital.
TMR0=0;      //Inicializa el registro TMR0.
Lcd_Init();                //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR);       //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);  //Apaga el cursor.
Lcd_Out(1,6,"Conteo:");
while (1)
{
  ByteToStr(TMR0,texto);
  Lcd_Out(2,6,texto);
}
}

Cuando este módulo trabaja como temporizador cuenta los ciclos de instrucción (sin prescaler) o los ciclos que recibe del prescaler. Como es un contador ascendente el TMR0 debe ser cargado con el valor de los ciclos que se desean contar restados de 256 que es el valor de desbordamiento. Por ejemplo, para contar 28 ciclos (de instrucción/prescaler), se carga el TMR0 con 228 (256-28). El ciclo de instrucción tiene una duración de 4us para una frecuencia de oscilador de 1MHz (PIC16F88). Sin prescaler mediría un tiempo de 28x4x1us = 112us. Con un prescaler 1:8, el tiempo medido sería 28x4x8us = 896us. De manera general, el intervalo de temporización T se puede calcular con la siguiente fórmula:
T=N x TCI x n
Donde:
N = número de ciclos de instrucción/prescaler
TCI = período del ciclo de instrucción
n = valor del prescaler

Mientras que el valor de carga Q del TMR0 se calcula así:
Q=256-N

Para medir 500us, con un prescaler 1:1 (prescaler asignado al perro guardián WDT) y un TCI = 4us se necesitan 500/4 = 125 ciclos de instrucción. El valor inicial del TMR0 debe ser 131 (256-125).

Los dispositivos de Microchip disponen de una amplia variedad de recursos incorporados para que el desarrollo de aplicaciones y proyectos sea más sencillo y eficiente para el Ingeniero o Diseñador. Estos recursos contribuyen a mejorar la confiabilidad, reducir los costos en componentes electrónicos, el tamaño de los circuitos electrónicos y el consumo de energía. Los recursos más sobresalientes son: Varias clases o tipos de reset (reset maestro, reset al encendido POR, reset por desvanecimiento BOR, etc), watchdog timer WDT (perro guardián), encendido de doble velocidad, oscilador de seguridad y modo de bajo consumo (sleep).

Nota: Los conceptos aqui explicados se basan en el PIC16F88 pero pueden aplicarse de forma general a cualquier microcontrolador PIC observando pequeños detalles tales como los nombres de algunos registros y la arquitectura del watchdog timer en la hoja de especificaciones particular.

El propósito del watchdog timer (WDT) es producir un reset del microcontrolador PIC cada cierto período de tiempo con lo cual se reinicia la ejecución del programa, con la finalidad de evitar que el dispositivo entre en un lazo infinito (se “cuelgue”) o se quede en una espera muy prolongada por un determinado evento que no ocurre. Durante la operación normal, el watchdog timer (conocido en español como perro guardián) genera un reset del microcontrolador PIC después del final de su período (período WDT). El reset puede evitarse si se reinicia el watch dog timer por medio de la ejecución de la instrucción CLRWDT antes del final de su período. Si el dispositivo está en modo Sleep, el watch dog timer ocasiona que se despierte el microcontrolador PIC y continúe con la operación normal (sin producir reset), esto se conoce como despertar WDT. El usuario tiene la posibilidad de emplear un prescaler para el watchdog timer (prescaler de 16 bits) y para el Timer0 (prescaler de 8 bits) al mismo tiempo.

El período WDT puede extenderse hasta 268 segundos, usando el prescaler de 16 bits y el postscaler (prescaler de 8 bits) simultáneamente, cuando el bit PSA  del registro OPTION_REG es igual a 1 (prescaler de 8 bits asignado al watch dog timer). Un postscaler es un circuito que reduce la frecuencia de generación de interrupciones (o reset por WDT) de un temporizador / contador.

Oscilador del watch dog timer

El watch dog timer obtiene su base de tiempo del oscilador INTRC de 31.25 kHz. El valor del registro WDTCON es ‘---0 1000’ (prescaler de 16 bits, 1:512) en todos los resets. Esto da una base nominal de 16,38ms, que es compatible con la base de tiempo generada en versiones anteriores de los microcontroladores PIC 16.
Cuando el OST es invocado, el WDT se mantiene en reset, debido a que el contador del WDT es empleado por el OST para realizar el conteo. Cuando finaliza el conteo OST, el WDT empezará a contar (si está habilitado).
Se ha añadido un nuevo prescaler para el perro guardián (figura 6.2). Este prescaler es de 16 bits y puede ser programado con los bits WDTPS<3:0> del registro WDTCON (figura 6.3), para dividir el oscilador RC desde 32 hasta 65536, dándole a la base de tiempo del WDT un rango nominal de 1ms hasta 2,097s .

Watchdog timer del microcontrolador PIC


Control del watch dog timer del microcontrolador PIC

Control del watchdog timer

Cuando el bit WDTEN de la palabra CONFIG1 es igual a 1 (WDT habilitado), el WDT funciona continuamente y el bit SWDTEN del registro WDTCON no tiene ningún efecto. Si se borra el bit WDTEN (WDT deshabilitado), entonces el bit SWDTEN puede ser empleado para encender y apagar el WDT en el instante deseado de forma muy precisa.

Ejemplo en mikroC PRO con el PIC16F88

Este primer ejemplo muestra cómo programar el WDT para que produzca un reset cada cierto tiempo. Debe notarse que el prescaler de 16 bits permanece en su valor inicial (1:512), por lo que la base de tiempo es de 16,38 ms, mientras que el prescaler de 8 bits (postscaler) se programa con un valor de 1:32, lo que da un período WDT = 16,38 x32 = 524,16 ms (aproximadamente 0,5 s). Otra característica importante de este ejemplo es cómo se puede añadir código ensamblador por medio de la declaración asm. El perro guardián permanece deshabilitado en la palabra CONFIG1 (WDTEN=0). Revisar por medio del comando Project>Edit Project y seleccionar Watchdog Timer: Off. Así el encendido/apagado del WDT se realiza de forma precisa por medio del bit SWDTEN del registro WDTCON.

Ejemplo-WDT1.c: El microcontrolador PIC se pone en modo de bajo consumo. El despertar se producirá cada vez que el WDT concluya su período, en ese momento se producirá un incremento de un contador que se visualizará en la pantalla y nuevamente volverá al modo de bajo consumo. El proceso debe repetirse cada medio segundo aproximadamente (circuito de la figura 3.2).

//WDT1.c
//OPTION_REG tiene todos sus bits en 1 después de cualquier
//reset y no cambia al despertar por WDT o interrupción, por lo tanto
//el Timer0 actúa como contador, incrementa en transición
//descendente y el prescaler está asignado al WDT.

//Declaración de las 12 variables necesarias para la conexión 
//del módulo LCD.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit; 
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Fin de declaración de variables de conexión.

char texto[4], contador=0; 

void main(){ 
OSCCON=0x40; //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
ANSEL=0x00;  //Bits AN6:AN0 como E/S digital.
Lcd_Init();                //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR);       //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);  //Apaga el cursor.
WDTCON=0x08;               //Prescaler 1:512 (Base de tiempo 16,38 ms).
OPTION_REG=0xFD;           //Postscaler 1:32 (Período WDT = 524,16 ms).
SWDTEN_bit=1;              //WDT encendido.
while (1)
{
  ByteToStr(contador,texto);
  Lcd_Out(1,6,texto);
  asm SLEEP                 //Modo de bajo consumo durante 524.16 ms.
  contador++;
}
}

Las interrupciones son eventos que hacen que el microcontrolador PIC deje de realizar la tarea actual y pase a efectuar otra actividad. Al finalizar la segunda actividad retorna a la primera y continúa a partir del punto donde se produjo la interrupción. Las interrupciones permiten que un solo microcontrolador ejecute varias tareas (no exactamente al mismo tiempo) dependiendo del evento que desencadene la interrupción. Estos dispositivos tienen desde 10 hasta 15 fuentes de interrupción dependiendo del tipo específico de PIC. El manejo de las interrupciones se programa por medio de registros especiales que controlan el comportamiento del microcontrolador bajo determinadas circunstancias.

El microcontrolador PIC16F88 tiene hasta 12 fuentes de interrupciones, el microcontrolador PIC16F628A tiene 10 y el microcontrolador PIC16F877A tiene 15.

El registro INTCON contiene las banderas de interrupciones generadas por diferentes eventos. También contiene los bits de habilitación global y particular de las distintas fuentes de interrupciones (observar las diferencias en algunos bits de este registro a lo largo de los siguientes temas).

Control de interrupciones del microcontrolador pic

Las banderas de interrupciones se activan independientemente del estado de sus bits de habilitación o del bit de habilitación global GIE. El bit GIE del registro INTCON permite habilitar o deshabilitar la generación de interrupciones. Cuando están habilitadas (GIE=1) y el bit de habilitación particular y la bandera correspondiente se activan, se produce un salto al vector de interrupción (dirección 0x0004). Las interrupciones individuales pueden habilitarse/deshabilitarse a través de sus bits de habilitación en diferentes registros. El bit GIE se borra al producirse un reset, por lo tanto la generación de interrupciones está deshabilitada normalmente. La instrucción RETFIE se emplea para salir de la rutina de servicio a la interrupción (ISR), así como rehabilitar la generación de interrupciones. Las banderas de las interrupciones INT, RB y del Timer0 se encuentran en el registro INTCON. Las banderas de interrupción de los periféricos están contenidas en los registros PIR1 y PIR2 (microcontrolador PIC16F877A), mientras que los bits de habilitación correspondientes se encuentran en los registros PIE1 y PIE2 (16F877A). El bit de habilitación de interrupciones de periféricos (PEIE) está en el registro INTCON.
Cuando se brinda atención a una interrupción, el bit GIE es borrado para deshabilitar cualquier interrupción adicional, la dirección de retorno es guardada (pushed) en la pila (stack) y el contador de programa (PC) es cargado con el valor 0x0004. Una vez dentro de la ISR, la fuente de la interrupción se puede determinar analizando las banderas de interrupción. Las banderas tienen que ser borradas por software antes de rehabilitar las interrupciones, para evitar interrupciones repetitivas.
Las interrupciones externas INT o RB4 RB7 pueden generarse cada cierto tiempo como mínimo, que va desde los tres a cuatro ciclos de instrucción, esto depende del instante en que se genera la interrupción. Las banderas de interrupción se activan independientemente del bit de habilitación particular, del bit PEIE o del bit GIE.

Interrupciones INT del microcontrolador PIC

La interrupción externa en el pin RB0/INT se activa por flanco ascendente o descendente, dependiendo del bit INTEDG del registro OPTION_REG. Cuando aparece una transición válida en el pin RB0/INT, la bandera INT0IF del registro INTCON toma un valor de 1. Esta interrupción puede ser habilitada/deshabilitada con el bit INT0IE del registro INTCON. La bandera INT0IF tiene que ser borrada por software dentro de la ISR antes de rehabilitar esta interrupción. La interrupción INT puede despertar al PIC, si el bit INT0IE se programó en 1 antes de ingresar al modo Sleep. El estado del bit GIE determina si se produce o no el salto al vector de interrupción después del despertar.

Interrupciones del Timer 0

El desbordamiento del registro TMR0 (desde 0xFF a 0x00) genera una interrupción, lo cual hace que el bit TMR0IF del registro INTCON sea igual a 1. La generación de esta interrupción se puede habilitar/deshabilitar con el bit TMR0IE del registro INTCON. El bit TMR0IF tiene que ser borrado por software dentro de la ISR antes de rehabilitar esta interrupción. Esta interrupción no puede despertar al microcontrolador PIC, ya que el temporizador está apagado durante el modo Sleep.

Interrupciones RB4 RB7

Un cambio de estado en cualquiera de los pines RB<7:4> genera una interrupción y hace que la bandera RBIF del registro INTCON tome un valor de 1. Esta interrupción puede habilitarse/deshabilitarse con el bit RBIE del registro INTCON. Únicamente los pines configurados como entradas pueden producir esta interrupción. Los pines de entrada RB<7:4> se comparan con el estado anterior que tenían en la última lectura del puerto B. Si no hay coincidencia en todos los pines, se genera la interrupción.
Esta interrupción puede despertar al microcontrolador PIC. El usuario, dentro de la ISR, puede borrar la bandera de interrupción con cualquiera de los métodos siguientes:

  • Lectura o escritura del registro PORTB. Esto concluye la condición de falta de coincidencia.
  • Borrar la bandera RBIF.

Esta interrupción se recomienda para despertar al PIC en caso de presionar una tecla o en el caso de que el puerto B se emplee únicamente para la interrupción RB4 RB7. La lectura continua (Polling) del puerto B no se recomienda mientras se usa la función de interrupción RB.

Manejo de interrupciones en mikroC PRO

Las interrupciones se pueden manipular fácilmente por medio de la palabra reservada interrupt. En mikroC PRO se ha declarado de manera implícita la función interrupt, la cual no puede ser redeclarada. Su prototipo es:

void interrupt(void);

Lo único que el usuario tiene que hacer es escribir la definición de esta función (rutina de servicio a la interrupción ISR) para manejar interrupciones en la aplicación que esté desarrollando. mikroC PRO se encarga de salvar y recuperar de la pila (stack) los registros W, STATUS, FSR y PCLATH.

Se pueden realizar llamadas a funciones desde la función interrupt. El compilador mikroC PRO toma en cuenta los registros que se están empleando tanto en la función interrupt como en la función main, y salva únicamente los registros que se emplean en ambas funciones.
En caso de que haya múltiples interrupciones habilitadas, se debe detectar la fuente de la interrupción por medio de las banderas de interrupción (flags) y proceder a la ejecución del código apropiado.

Ejemplo en mikroC PRO con el PIC16F88

El siguiente ejemplo fue resuelto en el capítulo del LCD 16x2 empleando la técnica de lectura continua (Polling) de la entrada RA4; ahora se resolverá con la interrupción INT. Nótese el uso del pin RB0/INT para cumplir dos funciones: como salida de datos hacia el LCD y como entrada para la interrupción INT. El programa se encarga de mantener el valor original del registro TRISB.

Ejemplo-INT1.c: Cada vez que presiona el pulsador conectado en RB0 se incrementa un contador que se visualiza en el centro de la segunda línea de la pantalla. Si la cuenta supera 100, el conteo se reinicia desde 0. En el centro de la primera línea se muestra la palabra “Conteo:”

Circuito para interrupciones del microcontrolador pic

//INT1.c
//Declaración de las 12 variables necesarias para la conexión
//del módulo LCD.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit; 
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Fin de declaración de variables de conexión.

char contador=0,texto[4], respaldo; 

void main(){ 
OSCCON=0x40;                //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
ANSEL=0x00;                 //Bits AN6:AN0 como E/S digital.
GIE_bit=1;                  //Interrupciones habilitadas.
NOT_RBPU_bit=0;             //Pull ups habilitados.
INTEDG_bit=0;               //INT por flanco descendente.

Lcd_Init();                 //Inicializa el LCD. 
Lcd_Cmd(_LCD_CLEAR);        //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);   //Apaga el cursor.
Lcd_Out(1,6,"Conteo:");
ByteToStr(contador,texto);
Lcd_Out(2,6,texto);

respaldo=TRISB;             //Guardar el estado de TRISB. 
TRISB0_bit=1;               //RB0 como entrada.
INTE_bit=1;                 //Interrupción INT habilitada.
while (1)
{
  asm SLEEP                  //Entra en modo SLEEP.
  asm NOP                    //Se despierta por INT, ejecuta NOP y
  //salta a "interrupt".
  ByteToStr(contador,texto); //Retorna de "interrupt" y continúa.
  TRISB=respaldo;            //Restaurar TRISB.
  Lcd_Out(2,6,texto);
  respaldo=TRISB;            //Guardar el estado de TRISB.
  TRISB0_bit=1;              //RB0 como entrada.
}
}

void interrupt(void) 
{
  Delay_ms(20);
  if (RB0_bit==0) contador++;  //Pulsador presionado.
  while (RB0_bit==0);          //Esperar mientras siga presionado.
  if (contador >100) contador=0;
  INTF_bit=0;
}

El teclado matricial (teclado 4x4) es muy empleado en el desarrollo de proyectos con microcontroladores PIC y encuentra aplicación en el ingreso de datos alfanuméricos de manera manual, en aquellos casos en que el uso de pulsadores simples (botones) no es lo más apropiado, ya sea por la presentación final del producto o por la restricción del número de líneas de entrada del microcontrolador. Recibe el nombre debido a que tiene 16 teclas formando una matriz que normalmente representan las cifras del sistema de numeración hexadecimal.

El teclado matricial 4x4 está constituido por una matriz de pulsadores dispuestos en filas (A,B,C,D) y columnas (1,2,3,4), con la intención de reducir el número de pines necesarios para su conexión. Las 16 teclas necesitan sólo 8 pines del microcontrolador, en lugar de los 16 pines que se requerirían para la conexión de 16 teclas independientes.  

Teclado matricial 4x4    Teclado matricial

Su funcionamiento es muy sencillo, cuando se presiona una tecla, se conectan internamente la fila y columna correspondientes; por ejemplo, al presionar la tecla “7” se conectan la fila C y la columna 1. Si no hay ninguna tecla presionada, las filas están desconectadas de las columnas.

Librería Keypad4x4 de mikroC PRO para teclado matricial 4x4

En la tabla siguiente se describen las funciones que se incluyen en la librería Keypad4x4 de mikroC PRO para el manejo del teclado matricial 4x4.

Funciones de mikroC PRO                        para teclado matricial 4x4

Para poder utilizar estas funciones se tiene que declarar previamente una variable que especifica el puerto que se empleará para la conexión del teclado matricial 4x4, como se observa en los ejemplos de programación. La conexión al PIC16F88 se muestra a continuación donde se ha empleado el puerto B: las columnas se conectan al nibble bajo, mientras que las filas se conectan al nibble alto del mismo puerto.

Teclado matricial 4x4 con microcontroladores PIC

Ejemplo en mikroC PRO con el PIC16F88

Debe notarse que el código que se obtiene al presionar una tecla es un número entero entre 1 y 16, de izquierda a derecha y de arriba abajo, comenzando por la fila A. Este número se emplea para asociarle  el símbolo respectivo impreso en el teclado matricial 4x4 (por medio de los códigos ASCII), para su uso posterior en el programa. Esto se detalla en el siguiente ejemplo.

Ejemplo-Teclado_1.c: Lo que se va escribiendo por el teclado es visualizado en la primera línea del LCD. Cuando llega al final se borra todo y comienza de nuevo.

//Teclado_1.c
// Variable necesaria para la conexión del teclado.
char  keypadPort at PORTB;
//Declaración de las 12 variables necesarias para la conexión
//del módulo LCD.
sbit LCD_RS at RA4_bit;
sbit LCD_EN at RA6_bit;
sbit LCD_D4 at RA0_bit;
sbit LCD_D5 at RA1_bit;
sbit LCD_D6 at RA2_bit;
sbit LCD_D7 at RA3_bit;

sbit LCD_RS_Direction at TRISA4_bit; 
sbit LCD_EN_Direction at TRISA6_bit;
sbit LCD_D4_Direction at TRISA0_bit;
sbit LCD_D5_Direction at TRISA1_bit;
sbit LCD_D6_Direction at TRISA2_bit;
sbit LCD_D7_Direction at TRISA3_bit;
// Fin de declaración de variables de conexión.
char kp, contador=0;

void main(){ 
OSCCON=0x40;                //Oscilador interno a 1MHz (TCI=4 us).
while (OSCCON.IOFS==0);  //Esperar mientras el oscilador está inestable.
ANSEL=0x00;                 //Bits AN6:AN0 como E/S digital.
Keypad_Init();              //Inicializa el teclado.
Lcd_Init();                 //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR);        //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);   //Apaga el cursor.

while (1){ 
  kp=0;
  do                         //Espera por una tecla.
  kp=Keypad_Key_Click();  //Lee el número de la tecla y lo guarda en kp.
  while (!kp);
  switch (kp){
    case  1: kp = 49; break;  //49 es el código ASCII del número 1.
    case  2: kp = 50; break;  //50 es el código ASCII del número 2.
    case  3: kp = 51; break;  //51 es el código ASCII del número 3.
    case  4: kp = 65; break;  // A
    case  5: kp = 52; break;  // 4
    case  6: kp = 53; break;  // 5
    case  7: kp = 54; break;  // 6
    case  8: kp = 66; break;  // B
    case  9: kp = 55; break;  // 7
    case 10: kp = 56; break;  // 8
    case 11: kp = 57; break;  // 9
    case 12: kp = 67; break;  // C
    case 13: kp = 42; break;  // *
    case 14: kp = 48; break;  // 0
    case 15: kp = 35; break;  // #
    case 16: kp = 68; break;  // D
  }
  Lcd_Chr_CP(kp);            //Presenta el carácter en el LCD.
  contador++;                //Cuenta el número de pulsaciones.
  if (contador==16){         //Si se han efectuado 16 pulsaciones.
    contador=0;
    Delay_1sec();             //Espera 1 s.
    Lcd_Cmd(_LCD_CLEAR);      //Borra la pantalla y retorna el cursor al
  }                          //origen.
}
}

Los periféricos son módulos o subsistemas que trabajan en coordinación con la CPU del microcontrolador y que le añaden gran poder y versatilidad. Los periféricos se encuentran incorporados dentro del propio microcontrolador y contribuyen a simplificar enormemente el proceso de diseño, tanto en hardware como en software, de una determinada aplicación. Entre los periféricos más importantes se encuentran los módulos PWM (Modulación de Ancho de Pulso) , los convertidores analógico/digital (Convertidor A/D), los módulos de comunicación serial SSP y AUSART (SCI) y los comparadores. En esta página se describe la operación de un control PWM para un motor DC utilizando microcontroladores PIC con el compilador mikroC PRO.

Control PWM

El control PWM es uno de los tres posibles modos de operación del módulo CCP de los microcontroladores PIC16F88, 16F628A y 16F877A, y se describe a continuación debido a su gran importancia en el campo de la automatización.

Una señal PWM es una forma de onda digital binaria de una determinada frecuencia y ciclo de trabajo (duty cycle) variable. Un ejemplo típico de aplicación es el control PWM de potencia, que se suele utilizar para el control de una lámpara incandescente o un motor DC. Si se considera que el nivel 0 representa OFF y el nivel 1 representa ON, la potencia que consume la carga será directamente proporcional a la duración del pulso.

Control pwm

En este modo, el pin CCP1 produce una señal PWM de hasta 10 bits de resolución, lo que significa que se tienen hasta 1024 opciones de configuración del ciclo de trabajo. Este pin tiene que configurarse como salida por medio del registro TRISB. La figura muestra un diagrama de bloques del módulo CCP operando como control PWM.

Módulo pwm de los microcontroladores pic

Una señal PWM se caracteriza por una base de tiempo (período) y un tiempo durante el cual la salida tiene un nivel alto (ciclo de trabajo). La frecuencia es el inverso del período.

Señal pwm de los microcontroladores pic

Funciones de mikroC PRO para control PWM

mikroC PRO para control PWM

Ejemplo en mikroC PRO con el PIC16F628A

Con una frecuencia de oscilador (FOSC) de 4MHz se tiene un período (TOSC) de 0,25 us; si el prescaler del Timer2 tiene un valor de 1 y el registro PR2 tiene un valor de 0, entonces se puede calcular el período mínimo (frecuencia máxima) de la señal PWM:

TPWMmín=(0+1)x4x0,25x1=1 us, y la frecuencia máxima será:  f PWMmáx=1MHz

El período máximo (frecuencia mínima) se obtiene cuando el prescaler del Timer2 tiene un valor de 16 y el registro PR2 tiene un valor de 255:

TPWMmáx=(255+1)x4x0,25x16=4096 us, y la frecuencia mínima será: f PWMmín=244Hz

En el siguiente ejemplo se trabaja con una frecuencia PWM de 333Hz.

Ejemplo-PWM_1.c: Realizar un control PWM de un motor DC de 12V para el ajuste de la velocidad en cinco pasos que se pueden seleccionar por medio de un pulsador conectado en RB7. Inicialmente el motor DC se encuentra detenido, al pulsar la primera vez la velocidad será del 25%, la segunda el 50%, la tercera el 75% y la cuarta el 100%. Si se vuelve a presionar, el motor DC se detiene. La velocidad actual se muestra en el LCD.

Control pwm de un motor dc con microcontroladores pic

//PWM_1.c
//Declaración de las 12 variables necesarias para la conexión
//del módulo LCD.
sbit LCD_RS at RB5_bit;
sbit LCD_EN at RB6_bit;
sbit LCD_D4 at RB1_bit;
sbit LCD_D5 at RB2_bit;
sbit LCD_D6 at RB0_bit;
sbit LCD_D7 at RB4_bit;

sbit LCD_RS_Direction at TRISB5_bit;
sbit LCD_EN_Direction at TRISB6_bit;
sbit LCD_D4_Direction at TRISB1_bit;
sbit LCD_D5_Direction at TRISB2_bit;
sbit LCD_D6_Direction at TRISB0_bit;
sbit LCD_D7_Direction at TRISB4_bit;
// Fin de declaración de variables de conexión.
char contador=0,estado=1;

void main(){
PORTB=0x00;                 //Inicialización.
TRISB3_bit=0;               //RB3 como salida.
Lcd_Init();                 //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR);        //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);   //Apaga el cursor.
Lcd_Out(1,3,"Control PWM.");
PWM1_Init(333);            //Frecuencia PWM.
PWM1_Start();
while (1){
  if (Button(&PORTB,7,1,0)) estado=0;     //Si se pulsa.
  if (estado==0 && Button(&PORTB,7,1,1)){ //Si se pulsa y se libera.
    contador++;
    if (contador>4) contador=0;
    estado=1;
  }
  switch (contador){
    case 0:
     Lcd_Out(2,3,"Veloc.=  0%");
     PWM1_Set_Duty(0);
     break;
    case 1:
     Lcd_Out(2,3,"Veloc.= 25%");
     PWM1_Set_Duty(64);
     break;
    case 2:
     Lcd_Out(2,3,"Veloc.= 50%");
     PWM1_Set_Duty(127);
     break;
    case 3:
     Lcd_Out(2,3,"Veloc.= 75%");
     PWM1_Set_Duty(191);
     break;
    case 4:
     Lcd_Out(2,3,"Veloc.=100%");
     PWM1_Set_Duty(255);
  }
}
}

Una rasgo de gran importancia que poseen los microcontroladores PIC es la capacidad de comunicarse con el computador a través de un módulo incorporado que tiene las características apropiadas para el intercambio de información. Este módulo se llama USART (Universal Synchronous Asynchronous Receiver Transmitter) y opera de acuerdo al estándar RS232 que también es muy utilizado en las computadoras personales u ordenadores, así como en otros dispositivos. Como interfaz entre los niveles TTL del PIC y RS232 del computador se suele utilizar el circuito integrado MAX232.

Este módulo puede configurarse para operación asincrónica (full -dúplex) y para su empleo en este modo se puede utilizar la librería UART del compilador mikroC PRO. Este es uno de los dos módulos serie E/S, también llamado Interfaz de Comunicación Serie SCI. El módulo USART de los microcontroladores PIC puede configurarse como un sistema asincrónico full-dúplex que puede comunicarse con dispositivos periféricos, tales como terminales CRT y computadoras personales, o puede configurarse como un sistema sincrónico half-dúplex que puede comunicarse con otros dispositivos tales como conversores A/D y D/A, EEPROMs serie, etc. Los modos de operación disponibles son los siguientes:

  • Asincrónico (full-dúplex)
  • Sincrónico-Maestro (half-dúplex)
  • Sincrónico-Esclavo (half-dúplex)

Protocolo RS232

Este es un protocolo de comunicación serie ampliamente difundido en las computadoras personales y empleado por los puertos COM del computador. El acceso físico a estos puertos es a través de un conector DB-25 o DB9, machos y hembras. La norma RS232 se estableció para comunicar un computador con un modem, por lo que en los conectores DB-25 aparecen muchos pines que en otras aplicaciones no se utilizan, y en las que es más común emplear el conector DB9. Cada uno de los terminales del conector RS232 tiene una función especificada por la norma. Unos pines transmiten y reciben datos, mientras que otros permiten el control de la comunicación. En la tabla se observan estos detalles.

rs232-pinout

Un dato  a tener muy en cuenta es la velocidad de transmisión, que es la cantidad de información enviada por la línea de transmisión en la unidad de tiempo. Se mide en Baudios y es proporcional a los Bits/segundo (bps). Las velocidades de transmisión normalizadas para los puertos COM son: 75, 150, 300, 600, 1200, 2400, 4800, 9600, etc. Baudios. Otra cuestión fundamental se refiere a los niveles de voltaje de la norma:

  • Los datos se transmiten con lógica negativa, es decir, un voltaje positivo representa 0, mientras que un voltaje negativo representa 1.
  • El 0L se encuentra entre +3 y +15V.
  • El 1L se encuentra entre -3 y -15V.
  • Los voltajes más usados son +12V para el 0L y -12V para el 1L.
  • Cuando un puerto no está transmitiendo mantiene el terminal de transmisión en 1L (-12V).

Circuito Integrado MAX232

El MAX232 es un estándar en la industria y se emplea como interfaz entre los niveles TTL y RS232 y requiere únicamente una fuente de +5V para su operación. Para generar los niveles de +12V y -12V necesita 4 capacitores de 1,0 uF. Dispone de dos entradas TTL con salida RS232, así como dos entradas RS232 con salida TTL. El MAX232 puede realizar la transferencia de datos a una velocidad máxima de 120 kbps.

Pinout max232 Polarización max232

Librería UART de mikroC PRO para el módulo USART

El módulo USART se incluye en los microcontroladores PIC16F88, 16F628A y 16F877A (algunos microcontroladores PIC, como el 16F84A, no tienen este módulo). La biblioteca UART de mikroC PRO proporciona las herramientas para hacer que el empleo de este módulo en modo asincrónico (full-dúplex) sea tan sencillo como nunca lo había sido hasta ahora. Esto permite la comunicación con otros dispositivos a través del protocolo RS232. En la tabla se pueden ver las funciones incorporadas con sus características más sobresalientes.

Funciones de la librería uart para usart de los microcontroladores pic

Ejemplo en mikroC PRO con el PIC16F88

Ejemplo-USART_01.c: Lo que escriba por el teclado del computador se visualizará en el módulo LCD y será enviado de vuelta al computador, por lo que se visualizará también en el monitor. Cuando se hayan ingresado 16 caracteres el LCD se borrará y empezará nuevamente en la primera fila y primera columna.

Comunicación por medio del MAX232 y el USART de los microcontroladores PIC

//USART_01.c
//Declaración de las 12 variables necesarias para la conexión
//del módulo LCD.
sbit LCD_RS at RA4_bit;
sbit LCD_EN at RA6_bit;
sbit LCD_D4 at RA0_bit;
sbit LCD_D5 at RA1_bit;
sbit LCD_D6 at RA2_bit;
sbit LCD_D7 at RA3_bit;
sbit LCD_RS_Direction at TRISA4_bit;
sbit LCD_EN_Direction at TRISA6_bit;
sbit LCD_D4_Direction at TRISA0_bit;
sbit LCD_D5_Direction at TRISA1_bit;
sbit LCD_D6_Direction at TRISA2_bit;
sbit LCD_D7_Direction at TRISA3_bit;
// Fin de declaración de variables de conexión.
char uart_rd, contador=0;
void main(){
  OSCCON=0x60;                //Oscilador interno a 4MHz (TCI=1 us).
  while (OSCCON.IOFS==0);  //Esperar mientras el oscilador está inestable.
  ANSEL=0x00;                 //Bits AN6:AN0 como E/S digital.
  Lcd_Init();                 //Inicializa el LCD.
  Lcd_Cmd(_LCD_CLEAR);        //Borra el display.
  Lcd_Cmd(_LCD_CURSOR_OFF);   //Apaga el cursor.

  UART1_Init(9600);           //Inicializa el USART a 9600 bps. 
  Delay_ms(100);              //Espera a que el USART se estabilice.
  UART1_Write_Text("Hola.");  //Envía este texto a través del USART.

  while (1){ 
    if (UART1_Data_Ready()){   //Si se recibe un dato,
      uart_rd = UART1_Read();   //lee el dato recibido,
      Lcd_Chr_CP(uart_rd);      //lo presenta en el LCD,
      UART1_Write(uart_rd);     //y lo envía a través del USART.

      contador++;
      if(contador==16){         //Detecta el ingreso de 16 caracteres,
        contador=0;              //reinicia el contador,
        Delay_1sec();            //espera 1 segundo,
        Lcd_Cmd(_LCD_CLEAR);     //y borra el LCD.
      }
    }
  }
}

El bus I2C (Inter-Integrated Circuit) o Interconexión de Circuitos Integrados es una tecnología o interfaz para comunicación serie por medio de dos conductores en una configuración maestro-esclavo (master-slave) con velocidades de transmisión que van desde los 100kbps (modo Estándar) hasta los 400kbps (modo Rápido) que se encuentra actualmente en la mayoría de microcontroladores PIC. Los dispositivos con modo Estándar o Rápido pueden operar en el mismo bus, siempre y cuando el bus trabaje a la velocidad del dispositivo más lento. Se ha desarrollado un protocolo para el bus I2C para asegurar que la transferencia de datos sea confiable (libre de errores).

Aquí se explica su uso con el microcontrolador PIC16F88 programado en mikroC PRO y la memoria EEPROM I2C 24LC256.

La especificación original, o modo Estándar, es para velocidades de transmisión de hasta 100kbps. También se ha desarrollado una especificación mejorada, o modo Rápido (400 kbps). Los dispositivos con modo Estándar o Rápido pueden operar en el mismo bus, si el bus opera a la velocidad del dispositivo más lento. El bus I2C emplea un protocolo para asegurar la transferencia confiable de los datos. Cuando se transmiten datos, uno de los dispositivos es el maestro (que suele ser un microcontrolador PIC), el cual inicia la transferencia en el bus y genera las señales de reloj para permitir esa transferencia, mientras que los otros dispositivos se comportan como esclavos.

La tabla siguiente define algunos de los términos del bus I2C. En el protocolo I2C cada dispositivo tiene una dirección que lo identifica. Cuando el maestro (microcontrolador PIC) desea iniciar la transferencia de datos, primero transmite la dirección del dispositivo con el cual desea comunicarse. Todos los dispositivos están atentos para determinar si es su dirección. Dentro de la dirección, un bit especifica si el maestro desea leer o escribir al esclavo. El maestro y el esclavo siempre están operando en modos complementarios (transmisor/receptor) durante una transferencia de datos. Es decir, pueden operar en cualquiera de los siguientes modos:

  • Maestro-transmisor y Esclavo-receptor
  • Esclavo-transmisor y Maestro-receptor

En los dos casos el maestro (microcontrolador PIC) genera la señal de reloj. Se emplean resistores externos de pull-up para asegurar un nivel alto cuando ninguno de los dispositivos  lleva las líneas a un nivel bajo. Un valor de 4k7 es satisfactorio para la mayoría de las aplicaciones.

Terminologia del bus i2c

Especificaciones del bus I2C

Se ha definido el siguiente protocolo de bus:

  • La transferencia de datos se puede iniciar únicamente cuando el bus I2C no está ocupado.
  • Durante la transferencia de datos, la línea de datos tiene que permanecer estable siempre que la línea de reloj esté en nivel ALTO. Si se producen cambios en la línea de datos mientras la línea de reloj está en ALTO, será interpretado como una condición de START o STOP.

De acuerdo a esto se han definido las siguientes condiciones:

Bus I2C desocupado (A). Las líneas de reloj y datos permanecen en ALTO.

Inicio de transferencia de datos. Condición de START (B) Una transición ALTO-BAJO en la línea SDA mientras la línea de reloj (SCL) está en ALTO determina la condición de START. Todos los comandos deben estar precedidos por una condición de START.

Fin de transferencia de datos. Condición de STOP (C) Una transición BAJO-ALTO en la línea SDA mientras la línea de reloj (SCL) está en ALTO determina la condición de STOP. Todas las operaciones deben finalizar con una condición de STOP.

Dato válido (D). El estado de la línea de datos representa datos válidos cuando, después de una condición de START, la línea de datos permanece estable durante el tiempo de nivel ALTO de la señal de reloj. Los datos en la línea tienen que cambiarse durante el tiempo de nivel BAJO de la señal de reloj. Hay un bit de datos por cada pulso del reloj. Cada transferencia de datos comienza con una condición de START y finaliza con una condición de STOP. El número de bytes de datos transferido está determinado por el dispositivo maestro.

Transferencia bus i2c

Reconocimiento ACK. Cada dispositivo receptor, cuando es direccionado, está obligado a generar una señal de reconocimiento ACK después de la recepción de cada byte. El dispositivo maestro tiene que generar un pulso de reloj adicional que está asociado con este bit de reconocimiento. El dispositivo que genera el reconocimiento tiene que colocar en BAJO la línea SDA durante el pulso de reloj correspondiente de tal manera que la línea SDA tenga un nivel BAJO estable durante el tiempo de nivel ALTO del ciclo de reloj. Durante las lecturas, el maestro tiene que informar al esclavo la finalización de los datos recibidos al NO generar un bit ACK en el último byte. En este caso, el esclavo dejará la línea de datos en ALTO para habilitar al maestro para que genere la condición de STOP.

Temporizacion bus i2c

El transmisor tiene que liberar la línea SDA al final del dato transmitido para permitir que el receptor lleve la línea a nivel BAJO como reconocimiento de los ocho bits de datos previos. El receptor tiene que liberar la línea al final del pulso de reloj para que el transmisor continúe enviando datos.

Librería Software_I2C de mikroC PRO para el bus I2C

La biblioteca Software_I2C de mikroC PRO contiene las funciones necesarias para establecer la comunicación  con dispositivos I2C. Estas funciones pueden emplearse con cualquier microcontrolador PIC (aunque no disponga de módulos I2C). Las funciones incorporadas permiten que el usuario emplee un microcontrolador PIC como maestro (el modo multi-maestro no está disponible). La tabla siguiente muestra las funciones que pueden ser utilizadas para la comunicación I2C.

Las interrupciones tienen que estar deshabilitadas cuando se emplea la biblioteca Software_I2C. Los pines empleados para la comunicación deben estar conectados a los resistores de pull-up. 

Funciones de mikroC PRO para bus i2c

Memoria EEPROM 24LC256 en bus I2C

En algunos proyectos es necesario almacenar gran cantidad de datos en memoria EEPROM, sin embargo, la memoria disponible para los microcontroladores es muy limitada. Este problema se puede solucionar fácilmente con las memorias EEPROM serie, manteniendo la simplicidad del hardware, debido a que un solo chip de 8 pines puede almacenar gran cantidad de información. Se ha seleccionado la EEPROM serie 24LC256 de Microchip, que es muy popular, con una capacidad de memoria de 32kbyte.

eeprom i2c 24lc256 pinout memoria eeprom i2c 24lc256

La EEPROM debe considerarse como un ejemplo fundamental, y puede ser tomado como referencia para la comunicación del microcontrolador PIC con otros dispositivos que acepten el protocolo I2C: termómetro (DS1624), reloj calendario (DS1307), conversor AD/DA (PCF8591), etc.

Ejemplo en mikroC PRO con el PIC16F88

En lenguaje C los strings o cadenas de caracteres terminan en el carácter NULO (0x00), lo cual se aprovecha en los siguientes ejemplos para determinar el final de la transferencia, tanto en operaciones de escritura como de lectura.

Ejemplo-I2C_01.c: Programa que escribe un mensaje de hasta 16 caracteres en la memoria 24LC256 a partir de la dirección 0x3B00. El mensaje se encuentra inicialmente en la memoria de programa del microcontrolador PIC. Luego el PIC lee el mensaje grabado anteriormente en la memoria y lo visualiza en el módulo LCD.

Circuito con bus i2c y microcontrolador pic

//I2C_01.c
//Variables de conexión I2C
sbit Soft_I2C_Scl at RB1_bit;
sbit Soft_I2C_Sda at RB2_bit;
sbit Soft_I2C_Scl_Direction at TRISB1_bit;
sbit Soft_I2C_Sda_Direction at TRISB2_bit;

//Variables  de conexión del módulo LCD. 
sbit LCD_RS at RA4_bit;
sbit LCD_EN at RA6_bit;
sbit LCD_D4 at RA0_bit;
sbit LCD_D5 at RA1_bit;
sbit LCD_D6 at RA2_bit;
sbit LCD_D7 at RA3_bit;

sbit LCD_RS_Direction at TRISA4_bit; 
sbit LCD_EN_Direction at TRISA6_bit;
sbit LCD_D4_Direction at TRISA0_bit;
sbit LCD_D5_Direction at TRISA1_bit;
sbit LCD_D6_Direction at TRISA2_bit;
sbit LCD_D7_Direction at TRISA3_bit;
// Fin de declaración de variables de conexión.

char dato, texto[]="Programe en C.", i=0; 

void main(){ 
  OSCCON=0x60;                //Oscilador interno a 4MHz (TCI=1 us).
  //while (OSCCON.IOFS==0);     //Esperar mientras el oscilador está inestable.
  ANSEL=0x00;                 //Bits AN6:AN0 como E/S digital.
  Soft_I2C_Init();            //Inicializa la comunicación I2C.
  Lcd_Init();                 //Inicializa el LCD.
  Lcd_Cmd(_LCD_CLEAR);        //Borra el display.
  Lcd_Cmd(_LCD_CURSOR_OFF);   //Apaga el cursor.

  //Escritura de una página. 
  Soft_I2C_Start();           //Envía una señal de START.
  Soft_I2C_Write(0b10100000); //Byte de Control. Operación de escritura.
  Soft_I2C_Write(0x3B);       //MSByte de dirección.
  Soft_I2C_Write(0x00);       //LSByte de dirección.
  while (texto[i] != 0x00){
    Soft_I2C_Write(texto[i]);  //Dato.
    i++;
  }
  Soft_I2C_Write(0x00);       //Dato (carácter NULO).
  Soft_I2C_Stop();            //Envía una señal de STOP.
  Delay_ms(5);                //Ciclo interno de escritura.

  //Lectura secuencial. 
  Soft_I2C_Start();           //Envía una señal de START.
  Soft_I2C_Write(0b10100000); //Byte de Control. Operación de escritura.
  Soft_I2C_Write(0x3B);       //MSByte de dirección.
  Soft_I2C_Write(0x00);       //LSByte de dirección.
  Soft_I2C_Start();
  Soft_I2C_Write(0b10100001); //Byte de Control. Operación de lectura.
  do{
    dato=Soft_I2C_Read(1);     //Lee un dato y responde con ACK.
    Lcd_Chr_CP(dato);          //Envía el carácter al LCD.
  }
  while (dato != 0x00);
  dato=Soft_I2C_Read(0);      //Lee el último dato (NULO) y responde con NO ACK.
  Soft_I2C_Stop();            //Envía una señal de STOP.
}

Los motores eléctricos CC ( DC) se emplean ampliamente en el área de la automatización, desde los juguetes hasta la robótica industrial, pasando por la medicina, las aplicaciones militares, la investigación espacial y submarina, los electrodomésticos, las computadoras, los dispositivos de entretenimiento, los simuladores, las máquinas herramientas, los automóviles, etc. Los más utilizados son los motores DC y los motores PAP (paso a paso) en los cuales se puede controlar el sentido de giro, la velocidad y la posición angular.

En este capítulo se estudia en detalle el control del sentido de giro, velocidad y posición angular de los motores CC ( DC) convencionales y los motores paso a paso (PAP) o stepper motor usando el driver L293D / L293B con los microcontroladores PIC programados en mikroC PRO.

Driver L293B

El circuito integrado L293B se ha diseñado con el propósito de realizar el control de los motores CC ( DC) de manera óptima y económica. Está conformado por cuatro amplificadores push-pull capaces de entregar una corriente de salida de 1A por canal.

Cada canal está controlado por entradas compatibles con los niveles TTL y cada par de amplificadores (un puente completo) está equipado con una entrada de habilitación, que puede apagar los cuatro transistores de salida. Tiene una entrada de alimentación independiente para la lógica, de manera que se puede polarizar con bajos voltajes para reducir la disipación de potencia. Los cuatro pines centrales se emplean para conducir el calor generado hacia el circuito impreso. Sus características sobresalientes son las siguientes:

  • Corriente de salida de 1A por canal.
  • Corriente pico de salida 2A por canal (no repetitiva).
  • Pines de Habilitación.
  • Alta inmunidad al ruido.
  • Fuentes de alimentación separadas.
  • Protección contra exceso de temperatura.

valores maximos del driver l293b

Pinout driver l293b

Conexión del driver l293b

Observe con cuidado la tabla de verdad y note que si el voltaje de entrada de habilitación Vinh tiene un nivel ALTO el voltaje de salida Vo tendrá el mismo nivel (ALTO o BAJO), aunque NO el mismo valor, del nivel de entrada Vi. Algo que debe tenerse muy en cuenta es que los valores del voltaje de entrada Vi no son los mismos valores del voltaje de salida Vo, ya que Vi corresponde a valores TTL mientras que Vo es el voltaje de alimentación de los motores Vs. Por otro lado, si Vinh tiene un valor BAJO, el pin de salida se pone en estado de alta impedancia Z (sin importar el valor del voltaje de entrada Vi).

Control de motores dc con l293b

La tabla de verdad muestra la posibilidad de controlar dos motores CC ( DC) en el mismo sentido de giro, con la diferencia de que M1 girará si la entrada A tiene un nivel BAJO, mientras que M2 girará si la entrada B tiene un nivel ALTO. Control de giro con l293b

Driver L293D

El driver L293D es similar al L293B, se diferencia fundamentalmente en su máxima corriente de salida y en la incorporación de los diodos de protección en cada uno de los cuatro amplificadores. Sus características principales son las siguientes:

  • Corriente de salida de 600 mA por canal.
  • Corriente pico de salida 1,2A por canal (no repetitiva).
  • Pines de Habilitación.
  • Alta inmunidad al ruido.
  • Fuentes de alimentación separadas.
  • Protección contra exceso de temperatura.
  • Diodos de protección incorporados.

Driver l293d

El L293D diseñado para recibir niveles TTL y alimentar cargas inductivas (relés, motores DC y PAP bipolares y unipolares) y transistores de potencia de conmutación. Este dispositivo se puede usar en aplicaciones de conmutación hasta los 5 kHz. Está encapsulado en formato DIP16 y sus cuatro pines centrales se han conectado juntos y se emplean como disipadores de calor.

Conexión del driver L293D al PIC

El control de giro de motores DC por medio del driver L293D se detalla en el siguiente ejemplo. También puede emplearse el L293B tomando en cuenta que se deben añadir los diodos de protección (pueden ser del tipo 1N4007).

Ejemplo-MotorDC_01.c: Conexión típica de un motor eléctrico DC al PIC a través del driver L293D. El giro del motor está determinado por el estado de los pines RB0 y RB1 de acuerdo a la tabla adjunta. El pin RB0 determina el encendido o apagado del motor, mientras que RB1 controla el sentido de giro.

Tabla de verdad de control de giro con L293D

Control de motores CC / DC con L293D y PIC16F88

//MotorDC_01.c
  void main(){
  OSCCON=0x60;                //Oscilador interno a 4MHz (TCI=1 us).
  while (OSCCON.IOFS==0);     //Esperar mientras el oscilador está inestable.
  PORTB=0x00;                 //Inicialización.
  NOT_RBPU_bit=0;             //Habilitar las pull-up.
  TRISB=0b11100011;           //RB<4:2> como salidas.
  while (1){
  if (RB0_bit==0) RB4_bit=0;         //Motor desconectado.
  if (RB0_bit==1){
  if (RB1_bit==0) PORTB=0b00011000; //Giro a la derecha.
  if (RB1_bit==1) PORTB=0b00010100; //Giro a la izquierda.
}
}
}

Un servomotor (también conocido como servo) es un dispositivo similar a un motor de corriente continua que tiene la capacidad de rotar su eje dentro de un rango de operación (generalmente 180 grados), y mantenerse estable en dicha posición. Los servomotores se controlan por medio de un pulso de ancho variable y frecuencia constante (PWM). Se debe notar que existen diferentes modelos de servomotores con distintas capacidades de rotación pero todos ellos tienen una posición neutral que generalmente se logra con pulsos de 1,5 ms (1.500 us). El terminal de control se utiliza para el ingreso de este pulso. De acuerdo a las restricciones de rotación del servo motor, la posición neutral se define como aquella en la que el servomotor dispone del mismo ángulo de giro hacia la izquierda y hacia la derecha, es decir es una posición central a partir de la cual el eje puede girar el mismo ángulo en ambos sentidos.

 

pulso-de-control-del-servomotor

El ángulo girado se determina por la duración del pulso. Esto es similar a la Modulación por Ancho de Pulso (PWM).  Los servo motores generalmente trabajan con una frecuencia de 50 Hz (periodo de 20 ms). La duración del pulso determina el ángulo girado. Por ejemplo, un pulso de 1,5 ms hará que el  servomotor se ubique en su posición neutral.

Cuando el servomotor recibe un pulso específico se mueve a la posición correspondiente y permanece en ella. Si se aplica una fuerza externa el servo ofrece resistencia a salir de dicha posición.  La máxima fuerza que el servo puede ejercer está relacionada con uno de sus parámetros de mayor importancia: el torque máximo. Los servos no mantendrán su posición para siempre; se debe repetir el pulso para que el servo motor permanezca en dicha posición.

Cuando el servomotor recibe un pulso menor que 1,5 ms gira hasta una nueva posición un determinado ángulo hacia la derecha a partir de su posición neutral. Cuando el pulso es mayor que 1,5 ms ocurre lo contrario. Los límites mínimo y máximo de duración del pulso dependen de cada servomotor. Diferentes marcas, e inclusive diferentes modelos de la misma marca,  normalmente tienen distintos límites mínimo y máximo.  De manera general el pulso mínimo está alrededor de 1 ms y el máximo aproximadamente 2 ms.

control-de-giro-del-servomotor

Otro parámetro que varía entre los servo motores es la velocidad de giro, que es el tiempo que le toma pasar de una posición a otra. Normalmente los fabricantes indican este parámetro para un ángulo de 60 grados, es decir, especifican la velocidad de giro de acuerdo al tiempo que le toma al servomotor girar un ángulo de 60 grados.

Temblor, oscilacion o vibracion del servomotor

Normalmente la señal de control se envia de forma continua todo el tiempo para que el servo mantenga su posicion (como en el ejemplo Servo.c de la parte inferior), sin embargo en algunos servos (especialmente los de bajo precio) esto puede ocasionar temblor (oscilacion o vibracion) del eje debido a que el sistema de control del servo esta continuamente reajustando la posicion; en tales circunstancias lo que se debe hacer es enviar la señal de control PWM unicamente durante el tiempo suficiente para que el eje se posicione y luego suspenderla, con esto se eliminara la oscilacion del eje.

Por ejemplo, si se aplican 80 ciclos de 20ms el tiempo total será de 1.6s; si el tiempo de aplicacion de la señal de control es muy pequeño el eje se moverá de forma irregular. De forma experimental se determinó que un tiempo de 1.6s permite el funcionamiento adecuado. Se puede experimentar con tiempos menores o mayores de ser necesario. Para obtener exactitud se ha tomado en cuenta el tiempo de ejecucion de las instrucciones:

 for (j=1;j<=80;j++){
    RA3_bit=1;         //La salida RA3 pasa a ALTO al finalizar esta instruccion.
    Delay_us (999);    //999us+
    RA3_bit=0;         //+1us=1000us en ALTO (RA3 pasa a BAJO al finalizar esta instruccion).
    Delay_us(19000);
  }

El Brown Out Reset BOD (Reset por caida de voltaje) debe dejarse deshabilitado para evitar el reset cuando se conectan servos de alto consumo (por ejemplo el servomotor MG995 que consume unos 500mA); de lo contrario, el reset del pic ocasiona que el servo opere irregularmente. Otra posible solucion a este problema seria usar dos fuentes de alimentacion independientes: una de baja corriente para el microcontrolador y otra de alta corriente para el servo motor.

servomotor hs-311

Especificaciones del servo motor Hitec HS-311

Como ejemplo tenemos un servomotor de uso común, el Hitec HS-311. Sus especificaciones son las siguientes:

  • Torque máximo: 51 onzas-pulgada
  • Velocidad máxima: 0,15  s/60 grados
  • Desplazamiento angular máximo: 90 grados (puede operar hasta 180 grados aplicando pulsos de  600us a 2400us).
  • Sistema de Control: Analógico. Control por ancho de pulso
  • Posición neutral: 1,5ms (1.500us)
  • Pulso requerido: 3-5 V pico a pico, onda rectangular
  • Voltaje de operación: 4,8 - 6,0V
  • Temperatura de operación: -20 a 60 grados Celsius
  • Velocidad (4,8V): 0,19 s/60 grados, sin carga
  • Velocidad (6,0V): 0,15 s/60 grados, sin carga
  • Torque (4,8V): 42 onzas-pulgada (3,0 kg-cm)
  • Torque (6,0V): 51 onzas-pulgada (3,7 kg-cm)
  • Consumo (4,8V): 7,4mA (reposo), 160mA en operación sin carga
  • Consumo (6,0V): 7,7mA (reposo), 180mA en operación sin carga
  • Angulo de operación: 45 grados con un pulso de 450 us
  • Dirección: Multi-direccional
  • Engranajes: Nylon
  • Longitud del cable de conexión: 30 cm
  • Peso: 43 gramos
  • Conector: Amarillo, Blanco ó Naranja (Señal de control), Rojo (V+), Negro ó Café (Negativo)

Dimensiones físicas (mm)

dimensiones-del-servomotor-hS-311

A=19,82          B=13,47          C=33,79          D=10,17          E=9,66          F=30,22

G=11,68          H=26,67          J=52,84          K=9,35          L=4,38          M=39,88

X=3,05

Ejemplo en mikroC PRO con el PIC16F628A

Servo.c: Control de giro de un servomotor HS-311 con un PIC16F628A (la señal de control se envia de forma continua todo el tiempo). Al presionar un botón conectado en el pin RA4 (pin 3) por primera vez el servo pasa a la posición neutral (centro), la segunda vez  gira 45 grados a la izquierda, la tercera se ubica 45 grados a la derecha del centro y la cuarta vez se ubica 90 grados a la derecha del centro.  Luego la secuencia de movimientos se repite actuando sobre el botón. Nótese, en el código fuente, que se ha tomado en cuenta el tiempo de ejecución de las instrucciones para obtener los pulsos con la duración exacta.

//servo.c
//Microcontrolador: PIC16F628A
//Oscilador: interno 4MHz
//Servo motor: Hitec HS-311

char contador=0,estado=1;

void main() {
  PORTB=0x00;
  TRISB=0x00;
  CMCON=0x07;
  while (1){
    if (Button(&PORTA,4,1,0)) estado=0;     //Si se pulsa.
    if (estado==0 && Button(&PORTA,4,1,1)){ //Si se pulsa y se libera.
      contador++;
      if (contador>4) contador=1;
      estado=1;
    }
    switch (contador){
      case 1:RB0_bit=1;
      Delay_us (1499);   //1.500us (neutral)
      RB0_bit=0;
      Delay_us(18500);
      break;
      case 2:RB0_bit=1;
      Delay_us (1949);   //1.950us (-45 grados)
      RB0_bit=0;
      Delay_us(18050);
      break;
      case 3:RB0_bit=1;
      Delay_us (1049);   //1.050us (+45 grados)
      RB0_bit=0;
      Delay_us(18950);
      break;
      case 4:RB0_bit=1;
      Delay_us (599);    //600us (+90 grados)
      RB0_bit=0;
      Delay_us(19400);
      break;
    }
  }
}

Esquema eléctrico:

servomotor-con-pic-16f628a

Este sistema TX/RX (Transmisor/Receptor) permite la implementación de enlaces de datos de radiofrecuencia, de forma muy simple, alcanzando distancias de hasta 80 metros dentro de edificaciones o 350 metros en campo abierto cuando opera con la fuente de 12V. Opera en el rango de los 433MHz (UHF) con modulación por desplazamiento de amplitud (ASK).

Transmisor de 433MHz

Transmisor TX de radiofrecuencia de 433MHz

Este módulo de radiofrecuencia de 433MHz es un transmisor de datos en UHF para montaje en circuito impreso (PCB). Cuando trabaja con el receptor de 433MHz que lo complementa, conformando un sistema TX/RX, permite la implementación de enlaces de datos de radiofrecuencia de forma muy simple, alcanzando distancias de hasta 80 metros dentro de edificaciones o 350 metros en campo abierto cuando opera con la fuente de 12V.  

Especificaciones técnicas:

  • Señal de radiofrecuencia: Modulación ASK (Modulación por Desplazamiento de Amplitud)
  • Fuente de alimentación: 12V (también disponible en versiones de 3V y 5V)
  • Consumo de corriente: <16 mA
  • Potencia de transmisión: 13 dBm
  • Desviación de frecuencia: +- 75kHz

Características

  • Alcance útil hasta 350 metros (12V), 230 metros (5V), 160 metros (3V)
  • Disponible en frecuencias de 433.92 MHz (433MHz) y 315.0 MHz
  • Velocidades de transmisión hasta 20kbps

Disponible para operar a 315 MHz y 433.92 MHz (433MHz), este sistema TX/RX de radiofrecuencia minimiza la radiación espuria y susceptibilidad. El transmisor es compatible con aplicaciones inalámbricas de enlaces de datos uno-a-uno o de varios nodos: apertura de puertas de garaje / compuertas, monitoreo remoto de procesos industriales, seguridad de edificios, Punto Electrónico de Ventas (EPOS) y seguimiento del inventario, interruptor remoto, lámpara de control remoto, sistema inalámbrico TX/RX de llamadas, etc.

Pinout (patillaje)

Pinout del transmisor TX de radiofrecuencia de 433MHz

  1. Vcc: Alimentación de CC regulada. Contenido máximo de rizado 0.1Vpp
  2. DATA: Entrada de señal modulada. Acepta datos digitales serie a niveles de 0V a 5V.
  3. GND: Referencia (tierra) del suministro de DC.
  4. ANT: Entrada de 50 ohm de la antena.

Valores máximos absolutos La superación de los valores indicados a continuación puede causar daños permanentes en el transmisor:

Máximos del transmisor TX de radiofrecuencia de 433MHz

Especificaciones de desempeño

Especificaciones del transmisor TX de radiofrecuencia de 433MHz

Consideraciones para el montaje.- El circuito puede montarse verticalmente u horizontalmente sobre la placa base. Las buenas prácticas de diseño de radiofrecuencia deben ser observadas, en particular, cualquier retorno de tierra requerido por la antena o la alimentación debe estar conectado directamente a la patilla RF GND en el terminal de antena del módulo, y no a la patilla de 0V que se configura sólo como una tierra de CC. Todas las pistas de conexión deben ser lo más cortas que sea posible para evitar cualquier problema con la recepción de parásitos de RF. Si la conexión entre el transmisor y la antena no forma parte de la propia antena, debe hacerse utilizando línea de microcinta o cable coaxial de 50 ohm o una combinación de ambos. Es conveniente (pero no esencial) llenar todo el área del PCB no utilizada alrededor del módulo con un plano de tierra.

Requisitos para la antena.- Se recomiendan y aprueban tres tipos de antena:

Antena del módulo TX/RX de radiofrecuencia de 433MHz

  • Helicoidal Bobina de alambre, conectada directamente al pin 2, circuito abierto en el otro extremo. Esta antena es muy eficiente, dado su pequeño tamaño (20 mm x 4 mm de diámetro). La antena helicoidal es una antena de alta Q, recortar la longitud del hilo o expandir la bobina para obtener resultados óptimos. Las antenas helicoidales se desintonizan mucho con la proximidad a otros objetos conductores.  
  • Lazo Un lazo de pista de PCB sintonizado por un condensador fijo o variable a tierra en el extremo "caliente" y alimentado desde el pin 2 en un punto a 20% desde el extremo de tierra. Los lazos tienen inmunidad a la desintonización por proximidad.  
  • Látigo Este es un alambre, varilla, pista de la placa o combinación conectado directamente a la patilla 2. La longitud total óptima es 15.5cm (1/4 de longitud de onda a 433MHz). Mantenga el extremo del circuito abierto (“caliente”) lejos de componentes de metal para evitar graves pérdidas de sintonía. Los látigos son sensibles a los planos de tierra y se beneficiarán de los radiales internos a tierra de ¼ de longitud de onda, si el producto es pequeño y está revestido de plástico.

La elección de la antena y su posición controlan directamente el alcance del sistema TX/RX. Mantenerlo libre de otro metal en el sistema, particularmente el extremo ‘caliente’. La mejor posición de lejos, es ubicarlo sobre la parte superior del producto. Esto a menudo no es deseable por razones prácticas / ergonómicas, por lo que se debe alcanzar un compromiso. Si se debe usar una antena interna, tratar de mantenerla alejada de otros componentes metálicos, en particular los grandes, como transformadores, baterías ,planos de tierra y pistas en circuito impreso. El espacio alrededor de la antena es tan importante como la propia antena.

Advertencia: No mojar el circuito. No está herméticamente sellado.

Receptor de 433MHz

Este es un receptor miniatura de datos en UHF,superregenerativo, para montaje en circuito impreso (PCB). Con el transmisor correspondiente (13dBm), permite la implementación sencilla de enlaces TX/RX inalámbricos de datos a velocidades de hasta 4.8kbps y distancias de hasta 40 metros dentro de edificios o 110 metros en campo abierto.

Receptor RX de radiofrecuencia de 433MHz

Resumen técnico

  • Conversión individual ASK superregenerativa
  • Fuente de alimentación: 5V
  • Consumo de corriente: 2.2mA

Características

  • Diseñado para cumplir con la norma EN 300 220-3 (radio) y EN 301 489-3 (EMC)
  • Velocidades de hasta 4.8kbps
  • Alcance utilizable de hasta 110 metros
  • Versiones disponibles en 433.92 MHz (433MHz) y 315.0MHz
  • Versiones disponibles: regulado y no regulado
  • Adopción de inductancia Murata ajustable para estabilizar la frecuencia
  • Rápido tiempo de establecimiento de datos

Disponible para operar en 315 MHz y 433.92 MHz, el receptor minimiza la radiación espuria y susceptibilidad. Es compatible con aplicaciones inalámbricas de enlaces de datos uno-a-uno o de varios nodos: Alarma de seguridad de coches, sistema de alarma  antirrobo para motos, lámpara remota, monitor remoto para niños, etc.

Debido al pequeño tamaño y el bajo consumo de corriente, es ideal para utilizar en aplicaciones portátiles inalámbricas de pilas, tales como terminales portátiles.

Pinout (patillaje)

Pinout del receptor RX de radiofrecuencia de 433MHz

  • GND (pin 1) Tierra del suministro de DC
  • DATA (pin 2) Salida de datos digitales. Puede ser utilizado para alimentar decodificadores externos. Los datos son datos verdaderos, es decir, como se ingresan al transmisor. Internamente conectado al pin 3.
  • DATA (pin 3) Salida de datos digitales. Puede ser utilizado para alimentar decodificadores externos. Los datos son datos verdaderos, es decir, como se ingresan al transmisor. Internamente conectado al pin 2.
  • VCC (pin 4) Suministro de 5V CC regulada, conectado internamente al pin 5. Contenido máximo de rizado 0.1Vpp.
  • ANT (pin 5) Entrada de antena de 50 ohm

Valores máximos absolutos.- La superación de los valores indicados a continuación puede causar daños permanentes en el receptor:

Máximos del receptor RX de radiofrecuencia de 433MHz

Especificaciones de desempeño

Especificaciones del receptor RX de radiofrecuencia de 433MHz

Notas:

  • La corriente se incrementa a niveles superiores de entrada de RF (>-20dBm o más)
  • Las cifras típicas son para la señal en la frecuencia central, las cifras máximas son para una desviación de +-75kHz
  • La antena tiene una gran influencia en el módulo receptor, lo mejor para la recepción es una antena de ¼ de longitud de onda.
  • El tiempo de ajuste de datos debe leerse antes de utilizar el módulo.

Consideraciones para el montaje.- Puede montarse verticalmente u horizontalmente sobre la placa base. Las buenas prácticas de diseño de RF deben ser observadas, en particular, cualquier retorno de tierra requerido por la antena o la alimentación debe estar conectado directamente a la patilla RF GND en el terminal de antena del módulo, y no a la patilla de 0V que se configura sólo como una tierra de CC. Todas las pistas de conexión deben ser lo más cortas que sea posible para evitar cualquier problema con la recepción de parásitos de RF. Si la conexión entre el receptor y la antena no forma parte de la propia antena, debe hacerse utilizando línea de microcinta o cable coaxial de 50 ohm o una combinación de ambos. Es conveniente (pero no esencial) llenar todo el área del PCB no utilizada alrededor del módulo con un plano de tierra.

Advertencia: No mojar el circuito. No está herméticamente sellado. El receptor adopta el modo ASK, cambiará un poco el ancho del pulso de datos recibido al recibir datos desde el transmisor, por lo que debe hacer una cierta medida correspondiente al compilar los datos inalámbricos. Por ejemplo: "1" Si el nivel alto es inferior a 500 us al recibir datos de decodificación puede ser juzgado como "1".

Receptor RX de 433MHz: nivel 1

"0" Si el nivel alto es más de 500 us al recibir datos de decodificación puede ser juzgado como "0".

Receptor RX de 433MHz: nivel 0

El código de preámbulo puede adoptar "1" o "0", el código inicial puede adoptar 2ms de nivel bajo.

Uso del modulo de radiofrecuencia de 433MHz con un microcontrolador PIC

La forma más practica, efectiva y recomendable para usar este modulo es por medio de los circuitos integrados HT12E y HT12D, que conforman una pareja de encoder y decoder respectivamente para control remoto.

El encoder se conecta al modulo transmisor, mientras que el decoder se conecta al modulo receptor. En el circuito de la figura anterior los interruptores conectados en los pines AD8-11 son los que permiten enviar la señal de control al actuar sobre ellos, activando el pin correspondiente D8-D11 (el nivel activo es BAJO) en el receptor. Los interruptores en el transmisor se pueden reemplazar fácilmente por los pines de un microcontrolador, de tal forma que al colocar un nivel BAJO en uno de los pines se envie la señal de control al receptor.

Como se ha indicado, este metodo es sumamente confiable ya que la comunicacion por radiofrecuencia esta totalmente asegurada debido a las elevadas prestaciones de los integrados HT12E y HT12D; otros metodos, como el uso del modulo USART o codificacion Manchester presentan muchos errores de conexion, siendo muy poco recomendables.

La comunicacion alámbrica entre microcontroladores PIC es de suma importancia pues permite tener sistemas con multiples microcontroladores ejecutando distintas tareas en forma coordinada. La transmision de datos se puede lograr de forma bidireccional usando el modulo USART incorporado o funciones propias del compilador mikroC PRO.

Se describe la comunicación entre dos microcontroladores PIC16F628A usando el módulo USART-Software de mikroC.

Consta de dos proyectos, uno para cada PIC:

  1. El proyecto PIC a PIC LCD es utilizado para recibir datos y presentarlos en un LCD 2x16.
  2. El proyecto PIC a PIC se utiliza para enviar datos.

Código en mikroC PRO (lenguaje C)

Primer código fuente:

//PIC_a_PIC_LCD.c
//Microcontrolador: PIC16F628A
//Oscilador: Interno-4MHz
//Este programa se almacena en uno de los dos microcontroladores (U2) y recibe continuamente un
//dato (la letra 'r') cada 300 ms por el pin de recepción RB6(12). El pin de transmisión es
//RB7(13). El dato recibido se va presentando en el LCD.
//La velocidad de transmisión de 600 Baudios fue seleccionada experimentalmente por un
//procedimiento de ensayo y error. El pin RB0(6) se enciende por 1 segundo en el caso de
//intentar establecer una velocidad de transmisión muy alta o muy baja.

//Declaración de las 12 variables necesarias para la conexión del módulo LCD.
sbit LCD_RS at RA4_bit;
sbit LCD_EN at RA6_bit;
sbit LCD_D4 at RA0_bit;
sbit LCD_D5 at RA1_bit;
sbit LCD_D6 at RA2_bit;
sbit LCD_D7 at RA3_bit;

sbit LCD_RS_Direction at TRISA4_bit;
sbit LCD_EN_Direction at TRISA6_bit;
sbit LCD_D4_Direction at TRISA0_bit;
sbit LCD_D5_Direction at TRISA1_bit;
sbit LCD_D6_Direction at TRISA2_bit;
sbit LCD_D7_Direction at TRISA3_bit;
// Fin de declaración de variables de conexión.

char error, byte_read;
void main(){
CMCON=0x07;                 //Pines RA<3:0> como E/S digital.
PORTB=0x00;
TRISB0_bit=0;
Lcd_Init();                 //Inicializa el LCD.
Lcd_Cmd(_LCD_CLEAR);        //Borra el display.
Lcd_Cmd(_LCD_CURSOR_OFF);   //Apaga el cursor.
error = Soft_UART_Init(&PORTB, 6, 7, 600, 0); //Inicializa el módulo UART-Software a 600 Baudios.
if (error >0){
  RB0_bit=1;
  Delay_ms(1000);
  RB0_bit=0;
  while(1);              //Detiene el programa en caso de error.
}
Delay_ms(100);
while(1) {
  byte_read = Soft_UART_Read(&error); //Recibe un dato y lo guarda en byte_read.
  if (!error)            //Si no hay error.
  Lcd_Chr_CP(byte_read); //Envía el dato recibido hacia el LCD.
  Delay_ms(200);
}
}

Segundo código fuente:

//PIC_a_PIC.c
//Microcontrolador: PIC16F628A
//Oscilador: Interno-4MHz
//Este programa se almacena en uno de los dos microcontroladores (U1) y transmite continuamente un
//dato (la letra 'r') cada 300 ms por el pin de transmisión RB6(12). El pin de recepción es
//RB7(13).
//La velocidad de transmisión de 600 Baudios fue seleccionada experimentalmente por un
//procedimiento de ensayo y error. El pin RB0(6) se enciende por 1 segundo en el caso de
//intentar establecer una velocidad de transmisión muy alta o muy baja.

char error;
void main(){
CMCON=0x07;                 //Pines RA<3:0> como E/S digital.
PORTB=0x00;
TRISB0_bit=0;
error = Soft_UART_Init(&PORTB, 7, 6, 600, 0); //Inicializa el módulo UART-Software a 600 Baudios.
if (error >0){
  RB0_bit=1;
  Delay_ms(1000);
  RB0_bit=0;
  while(1);              //Detiene el programa en caso de error.
}
Delay_ms(100);
while (1){
  Soft_UART_Write('r');  //Envía el carácter 'r' cada 300 ms.
  Delay_ms(300);
}
}

Esquema eléctrico de la comunicación PIC a PIC:

comunicación pic a pic

El LCD grafico (GLCD 128x64) brinda mucha flexibilidad para el desarrollo de aplicaciones en las que sea necesario presentar texto o imágenes. Se compone de una matriz de pixeles dispuestos en filas y columnas. Cada pixel puede manejarse individualmente y permite mostrar texto, gráficos o una combinación de ambos. Se emplea en aquellos casos en los que es necesario tener un control total del área de la pantalla; sin embargo, la flexibilidad implica una mayor dificultad en el diseño del circuito de control. Afortunadamente existen controladores especiales para este propósito (el circuito integrado T6963C de Toshiba es uno de los más utilizados actualmente) que vienen incorporados de fábrica en el módulo GLCD 128x64.

GLCD

Retroiluminación LED (LED backlighting)

Los LCDs crean las imágenes con la manipulación de la luz ambiental visible. En ausencia de esta luz, se tiene que añadir retroiluminación (backlight) o luz de fondo para que las imágenes sean visibles. Hay muchas opciones para agregar iluminación de fondo a un LCD. Cada una tiene sus ventajas y desventajas, y no hay un único método para todas las aplicaciones.

Retroiluminación (backlight) LED

La Retroiluminación LED (LED backlighting) es la técnica más popular para LCDs medianos y pequeños. Las ventajas de los LEDs son su bajo costo, larga vida, inmunidad a la vibración, bajo voltaje de operación, y control de intensidad preciso. La principal desventaja es que requiere más potencia que la mayoría de los demás métodos. La retroiluminación (backlight) LED viene en muchos colores, siendo el amarillo-verde el más común, mientras que el blanco se está volviendo muy popular y de bajo costo.  La vida de operación es muy larga (50.000 horas como mínimo), y son más brillantes que los ELPs. Al ser de estado sólido, se configuran para operar con 5 o 12 VDC, así que no requieren un inversor. La retroiluminación (backlight) LED tiene dos configuraciones básicas: matricial (array) y de borde (edge). En ambos tipos la luz de los LEDs se enfoca sobre un difusor que distribuye la luz uniformemente detrás de la pantalla. En la configuración matricial hay muchos LEDs distribuidos uniformemente tras la pantalla, esto produce un alumbrado más uniforme y brillante y consume más potencia. En la configuración  de borde, los LEDs se ubican en una de las orillas (típicamente la orilla superior) y se enfocan sobre el borde del difusor, esto permite tener un módulo más delgado con menor consumo de potencia.

led-de-borde led-matricial

Control de contraste del LCD

Es habitual utilizar el concepto de contraste para nombrar a la diferencia relativa en intensidad que existe entre un punto de una imagen y sus alrededores. Cuando el contraste es nulo, resulta imposible distinguir un objeto de su fondo. En cambio, a mayor contraste, mayor facilidad para la diferenciación. El contraste, en el aspecto visual de una imagen, también hace referencia a la escasez de tonos intermedios, de forma que resalta con notoriedad lo claro y lo oscuro. 

Cuando se usa un LCD, se debe disponer de un control para ajustar el voltaje de polarización de la pantalla. Este ajuste permitirá el control del contraste entre los segmentos encendidos y apagados, diferenciandolos claramente entre sí y mejorando la visualizacion de los datos en pantalla.

Ajuste del contraste del LCD

El ajuste del contraste también modifica el ángulo de visión de la pantalla. Una pantalla de 12h00 se puede optimizar para ser vista desde las 6h00 por medio del ajuste del contraste; aunque el resultado no será tan bueno como una pantalla de 6h00 optimizada para ser vista desde las 6h00. Si se va a ver la pantalla de frente, se puede escoger una de 12h00 o una de 6h00 y realizar un ajuste ligero del contraste para optimizar la imagen desde esa posición. Para el ajuste del contraste se emplea normalmente un potenciómetro (conectado entre Vdd y Vss, ó Vee y Vdd para módulos LCD de alto voltaje). El terminal móvil del potenciómetro se conecta a Vo (voltaje de contraste). Actuando sobre este potenciómetro se logra la apariencia deseada.

Control de contraste del GLCD 128x64 t6963c

Librería T6963C_Graphic_LCD de mikroC PRO para GLCD 128x64

mikroC PRO proporciona una librería de funciones para el trabajo con el GLCD 128x64 que tenga incorporado el controlador Toshiba T6963C.

Funciones de mikroC PROC para glcd 128x64 con t6963c

LM4228: GLCD 128x64 con controlador Toshiba T6963C

El LM4228 es un módulo GLCD 128x64, con tecnología CMOS y controlador Toshiba T6963C. Armado en tablero de circuito impreso, con marco de soporte de metal y retroiluminacion LED. 

Precauciones

Precauciones de manipulación

  • Este dispositivo es susceptible a los daños por descarga electrostática (ESD). Se deben tener en cuenta los cuidados contra la electricidad estática.

Precauciones de la fuente de alimentación

  • Tomar siempre en cuenta los valores máximos permitidos.
  • Evitar la aplicación de voltaje con polaridad invertida en los pines VDD y VSS, aunque sea por un tiempo muy breve.
  • Usar una fuente bien regulada y libre de transitorios.
  • Evitar las señales en el bus de datos mientras el módulo está apagado.
  • No colocar un capacitor entre Vo (contraste) y el pin de referencia VSS. VDD tiene que ser siempre mayor que Vo (en el instante de apagado el voltaje almacenado en el capacitor puede hacer que Vo sea mayor que VDD, lo cual puede dañar el módulo).

Precauciones de operación

  • No conectar o desconectar el módulo cuando el sistema está alimentado.
  • Minimizar la longitud de cable entre el módulo y el microcontrolador (máximo 30 cm).
  • El módulo debe trabajar dentro de los límites de temperatura especificados por el fabricante.

Precauciones ambientales y mecánicas

  • Uno de los mayores motivos de dificultades es un proceso inapropiado de soldadura. No se recomienda el uso de pastas o cremas limpiadoras ya que pueden deslizarse en el interior del módulo y producir fallas.
  • El módulo instalado debe estar libre de esfuerzos mecánicos.
  • La superficie del módulo LCD no se debe tocar ni rayar. La superficie frontal es un polarizador plástico muy fácil de rayar. Limpiar la pantalla solo cuando sea necesario con un algodón humedecido en un líquido apropiado para la limpieza de LCDs.
  • Siempre se deben tener en cuenta los procedimientos anti estática cuando se manipule el módulo.
  • Evitar el ingreso de humedad al módulo y tener en cuenta los límites de temperatura de operación y almacenamiento.
  • No exponerlo a la luz del sol de forma directa.
  • Si se produce una fuga del cristal líquido, evitar el contacto y la ingestión. Si se produce el contacto, lavarlo con abundante agua y jabón.

Valores máximos absolutos

Los valores mostrados aquí deberían explicarse por sí solos, no obstante es necesario recalcar que el máximo voltaje de alimentación es de 7V (lo normal es 5V). Nótese que los voltajes VDD-VSS y VDD-VEE no deberían ser negativos en ningún momento, ya que, como se dijo anteriormente esto puede dañar seriamente al dispositivo.

Máximos del GLCD 128x64 con T6963C

Características eléctricas

El LM4228 consume una corriente de 10 mA para su funcionamiento (aparte de la corriente consumida por la retroiluminacion LED). Si se emplea una fuente negativa externa VEE de 18V, el GLCD 128x64 consumirá una corriente de 6 mA de esta fuente.

Características eléctricas del GLCD 128x64 con T6963C  

Especificaciones de la retroiluminación (LED backlight)

El GLCD 128x64 no incorpora el resistor de polarización de la luz de fondo (retroiluminación), por lo que debe ser añadido externamente, como se muestra en la figura. Se puede emplear normalmente una resistencia de 10 ohm / 0,25W (la alimentación es de 5V).

Retroiluminación (backlight) LED del GLCD 128x64 con T6963C

Fuente de alimentación

La figura muestra las posibles formas de conectar la fuente de alimentación al módulo, dependiendo de las características particulares de éste. En la mayoría de los casos el GLCD 128x64 ya incorpora el generador de voltaje negativo VEE, pero no trae el circuito de compensación de temperatura, así que se debe tomar como referencia la figura de la parte superior derecha. VR es un potenciómetro de 10kohm que se emplea para ajustar el contraste (más abajo se puede encontrar la conexión detallada).  

Alimentación del GLCD 128x64 con T6963C

Descripción de los pines del LM4228

Pinout del GLCD 128x64 con T6963C

Configuración del GLCD 128x64 con T6963C

Diagrama de bloques

El diagrama muestra que el LM4228 es una pantalla Single Scan (1 Screen), pues los controladores de columnas (COL) no aparecen duplicados (una pantalla Dual Scan (2 Screens) mostraría en total cuatro controladores de columnas: dos en la parte inferior y dos en la parte superior del LCD PANEL).

Diagrama de bloques del GLCD 128x64 con T6963C

Dimensiones del módulo y pinout (patillaje)

En la figura se puede ver que los pines del 1 al 20 se encuentran en la parte inferior del GLCD 128x64, distribuidos de acuerdo al detalle de las figuras adjuntas. Los pines para la alimentación de la retroiluminación LED se encuentran en el medio, a la izquierda (BL1-Anodo y BL2-Cátodo).

Dimensiones del GLCD 128x64 con T6963C

Detalle de los pines y conexión del contraste y la alimentación:

Conexión del GLCD 128x64 con T6963C

          Patillaje (pinout) del GLCD 128x64 con T6963C

Descripción del número de parte para las opciones disponibles

Las opciones disponibles se especifican por medio de los caracteres identificados con las posiciones 1 a 5.

Número de parte GLCD 128x64 con T6963C

Por ejemplo, el LM4228 EG64G128SNB tiene las siguientes características:

  • E    Polarizador transmisor. Fondo obscuro con retroiluminación LED.
  • G    Retroiluminación LED de color amarillo-verde.
  • S    Rango estándar de temperatura. Generación de voltaje negativo incorporado.
  • N    Cristal líquido STN. Sin compensación de temperatura.
  • B    Fondo de color azul.

opciones-disponibles-lm4228 significado-de-opciones-glcd

Ejemplo en mikroC PRO con el PIC16F877A

Ejemplo-GLCD_01.c: Programa para animar la imagen de un camión en sentido vertical, y a continuación presentar un mensaje de texto. Se emplea una pantalla LM4228 (GLCD 128x64 con controlador T6963C) y un PIC16F877A (la conexión detallada de los pines Vo y VEE para el control de CONTRASTE, y de la luz de fondo o RETROILUMINACIÓN se puede encontrar más arriba).

Circuito con PIC16F877A y GLCD 128x64 con T6963 

//GLCD_01.c
//El archivo T6963C.h contiene la definición de constantes y macros. Este
//archivo se encuentra en la carpeta del proyecto. La función T6963_Init se
//encarga de configurar el tamaño real de la pantalla (16 columnas).
#include "T6963C.h"

//Declaración de variables de conexión del T6963C
char T6963C_dataPort at PORTD;                   // Puerto de Datos

sbit T6963C_ctrlwr  at RB2_bit;                  // Señal WR write
sbit T6963C_ctrlrd  at RB1_bit;                  // Señal RD read
sbit T6963C_ctrlcd  at RB0_bit;                  // Señal CD command/data
sbit T6963C_ctrlrst at RB4_bit;                  // Señal RST reset
sbit T6963C_ctrlwr_Direction  at TRISB2_bit;     // Señal WR write
sbit T6963C_ctrlrd_Direction  at TRISB1_bit;     // Señal RD read
sbit T6963C_ctrlcd_Direction  at TRISB0_bit;     // Señal CD command/data
sbit T6963C_ctrlrst_Direction at TRISB4_bit;     // Señal RST reset

//Señales no empleadas por la librería, se configuran en la función main
sbit T6963C_ctrlce at RB3_bit;                   // Señal CE
sbit T6963C_ctrlfs at RB6_bit;                   // Señal FS
sbit T6963C_ctrlmd at RB5_bit;                   // Señal MD
sbit T6963C_ctrlce_Direction  at TRISB3_bit;     // Señal CE
sbit T6963C_ctrlfs_Direction  at TRISB6_bit;     // Señal FS
sbit T6963C_ctrlmd_Direction  at TRISB5_bit;     // Señal MD
//Final de declaración de variables de conexión del T6963C

chari,j;
unsigned char const camion128x64_bmp[1024] = {
0,  0,  1,255,255,255,255,255,252,  0,  0,  0,  0,  0,  0,  0,
0,  0,126,  0,  0,  0,  0,  0,  6,  0,  0,  0,  0,  0,  0,  0,
0, 15,128,  0,  0,  0,  0,  0, 59,  0,  0,  0,  0,  0,  0,  0,
7,255,255,255,255,255,255,255,249,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 17,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 17,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 21,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 21,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 21,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 21,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 21,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 21,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 25,  0,  0,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 27,255,255,  0,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 31,224,  0,240,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 27,  0,  0,  8,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 24,  0,  0, 12,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 16,  0,  0,114,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 16,  0,  1,202,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 23,255,242,  4,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 20,  0, 10,  5,  0,  0,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 20,  0,  5,  3,191,192,  0,  0,
4,  0,  0,  0,  0,  0,  0,  0, 20,  0,  4,199,112,249,128,  0,
4,  0,  0,  0,  0,  0,  0,  0, 20,  0,  4,188,195,231, 64,  0,
4,  0,  0,  0,  0,  0,  0,  0, 20,  0,  4,142,  0, 31, 48,  0,
4,  0,  0,  0,  0,  0,  0,  0, 27,255,255,143,  0,  0, 38,  0,
4,  0,  0,  0,  0,  0,  0,  0, 27,128,  1,  8,255,  0, 22,  0,
4,  0,  0,  0,  0,  0,  0,  0, 18,  0,  1,  0,  1,  7,  6,128,
4,  0,  0,  0,  0,  0,  0,  0, 24,  0,  3, 96,  1,248,140,128,
7,255,255,255,255,255,255,252,120,  0,  3,128,  0,  1,206,128,
3,255,255,255,255,255,255,255,248,  0,  6,  0,  0,  0,172,  0,
0, 64,  0,  0,  0,  0,  0,  0,120,  0,  8,  0,  0,  0, 11,  0,
0,127,255,255,255,255,255,255,248,  0,  8,  0,  0,  0,136,  0,
0,  0, 63,248, 70,255,255,255,240,  0,  8,  0,  0,  0,129,  0,
0,  0, 63,159,225,191,255,255,248,  0,  8,  0,127,224,132,  0,
0,  0, 63,127,240,239,255,255,255,255,248,  1,255,252,242,  0,
0,  0, 63,255,254,123,255,255,255,255,224,  3,255,252, 41,  0,
0,  0, 63,243,207, 59,255,255,255,255,240,  3,201, 62, 73,192,
0,  0, 63,238, 55,157,255,255,255,255,240,  3,184,223, 38, 64,
0,  0,  3,209,139,143,254,  1,192, 32,120,  7,104, 13,240,128,
0,  0,  7,209,167,143,249,253,252,  0, 15,215,112,  4,129,  0,
0, 63,255,246,  5,143,255,255,255,255,255,254, 89, 22,254,  0,
0,127,255,247,  5,239,255,255,255,255,255,255,120,183,128,  0,
7,255,255,211,131,239,255,255,255,255,255,255,127, 15,128,  0,
7,255,255,236, 55,255,255,255,255,255,255,255,184, 79,191,  0,
7,255,255,247,143,221,255,255,255,255,255,255,205, 62,127,128,
15,255,255,252, 63,255,255,255,255,255,255,247,248,254,254,  0,
31,255,255,255,255,247,255,255,255,255,255,255,255,249,255,  0,
31,255,255,191,255,223,255,255,255,255,255,254,255,255,255,192,
1,255,255,239,254,127,255,255,255,255,255,255,191,223,255,192,
0, 63,255,252, 31,255,255,255,255,255,255,255,251,255,254,  0,
0,  1,220,255,255,255,255,255,255,255,255,255,255,255,248,  0,
0,  0,  0,  0,  3,255,199,255,255,255,255,255,255,255,224,  0,
0,  0,  0,  7,255,255,255,255,255,255,255,255,255,240, 32,  0,
0,  0,  0,  0, 15,255, 58,255,255,255,255,195,255,224,  0,  0,
0,  0,  0,  0,  7,255,255,255,255,255,240,255,255,128,  0,  0,
0,  0,  0,  0,  0,  6,192, 15,255,248, 31,252,127,  0,  0,  0,
0,  0,  0,  0,  0,  0,  0,  0, 15,255,254, 31,255,128,  0,  0,
0,  0,  0,  0,  0,  0,  0,  0,  0, 23,131,131,254,  0,  0,  0,
0,  0,  0,  0,  0,  0,  0,  0,  1,228,  0,  0,239,  0,  0,  0,
0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 59,216,  0,  0,  0,  0,
0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
};

void main() {
T6963C_ctrlce_Direction = 0;
T6963C_ctrlce = 0;            //Habilitar el T6963C.
T6963C_ctrlfs_Direction = 0;
T6963C_ctrlfs = 0;            //Fuente 8x8 (FS<1:0>=00).
T6963C_ctrlmd_Direction = 0;
T6963C_ctrlmd = 1;            //32 columnas (MD<3:2>=11) (pantalla virtual)

T6963C_Init(128, 64, 8);      //Inicializa el T6963C. Caracteres de 8 bits.

T6963C_Graphics(1);           //Habilita la presentación de gráficos.
T6963C_Text(1);               //Habilita la presentación de texto.

while(1){
  T6963C_GrFill(0);            //Borra la pantalla gráfica.
  T6963C_TxtFill(0);           //Borra la pantalla de texto.

  Delay_ms(800);

  T6963C_Image(camion128x64_bmp);  //Dibuja la imagen en el GLCD.
  Delay_ms(1500);

  //Animación. Se logra cambiando el valor de GH.
  //GH corresponde a la esquina superior izquierda del GLCD.
  for (j=0;j<=3;j++){
    for (i=0;i<=0x0F;i++){
      T6963C_WriteData(i*0x10);
      T6963C_WriteData(j);
      T6963C_WriteCommand(T6963C_GRAPHIC_HOME_ADDRESS_SET);//Configurar GH.
      Delay_ms(30);
    }
  }
  T6963C_GrFill(0); //Borrar la pantalla gráfica.

  T6963C_WriteData(0);
  T6963C_WriteData(0);
  T6963C_WriteCommand(T6963C_GRAPHIC_HOME_ADDRESS_SET);//Restablecer GH.

  T6963C_Write_Text("Animacion de",0,2,T6963C_ROM_MODE_OR);
  T6963C_Write_Text("imagenes en",0,3,T6963C_ROM_MODE_OR);
  T6963C_Write_Text("mikroC.",0,4,T6963C_ROM_MODE_OR);
  Delay_ms(1000);
}
}

En términos muy simples, una pantalla táctil es una combinación de una pantalla gráfica estándar GLCD 128x64 a la que se le ha añadido un panel táctil (touch panel TP) lo que permite crear interfaces de usuario muy simples, intuitivos, versátiles y sumamente atractivos (similares a las pantallas táctiles de los teléfonos moviles y otros equipos electrónicos). La tecnología táctil es lo más moderno que existe actualmente para la interacción entre el usuario y un dispositivo electrónico y se usa ampliamente en teléfonos celulares, tablets, computadoras personales y otros artefactos electrónicos. Normalmente para convertir una pantalla gráfica (GLCD 128x64) a la tecnología táctil se coloca sobre aquélla un panel táctil (se lo puede comprar por separado o incorporado al GLCD). El control del panel táctil se logra actuando sobre sus cuatro terminales de conexión a través de un pequeño circuito transistorizado y un microcontrolador. La pantalla táctil se conecta de la manera convencional al microcontrolador, y debido al número relativamente alto de conexiones necesarias se debe utilizar un microcontrolador con la cantidad suficiente de pines disponibles, por ejemplo puede ser el PIC16F877A o el PIC16F887.

Pantalla táctil GLCD 128x64 con panel táctil

El panel táctil dispone de cuatro pines de conexión (en una cinta de 4 terminales); estos terminales se identifican de la siguiente forma (se puede identificar visualmente cada pin observando con atencion a cual segmento del panel tactil esta conectado):

  • T-Top (Arriba)
  • R-Right (Derecha)
  • B-Bottom (Abajo)
  • L-Left (Izquierda)

Los pines R-L conforman lo que se llama superficie X, y permiten determinar la coordenada x del panel tactil. Los pines T-B conforman lo que se llama superficie Y, y permiten determinar la coordenada y del panel tactil.

Conexión del GLCD 128x64 y el panel táctil a un PIC16F877A

La conexión del GLCD 128x64 al PIC16F877A requiere 15 pines del PIC. Mientras que la conexión del panel táctil se logra por medio de un pequeño circuito transistorizado y necesita 4 pines más del PIC, como se indica en las siguientes figuras: Circuito con pantalla táctil glcd 128x64 y pic16f877aConexión del panel táctil

Los transistores pueden ser los siguientes (o en su defecto cualquier transistor de propósito general de características similares a los indicados):

  • BC556 ó 2N3906 (PNP, Si)
  • BC546 ó 2N3904 (NPN, Si)

Una desventaja de la pantalla táctil es su elevado número de conexiones, que al final se ve compensada por los resultados obtenidos. 

Ejemplo en mikroC PRO con el PIC16F877A

GLCD_tactil.c: Pantalla táctil con GLCD 128x64 funcionando como Hoja de dibujo con el microcontrolador PIC16F877A en C (mikroC PRO). Dispone de comandos en pantalla (estos comandos se activan al tocar sobre ellos) para borrar todo CLEAR, para seleccionar el ancho del pincel (los tres puntos cuadrados), para usar el pincel como borrador ERASE y para usar el pincel como lápiz WRITE. Cuando el pincel trabaja como lápiz se puede dibujar cualquier forma en la pantalla simplemente desplazando un señalador de punta redonda (para no dañar el panel táctil). Si se desea también se puede cambiar la función del pincel para que actúe como borrador. Librerías activas de mikroC PRO: ADC, T6963C, TouchPanel y Trigonometry

//GLCD_tactil.c
//Microcontrolador: PIC16F877A
//Oscilador: Externo 4MHz (Modo HS)
//El archivo T6963C.h contiene la definición de constantes y macros. Este
//archivo se encuentra en la carpeta del proyecto.

#include        "T6963C.h"

//Declaración de variables de conexión del T6963C
char T6963C_dataPort at PORTD;                   // Puerto de Datos

sbit T6963C_ctrlwr  at RB2_bit;                  // Señal WR write
sbit T6963C_ctrlrd  at RB1_bit;                  // Señal RD read
sbit T6963C_ctrlcd  at RB0_bit;                  // Señal CD command/data
sbit T6963C_ctrlrst at RB4_bit;                  // Señal RST reset
sbit T6963C_ctrlwr_Direction  at TRISB2_bit;     // Señal WR write
sbit T6963C_ctrlrd_Direction  at TRISB1_bit;     // Señal RD read
sbit T6963C_ctrlcd_Direction  at TRISB0_bit;     // Señal CD command/data
sbit T6963C_ctrlrst_Direction at TRISB4_bit;     // Señal RST reset

//Señales no empleadas por la librería, se configuran en la función main
sbit T6963C_ctrlce at RB3_bit;                   // Señal CE
sbit T6963C_ctrlfs at RB6_bit;                   // Señal FS
sbit T6963C_ctrlmd at RB5_bit;                   // Señal MD
sbit T6963C_ctrlce_Direction  at TRISB3_bit;     // Señal CE
sbit T6963C_ctrlfs_Direction  at TRISB6_bit;     // Señal FS
sbit T6963C_ctrlmd_Direction  at TRISB5_bit;     // Señal MD
//Final de declaración de variables de conexión del T6963C

// Touch Panel (TP) module connections
sbit DriveA at RC0_bit;
sbit DriveB at RC1_bit;
sbit DriveA_Direction at TRISC0_bit;
sbit DriveB_Direction at TRISC1_bit;
// End Touch Panel module connections

char         write_erase;
char         pen_size;
char write_msg[] = "WRITE";                                // GLCD menu messages
char clear_msg[] = "CLEAR";
char erase_msg[] = "ERASE";
unsigned int x_coord, y_coord;

void Initialize() {
  DriveA_Direction = 0;                                    // Set DriveA pin as output
  DriveB_Direction = 0;                                    // Set DriveB pin as output
  TRISA  = 3;
  ADC_Init();                                              // Initialize ADC
  TP_Init(128, 64, 0, 1); //Initialize TP. Canal 0(AN0) para la posición x, canal 1(AN1)
  //para la posición y.
  TP_Set_ADC_Threshold(900);                       // Set touch panel (TP) ADC threshold
}

  void Calibrate() {
  T6963C_Dot(0,63,T6963C_WHITE);                           // Draw bottom left dot
  T6963C_Write_Text("TOUCH BOTTOM LEFT",0,3,T6963C_ROM_MODE_OR);
  TP_Calibrate_Bottom_Left();                     // Calibration of bottom left corner
  Delay_ms(1000);

  T6963C_Dot(0,63,T6963C_BLACK);                           // Clear bottom left dot
  T6963C_Dot(127,0,T6963C_WHITE);                          // Draw upper right dot
  T6963C_Write_Text("                 ",0,3,T6963C_ROM_MODE_OR);
  T6963C_Write_Text("TOUCH UPPER RIGHT",0,4,T6963C_ROM_MODE_OR);
  TP_Calibrate_Upper_Right();                     // Calibration of upper right corner
  Delay_ms(1000);
}

void main() {
T6963C_ctrlce_Direction = 0;
T6963C_ctrlce = 0;            //Habilitar el T6963C.
T6963C_ctrlfs_Direction = 0;
T6963C_ctrlfs = 0;            //Fuente 8x8 (FS<1:0>=00).
T6963C_ctrlmd_Direction = 0;
T6963C_ctrlmd = 1;            //32 columnas (MD<3:2>=11) (pantalla virtual)

T6963C_init(128, 64, 8);      //Inicializa el T6963C. Caracteres de 8 bits.
T6963C_graphics(1);           //Habilita la presentación de gráficos.
T6963C_text(1);               //Habilita la presentación de texto.

Initialize();

T6963C_Write_Text("CALIBRATION",0,3,T6963C_ROM_MODE_OR);
Delay_ms(1000);
T6963C_txtFill(0);                                            // Clear GLCD
Calibrate();
T6963C_txtFill(0);
T6963C_Write_Text("WRITE ON SCREEN",0,5,T6963C_ROM_MODE_OR) ;
Delay_ms(1000);
T6963C_txtFill(0);                                            // Clear GLCD
T6963C_Write_Text(clear_msg,0,0,T6963C_ROM_MODE_OR);
T6963C_Write_Text(erase_msg,11,0,T6963C_ROM_MODE_OR);

// Pen Menu:
T6963C_Rectangle(41,0,52,9,T6963C_WHITE);
T6963C_Box(45,3,48,6,T6963C_WHITE);
T6963C_Rectangle(63,0,70,7,T6963C_WHITE);
T6963C_Box(66,3,67,4,T6963C_WHITE);
T6963C_Rectangle(80,0,86,6,T6963C_WHITE);
T6963C_Dot(83,3,T6963C_WHITE);

write_erase = T6963C_WHITE;
pen_size = 1;
while (1) {
  if (TP_Press_Detect()) {
    // After a PRESS is detected read X-Y and convert it to 128x64 space
    if (TP_Get_Coordinates(&x_coord, &y_coord) == 0) {

      if ((x_coord < 31) && (y_coord < 8)) {
        T6963C_grFill(0);
        T6963C_txtFill(0);

        // Pen Menu:
        T6963C_Rectangle(41,0,52,9,T6963C_WHITE);
        T6963C_Box(45,3,48,6,T6963C_WHITE);
        T6963C_Rectangle(63,0,70,7,T6963C_WHITE);
        T6963C_Box(66,3,67,4,T6963C_WHITE);
        T6963C_Rectangle(80,0,86,6,T6963C_WHITE);
        T6963C_Dot(83,3,T6963C_WHITE);

        T6963C_Write_Text(clear_msg,0,0,T6963C_ROM_MODE_OR);
        if (write_erase)
        T6963C_Write_Text(erase_msg,11,0,T6963C_ROM_MODE_OR);
        else
        T6963C_Write_Text(write_msg,11,0,T6963C_ROM_MODE_OR);
      }

      // If write/erase is pressed
      if ((x_coord > 96) && (y_coord < 8)) {
        if (write_erase) {
          write_erase = T6963C_BLACK;
          T6963C_Write_Text(write_msg,11,0,T6963C_ROM_MODE_OR);
          Delay_ms(500);
        }
        else {
          write_erase = T6963C_WHITE;
          T6963C_Write_Text(erase_msg,11,0,T6963C_ROM_MODE_OR);
          Delay_ms(500);
        }
      }

      // If pen size is selected
      if ((x_coord >= 41) && (x_coord <= 52) && (y_coord <= 9))
      pen_size = 3;

      if ((x_coord >= 63) && (x_coord <= 70) && (y_coord <= 7))
      pen_size = 2;

      if ((x_coord >= 80) && (x_coord <= 86) && (y_coord <= 6))
      pen_size = 1;

      if (y_coord < 11)
      continue;

      switch (pen_size) {
        case 1 : {
          if ( (x_coord >= 0) && (y_coord >= 0) && (x_coord <= 127) && (y_coord <= 63) )
          T6963C_Dot(x_coord, y_coord, write_erase);
          break;
        }
        case 2 : {
          if ( (x_coord >= 0) && (y_coord >= 0) && (x_coord <= 127-1) && (y_coord <= 63-1) )
          T6963C_Box(x_coord, y_coord, x_coord + 1, y_coord + 1, write_erase);
          break;
        }
        case 3 : {
          if ( (x_coord >= 1) && (y_coord >= 1) && (x_coord <= 127-2) && (y_coord <= 63-2) )
          T6963C_Box(x_coord-1, y_coord-1, x_coord + 2, y_coord + 2, write_erase);
          break;
        }
      }
    }
  }
}
}

Al iniciar la ejecución del programa se debe realizar en primer lugar la calibración del panel táctil, de tal forma que las coordenadas del panel coincidan con los puntos que se muestran en el GLCD 128x64 (de lo contrario, al presionar un punto en el panel se encenderá un punto del GLCD en otras coordenadas). Para la calibración hay que seguir las instrucciones que se van dando (se recomienda usar un señalador de punta delgada pero redonda, para mejorar la precisión y al mismo tiempo evitar el deterioro de la superficie del panel táctil). A continuación se pueden ver las fotografías del proceso de calibración y algunos ejemplos:

Calibracion

Panel táctil 128x64 - Ej.0

Tocar la esquina inferior izquierda

Panel táctil 128x64 - Ej.1

Tocar la esquina superior derecha

Panel táctil 128x64 - Ej.2

Pantalla lista para dibujar

Ejemplos

Panel táctil 128x64 - Ej.4

Panel táctil 128x64 - Ej.5

Información complementaria

Reloj digital con PIC16F877A y display de 7 segmentos. La hora se muestra en formato de 24 horas; por ejemplo 14:35 (dos de la tarde y 35 minutos). Dispone de botones para ajuste de horas y minutos. Un botón adicional permite activar la presentación (encender el display) por un lapso de 1 segundo para ver la hora actual, luego de lo cual el display se apaga pero el conteo del tiempo sigue corriendo; esta funcion apaga el display de forma automatica con el proposito de reducir el consumo y ahorrar energia, muy util si la alimentacion se obtiene de una bateria.

Además, un pin se activa por un lapso de 1 segundo a dos horas diferentes programables por software.

Para que los proyectos funcionen correctamente, el PIC16F877A se tiene que polarizar de acuerdo al esquema indicado en la polarización básica (ver link más abajo).

Reloj digital en mikroC PRO con el PIC16F877A

A continuación se muestra el código completo para este reloj digital, con el PIC16F877A trabajando con el cristal oscilador externo de 4MHz. Luego de varios intentos fallidos de simulación en Proteus ISIS pude comprobar que el problema se debe a un error generado por el propio simulador, para eso me valí de un ejemplo muy sencillo con el cual pude comparar los resultados experimentales y simulados. Aparentemente falta depurar esta versión del famoso simulador pues presenta problemas con el puerto E.

//reloj7seg.c
//Microcontrolador: PIC16F877A
//Oscilador: Externo 4MHz (modo HS)
//******
//El Proteus 7.5 Professional no acepta la simulación del puerto E y presenta un mensaje de error
//al intentar su simulación. Se probó un ejemplo básico para encender un LED el cual
//funcionó perfectamente en la práctica pero el Proteus generaba el error "Internal Exception:
//acces violation in module PIC16.DLL".
//******
//Entradas:
//AA: Avance Automático al mantener presionado (también avance paso a paso al pulsar y soltar).
//Ajuste de HORAS (AA) ->RB7(40)
//Ajuste de MINUTOS (AA) ->RC7(26)
//ACTIVAR ->RD7(30)
//Salidas:
//Horas -> Puertos  A y B
//Minutos -> Puertos C y D
//Dos puntos (:) ->RE1(9)
//Pulso de 1 segundo -> RE0(8)

//Función para transformar de binario(decimal) a 7 segmentos:
char Bin2_7seg(char digit){
  switch (digit){
    case 0: return 0x3F;  //0x3F es el código 7-segmentos del 0.
    case 1: return 0x06;  //0x06 es el código 7-segmentos del 1.
    case 2: return 0x5B;
    case 3: return 0x4F;
    case 4: return 0x66;
    case 5: return 0x6D;
    case 6: return 0x7D;
    case 7: return 0x07;
    case 8: return 0x7F;
    case 9: return 0x67;
  }
}

char contador=0,segundos=0,minutos=0,horas=0, minutosBCD, unidades, decenas, horasBCD, j=0;
bit activar;

void main(){
PORTA=0x00;
RE0_bit=0;
RE1_bit=0;
ADCON1=0x06; //Pines RA<5:0> como E/S digital.
PORTB=0x00;  //Inicialización.
PORTC=0x00;
PORTD=0x00;
TRISA=0x00;  //Puerto A como salida.
TRISB=0x80;  //RB7 como entrada. RB<6:0> como salidas.
TRISC=0x80;  //RC7 como entrada. RC<6:0> como salidas.
TRISD=0x80;  //RD7 como entrada. RD<6:0> como salidas.
TRISE0_bit=0;  //RE0 como salida.
TRISE1_bit=0;  //RE1 como salida.
OPTION_REG=0b01010111;      //Pull ups habilitados.Timer0 como temporizador.
                            //Prescaler asignado al Timer0. Prescaler 1:256.

TMR0=61;                    //Valor inicial del TMR0. Interrupción cada 50 ms.
GIE_bit=1;                  //Interrupciones habilitadas.
T0IE_bit=1;                 //Interrupción del Timer0 habilitada.
activar=1;
while (1){
  if (segundos==60){
    minutos++;
    segundos=0;
  }

  if (minutos==60){
    horas++;
    minutos=0;
  }

  if (horas==24) horas=0;

  //Encender los displays por 1 segundo al presionar ACTIVAR:
  if (activar==1){
    //Encender los dos puntos ":" :
    RE1_bit=1;

    //Transformar los minutos para su presentación:
    minutosBCD=Dec2Bcd(minutos);          //Transforma de binario a BCD.
    unidades=0b1111&minutosBCD;           //Sacar las unidades.
    decenas=0b11110000&minutosBCD;        //Sacar las decenas.
    decenas=decenas>>4;                   //Desplazar 4 bits a la derecha.
    PORTD=Bin2_7seg(unidades);            //Unidades al puerto D.
    PORTC=Bin2_7seg(decenas);             //Decenas al puerto C.

    //Transformar las horas para su presentación:
    horasBCD=Dec2Bcd(horas);              //Transforma de binario a BCD.
    unidades=0b1111&horasBCD;             //Sacar las unidades.
    decenas=0b11110000&horasBCD;          //Sacar las decenas.
    decenas=decenas>>4;                   //Desplazar 4 bits a la derecha.
    PORTB=Bin2_7seg(unidades);            //Unidades al puerto B.
    if (decenas==1)
      PORTA=Bin2_7seg(decenas);            //Decenas al puerto A.
    if (decenas==2)
      PORTA=0x3B;                          //Formar el número "2".
    if (decenas==0) PORTA=0;              //Apagar las decenas cuando valgan cero.
  }
  else{
    PORTA=0;
    PORTB=0;
    PORTC=0;
    PORTD=0;
    PORTE=0;
  }

  //Generar un pulso a una determinada hora, por ejemplo a las 2h01.
  if (horas==2 && minutos==01 && segundos==0)
    RE0_bit=1;
  if (horas==2 && minutos==01 && segundos==1)
    RE0_bit=0;

  //Generar un pulso a una determinada hora, por ejemplo a las 15h25.
  if (horas==15 && minutos==25 && segundos==0)
    RE0_bit=1;
  if (horas==15 && minutos==25 && segundos==1)
    RE0_bit=0;
}
}

void interrupt(void){
  //Botón HORAS presionado:
  if (Button(&PORTB,7,1,0)){
    activar=1;
    horas++;
    if (horas==24) horas=0;
    Delay_ms(200);
  }

  //Botón MINUTOS presionado:
  if (Button(&PORTC,7,1,0)){
    activar=1;
    minutos++;
    if (minutos==60) minutos=0;
    Delay_ms(200);
  }

  //Botón ACTIVAR presionado:
  if (Button(&PORTD,7,1,0))
  activar=1;

  //Medir 1 segundo (para el encendido de los displays):
  if (activar==1){
    j++;
    if (j==20){
      j=0;
      activar=0;
    }
  }

  //Medidor de segundos (para el reloj):
  TMR0=61;                   //Valor inicial del TMR0. Interrupción cada 50 ms.
  contador++;
  if (contador==20){
    segundos++;
    contador=0;
  }
  T0IF_bit=0;              //Borra la bandera de interrupción.
}

Circuito del reloj digital con PIC16F877A

Circuito del reloj digital con PIC y display 7 segmentos Información complementaria

Este motor PAP unipolar modelo 28BYJ-48 cuenta con un conector de cinco terminales, cuatro de los cuales corresponden a las bobinas y el quinto se utiliza para la conexión de la fuente de alimentación. Incorpora un mecanismo reductor de velocidad (esto incrementa su fuerza), lo que hace necesario ejecutar una cantidad bastante grande de pasos para obtener un movimiento apreciable del eje externo (ver ejemplo de programación). Es un motor de bajo costo y puede ser utilizado en múltiples proyectos tanto básicos como avanzados.

motor pap unipolar

Dimensiones físicas (mm)

dimensiones-motor-pap-12v

Nota:d=diámetro  

Ejemplo en mikroC PRO con el PIC16F628A

MotorPAP12V.c: Realizar un control de giro de un motor PAP unipolar de 12V por medio de un PIC16F628A y un driver L293D, de tal forma que el motor ejecute una secuencia repetitiva de movimientos en sentido horario y en sentido antihorario. El encendido y apagado del motor se controla por medio de un interruptor conectado al PIC en el pin RB7, de tal forma que cuando el nivel de entrada es 0 (interruptor cerrado) el motor esté apagado, y cuando el nivel sea 1 (interruptor abierto) el motor se encienda (en el ejemplo, el motor efectúa 645 pasos en sentido horario y 650 en sentido contrario). La inversión del sentido de giro también se puede hacer intercambiando los cables Azul y Amarillo (ó los cables Naranja y Rosa).

conexión-de-un-motor-pap-unipolar-de-12v

//MotorPAP12V.c
//Microcontrolador: PIC16F628A
//Oscilador: Interno 4MHz
//Modo HALF STEP (medio paso)
void pasosCW();             //Ocho pasos CW (horario).
void pasosCCW();            //Ocho pasos CCW (antihorario).
#define PAUSA 5             //5 ms
char i;
void main(){
  PORTB=0x00;                 //Inicialización.
  NOT_RBPU_bit=0;             //Habilitar las pull-up.
  TRISB=0b10000000;           //RB<6:0> como salidas. RB7 como entrada.

  while(1){
    if (RB7_bit==0){
      RB4_bit=0;                //Motor desconectado.
      RB5_bit=0;                //Motor desconectado.
    }

    if (RB7_bit==1){
      //645 pasos CW
      for (i=1; i<=80;i++)
      pasosCW();
      PORTB=0b00110110;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00110111;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00110101;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00111101;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00111001;         //Secuencia continua.
      Delay_ms(PAUSA);

      //650 pasos CCW
      PORTB=0b00111101;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00110101;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00110111;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00110110;         //Secuencia continua.
      Delay_ms(PAUSA);
      for (i=1; i<=80;i++)
      pasosCCW();
      PORTB=0b00111110;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00111010;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00111011;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00111001;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00111101;         //Secuencia continua.
      Delay_ms(PAUSA);
      PORTB=0b00111111;         //Apagar el motor.
      Delay_ms(500);           //Esperar 5 segundos antes de repetir.
    }
  }
}

//Definición de funciones.
void pasosCW(){
  PORTB=0b00110110;
  Delay_ms(PAUSA);
  PORTB=0b00110111;
  Delay_ms(PAUSA);
  PORTB=0b00110101;
  Delay_ms(PAUSA);
  PORTB=0b00111101;
  Delay_ms(PAUSA);
  PORTB=0b00111001;
  Delay_ms(PAUSA);
  PORTB=0b00111011;
  Delay_ms(PAUSA);
  PORTB=0b00111010;
  Delay_ms(PAUSA);
  PORTB=0b00111110;
  Delay_ms(PAUSA);
}

void pasosCCW(){
  PORTB=0b00111110;
  Delay_ms(PAUSA);
  PORTB=0b00111010;
  Delay_ms(PAUSA);
  PORTB=0b00111011;
  Delay_ms(PAUSA);
  PORTB=0b00111001;
  Delay_ms(PAUSA);
  PORTB=0b00111101;
  Delay_ms(PAUSA);
  PORTB=0b00110101;
  Delay_ms(PAUSA);
  PORTB=0b00110111;
  Delay_ms(PAUSA);
  PORTB=0b00110110;
  Delay_ms(PAUSA);
}

Este tacometro trabaja con un sensor de herradura y un disco rotatorio que tiene una sola ranura. El disco está unido a un eje que girará al ponerlo en contacto con el eje de cualquier motor en funcionamiento (el movimiento se transmite por fricción).

El tacómetro digital con PIC consta de un PIC16F88, una pantalla LCD 2x16 , un sensor tipo herradura GP3S62 de Sharp, y un regulador de 5V/100mA.

El Timer0 del PIC trabaja como contador de las transiciones alto-bajo en el pin RA4/T0CKI durante 1 segundo. Este valor corresponde al número de revoluciones por segundo (r.p.s) el cual es transformado a r.p.m y rad/s para su presentación en el LCD. La lectura se actualiza continuamente cada 2 segundos. Se genera una transición cada vez que la ranura en el disco giratorio pasa  en frente del emisor de luz, es decir una transición por vuelta.

Ejemplo en mikroC PRO con el PIC16F88

//Tacometro.c
//El registro OPTION_REG tiene todos sus bits en 1 después del 
//encendido por lo tanto el Timer0 actúa como contador, 
//incrementa en transición descendente y el prescaler 
//está asignado al WDT.
//Declaración de las 12 variables necesarias para la conexión
//del módulo LCD.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB6_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB6_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Fin de declaración de variables de conexión.

char texto1[7], texto2[7], numflancos=0;
int rpm, rads;

void main(){
  OSCCON=0x40; //Oscilador interno a 1MHz.
  ANSEL=0x00;  //Pines AN<6:0> como E/S digital.
  Lcd_Init();                //Inicializa el LCD.
  Lcd_Cmd(_LCD_CLEAR);       //Borra el display.
  Lcd_Cmd(_LCD_CURSOR_OFF);  //Apaga el cursor.
  Lcd_Out(1,1,"TacometroDigital");
  Lcd_Out(2,1,"Wmax=15.300 rpm");
  Delay_ms(3000);
  Lcd_Cmd(_LCD_CLEAR);       //Borra el display.
  while (1){
    TMR0=0;                   //Inicializa el registro TMR0.
    Delay_1sec();             //Cuenta durante 1 segundo.
    numflancos=TMR0;          //numflancos=velocidad en rps.
    rpm=60*numflancos;        //Transformación a rpm.
    rads=6.28*numflancos;     //Transformación a rad/s.
    IntToStr(rpm,texto1);     //Transformación de rpm a texto.
    Lcd_Out(1,1,"W[rpm]=");
    Lcd_Out(1,10,texto1);
    IntToStr(rads,texto2);    //Tramsformación de rads a texto.
    Lcd_Out(2,1,"W[rad/s]=");
    Lcd_Out(2,10,texto2);
    Delay_ms(1000);           //Espera para la nueva medición.
  }
}

Esquema eléctrico del tacómetro digital con PIC

Circuito de un tacómetro digital con PIC
Información complementaria

El decodificador DTMF MT8870 opera en conjunto con un PIC16F628A configurado para trabajar con su oscilador interno de 4MHz. Se genera una interrupción debida al Timer0 cada 50ms (0,050 segundos) que se toma como base de tiempo para contabilizar los diferentes intervalos necesarios para el funcionamiento del circuito.

Para este ejemplo, el propósito es activar y desactivar el pin RB0 (6) por medio de una clave ingresada por el teclado del teléfono. La clave de activación es 1973, la clave de desactivación es 1974. Si el circuito se apaga por cualquier motivo, al encenderlo nuevamente se restablece el último estado que tenía el pin RB0.

Además, al ingresar la clave 3579 el pin RB1 (7) se activa durante 10 segundos. Al ingresar los dígitos el PIC espera 3 segundos. Si no se ingresa un nuevo dígito el PIC efectúa la tarea correspondiente. Si se ingresan menos o más de 4 dígitos el PIC no efectúa ninguna acción. Para ingresar una nueva clave simplemente hay que esperar más de 3 segundos. Cada 12 horas se enciende el pin RB2 (8) por un lapso de 1 hora.

Para comprobar la correcta operación del DTMF MT8870 se puede armar un circuito muy simple como se indica en el Probador para el MT8870, más abajo en la Información complementaria.

Ejemplo en mikroC PRO con el PIC16F628A

//DTMF.c
//Microcontrolador: PIC16F628A.
//Oscilador interno: 4MHz

char tecla[12], i=0, j, num_cifras, conteo=0, m=0, estado=0, pin=0, p=0;
int k=0, n=0;

//Función principal.
void main(){
  PORTB=0x00;  //Inicialización.
  CMCON=0x07;  //Pines RA<3:0> como E/S digital.
  TRISB=0x00;  //Puerto B como salida.
  OPTION_REG=0b11010111; //Timer0 como temporizador. Prescaler asignado
                        //al Timer0. Prescaler 1:256.
  GIE_bit=1;             //Interrupciones habilitadas.
  T0IE_bit=1;            //Interrupción del Timer0 habilitada.
  RB0_bit=EEPROM_Read(0x00);  //Actualiza el pin RB0 a su último estado.
  //La primera vez que se enciende el PIC, el estado del
  //pin RB0 será 1.
  TMR0=61;               //Valor inicial del TMR0 (interrupción cada 50ms).
  while (1){
    while (RA4_bit==0) ; //Esperar mientras no hay dato disponible.
    while (RA4_bit==1) ; //Dato disponible. Esperar mientras RA4 está en alto.
    i++;
    estado=1;
    num_cifras=i;
    tecla[i]=PORTA;      //Lee el dato disponible y lo almacena.
    conteo=0;
  }
}

void interrupt(void){
  TMR0=61;             //Valor inicial del TMR0.
  conteo++;
  if (conteo==60 && estado==1){
    if (tecla[1]==1 && tecla[2]==9 && tecla[3]==7 && tecla[4]==3 && num_cifras==4){ //Clave:1973
      RB0_bit=1;              //Activa el pin RB0.
      EEPROM_Write(0x00,1);   //Guarda el estado del pin RB0.
    }
    if (tecla[1]==1 && tecla[2]==9 && tecla[3]==7 && tecla[4]==4 && num_cifras==4){ //Clave:1974
      RB0_bit=0;              //Desactiva el pin RB0.
      EEPROM_Write(0x00,0);   //Guarda el estado del pin RB0.
    }
    if (tecla[1]==3 && tecla[2]==5 && tecla[3]==7 && tecla[4]==9 && num_cifras==4){ //Clave:3579
      RB1_bit=1;              //Activa el pin RB1.
      for (j=1;j<=10;j++)     //Espera 10 segundos.
      Delay_1sec();
      RB1_bit=0;              //Desactiva el pin RB1.
    }
    i=0; conteo=0; estado=0;
  }

  if (conteo==60)           //Reinicia la variable conteo si no se ha pulsado tecla alguna
  conteo=0;                //en 3 segundos.  

  k++;
  if (k==28800){            //Contabiliza 12 horas (28.800x30x0,050 segundos).
    k=0;
    m++;
    if (m==30){
      m=0;
      RB2_bit=1;              //Enciende el pin RB2.
      pin=1;                  //Registra el encendido de RB2.
    }
  }

  if (pin==1){             //Contabiliza 1 hora si RB2 está encendido.
    n++;
    if (n==14400){          //Contabiliza 1 hora (14.400x5x0,050 segundos).
      n=0;
      p++;
      if (p==5){
        p=0;
        RB2_bit=0;            //Apaga el pin RB2 luego de 1 hora.
        pin=0;
      }
    }
  }
  T0IF_bit=0;               //Borra la bandera de interrupción.
}

Esquema eléctrico del decodificador DTMF MT8870:

decodificador dtmf mt8870

Información complementaria

El L298N es un driver de potencia para el control de motores paso a paso (PAP) bipolares o unipolares de hasta 2A. Este driver puede soportar hasta 46V con una salida total de corriente de hasta 4A. El siguiente circuito tiene el propósito de ser utilizado para la prueba de cualquier motor pap unipolar o bipolar de manera rápida, para constatar su funcionamiento. El circuito consta de 4 terminales de salida para la conexión de las bobinas (fases) de los motores PAP, dos terminales para la fuente de alimentación de 5V y dos terminales para la fuente de alimentación de potencia (hasta 46V). En algunas ocasiones puede ser necesario utilizar dos fuentes independientes (una fuente para el motor y otra fuente de 5V para la lógica interna), ya que el empleo de una sola fuente (con un regulador de 5V adicional para la obtención de la alimentación de bajo voltaje) puede producir problemas de funcionamiento debido a las fluctuaciones de voltaje ocasionadas por los motores, especialmente cuando consumen corrientes elevadas. El driver L298N requiere 8 diodos externos de protección, que pueden ser los comunes 1N4007 (a menos que se trabaje con un elevado número de pulsos por segundo PPS, por encima de los 400 PPS, en cuyo caso se requieren diodos especiales de acuerdo a como lo indica la datasheet del driver L298N). Igualmente, es imprescindible el empleo de los condensadores indicados, los que ayudan a controlar los problemas ocasionados por las variaciones de voltaje propias de un sistema digital. El driver L298N tiene que estar adecuadamente refrigerado por medio de un disipador de calor de aluminio de tamaño apropiado.

El PIC 16F628A ha sido programado para que genere una secuencia de 200 pulsos en sentido horario y 200 pulsos en sentido antihorario, de forma continua. Los pulsos se aplican con un intervalo de 10ms (es decir, 100 PPS). Se indica el código fuente en lenguaje C y también se ha añadido un enlace de descarga del código ejecutable (.hex) para que el lector pueda probarlo rápidamente.

Motor paso a paso bipolar

Motor paso a paso unipolar

Nótese que la fuente de potencia (identificada como C1(1) ) se conecta directamente al punto común de las bobinas del motor (ya sea de cinco, seis u ocho terminales), y los cuatro terminales restantes del motor se conectan normalmente en las salidas del driver L298N (puede ser necesario probar varias combinaciones de estos cuatro terminales hasta lograr que el motor empiece a moverse).

Ejemplo en mikroC PRO con el PIC16F628A

//MotorPAP.c
//Microcontrolador: PIC16F628A
//Oscilador: Interno de 4MHz
//Programa para prueba de motores PAP unipolares y bipolares con
//el driver L298N. Realiza una secuencia de 200 pasos en sentido horario
//y 200 pasos en sentido antihorario de forma continua.
//Las funciones CW y CCW están escritas para mantener la continuidad
//en la secuencia de estados(de lo contrario el motor paso a paso se movera
//de forma irregular y brusca).

void pasosCW(); //Cuatro pasos CW (horario).
void pasosCCW(); //Cuatro pasos CCW (antihorario).

char i;
#define PAUSA 10 //Pausa de 10ms entre pasos.

void main(){
  CMCON=0x07; //Pines RA<3:0> como E/S digital.
  PORTA=0x00; //Estado inicial del puerto A.
  TRISA=0x00; //Puerto A como salida.
  PORTB=0x00; //Estado inicial del puerto B.
  TRISB=0x00; //Puerto B como salida.
  while(1){
     //200 pasos CW
     for (i=1;i<=50;i++)
     pasosCW();
     PORTB=0b0000; //Apagar el motor.
     Delay_ms(500); //Pausa de 500ms al final del movimiento.

     //200 pasos CCW
     for (i=1;i<=50;i++)
     pasosCCW();
     PORTB=0b0000; //Apagar el motor.
     Delay_ms(500); //Pausa de 500ms al final del movimiento.
  }
}

//Definición de funciones.
void pasosCW(){
  PORTB=0b0110;
  Delay_ms(PAUSA);
  PORTB=0b0101;
  Delay_ms(PAUSA);
  PORTB=0b1001;
  Delay_ms(PAUSA);
  PORTB=0b1010;
  Delay_ms(PAUSA);
}

void pasosCCW(){
  PORTB=0b1001;
  Delay_ms(PAUSA);
  PORTB=0b0101;
  Delay_ms(PAUSA);
  PORTB=0b0110;
  Delay_ms(PAUSA);
  PORTB=0b1010;
  Delay_ms(PAUSA);
}

Información complementaria

Este es sólo un ejemplo muy básico de un semáforo con PIC. El propósito es presentar al lector las líneas iniciales de la programación de microcontroladores en lenguaje C. El lector debe tener en cuenta que a partir de este ejemplo, y una vez que comprenda los fundamentos, podrá ir creando sus propios diseños. Por ejemplo, como paso siguiente se propone al lector que relice las modificaciones necesarias para conseguir un semáforo con PIC para cruce de vías. Por lo tanto constará de 6 luces que deberán activarse de forma sincronizada.

El semáforo con PIC consta de un PIC16F88, tres LEDs (conectados directamente al PIC, sin resistencia en serie, ya que el PIC limita la corriente de salida a 25mA). Se recomienda colocar un condensador de 100nF (0.1uF) entre los pines VDD y VSS del PIC, lo más cerca que sea posible a éste. Con este condensador se eliminarán los posibles problemas ocasionados por las variaciones de voltaje producidas cuando los pines del PIC cambian de nivel.

Ejemplo en mikroC PRO con el PIC16F88

//Semaforo.c
//RB1 -> rojo
//RB2 -> amarillo
//RB3 -> verde
void main(){
OSCCON=0x40; //Oscilador interno a 1MHz.
PORTB=0x00;  //Inicialización.
TRISB=0x00;  //Puerto B como salida.
while (1){
  PORTB=0b0010;  //Encender LED conectado en RB1(pin7).
  Delay_ms(3000);//Esperar 3 segundos.
  PORTB=0b1000;  //Encender LED conectado en RB3(pin9).
  Delay_ms(3000);//Esperar 3 segundos.
  PORTB=0b1100;  //Encender LEDs conectado en RB3:RB2(pines 9,8).
  Delay_ms(3000);//Esperar 3 segundos.
}
}

Esquema eléctrico del semáforo

esquema-eléctrico-del-semáforo-con-pic

El ejemplo mostrado intenta describir únicamente el proceso básico de generación de llamadas con el microcontrolador PIC16F628A y el IC W91314A.

El discador telefónico DTMF W91314A de Windbond Electronics es un circuito integrado monolítico que proporciona las señales necesarias para marcación por pulsos o tonos. El circuito integrado W91314A tiene una memoria de redial.

Características

  • Discador telefónico conmutable entre tonos DTMF ó pulsos
  • 32 dígitos para la memoria de redial
  • Tecla de Pulsos a Tonos (P -> T) para el funcionamiento de llamadas de larga distancia
  • Utiliza un teclado 4x4 o control electrónico de un microcontrolador
  • Fácil manejo con teclas de redial, flash, pausa y P -> T
  • Las funciones de Flash, pausa, P -> T (pulso-a- tonos) se pueden almacenar como un dígito en la memoria
  • Duración mínima de los tonos de salida: 100 ms
  • Pausa mínima entre tonos: 100 ms
  • Reset al encendido incorporado en el chip
  • Utiliza un cristal o resonador cerámico de 3.579545 MHz
  • Envasado en DIP plástico de 18 pines

Los diferentes discadores en la serie W91310 se muestran en la siguiente tabla:

discador telefónico w91314a

Pinout (patillaje)

Pinout del discador telefónico w91314a

R<4:1> - C<4:1> Entradas de Filas-Columnas
La entrada de teclado puede ser tanto del teclado estándar 4x4 o un teclado simple de un solo contacto y bajo costo. También se puede utilizar la entrada electrónica desde un microcontrolador. Una entrada de teclado válida se define como una sola fila conectada a una sola columna.

XT, /XT
Cristal o resonador cerámico de 3.579545 MHz.

MODE (Entrada)
Al conectar el pin MODE a Vss pone al chip en el modo de Tonos. Al conectar el pin MODE a VDD pone al W91314A en el modo de Pulsos (10 pps). Dejando el pin sin conectar pone al W91314A en el modo de Pulsos (20 pps).

/HKS (Entrada)
Entrada del interruptor de Colgado.
/HKS = 1: Estado de Colgado. Chip en modo suspendido, ninguna operación.
/ HKS = 0: Estado de Descolgado. Chip habilitado para operación normal.
El pin /HKS se conecta a VDD por una resistencia interna.

DTMF (Salida)

frecuencias dtmf

En el modo de Pulsos, se mantiene en estado bajo en todo momento. En el modo de Tonos, esta salida del discador telefónico emite un tono doble o individual.

VDD, Vss
Pines de alimentación.

B/M (Entrada)
Este pin no cumple función alguna en el modo de Tonos.

Operación con teclado y microcontrolador PIC16F628A

Operación con teclado

teclado del discador telefónico

Para generar una llamada, simplemente hay que poner al discador telefónico W91314A en el modo de Descolgado (/HKS = 0) y a continuación presionar las teclas correspondientes al número telefónico deseado. Al conectar una fila (R) con una columna (C) se generan simultáneamente los dos tonos indicados en la tabla anterior, los cuales son enviados por el pin DTMF.

Operación con microcontrolador PIC16F628A

Si se utiliza un microcontrolador PIC16F628A para remplazar al teclado, la idea fundamental es la misma: si se desea generar una llamada, se debe poner al W91314A en modo de Descolgado y luego conectar las filas y columnas de acuerdo a cada dígito que se quiere marcar. La técnica consiste en unir los 8 pines R<4:1> - C<4:1> del W91314A a 8 pines del microcontrolador (configurados momentáneamente como salidas) y luego enviar niveles bajos (GND) a los dos pines del PIC que están unidos a los dos pines del W91314A que se quieren juntar. Por ejemplo, para marcar el dígito “8”, se deben poner en nivel bajo los 2 pines del PIC conectados a C2 y R3; de esta forma los pines C2 y R3 quedan conectados a GND lo que equivale a una unión directa C2 - R3. En el siguiente circuito se pueden observar los detalles:

Discador telefónico dtmf con pic16f628a

Ejemplo con PIC16F628A en mikroC PRO

En el siguiente código, escrito en mikroC PRO, se debe observar que originalmente los pines del microcontrolador PIC16F628A se encuentran configurados como entradas (por defecto) lo que hace que presenten un estado de alta impedancia. Las parejas de pines se configuran momentáneamente como salidas para enviar el nivel bajo (GND) y luego se restablecen a su configuración inicial de alta impedancia. De otra forma se producirían interconexiones indeseadas de los pines del W91314A.

DiscadorDTMF.c : Genera una llamada al número 0987438877 usando el circuito W91314A como generador DTMF y el PIC16F628A como teclado electrónico. El discador se encuentra en modo Descolgado ya que el pin / HKS está conectado a GND (0).

//DiscadorDTMF.c
//Microcontrolador: PIC16F628A
//Oscilador interno: 4MHz (TCI=1us)

#define R4 RB7_bit
#define R3 RB6_bit
#define R2 RB5_bit
#define R1 RB4_bit

#define R4D TRISB7_bit
#define R3D TRISB6_bit
#define R2D TRISB5_bit
#define R1D TRISB4_bit

#define C4 RA3_bit
#define C3 RA2_bit
#define C2 RA1_bit
#define C1 RA0_bit

#define C4D TRISA3_bit
#define C3D TRISA2_bit
#define C2D TRISA1_bit
#define C1D TRISA0_bit

void main(){
CMCON=0x07;  //Pines RA como E/S digital.
TRISA=0xFF;  //Puerto A como entrada.
TRISB=0xFF;  //Puerto B como entrada.

Delay_ms (2000); //Espera 2 segundos antes de hacer la llamada.

//0
C2=0; R4=0;    //Escribir niveles bajos en los latch de salida.
C2D=0; R4D=0;  //Enviar los niveles bajos a los pines de salida.
Delay_ms(80);  //Generar los tonos durante 80 ms.
C2D=1; R4D=1;  //Restablecer los pines a su estado de alta Z.
Delay_ms(200); //Esperar 200ms antes de enviar el siguiente dígito.

//9
C3=0; R3=0;
C3D=0; R3D=0;
Delay_ms(80);
C3D=1; R3D=1;
Delay_ms(200);

//8
C2=0; R3=0;
C2D=0; R3D=0;
Delay_ms(80);
C2D=1; R3D=1;
Delay_ms(200);

//7
C1=0; R3=0;
C1D=0; R3D=0;
Delay_ms(80);
C1D=1; R3D=1;
Delay_ms(200);

//4
C1=0; R2=0;
C1D=0; R2D=0;
Delay_ms(80);
C1D=1; R2D=1;
Delay_ms(200);

//3
C3=0; R1=0;
C3D=0; R1D=0;
Delay_ms(80);
C3D=1; R1D=1;
Delay_ms(200);

//8
C2=0; R3=0;
C2D=0; R3D=0;
Delay_ms(80);
C2D=1; R3D=1;
Delay_ms(200);

//8
C2=0; R3=0;
C2D=0; R3D=0;
Delay_ms(80);
C2D=1; R3D=1;
Delay_ms(200);

//7
C1=0; R3=0;
C1D=0; R3D=0;
Delay_ms(80);
C1D=1; R3D=1;
Delay_ms(200);

//7
C1=0; R3=0;
C1D=0; R3D=0;
Delay_ms(80);
C1D=1; R3D=1;
Delay_ms(200);
}
   

El ejemplo mostrado intenta describir únicamente el proceso básico de generación de llamadas con el microcontrolador PIC16F628A y el IC W91314A. Se puede mejorar para que la conexión de la línea sea automatizada así como el estado de Descolgado. También se pueden agregar otras opciones a gusto del lector, como el llamado a varios números telefónicos, la generación de llamadas activadas por uno o varios sensores, la transmisión de mensajes de voz grabados, etc.

El display POV (Persistense Of Vision) opera en base a la persistencia de la visión humana cuando un objeto se mueve rapidamente; la rotación de una columna de LEDs que se encienden en determinada secuencia hace que se forme en la mente del observador una imagen que depende del codigo programado en un microcontrolador PIC.

Display POV

El display POV consta de un PIC16F88, un regulador de voltaje ajustable ECG1900 para el PIC (para tener control de la corriente que circula por los LEDs),  una columna de 7 LEDs RGB y un motor de CD de 5V, con control de velocidad por variación de voltaje LM317T. Para cada letra el PIC envía secuencialmente 5 grupos de 7 bits, ya sea al puerto A (verde) o al puerto B (rojo). Debido a la rotación de la columna de LEDs en sentido antihorario  y al fenómeno de la persistencia de la visión, se va formando en la mente del observador la imagen correspondiente. El PIC se puede programar con diferentes secuencias para presentar una gran variedad de mensajes.

Código en lenguaje C (mikroC PRO)

	
//POV.c
void main(){
OSCCON=0x70; //Oscilador interno a 8MHz (TCI=0,5 us).
PORTA=0x00;  //Inicialización.
PORTB=0x00;
ANSEL=0x00;  //Pines AN como E/S digital.
TRISA=0x00;  //Puerto A como salida.
TRISB=0x00;  //Puerto B como salida.

//Delay_us(5000);
PORTB=0x7E;Delay_us(500);  //m
PORTB=0x02;Delay_us(900);
PORTB=0x7E;Delay_us(500);
PORTB=0x02;Delay_us(900);
PORTB=0x7C;Delay_us(500);
PORTB=0x00;Delay_us(1500);

PORTA=0xDA;Delay_us(500);  //i
PORTA=0x00;Delay_us(1500);

PORTB=0x3C;Delay_us(500);  //c
PORTB=0x42;Delay_us(1500);
PORTB=0x24;Delay_us(500);
PORTB=0x00;Delay_us(1500);

PORTA=0xDE;Delay_us(500);  //r
PORTA=0x04;Delay_us(500);
PORTA=0x02;Delay_us(1000);
PORTA=0x04;Delay_us(500);
PORTA=0x00;Delay_us(1500);

PORTB=0x3C;Delay_us(500);  //o
PORTB=0x42;Delay_us(1500);
PORTB=0x3C;Delay_us(500);
PORTB=0x00;Delay_us(1500);

PORTA=0x5E;Delay_us(500);  //C
PORTA=0x81;Delay_us(1500);
PORTA=0x42;Delay_us(500);
PORTA=0x00;
}

Circuito del Display POV