PIC uControl + Ensamblador desde 0

September 13, 2017 | Author: Totito_97 | Category: Microcontroller, Computer Program, Bit, Liquid Crystal Display, Programming Language
Share Embed Donate


Short Description

Descripción: Tutorial sobre microcontroladores pics y lenguaje ensamblador para principiantes...

Description

Microcontroladores PIC Estructura, programación y ejemplos prácticos

  

1   

 



Introducción al PIC16F84A 



 

 

 

 

 

 

 

 

 

  3 

Mi Primer Programa, control de un LED 

 

 

 

 

 

 

 

 

  6 



Creación de Demoras, LED titilando 

 

 

 

 

 

 

 

 

  9 



Creación de Tablas, Control display 7 Segmentos 

 

 

 

 

 

 

 

12 



Direccionamiento Indirecto, Control display 7 Segmentos 

 

 

 

 

 

 

16 



Control de varios displays 7 Segmentos por multiplexado 

 

 

 

 

 

 

18 



Control de varios displays 7 Segmentos con decodificadores BCD 

 

 

 

 

 

22 



Interrupciones, Registros y guardado temporario de STATUS y W 

 

 

 

 

 

23 



Interrupción TMR0, modo Temporizador   

 

 

 

 

 

 

 

25 



Interrupción TMR0, modo Contador 

 

 

 

 

 

 

 

 

28 



Interrupción RB0, Control de LED 

 

 

 

 

 

 

 

 

31 



Interrupción RB4 a RB7, Control Teclado Matricial   

 

 

 

 

 

 

33 



Control del LCD, Pantalla de Cristal Líquido  

 

 

 

 

 

 

 

36 



Comunicación RS232   

 

 

 

 

 

 

 

 

 

41 



Introducción   

 

 

 

 

 

 

 

 

 

 

45 



Timer1 + Ejemplo 

 

 

 

 

 

 

 

 

 

 

51 



Timer2 + Ejemplo  

 

 

 

 

 

 

 

 

 

 

54 



Módulo de comunicación serie (Usart) + Ejemplo 

 

 

 

 

 

 

 

56 



Comparadores analógicos + Ejemplo 

 

 

 

 

 

 

 

 

60 



Introducción Módulo CCP 

 

 

 

 

 

 

 

 

 

65 



Modo Captura  

 

 

 

 

 

 

 

 

 

 

69 



Modo PWM   

 

 

 

 

 

 

 

 

 

 

71 



Registro de desplazamiento 74LS164N 

 

 

 

 

 

 

 

 

76 



Como hacer Cartel de LEDs 7×32  

 

 

 

 

 

 

 

 

79 

    Herramientas:  



Software para escribir nuestro código y compilar: MPLAB 



Software para simular: Proteus 



Una plaquita programadora. 



Software para grabar nuestro PIC: WinPic800 o el Icprog 



ConfigPIC: Software utilitario para crear automáticamente el código de configuración de estos PICs, además de tener otras  herramientas que nos permite calcular temporizaciones, Baud Rate, PWM, etc. 

    

Protoboard  PIC16F84A  PIC16F628A  Cristal de 4 MHz  Resistencias, capacitores, leds, Display, LCD, teclado matricial, etcétera.     

Hojas de datos (datasheets): 



Datasheet del PIC16F84A 



Datasheet del PIC16F628A 

     

2   

Introducción al PIC16F84A  En esta entrega veremos en detalle la estructura interna del microcontrolador PIC16F84A. Se trata de un modelo antiguo, pero que se  utiliza con frecuencia como herramienta de aprendizaje porque es mucho más sencillo que los modelos más modernos. Resulta ideal  para conocer las partes de un microcontrolador, la función que realizan y cómo podemos hacer que funcionen de la forma que nos  resulte conveniente para nuestros proyectos.    Introducción  El PIC16F84A está fabricado en tecnología CMOS, posee memoria FLASH, y consumo bajo de potencia. Está compuesto básicamente de  una memoria ROM (1024 palabras de memoria de programa), una memoria RAM (de acceso aleatorio, 68 bytes), líneas de entrada y  salida (2 Puertos) y una lógica de control que coordina la interacción de los demás bloques.  Estos micros pertenecen a la gama media y dispones de un set de 35 instrucciones, tipo RISC (Computador con Set de Instrucciones  Reducido) pocas pero muy poderosas.  Algunas funciones especiales que dispone este PIC: 



Temporizador programable (Timer). Si se quiere medir periodos de tiempo entre eventos, generar temporizaciones o salidas con  frecuencia específica, etc. 



Perro Guardián o Watchdog. Consiste en un temporizador que, cuando se desborda ya pasa por 0, provoca un reset automático,  utilizado para sistemas que no tienen control de un supervisor, y al bloquearse el micro se resetea. Si se utiliza el código debe  resetearlo antes de que se desborde. 



Memoria EEPROM de 64 bytes, para guardar datos que no se alteran a pesar de quitar la alimentación. 



Interrupciones, cuando una señal externa, o una condición interna activa una línea de interrupción, dejando de lado la tarea que  está ejecutando, atiende dicha interrupción y luego continúa con lo que estaba haciendo. 



Protección ante fallo de alimentación. Se trata de un circuito que resetea al micro cuando el voltaje Vdd es inferior al mínimo. 



Estado de bajo consumo (Sleep). Si el micro debe esperar mucho tiempo sin hacer nada, posee una instrucción especial, Sleep, que  lo pasa al estado de reposo. Al activarse una interrupción se “despierta” y reanuda su trabajo. (Reset externo, desbordamiento de  Watchdog, interrupción por RB0, interrupción por cambio de nivel en RB4 a RB7, interrupción por escritura completada en  EEPROM) 

Veamos el diagrama de pines, para ver cómo están distribuidos sus pines. Este microcontrolador cuenta con dos puertos configurables  como estradas y salidas, y consta de 18 pines los cuales se encuentran asignados de la siguiente manera: 

  El puerto A tiene solo cinco pines y el pin 3, o sea, el pin RA4/TOCKI puede ser configurado a su vez como entrada/salida o como  temporizador/contador. Cuando es salida se comporta como colecto abierto, por lo tanto debemos poner una resistencia Pull‐up a Vdd  de 1 Kohm. Cuando se configura como entrada, funciona como disparador Schmitt Trigger por lo que puede reconocer señales con un  poco de distorsión.  El puerto B tiene 8 pines que pueden ser configurados como entrada/salida. RB0 puede programarse además como entrada de  interrupción externa. Los pines RB4 a RB7 pueden programarse para responder a interrupciones por cambio de estado y los pines RB6 y  RB7 se corresponden con líneas de entrada de reloj y entrada de datos cuando esta en modo programación. 

3   

MCLR/Vpp es la entrada de reset si está a nivel bajo, también es habilitador de tensión de programación. Cuando su tensión es Vdd el PIC  funciona normalmente.  Vss y Vdd son los pines de masa y alimentación. La tensión de alimentación está comprendida entre los 2 y 5.5 Volt.  OSC1/CLKIN y OSC2/CLKOUT, pines de entrada externa de reloj y salida de oscilador a cristal respectivamente.  Capacidad de corriente de los puertos:  La máxima capacidad de corriente de cada uno de los pines de los puertos en modo sumidero es de 25 mA y modo fuente de 20 mA. La  máxima capacidad de corriente total de los puestos es,  Puerto A: Modo sumidero 80 mA; Modo fuente 50 mA.  Puerto B: Modo sumidero 150 mA; Modo fuente 100 mA.  El Oscilador externo:  Es un circuito externo que le indica al microcontrolador la velocidad a la que debe trabajar. Puede utilizar cuatro tipos distintos: 



RC, Oscilador con resistencia y condensador (Poco preciso) 



XT, Cristal de cuarzo. 



HS, Cristal de alta velocidad 



LP, Cristal de baja frecuencia y bajo consumo de potencia. 

Al momento de programar un micro se debe especificar qué tipo de oscilador se usa.  Internamente la frecuencia del oscilador es dividida por 4, así que si temeos un oscilador de 4 MHz, la frecuencia de trabajo es de 1 MHz,  por lo que cada instrucción se ejecuta cada 1 us.  Aquí utilizaremos un cristal XT de 4 MHz que debe ir acompañado de dos condensadores: 

  Reset:  El PIC 16F84A posee un temporizador interno conectado al pin de reset, que funciona cuando se da alimentación al microcontrolador.  Esto hace que al encender el sistema el microcontrolador quede en reset por un tiempo mientras se estabilizan todas las señales del  circuito. Para tener control sobre el reset se utiliza el siguiente circuito: 

  Estructura interna del Microcontrolador 

4   

Arquitectura del PIC, existen dos arquitecturas, la clásica de Von Neumann y la arquitectura Harvard, esta última es la que usan los PIC’s.  Dispone de dos memorias independientes, una que contiene solo instrucciones y la otra solo contiene datos. Ambas disponen de sus  respectivos buses de acceso y es posible realizar operaciones de acceso simultáneamente en ambas. 

  Memoria del programa: Aquí almacenamos nuestro programa o código que debe ejecutar, en el PIC16F84A es FLASH, es rápida, de bajo  consumo y alta capacidad de almacenamiento. Se divide en 2048 posiciones, pero este PIC solo tiene implementadas 1024 posiciones, de  0×00 hasta 0x3FF. 

  Cuando ocurre un reset, el contador de programa (PC) apunta a la dirección 0×00, y el micro inicia nuevamente. Aquí se debe escribir  todo lo relacionado con la iniciación del mismo, por ejemplo configuración de puertos, etc.  Si ocurre una interrupción PC apunta a la dirección 0×04, y aquí debemos escribir el código necesario para atender a dicha interrupción. 

5   

  Memoria RAM estática: Donde se encuentran los 24 registros específicos (SFR) y 68 registros de propósito general (GPR). Se halla  dividida en 2 Bancos de 128 bytes cada uno.  Algo que se debe tener en cuenta es la pila o Stack, que consta de 8 posiciones, cada posición contiene la dirección y datos de la  instrucción que se está ejecutando, así cuando se ejecuta una llamada call o una interrupción, el PC sabe dónde regresar.   

Mi Primer Programa, control de un LED  En esta entrega escribiremos un programa que es, en el mundo de los PICs, el equivalente al clásico “Hello World” que se utiliza como  primer programa durante el aprendizaje de cualquier lenguaje de programación. Dado que todavía no sabemos cómo utilizar una  pantalla LCD para escribir un mensaje, nuestro “Hello World” será encender y apagar un LED conectado a un pin del microcontrolador. A  pesar de su aparente sencillez, este ejemplo nos permitirá conocer los primeros elementos de la programación de esta plataforma.   A continuación vamos a desarrollar nuestro primer programa. Consideramos de mucha utilidad repasar atentamente el curso de lenguaje  assembler (MPLAB) que el usuario Leon Pic ha desarrollado en el foro uControl.  Este programa activará un led conectado a RB0 siempre que el interruptor conectado a RA0 esté cerrado. Para ello vamos a necesitar el  siguiente circuito: 

6   

  En RA0 tenemos conectado un pulsador de forma que cuando lo pulsemos se introduzca un cero lógico en el pin y cuando no lo pulsemos  se introduzca un uno lógico. Tenemos un Led con su correspondiente resistencia limitadora de corriente en el pin RB0.  Diagrama de Flujo: 

  Primero que nada debemos especificar con que microcontrolador estamos trabajando, esto lo realizamos es las dos primeras líneas: 

  En el archivo P16F84A.inc se encuentran las definiciones de las direcciones de los registros específicos, los bits utilizados en cada registro  y los fusibles del micro. 

7   

Configuración de fusibles: Hay ciertos aspectos del PIC que han de ser activados o desactivados mediante hardware a la hora de  programarlo. Esto quiere decir que no se pueden volver a cambiar hasta que el chip no se reprograme de nuevo. El PIC16F84A dispone de  4 fuses o fusibles (los modelos superiores tienen más). Cada fuse activa o desactiva una opción de funcionamiento:  1.

OSC: Este fuse controla el modo de oscilación que usará el PIC para funcionar. Como ya sabemos, el oscilador se puede  configurar de 4 maneras distintas, dependiendo de la velocidad y del tipo de circuito oscilador empleado. 

2.

WDT: El famoso “perro guardián” del PIC se configura aquí. Esta es una capacidad del microcontrolador de autorresetearse. 

3.

PWRT: Si activamos este fuse, lo que conseguimos es que se genere un retardo en la inicialización del microcontrolador. 

4.

CP: Activando este fuse tendremos la garantía de que el código que escribamos en el PIC no pueda ser leído por otra persona,  para que no nos lo copien, modifiquen, etc. (Code Protection). Esto no impide que el PIC funcione como siempre, ni que no se  pueda sobrescribir su contenido 

  Definición de variables que utilizaremos en nuestro proyecto: En este caso solo definiremos bits, por ejemplo Led y Pulsador.  Para organizar nuestro programa lo estructuraremos de la siguiente manera:  Nivel Directiva Operandos ; Comentarios 

  Configuración de puertos: Para la configuración necesitamos los siguientes registros: 



STATUS > 0×03 



PORTA > 0×05 



PORTB > 0×06 



TRISA > 0×86 



TRISB > 0×86 

Por defecto los puertos quedan configurados como entradas de datos y si se quiere cambiar hay que configurarlos. Esto se realiza con los  registros TRISA y TRISB, teniendo en cuenta que si se asigna un cero (0) a un pin, quedara como salida y si se asigna un uno (1), quedara  como entrada.  En nuestro caso se necesita colocar TRISA igual a 11111 (o se puede dejar por default) y TRISB 11111110. Ahora bien, cuando el PIC  arranca se encuentra en el Banco 0, TRISA y TRISB se encuentran en el Banco 1, entonces debemos cambiar de Banco. Esto se realiza con  el bit RP0 del registro STATUS. Si este se pone un cero a RP0, estaremos en el Banco 0. Si se coloca un uno, estaremos en el Banco 1.  Registro de trabajo W: es el registro más importante que tiene el microcontrolador y es denominado ACUMULADOR. Este registro  almacena temporalmente uno de los datos que intervienen en la operación de la Unidad lógica y Aritmética (ALU). ALU como indica su  nombre, realiza las operaciones aritméticas y lógicas previstas en la colección de instrucciones del microcontrolador. 

     

8   

Ya configurado nuestro PIC, vamos a realizar la rutina que ejecutará: 

  Aquí solamente en un bucle infinito testeamos continuamente el estado del pulsador, y según su estado se encenderá o apagará el Led.  Programa completo: 

  Bueno aquí ya tenemos nuestro programita terminado, solo falta compilarlo y simularlo para detectar errores, esto esta mínimamente  explicado en el tutorial del Utilitario MPLAB adjuntado al principio.   

Creación de Demoras, LED titilando  Uno de los temas más importantes a la hora de programar una aplicación en un PIC es la correcta implementación de las rutinas de  demoras. A pesar de que a primera vista puede parecer que nuestro código debería ser lo más rápido posible y carecer por completo de  demoras, lo cierto es que continuamente necesitamos de estas rutinas, ya sea para esperar que un periférico esté listo o que haya  trascurrido el tiempo necesario para que un dato haya sido transmitido o recibido. En esta entrega aprenderemos a programar demoras  con una gran precisión.   Denominamos Ciclo de maquina a la unidad básica de tiempo que utiliza el microcontrolador, y equivale a 4 ciclos de reloj. Ósea, si  tenemos un oscilador de 4 MHz, el ciclo de reloj seria de 250 ns y el ciclo máquina de 1 us.  Las instrucciones del microcontrolador necesitan 1 ciclo máquina, excepto algunas excepciones como son los comandos que incluyen  saltos (goto, call, btfss, btfsc, return, etc) que necesitan dos ciclos máquina.       

9   

Demoras mediante lazo simple: 

  Entre paréntesis se muestra el número de ciclos que demora cada instrucción.  De manera que el número de ciclos de instrucción Tsub consumidos por la rutina, incluyendo los 2 ciclos de la llamada (CALL) serán  Tsub = [2 + 1 + 1 + (0xXX ‐ 1)*(1 + 2) + 2 + 2] ciclos = (3*0xXX + 5) *Tcy  Donde Tcy es la duración en segundos de un ciclo de instrucción. Utilizando un oscilador de 4 MHz la mayor duración posible es de 770  us, con 0xXX = 0xFF.  Demoras mediante Lazos anidados: Para lograr demoras de mayor duración deben utilizarse lazos anidados, poniendo un lazo de  demora dentro de otro. 

  La duración de esta rutina en ciclos de reloj será  Tsub = 2 + 1 + 1 + (0xXX)*[1 + 1 + (0xYY ‐ 1)*(1 + 2) + 2 + 1 + 2] + [1 + 1 + (0xYY ‐ 1)*(1 + 2) + 2 + 2 + 2] ciclos  Lo cual se puede simplificar como sigue  Tsub = [0xXX*((0xYY ‐ 1)*3 + 7) + 5] Tcy  En este caso el tiempo máximo de demora que se puede conseguir es de aproximadamente 196 milisegundos.  Bueno ahora que se entiende como se realizan las demoras, les adjunto un programita que obtiene el código necesario para una pausa,  ingresando el valor de la misma y la frecuencia del oscilador utilizado.    Ejemplo: Veamos como calcular demoras. Se hará titilar un led conectado a RB0 siempre que el interruptor conectado a RA0 esté  cerrado.                   

10   

Diagrama de Flujo: 

  Programa: 

  11   

     

Creación de Tablas, Control display 7 Segmentos  Uno de los componentes más utilizados para mostrar información en los proyectos controlados por un microcontrolador son los displays  de 7 segmentos. Constan de 7 (u ocho) diodos LED conectados en forma de “8″, a veces con un punto decimal, y son capaces de  representar dígitos del 0 al 9. En esta entrega veremos cómo utilizarlos en nuestros proyectos, a la vez que evitamos los “rebotes” de un  pulsador. Como siempre, una entrega muy importante de este tutorial.  Creación de Tablas: Control de un Display de 7 Segmentos.  Un display es una colección de LEDs ubicados de forma estratégica. Si se los agrupa uniendo sus cátodos será de CÁTODO COMÚN, o  bien agrupando sus ánodos, un display de ÁNODO COMÚN.  Por otro lado estos LEDs pueden ser fabricados en forma de puntos o segmentos, tal es así que se encuentran display de 7 segmentos,  como los de la imagen: 

  El programa que realizaremos leerá la cantidad de veces que se activa un pulsador y mostraremos el resultado. Conectaremos el display  en forma directa, es decir conectando el puerto B del micro a los pines del display, y luego encender cada uno de los segmentos del   para  visualizar el valor correspondiente. Para ello crearemos una tabla que contenga los distintos códigos para el numero que necesitemos  visualizar.  

12   

  Es obvio que con un solo display solamente podremos contar de 0 a 9.  Diagrama de Flujo: 

 

13   

Antes de continuar tratare de explicar algunos registros importantes:  El PC (Program Counter o Contador de Programa). Direccionamiento del programa: Especifica la dirección de la instrucción que se  ejecutará. Consta de 13 bits, con lo que es posible direccionar hasta 8K palabras, pero en el 16F84A solo se implementa 1k. 

  La parte alta del contador de programa (PCH) no se puede acceder directamente, ella debe cargarse desde los 5 bits más bajos del  registro llamado PCLATCH (dirección 0×08).  En la creación de tablas, la posición a leer de la misma se realiza con el control del registro PCL. Este registro es de 8 bits, por lo que  direcciona solo 256 posiciones, por ello se debe tener en cuenta: 



 La posición de la tabla en la memoria de programa. 



 El tamaño de la tabla, si nuestra tabla tiene más de 255 posiciones, si o si debemos manejar los bits más significativos de PC  [PCLATCH]). 

Para devolver el valor direccionado se utiliza retlw, esta instrucción devuelve un valor en el acumulador al retornar de una subrutina. La  creación de la tabla se hará de la siguiente forma: 

  Donde Valor0, Valor1, Valor2… etc. son los valores que queremos almacenar en la tabla.  La estrategia a seguir para consultar algún valor de la tabla es cargar en el acumulador (W) la dirección de la tabla donde se encuentra el  valor que quieres leer y después llamar a la subrutina TABLA (con un CALL).  Advertencia: la carga de W no puede superar el número de valores de la tabla, sino se estará ejecutando una instrucción errónea  provocando un mal funcionamiento del programa. 

14   

Explicado lo necesario pasamos al código del ejemplo: 

 

 

15   

Una manera más cómoda de escribir la tabla de instrucciones RETLW puede lograrse usando la directiva DT (Define Table) del  ensamblador, la cual nos permite definir una tabla de datos que será sustituida por una lista de instrucciones RETLW; así, la tabla anterior  puede quedar como sigue: 

  Control anti rebote:  En el momento de presionar un botón pulsador o cualquier conmutador electromecánico es inevitable que se produzca un pequeño arco  eléctrico durante el breve instante en que las placas del contacto se aproximan o se alejan de sus puntos de conexión. 

  La duración de este depende de la calidad de los switches y la velocidad de accionamiento, pero no dura más de 20 milisegundos.  Se adjunta    

Direccionamiento Indirecto, Control display 7 Segmentos  En la entrega anterior aprendimos a utilizar tablas para guardar datos, y aplicamos ese conocimiento para elaborar un programa capaz  de mostrar dígitos en un display de 7 segmentos. En la presente entrada veremos otras formas de implementar una tabla,  concretamente la que se conoce como direccionamiento indirecto, mediante el uso de los registros FSR y INDF. Esto nos brindará una  nueva manera de acceder a tablas o arreglos de datos.    Otra forma de crear una tabla: Direccionamiento Indirecto.  En la programación de los microcontroladores PIC la mayoría de las instrucciones emplean direccionamiento directo, pero también es  posible que operen en un modo de direccionamiento indirecto. Para el direccionamiento indirecto se emplean dos registros especiales:  el FSR y el INDF (este último no es un registro físico). El registro FSR se emplea para “señalar o apuntar” a una dirección de la memoria  RAM cuyo contenido puede ser leído o escrito de forma indirecta empleando cualquier instrucción que use como operando al registro  INDF.  Esta forma de direccionamiento es particularmente útil cuando se manejan tablas o arreglos de datos.  Directo vs Indirecto: 

 

16   

  Utilizaremos el direccionamiento Indirecto para crear la tabla de control del display. Aquí no utilizaremos el pulsador, solo se hará el  contador automático de 0 a 9. Al iniciar el microcontrolador cargaremos el código de 7 Segmentos para controlar el Display en la  memoria de Datos con direccionamiento indirecto. Luego, al realizar el conteo leeremos el código correspondiente almacenado y lo  enviaremos al PORTB.  Aquí utilizamos el registro STATUS nuevamente, pero para control de las operaciones aritméticas. Nosotros guardaremos el código de 7  Segmentos del 0 al 9, en los registros 0×10 a 0×19. Si nuestro contador nos direcciona el registro ubicado en 0x1A, que sería el “10”, lo  reseteamos y direccionamos el “0”, ósea registro 0×10. Esto lo hacemos realizando la resta del registro seleccionado y 0x1A, FSR – 0x1A,  y si el resultado es cero, reseteamos.  El bit Z (Zero) del registro STATUS, este indica si una operación lógica o aritmética realizada da como resultado cero. También tenemos el  bit C (Carry) (0), que en instrucciones aritméticas se activa cuando se presenta un acarreo desde el bit mas significativo del resultado, el  bit DC (Digit Carry), que en operaciones aritméticas se activa si ocurre acarreo entre el bit 3 y bit 4.    Código completo: 

 

17   

 

 

 

  Control de varios displays 7 Segmentos por multiplexado  Hemos visto cómo acceder a datos guardados en tablas, ya sea de modo directo como de modo indirecto. En esas entregas utilizamos  este mecanismo para representar dígitos sobre un display de 7 segmentos. Pero en general estos displays se utilizan en grupos, a veces  muy numerosos. Cuando esto ocurre se implementa lo que se denomina “multiplexado“, que es la técnica que aprenderemos a utilizar  en la presente entrega de este tutorial.  Para el control de varios display la idea es multiplexar la señal enviada por el microcontrolador, con él administraremos el encendido de  cada display y sus segmentos (lo cual se hace por programa). Para ejemplificar haremos un contador automático de 0 a 999. El hardware  necesario es el siguiente: 

18   

  Diagramas de Flujo: 

 

19   

  Se observa que el Puerto B se utiliza para enviar los datos a mostrar en cada display, mientras que por el Puerto A seleccionas el display  que mostrará ese dato. Supongamos que quiero mostrar “231“, pues muy fácil, pongo el puerto B en 0000110 (código para el 1), y activo  ahora el 3º transistor por un periodo de tiempo corto, desactivamos este transistor, cargamos el puerto B con 1001111 y activamos el 2º  transistor por un instante, y lo mismo hacemos para mostrar “1”. Repetimos esta misma secuencia mientras se quiera mostrar este valor.  La secuencia es tan rápida que el observador no nota el momento en que cambias de display.  Control de conteo:  Para realizar el conteo incrementamos continuamente Unidad, cuando está llega a 10, las reseteamos a 0, e incrementamos en 1 Decena.  La misma operación se realiza con Decena, al llegar a 10 se lleva a 0 y se incrementa Centena. 

 

20   

21   

  En este ejemplo se mantiene la visualización del mismo valor durante aprox. 300 ms, se puede determinar ya que utilizamos 3 demoras  de 5 ms despreciando los ciclos utilizados en los comandos, que son aprox. 30 (30 us). Entonces por ciclo tenemos 15 ms, y por 20  repeticiones, 300 ms.   

Control de varios displays 7 Segmentos con decodificadores BCD  Siempre hay más de una forma de realizar una tarea, y la programación de PICs no es una excepción a esta regla. Hemos visto como  controlar varios displays de 7 segmentos mediante el multiplexado de las señales que genera el PIC, pero esa no es la única forma de  hacerlo. Hoy veremos cómo utilizar los populares circuitos 74LS47, 74LS249 o el CD4511, que son lo que se denominan “decodificadores  BCD“.  Decodificador BCD:  La otra posibilidad es utilizar un decodificador BCD como el 74LS47 o el 74LS249, o el CD4511. Estos integrados disponen de 4 entradas  correspondientes a un código binario BCD, y 7 salidas que se conectan a un directamente a un display. 

  Lo importante de este integrado, es que posee 4 pines de entrada y 7 de salida, más unos cuantos de configuración. El hecho es que los 4  pines de entrada (A, B, C y D) serán los que reciban el código en binario enviado por el micro. Una vez recibido el dato, el integrado se  hará cargo de decodificarlo y enviarlo por los pines de salida (a, b, c, d, e, f y g) para mostrarlo en el display. Lo que necesitamos saber  es que dato deberé enviar al decodificador. Y eso lo podemos hacer implementando una tabla como la siguiente:  DCBA Valor que muestra el Display  0000              0  0001              1  0010              2  0011              3  0100              4  0101              5  0110              6  0111              7  1000              8  1001              9  Una vez que hemos construido la tabla, podemos implementar el programa como hemos hecho antes, utilizando el modo de  direccionamiento directo o el direccionamiento indirecto.   

22   

Interrupciones, Registros y guardado temporario de STATUS y W  Una de las características más interesantes de los microcontroladores es el manejo de interrupciones. En pocas palabras, es un  mecanismo que interrumpe (de ahí su nombre) la ejecución normal de un programa cuando ocurre un evento determinado. Se pueden  provocar interrupciones por tiempo, por la modificación del estado de un pin, etcétera. El conocimiento de las técnicas necesarias para  programar interrupciones es fundamental para aprovechar a fondo un microcontrolador.   INTERRUPCIONES  Una de las características más importante de los microcontroladores y que mencionamos al inicio del tutorial, es que tienen la  posibilidad de manejar interrupciones. Se trata de un acontecimiento que hace que el micro deje de lado lo que se encuentra  realizando, atienda ese suceso y luego regrese y continúe con lo suyo.  Hay dos tipos de interrupciones posibles, una es mediante una acción externa (es decir por la activación de uno de sus pines), la otra es  interna (por ejemplo cuando ocurre el desbordamiento de uno de sus registros)  En el PIC16F84A hay 4 fuentes de interrupción: 



Por el pin RB0/INT, que regresa al PIC del modo SLEEP (interrupción externa). 



Por los pines RB4 a RB7, configurados como entrada y en caso de que alguno de ellos cambie de estado (interrupción externa). 



Por desbordamiento del registro TMR0, cuando este registro pasa de 255 a 0 en decimal (interrupción interna). 



Al completar la escritura de la EEPROM de datos (interrupción interna). 

Cada fuente de interrupción está controlada por 2 bits. Un bit local de interrupciones (Terminado en E) de permiso o prohibición de  ejecución. Si está en 0 bloqueará la solicitud de interrupción, y si esta en 1 permitirá la ejecución. Un bit que actúa como señalizador  (Terminado en F) el cual es activado (puesto a 1) si se ha producido la interrupción. Además existe 1 bit de control global, el bit GIE  (INTCON ) el cual si esta desactivado bloquea todas las solicitudes de interrupción.  Lo anterior descrito puede entenderse observando el diagrama lógico de la siguiente figura: 

  El bit GIE se borra automáticamente cuando se reconoce una interrupción para evitar que se produzca otra mientras se está atendiendo  a la primera y al retornar de la interrupción con la instrucción RETFIE, el bit GIE se vuelve a activar poniéndose a 1. En cambio los bits  señalizadores o banderas de interrupción deben ser puestos a cero por el tratamiento de la interrupción realizada por el usuario (el  programador)  Cuando una interrupción está habilitada (su bit local de habilitación está activado, el bit GIE está activado) y ocurre el evento que la 

23   

activa, el valor de PC se guarda en la PILA y en éste se carga el 0×04 (único vector de interrupción). Es a partir de esta dirección que se  debe colocar el tratamiento de la interrupción, detectando por medio de los bits banderas cuál de los eventos ha ocurrido y actuar según  sea el caso.  Nota: El único registro que se salva en la PILA es PC, para preservar algún otro registro debe ser el propio programa de atención a la  interrupción el que se encargue de salvar su estado al inicio de la rutina y de devolverlos al final del mismo.  Resumiendo, las acciones que se realizan automáticamente el microcontrolador y las que el programador debe tener en cuenta en sus  programas son las siguientes: 



Cuando se activa una posible causa de interrupción, el flag correspondiente se activa. Si el bit de permiso correspondiente está a 1 y  el bit de habilitación de todas las interrupciones (GIE) está a 1, se produce la interrupción. 



Para evitar que se produzca otra interrupción mientras se está atendiendo a otra anterior, el bit GIE se pone a 0. 



El valor del PC se guarda en la PILA 



El PC se carga con el valor 0×04, que es el vector de interrupciones 



El programador, debe comenzar la rutina de atención a la interrupción con un salto a la posición de memoria donde se encuentra el  programa, seguidamente se guardan todos los registros que puedan ser modificados por esta, seguidamente si están habilitadas  varias vías de interrupción, se debe explorar el valor de las banderas para determinar la causa de la interrupción. 



Dependiendo de la causa de la interrupción, la rutina de interrupción se bifurca a la subrutina correspondiente. 



Se deben devolver los valores que tenían los registros antes de producirse la interrupción y se deben borrar por software las  banderas que indican las fuentes de las interrupciones, antes del retorno al programa principal. 



Cuando se llega a la última instrucción de la rutina de interrupción, RETURN, se carga el PC con el valor que se guardó inicialmente  en la PILA y el bit GIE se pone automáticamente a 1. 

Bits utilizados: 



INTF para RB0/INT, bit 1 de INTCON, si es 1 ocurrió interrupción externa 



RBIF para los pines B4 a RB7, bit 0 de INTCON, si es 1 por lo menos un pin cambio de estado 



T0IF para TMR0, bit 2 de INTCON, si es 1 TMR0 desbordado 



EEIF para la EEPROM, bit 4 de EECON1, si es 1 se ha completado escritura 



GIE, bit 7 de INTCON, si es 1 habilita todas las interrupciones 



EEIE, bit 6 de INTCON, si es 1 se activa interrupciones de periféricos 



T0IE, bit 5 de INTCON, si es 1 int. TMR0 activada 



INTE, bit 4 de INTCON, si es 1 int. Externa activada 



RBIE, bit 3, si es 1 int. Por RB4 a RB7 activada 

Todos estos bits al resetearse o iniciarse el micro se encuentran en 0.  Rutina de Servicio de Interrupciones:  Primero debes guardar el contenido del registro W, el problema de mover W a otro registro (haciendo uso de movf) es que esta  instrucción corrompe la bandera Z, modificando el registro de STATUS. Según la hoja de datos otorgada por Microchip, en uno de sus  apartados recomienda una secuencia de código que permite guardar y restaurar los registros sin modificarlos. 

24   

  Los registros W_Temp y STATUS_Temp son registros alternativos para guardar temporariamente sus valores correspondientes.   

Interrupción TMR0, modo Temporizador  En esta oportunidad veremos cómo tratar las interrupciones que se “disparan” mediante el contador / temporizador de 8 bits TMR0. Se  trata de un registro que se incrementa continuamente, a un ritmo que le impone un preescaler y el reloj interno del microcontrolador.  Puede funcionar en modo temporizador, y seguramente encontrarás decenas de aplicaciones para todo lo que aprendas en esta entrega.    INTERRUPCION POR TMR0  El Timer 0 es un contador / temporizador de 8 bits. El registro principal de este módulo es TMR0 (0×01). Este registro se incrementa  continuamente a una frecuencia seleccionable manejada por un preescalador y el reloj interno Fosc/4 (modo temporizador) o bien, por  un preescalador y una señal externa (modo contador).  En la siguiente figura se muestra un diagrama de bloques de este módulo, en donde se indican los bits que afectan su operación y la  manera en que lo hacen. 

 

25   

  El modo Temporizador  En el modo temporizador la señal de reloj que controla el incremento del registro TMR0 es la frecuencia Fcy = Fosc/4, la cual puede ser  dividida opcionalmente por el preescalador. Este modo es seleccionado al limpiar el bit T0CS (OPTION_REG). En este modo si se  realiza una escritura al registro TMR0, su incremento es inhibido por los siguientes dos ciclos de instrucción (Tcy) y si el preescalador está  asignado se pierde la cuenta pero no su asignación.  El modo Contador  En el modo contador, la señal que controla los incrementos del registro TMR0 es una señal externa que proviene de la patita T0CKI  poniendo el bit T0CS en alto. Se puede seleccionar la transición que provoca los incrementos mediante el bit “Timer0 Source Edge Select”  T0SE (OPTION_REG), limpiando este bit se selecciona la transición de subida, mientras que al ponerlo en alto se selecciona la de  bajada.  Observación: En este modo, la señal conectada a TOCKI es muestreada durante los ciclos Q2 y Q4 del reloj interno, por ello es necesario  que permanezca en alto al menos por 2 Tosc más un pequeño retardo de 20nseg y lo mismo en bajo. (Es decir, señales demasiado  rápidas no podrán ser detectadas).  El preescalador:  El preescalador es un divisor de frecuencia de módulo seleccionable. Como se puede ver en la figura anterior, el preescalador está  compartido entre el timer0 y el módulo Watchdog, sin embargo sólo puede conectarse a uno de los dos y esto se establece mediante el  bit PSA (OPTION_REG), así, con este bit en alto el preescalador es asignado al reloj del Watchdog, mientras que con un nivel bajo en  PSA el preescalador dividirá la frecuencia que maneja al Timer 0.  La selección del módulo (valor de división de frecuencia) del preescalador se puede realizar mediante los bits PS2, PS1, PS0  (OPTION_REG) de acuerdo a la siguiente tabla: 

  Ejemplo modo temporizador:  Para calcular una temporización se necesita el tiempo de un ciclo de instrucción (es decir 1 microsegundo, si estás trabajando con un XT  de 4 Mhz), el valor del Divisor de Frecuencia (el que seleccionabas con los bits PS2, PS1 y PS0), y finalmente el complemento del valor  cargado en TMR0 (es decir 255‐TMR0). Entonces tenemos: Temporización = Ciclo de instrucción. (256‐TMR0) .Divisor de Frecuencia  De este modo si queremos temporizar 4 ms con un divisor de frecuencia de 32, tendríamos:  TMR0 = 256 – ^[4000us / (1us x 32)]  TMR0 = 131  Vemos que la máxima temporización posible es con TMR0 = 0, y Divisor de Frecuencia en 256, lográndose unos 65.5 ms aprox.  Para ejemplificar el uso de esta interrupción haremos titilar un led conectado al PIN RB0 cada 200 ms, para ello haremos una  temporización con TMR0 de 50ms y contaremos 4 desbordes del mismo para lograr los 200 ms necesarios. Lo interesante de usar  interrupción es que con el micro se puede estar ejecutando cualquier tarea y no ocupar este tiempo en un bucle de demora. El hardware  necesario es equivalente al primer ejemplo realizado.       

26   

Diagrama de flujo: 

 

 

27   

  Una ayuda adicional:  El programita presentado en el primer post tiene una utilidad que nos ayudará en el cálculo del preescaler y valor inicial del Timer para  obtener una temporización deseada, aparte de generar el código.   

Interrupción TMR0, modo Contador  En la entrega anterior comenzamos a ver cómo aprovechar las interrupciones, y explicamos que podíamos utilizar las interrupciones en  modo temporizador y en modo contador. Cada uno de estos modos tiene sus ventajas, y resulta adecuado en diferentes aplicaciones. En  esta oportunidad veremos un ejemplo de las interrupciones en modo contador, contando (valga la redundancia) el número de veces que  se produce un cambio de estado en un pin del PIC.  Ejemplo modo contador: 

28   

El siguiente programa realiza el conteo del número de veces que produce una transición de bajo a alto en la patita T0CKI. El valor del  contador se incrementará una vez por cada dos transiciones, y al detectarse 10 cambiamos el estado del LED conectado a RB0. 

  Diagrama de Flujo: 

             

29   

Código: 

 

 

  30   

Interrupción RB0, Control de LED  Seguimos aprendiendo como utilizar las interrupciones. Ya hemos visto con anterioridad algunas de sus particularidades, y en esta  oportunidad aprenderemos como utilizar interrupciones externas, es decir, las que se “disparan” como respuesta a un evento que tiene  lugar fuera del microcontolador. Comenzaremos con las que provienen de modificaciones en el estado del pin RBO/INT.  INTERRUPCION EXTERNA, RB0/INT  Para el control de la interrupción externa se necesitan dos bits más, ellos son RPBU (OPTION_REG, que activa o desactiva las  resistencias Pull‐Up internas del PORTB, en caso de que el dispositivo conectado al puerto sea de colector abierto y el más importante  INTEDG (OPTION_REG), si esta en 1, la interrupción se genera por flanco ascendente, y en 0, la interrupción se genera por flanco  descendente.  Para mostrar su uso haremos un ejemplo sencillo que muestre como se configura, el cual al presionar un pulsador conectado a RB0  cambiará el estado de un led conectado a RB1, para ello configuramos que la interrupción de genere por flanco ascendente.  Diagrama de Flujo: 

 

31   

Código: 

 

  . 

  32   

Interrupción RB4 a RB7, Control Teclado Matricial  Continuamos aprendiendo a sacar provecho de las interrupciones externas. Habíamos visto como utilizar los cambios en el estado del pin  RB0/INT, y hoy aprenderemos a utilizar las que provienen de los pines RBA a RB7 para detectar que tecla se ha presionado en un teclado  matricial. Esta entrega es muy importante, ya que nos permite aprender a utilizar teclados, algo muy común en los proyectos que utilizan  microcontroladores.    INTERRUPCION EXTERNA, RB4 a RB7  Aprovecharemos esta interrupción para detectar cuando se ha presionado una tecla de un Teclado Matricial. Un teclado matricial es un  simple arreglo de botones conectados en filas y columnas, de modo que se pueden leer varios botones con el mínimo número de pines  requeridos. Un teclado matricial 4×3 solamente ocupa 4 líneas de un puerto para las filas y otras 3 líneas para las columnas, de este  modo se pueden leer 12 teclas utilizando solamente 7 líneas de un microcontrolador.  Para detectar la tecla presionada se utilizara el siguiente hardware: 

  Configuraremos RB0 a RB3 como salidas y las colocaremos a nivel bajo. RB4 a RB7 configuradas como entradas, y en estado normal (sin  presión de teclas) estarán a nivel alto. Al presionar una tecla se conecta una fila con una columna, se produce un cambio de nivel en  alguna de las columnas (de nivel alto a bajo), y se genera la interrupción. Para detectar que tecla se ha presionado, se colocan RB0 a RB3  a nivel alto, y se pasan a nivel bajo de a una por vez, detectando si se produce algún cambio en las columnas. 

33   

  Se utiliza una variable que se incrementa con la cuenta de las teclas revisadas, de este modo al detectar una pulsación el valor de la  cuenta será el valor de la tecla presionada. Si al final no se presionó ninguna tecla la variable se pone a cero y la cuenta vuelve a  comenzar. En nuestro ejemplo representaremos la tecla presionada en forma binaria con leds conectados al puerto A.  Diagrama de Flujo: 

 

34   

Código: 

 

 

35   

  También con la variable NTecla (Numero de Tecla presionada) se puede utilizar como entrada a una tabla para codificar en ASCKII la tecla  presionada:  Código: 

 

 

Control del LCD, Pantalla de Cristal Líquido  Cuando explicamos como mostrar información en uno o más displays de LEDs seguramente pensaste que en algunos casos sería mejor  utilizar una pequeña pantalla LCD alfanumérica. En esta entrega, luego de haber visto cómo utilizar un teclado matricial, vamos a  analizar las rutinas necesarias para que nuestros proyectos puedan incorporar estas versátiles pantallas. Con estos elementos nuestros  proyectos estarán a la altura de los profesionales.    Control del LCD  La pantalla de cristal líquido o LCD (Liquid Crystal Display) es un dispositivo µControlado de visualización grafico para la presentación de  caracteres, símbolos o incluso dibujos (en algunos modelos). En este caso dispone de 2 filas de 16 caracteres cada una y cada carácter  dispone de una matriz de 5×7 puntos (pixels), aunque los hay de otro número de filas y caracteres. Este dispositivo está gobernado  internamente por un microcontrolador Hitachi 44780 y regula todos los parámetros de presentación, este modelo es el más  comúnmente usado y la información que se adjunta se basará en el manejo de este u otro LCD compatible. 

36   

  

 

Conexión del módulo LCD al PIC16F84A mediante bus de 4 bits.    En este ejemplo haremos uso de dos directivas más de ensamblador. Estas son #DEFINE y macro.  #DEFINE es empleado para crear sustituciones dentro del texto del programa que lo simplifiquen. La forma correcta es #DEFINE NOMBRE  TEXTO, con lo que, cada vez que el compilador encuentre la orden NOMBRE, la sustituirá por el texto. El problema que se nos plantea es  que, si bien es más flexible que la directiva EQU, puesto que esta sólo nos permitía asignar un valor, sólo se nos permite con #DEFINE una  línea de texto, y esta debe ser fija.    Este problema se soluciona mediante macro. Esta directiva tiene la siguiente forma: 

  De este modo NOMBRE será sustituido como comando por la secuencia completa definida tras macro hasta endm, y los sucesivos  argumentos serán, a su vez, sustituidos dentro del texto.  En nuestro ejemplo lo utilizaremos para enviar un carácter o un comando al LCD, de la siguiente manera:  Código: 

       

37   

Rutinas de Control: 



LCD_Config_puertos: Configura los puertos del PIC para el uso del módulo LCD, solo afecta a los pines utilizados. 



LCD_Init: Inicializa el módulo LCD para su correcto funcionamiento. Es necesario ejecutar esta subrutina al principio de los  programas que vayan a utilizar la visualización mediante LCD. 



LCD_Bandera: Explora el estado de la bandera Busy (ocupado) del módulo LCD y espera que termine cualquier comando previo  antes de volver a la rutina que le llamo. 



LCD_Enable: Habilita el módulo LCD durante 2us para recepción de datos o envío.‐ 



LCD_Comando: Configura módulo LCD para recibir un comando mediante rutina LCD_Envio_Data. 



LCD_Caracter: Configura módulo LCD para recibir un carácter mediante rutina LCD_Envio_Data. 



LCD_Envio_Data: Envía dato al LCD, Cargando el nibble alto y luego el nibble bajo. 

Nota: Observar que las líneas de control y bus de datos es fácilmente modificable en Declaración de bits para control LCD y Declaración  de Bytes del LCD.  Como ejemplo de aplicación se muestra un ejemplo donde se visualiza un mensaje (“Ucontrol”):  Código: 

 

 

38   

39   

 

 

40   

 

  Comunicación RS232  En esta entrega llega a su fin la primera parte de este curso. En efecto, con la explicación de cómo utilizar el puerto serie RS232 para  enviar y recibir datos con un microcontrolador terminamos la sección de este tutorial dedicada al microcontrolador PIC16F84A.  En la  entrega siguiente aprovecharemos todo lo aprendido para comenzar a desarrollar temas relativos al microcontrolador PIC16F628A, más  potente, moderno y económico el clásico PIC16F84A que hemos utilizado hasta este momento.  El RS232 es un estándar de comunicaciones propuesto por la Asociación de Industrias Electrónicas (EIA) la cual define la interfase  mecánica, los pines, las señales y los protocolos que debe cumplir la comunicación serial. La velocidad se mide en baudios (bits/segundo) y  está normalizada a 2400, 4800, 9600, 19200, 38400, etc. Y sólo son necesarios dos cables, uno de transmisión y otro de recepción.  Todas las normas RS‐232 cumplen con los siguientes niveles de voltaje: 



Un “1” lógico es un voltaje comprendido entre –5v y –15v 



Un “0” lógico es un voltaje comprendido entre +5v y +15 v 

  Los puertos series son accesibles mediante conectores. La norma RS232 establece dos tipos de conectores llamados DB‐25 y DB‐9,  machos y hembras. La norma RS232 se estableció para conectar un ordenador con un modem, por lo que aparecen muchas patillas en los  conectores DB‐25 que en otro tipo de aplicaciones no se utilizan y en las que es más común utilizar el conector DB‐9.  Cada una de las patillas del conector RS232 tiene una función específica. Patillas del DB‐9: 

41   

  Los pines que portan los datos son RxD y TxD los demás se encargan de otros trabajos, el DTR indica que el ordenador esta encendido,  DSR que el dispositivo conectado al puerto esta encendido, RTS que el ordenador al no estar ocupado puede recibir datos, al revés  de CTS que lo que informa es que es el dispositivo el que puede recibir datos, DCD detecta que existen presencia de datos, etc.  Formato de un byte:  El protocolo establecido por la norma RS232 envía la información estructurada en 4 partes: 



Bit de inicio o arranque (START). Es un paso de ‐12V a +12V, es decir de un “1” a un “0” lógico en la lógica negativa de la norma  RS232. 



Bits de datos (Datas) Los bits de datos son enviados al receptor después del bit Start. El bit de menos peso LSB es trasmitido  primero. Un carácter de datos suele consistir en 7 u 8 bits. 



Bit de Paridad (Parity) Dependiendo de la configuración de la transmisión un bit de paridad puede ser enviado después de los bits de  datos. Con este bit se suele descubrir errores en la transmisión, puede dar paridad par o impar. 



Bit de Parada (STOP) la línea que a ‐12V después del último bit enviado, es decir queda a “1” en lógica negativa de la norma. El  protocolo permite 1, 1.5 o 2 bits de parada. 

MAX 232:  En el mercado hay muchos circuitos integrados que permiten la conversión entre niveles TTL y niveles RS232. El más destacado es el  transceptor MAX232: 

  Este convierte los niveles RS232  a voltajes TTL  y viceversa sin requerir más que una fuente de +5V y un par de  capacitores. Para ejemplificar el uso de este protocolo para establecer comunicación con la PC, haremos un programita que reciba la data  de la PC y se la reenviaremos inmediatamente. 

42   

  Para la recepción de datos aprovecharemos la interrupción externa por RB0, configurada en flanco descendente (detectará cuando la PC  envié un bit de Start). Deja pasar un tiempo una y media veces mayor que el periodo de transmisión para saltarse el bit de Start y lee el  primer bit en su mitad. Lee el resto de los bits de datos, esperando un tiempo igual a la duración del periodo entre lectura y lectura para  testearlos en mitad del bit. Kbhit indica si ha llegado o no un dato desde PC.   Para el envío de datos se envía un “0″ durante un tiempo igual al periodo de la velocidad de transmisión. Este es el bit de “Start”. Luego  se envía el bit correspondiente al dato a enviar: Si va a enviar un “0″ permanece en bajo durante el periodo correspondiente y si se va a  escribir un “1″ permanece en alto durante el periodo correspondiente. Al enviar los 8 bits de datos se envía un bit de Stop, nivel alto  durante un periodo.   Los parámetros adoptados para la comunicación son los siguientes: 



Velocidad 9600 baudios 



Dato de 8 bits 



Sin Paridad 



1 bit de Stop 

Para establecer comunicación con el microcontrolador utilizaremos el software Siow, es un monitor del puerto serie muy sencillo de usar,  solo hay que configurar los parámetros de comunicación. (También se puede usar el Hyperterminal de Windows) 

 

43   

Código: 

 

 

 

44   

 

  Con la explicación de cómo utilizar el puerto serie RS232 para enviar y recibir datos con un microcontrolador terminamos la sección de  este tutorial dedicada al microcontrolador PIC16F84A.  En la entrega siguiente aprovecharemos todo lo aprendido para comenzar a  desarrollar temas relativos al microcontrolador PIC16F628A, más potente, moderno y económico el clásico PIC16F84A que hemos  utilizado hasta este momento   

Introducción al PIC 16F628A  Cuando comenzamos a trabajar con microcontroladores en ASM necesitamos de toda la ayuda con la que podamos contar. Ya hemos  visto en profundidad el microcontrolador PIC16F84A, y ahora es el turno de su “hermano mayor” PIC16F628A. Al igual que la primera  parte del tutorial, esta consta de varios capítulos que estamos seguros de que te resultarán muy útiles. Esta entrega es algo más larga de  lo normal, pero te aseguramos que vale la pena.  PIC16F628A 

45   

Haré una introducción a los micros y realizare ejemplos para los módulos que no trae el PIC16F84A. Empezaré por sus características  principales 



Conjunto reducido de instrucciones (RISC). Solamente 35 instrucciones que aprender a utilizar 



Oscilador interno de 4MHz 



Opera con una frecuencia de reloj externa de hasta 20 MHz (ciclo de máquina de 200 ns) 



Memoria de programa: 2048 locaciones de 14 bits 



Memoria de datos: Memoria RAM de 224 bytes (8 bits por registro) 



Memoria EEPROM: 128 bytes (8 bits por registro) 



Stack de 8 niveles 



16 Terminales de I/O que soportan corrientes de hasta 25 mA 



3 Temporizadores 



Módulo de comunicación serie (Usart 



Módulo CCP (captura/comparación/PWM) 



2 Comparadores analógicos, una referencia de voltaje programable 



Nota: Los módulos descriptos para el PIC16F628A son idénticos a los del PIC16F648A, lo único que varía entre ellos son las siguientes  características: 



Memoria de programa: PIC16F648A‐4096 locaciones de 14 bits 



Memoria de datos: PIC16F648A‐Memoria RAM de 256 bytes (8 bits por registro) 



Memoria EEPROM: PIC16F648A‐256 bytes (8 bits por registro) 

De aquí en adelante me refiero al PIC16F628A pero los ejemplos son aplicables al PIC16F648A haciendo el cambio de encabezado: 

 

  Puertos:  Los PIC16F628/648A cuentan con dos puertos (PORTA y PORTB), algunos pines de estos puertos de entrada/salida son multiplexados con  una función alternativa de los periféricos del dispositivo. Cuando un periférico es activado el pin no puede ser usado para propósitos  generales de e/s.  El PUERTO A es un puerto de entrada de 8 bits. Todos los pines, excepto RA5, pueden ser configurados como entrada o salida con la  respectiva configuración del registro TRISA. El pin RA4 esta multiplexado con la entrada de reloj T0CKI y como salida se comporta como  colecto abierto, por lo tanto debemos poner una resistencia Pull‐up a Vdd. El pin RA5 es un disparador Schmitt solo de entrada y no  cuenta con controladores de salida, según la configuración, puede ser usado como Mclr (Reset externo), y además sirve también para  entrar en el modo de programación cuando se aplica una tensión igual a Vpp (13,4V mínimo). Los demás pines del puerto trabajan de  entrada como disparador de Schmitt Trigger y como salida lógica CMOS. Los pines RA0‐RA3 sirven de entrada para el comparador  analógico.  Importante: Si se utiliza en puerto A como I/O Digital, se debe deshabilitar los Comparadores Analógicos, cargando un 0×07 en CMCON.   

46   

El PUERTO B es un puerto bidireccional de 8 bits, del cual por software se pueden habilitar resistencias de pull‐up internas. El PORTB es  multiplexado con interrupciones externas, tales como detección de flanco por RB0, cambio de nivel por RB4 a RB7, USART, el módulo CCP  y el reloj de entrada/salida TMR1.  Otros pines: 



VDD: Pin de alimentación positiva. De 2 a 5,5 Vcc 



VSS: Pin de alimentación negativa. Se conecta a tierra o a 0 Vcc 



MCLR: Master Clear (Reset). Si el nivel lógico de este terminal es bajo (0 Vcc), el microcontrolador permanece inactivo. Este Reset se  controla mediante la palabra de configuración del PIC 



OSC1/CLKIN: Entrada de oscilador externo 



OSC2/CLKOUT: Salida del oscilador. Dependiendo de cómo se configure puede proporcionar una salida de reloj por medio de este  pin 

Organización de la memoria: 

 

Organización de la memoria 

47   

El PIC16F628A posee un contador de programa de 13 bits, capaz de direccionar un espacio de memoria de 8Kx14. Sin embargo,  únicamente los primeros 2Kx14, desde 0000h hasta 07FFh, están implementados. Los vectores de reset e interrupción están en las  direcciones 0000h y 0004h, respectivamente. La pila (stack) es de 8 niveles, lo cual significa que puede soportar hasta 8 direcciones de  retorno de subrutina.  El PIC16F628A posee un espacio de memoria RAM de datos de 512×8, dividido en 4 bancos de 128 bytes cada uno. Sin embargo, sólo  están implementados 330 bytes, correspondiendo 224 al área de los registros de propósito general (GPR) y 36 al área de los registros de  función especial (SFR). Los restantes 70 bytes implementados son espejos de algunos SFR de uso frecuente, así como de los últimos 16  GPR del banco 0. Por ejemplo, las posiciones 0Bh, 8Bh, 10Bh y 18Bh corresponden al registro INTCON, de modo que una operación hecha  en cualquiera de ellos, se refleja automáticamente en los otros. Se dice, entonces, que las posiciones 8Bh, 10Bh y 18Bh están mapeadas  en la posición 0Bh. Esta característica agiliza el acceso a estos registros, puesto que no siempre es necesario especificar el banco donde  se encuentran. La selección del banco de ubicación de un SFR o un GPR particular se hace mediante los bits 6 (RP1) y 5 (RP0) del registro  STATUS. 

 

Registros 

48   

 Interrupciones:  Registros utilizados:  INTCON: Registro de lectura y escritura que contiene varios bits de señalización y habilitación para el desbordamiento del TMR0, cambio  sobre el puerto RB e interrupción externa en la patilla RB0/INT. 



0. RBIF: Indicador de interrupción por cambio de estado RB4‐RB7 



1. INTF: Indicador de interrupción externa 



2. T0IF: Indicador de interrupción por desbordamiento de Timer 0 



3. RBIE: Habilitación de interrupción por cambio de estado RB4‐RB7 



4. INTE: Habilitación de interrupción externa 



5. T0IE: Habilitación de interrupción por desbordamiento de Timer 0 



6. PEIE: Habilitación de interrupción de periféricos 



7. GIE: Habilitación general de interrupciones 

PIR1: El registro PIR1 contiene los bits de señalización individual de las interrupciones de periféricos  0. TMR1IF: Indicador de interrupción por desbordamiento de Timer 1 



1. TMR2IF: Indicador de interrupción por desbordamiento de Timer 2 



2. CCP1IF: Indicador de interrupción del módulo de Captura/Comparación. 



a) Modo Comparador: Coincidencia entre TMR1 y CCP1 



b) Modo Captura: Ha ocurrido una captura de TMR1 



3. No Implementado. 



4. TXIF: Indicador de interrupción de fin de transmisión USART 



5. RCIF: Indicador de interrupción de llegada de datos USART 



6. CMIF: Indicador de interrupción por cambio de estado de alguna de las salidas de los comparadores. 



7. EEIF: Indicador de interrupción de fin de escritura eeprom interna. 

PIE1: Registro que posee los bits de habilitación individual para las interrupciones de periféricos. El bit PEIE del registro INTCON debe ser  1 para permitir la habilitación de cualquier interrupción de periférico. 



0. TMR1IE: Habilitación de interrupción por desbordamiento de Timer 1 



1. TMR2IE: Habilitación de interrupción por desbordamiento de Timer 2 



2. CCP1IE: Habilitación de interrupción del módulo de Captura/Comparación/PWM. 



3. No Implementado. 



4. TXIE: Habilitación de interrupción de fin de transmisión USART 



5. RCIE: Habilitación de interrupción de llegada de datos USART 



6. CMIE: Habilitación de interrupción por cambio de estado de alguna de las salidas de los comparadores. 



7. EEIE: Habilitación de interrupción de fin de escritura eeprom interna. 

Lógica de Interrupciones: 

 

49   

Palabra de Configuración:  El PIC16F628 ha sido construido con características tales que se puede configurar para funcionar en modos de operación que no  necesitan componentes externos tales como el circuito de reloj o de reset. Esto implica que es necesario configurar su modo de  operación a través de una palabra de configuración. La palabra de configuración se encuentra mapeada en la dirección 2007h de la  memoria de programa y solo puede ser accedida durante la programación de dispositivo. 

 

Palabra de Configuración  CP1:CP0: Bits de protección de código  Los bits 13‐10 encargados de proteger la memoria de programa.  CPD: Bit de protección para código de datos 



1 = Protección deshabilitada de la memoria de datos. 



0 = Protección habilitada en la memoria de datos. 

LVP: Habilitación de la programación por voltaje bajo 



1 = LVP habilitado, la terminal RB4/PGM tiene tal función. 



0 = LCP: deshabilitado, RB4/PGM es una terminal I/O. 

BODEN: Bit de reset por voltaje de alimentación bajo 



1 = Reset por BOD habilitado 



0 = Reset por BOD deshabilitado 

MCLRE: Habilitacion del terminal de reset 



1 = Terminal de reset en RA5. 



0 = MCLR conectado internamente a Vdd, RA5 es un pin I/O. 

PWRTEN: Bit de habilitación de temporizador al energizar 



1 = PWRT habilitado. 



0 = PWRT deshabilitado. 

WDTEN: Bits de habilitación de Watch‐Dog 



1 = WDT habilitado 



0 = WDT deshabilitado. 

FOSC2:FOSC1:FOSC0: Bits de selección del tipo de oscilador   

 

50   

 

  Timer1 + Ejemplo  Comenzaremos a analizar los módulos TImer0, Timer1 y Timer2 del microcontrolador PIC16F628A. En realidad, el primero de los tres no  tiene diferencias con el que se incluye en el microcontrolador PIC16F84A, por lo que simplemente podemos leer lo escrito en la primera  parte de esta serie de entradas. En el resto, por supuesto, hay diferencias que ya mismo vamos a analizar.   El Módulo del Timer 0, como decíamos, es idéntico al del PIC16F84A.  El Módulo del Timer 1:  El Timer 1 a diferencia del Timer 0 es un temporizador/contador de 16 bits. El conteo es realizado por dos registros de 8 bits:  (TMR1H (0Fh) y TMR1L (0Eh)) que son tanto leíbles como escribibles.  Así, el registro TMR1 se incrementa de 0000h a FFFFh y en la siguiente cuenta se reinicia en 0000h y así sucesivamente, al reciclarse se  activa (en alto) la bandera TMR1IF (PIR1), la cual puede ser utilizada para generar una interrupción, o bien, para ser consultada por  poleo.  En la siguiente figura se muestra un diagrama de bloques de este módulo, en donde se indican los bits que afectan su operación y la  manera en que lo hacen: 

 

51   

Modo temporizador  En este modo el Timer se incrementa (si no se considera preescalador) en cada ciclo de instrucción (a la frecuencia Fosc/4). Este modo se  selecciona limpiando el bit TMR1CS (T1CON).  El preescalador que se puede intercalar entre el reloj Fosc/4 y el registro TMR1 puede tener sólo uno de 4 valores: 1/1, 1/2, 1/4 y 1/8.  En este caso la temporización de calcula:  Temporización = Ciclo de instrucción. (65536‐TMR1) .Divisor de Frecuencia  Vemos que la máxima temporización posible es con TMR1 = 0, y Divisor de Frecuencia en 8, lográndose unos 524.3 ms aprox.  Modo contador:  El Timer 1 también puede operar como contador asíncrono o síncrono contando los flancos ascendentes que ocurren en pin  RB6/T1OSO/T1CKI poniendo a 1 el bit TMR1CS. Después de que el Timer1 se programe en modo contador, el módulo esperará un flanco  de bajada antes de comenzar los incrementos con los flancos de subida.  Contador sincronizado: Si SYNC T1 se borra, la entrada externa de reloj se sincroniza con la fase interna de reloj. La sincronización se  produce después de la etapa del Predivisor. Este bloque es un contador cíclico asíncrono.  Contador asincrónico: Si el bit de control SYNC T1 se activa, la entrada de reloj externa no queda sincronizada con el reloj interno. El  temporizador continuará funcionando durante el estado de SLEEP, y puede provocar una interrupción en su desbordamiento que saque  de su “siesta” a la CPU.  Oscilador del Timer1:  Se debe conectar un cristal de cuarzo entre las patillas T1OSI (entrada) y T1OSO (salida del amplificador oscilador). El oscilador se habilita  con el bit T1OSCEN (T1CON), y funcionará en bajo consumo a partir de 200 KHz. Este oscilador continúa funcionando aunque la CPU  entre en modo SLEEP, y está diseñado especialmente para trabajar a 32.768 Hz.  Configuraciones:  El Timer 1 posee un bit para habilitación / deshabilitación, este es el bit TMR1ON (T1CON) y habilita en alto.  Además, el Timer 1 posee una entrada interna de RESET, el cual puede ser activado por uno cualquiera de los módulos CCP .  A continuación se describe el principal registro relacionado con el Timer 1 y todos sus bits, excepto los que tienen que ver con el modo  contador:  Registro T1CON (10h) 

 

Principal registro relacionado con el Timer 1 y todos sus bits.  Bits 5:4 T1CKPS1:T1CKPS0.‐ Bits de selección del valor del divisor de frecuencia del preescalador: 



1 1 = divisor 1/8 



1 0 = divisor 1/4 



0 1 = divisor 1/2 



0 0 = divisor 1/1 

bit 3 T1OSCEN: Bit de control de habilitación de oscilador para TMR1. 



1 = Oscilador habilitado. 



0 = Oscilador anulado. 

Bit 2 T1SYNC: Bit de control de sincronización de la entrada de reloj externo de Timer1.  TMR1CS = 1 



1 = Entrada de reloj externo no sincronizada. 



0 = Entrada de reloj externo sincronizada 

52   

TMR1CS = 0  En esta circunstancia, Timer1 usa el reloj interno.  Bit 1 TMR1CS.‐ Bit de selección de la fuente de reloj 



1 = Modo contador (fuente de reloj: patita RB6/T1OSO/T1CKI) 



0 = Modo Temporizador (fuente de reloj Fosc/4) 

Bit 0 TMR1ON.‐ Bit de habilitación / deshabilitación del Timer 1: 



1 = habilita Timer 1 



0 = Deshabilita Timer 1 

ConfigPIC trae una herramienta adicional que nos ayuda a seleccionar el preescaler y valor inicial del Timer para obtener una  temporización deseada: 

   Para ejemplificar haremos un simple ejemplo donde lo utilizamos como temporizador. Se hará titilar un led conectado al PIN RB0 cada  300 ms. Como se puede ver es idéntico al ejemplo realizado para Timer 0 del PIC16F84A, solo que en este caso no necesitaremos un  registro adicional para lograr la demora deseada.  Hardware: 

 

53   

Código: 

 

  Timer2 + Ejemplo    Seguimos analizando los módulos TImer0, Timer1 y Timer2 del microcontrolador PIC16F628A. En la entrega anterior nos ocupamos de  los dos primeros, e hicimos notar que el primero de ellos no tiene diferencias con el que se incluye en el microcontrolador PIC16F84A,  por lo que simplemente podíamos aplicar lo aprendido en la primera parte de esta serie de entradas. Hoy nos ocupamos de los detalles  del tercero de ellos, para sacar todo el jugo a las posibilidades del Timer2.  El Módulo del Timer 2:  El Timer2 es un temporizador (sin opción de trabajar como contador) de 8 bits. Su registro principal denominado TMR2 (11h) es un  registro de 8 bits que se incrementa continuamente a la frecuencia seleccionada de Fosc/4 dividida por un preescalador. En la siguiente  figura se muestra un diagrama de bloques del módulo del Timer2. 

  El preescalador:  La frecuencia que incrementa al registro TMR2 puede ser dividida por un preescalador por un factor de 1/1, 1/4 o 1/16, seleccionable por  los bits T2CKPS1:T2CKPS0 (T2CON)  El Registro de comparación o de Periodo:  En operación, el contenido del registro TMR2 se compara continuamente con un registro de periodo denominado PR2 (92h) cuyo valor  podemos establecer por software.  Cada vez que la cuenta de TMR2 es igual a PR2, se reinicia el conteo en TMR2 desde cero, y además se genera una señal de salida, la cual  es tratada por un postescalador, para poder generar una señal TMR2IF (PIR1) que puede ser usada para solicitar una interrupción, o  para ser leída por poleo. 

54   

El Postescalador:  El postescalador divide la frecuencia con que ocurre una activación de la bandera TMR2IF, es decir, si el valor del postescalador es 1/1,  esta bandera se activará cada vez que TMR2 se reinicie, en cambio, si es 1/16 (por ejemplo), TMR2IF se activará cada 16 reinicios  de TMR2. En forma similar a los otros dos Timers, esta bandera debe ser limpiada previamente, si se quiere detectar su activación, esto  puede ser hecho en la rutina de atención a la interrupción, o bien en la rutina que la detecta por poleo.  El valor de división del postescalador puede establecerse por software mediante los bits T2OUPS3:T2OUPS0 (T2CON).  En este caso la temporización de calcula así:  Temporización = Ciclo de instrucción. (PR2‐TMR2) .Divisor de Frecuencia Pre. Divisor de frecuencia Post  Vemos que la máxima temporización posible es con TMR2 = 0, y Divisor de Frecuencia Pre en 16, Divisor de frecuencia Post en 16,  lográndose unos 65.5 ms aprox.  A continuación se describe el principal registro relacionado con el Timer 2 y todos sus bits.  Registro T2CON (12h) 

  Bits 6:3  T2OUPS3:T2OUPS0 Bits de selección del valor del divisor de frecuencia del postescalador, de acuerdo a la siguiente tabla: 



0 0 0 0 = divisor 1/1 



0 0 0 1 = divisor 1/2 



0 0 1 0 = divisor 1/3 



… 



1 1 1 1 = divisor 1/16 

Bit 2  TMR2ON Bit de encendido del Timer 2 



1 = Enciende (energiza) el Timer 2 



0 = Apaga (desconecta) el Timer 2 

Bits 1:0  T2CKPS1:T2CKPS0 Bits de configuración del valor del preescalador de acuerdo a la siguiente tabla: 



0 0 = divisor 1/1 



0 1 = divisor 1/4 



1 x = divisor 1/16 

Ejemplo de configuración para lograr una temporización de 20 ms:  Código: 

 

55   

 

  Módulo de comunicación serie (Usart) + Ejemplo  Luego de analizar los módulos TImer0, Timer1 y Timer2 del microcontrolador PIC16F628A En vamos a ver los detalles de su USART. Al  igual que antes, esta entrada tiene su equivalente en la primera parte de este curso, cuando estudiamos el microcontrolador PIC16F84A,  por lo sería de mucha ayuda volver a leer lo escrito en la primera parte de esta serie de entradas. En el resto, por supuesto, hay  diferencias que ya mismo vamos a analizar.    La USART del PIC16F628:  La USART del PIC16F628Apuede ser configurada para operar en tres modos:  1.

Modo Asíncrono (full duplex (transmisión y recepción simultáneas)), 

2.

Modo Síncrono – Maestro (half duplex) 

3.

Modo Síncrono – Esclavo (half duplex) 

Aquí solo trataremos el modo asíncrono.  Modo Asíncrono:  En este modo la USART usa un formato estándar NRZ asíncrono, el cual para la sincronización usa: 1 bit de inicio (I), 8 o 9 bits de datos y  1 bit de paro (P). Mientras no se están transmitiendo datos la USART envía continuamente un bit de marca. El modo asíncrono se  selecciona limpiando el bit SYNC del registro TXSTA (98H). El modo asíncrono es deshabilitado durante el modo SLEEP.  Cada dato es transmitido y recibido comenzando por el LSB. El hardware no maneja bit de Paridad, pero el noveno bit puede ser usado  para este fin y manejado por software.  El módulo Asíncrono de la USART consta de los siguientes módulos fundamentales: 



El circuito de muestreo 



El generador de frecuencia de transmisión (Baud Rate) 



El transmisor asíncrono 



El receptor asíncrono. 

El circuito de muestreo:  El dato en la patita de recepción (RB1/RX/DT) es muestreado tres veces para poder decidir mediante un circuito de mayoría, si se trata  de un nivel alto o un nivel bajo.  El Generador de Baud Rate (BRG):  Este generador consiste de un contador/divisor de frecuencia de 8 bits controlado por el registro SPBRG (99H) . De tal manera que la  frecuencia de transmisión se calcula de acuerdo a la siguiente tabla: 

  En esta tabla X=valor de 8 bits en el registro del divisor, SPBRG. El bit BRGH corresponde a TXSTA.  En el datasheet del PIC16F628 hay tablas donde se muestran algunos valores baud estándares, el divisor necesario (X=SPBRG) bajo  diferentes frecuencias Fosc y el error producido en porcentaje.   

56   

El transmisor asíncrono:  En la siguiente figura se muestra el diagrama de bloques del transmisor de la USART: 

  El corazón de este módulo es el registro de corrimiento (transmit shift register, TSR). La única manera de acceder al registro TSR es a  través del registro TXREG (19H).  Para transmitir un dato, el programa deberá ponerlo primero en el registro TXREG. En cuanto el TSR termina de enviar el dato que tenía  (en cuanto transmite el bit de paro) lee el dato contenido en TXREG (si hay alguno) esto ocurre en un ciclo TCY. En cuanto el dato  de TXREG es transferido al TSR el TXREG queda vacío esta condición es indicada mediante el bit bandera TXIF (que es el bit 4 del  registro PIR1 (0Ch) ), el cual se pone en alto. Este bit NO puede ser limpiado por software, sólo dura un instante en bajo cuando se escribe  un nuevo dato a TXREG. Si se escribe un dato seguido de otro (back to back) a TXREG el primero se transfiere inmediatamente a TSR y el  otro tiene que esperar hasta que el TSR termine de enviar el bit de Stop del primero. Durante esta espera TXIF permanece en bajo.  Existe otro bit, llamado TRMT (TXSTA), el cual muestra el estado del TSR. TRMT se pone en alto cuando TSR está vacío, y en bajo  cuando TSR está transmitiendo un dato. Mientras que TXIF puede generar una interrupción TRMT no lo puede hacer, TRMT está pensado  para ser consultado por “poleo” (sin usar interrupciones).  Para habilitar el módulo de transmisión es necesario poner en alto el bit TXEN (TXSTA), mientras no se habilite el módulo, la patita de  transmisión (RB2/TX/CK) se mantiene en alta impedancia. Si TXEN es deshabilitada a la mitad de una transmisión, está será abortada y el  transmisor será reseteado.  Si se está usando un noveno bit TX9 (TXSTA), éste deberá ser escrito antes de escribir los 8 bits restantes a TXREG, ya que en cuanto  se escribe un dato a este registro inmediatamente es transferido a TSR (si éste está vacío).  De acuerdo a lo anterior, la inicialización del módulo de transmisión consiste en los siguientes pasos:  1.

 Inicializar baud rate escribiendo al registro SPBRG el divisor adecuado y opcionalmente al bit BRGH. 

2.

 Habilitar comunicación asíncrona limpiando el bit SYNC y poniendo el bit SPEN. 

3.

 Si se van a usar interrupciones, poner el bit TXIE (PIE). 

4.

 Poner el bit TX9 si se desea transmitir datos de 9 bits 

5.

 Habilitar transmisión poniendo el bit TXEN, lo cual pondrá el bit TXIF. 

6.

 Colocar el noveno bit del dato en TX9D si se están usando datos de 9 bits. 

7.

 Cargar el dato al registro TXREG (inicia la transmisión). 

El receptor asíncrono:  El módulo de recepción es similar al de transmisión, en la siguiente figura se muestran los bloques que lo constituyen: 

 

57   

Una vez que se ha seleccionado el modo asíncrono, la recepción se habilita poniendo en alto el bit CREN (RCSTA)  El dato es recibido mediante la línea RB1/RX/DT, la cual maneja un registro de corrimiento de alta velocidad (16 veces el Baud rate).  El corazón del receptor es el registro de corrimiento RSR. Este registro no es accesible por software, pero, cuando el dato recibido se ha  completado (se ha recibido el bit de Stop) el dato de RSR es transferido automáticamente al registro RCREG (1Ah) si éste está vacío y al  mismo tiempo es puesto en alto la bandera de recepción RCIF (PIR1). La única manera de limpiar la bandera RCIF es leyendo el/los  datos del registro RCREG. El registro RCREG puede contener hasta dos datos, ya que es un buffer doble que funciona como una cola de  dos posiciones.  Si las dos posiciones del registro RCREG están llenas (no han sido leídas) y se detecta el bit de Stop de un tercer dato de recepción, lo cual  ocasiona un transferencia automática del dato recibido a RCREG, esto destruirá el primer dato recibido y activará el indicador de  sobreescritura OERR (RCSTA). Para evitar esto, se deberán leer los dos datos en RSREG haciendo dos lecturas consecutivas.  La única manera de limpiar el bit OERR una vez que ha sido activado es reseteando el módulo de recepción (limpiando CREN y  volviéndolo a poner), si no se limpia OERR se bloquea la transferencia de datos de RSR a RCREG y no puede haber más recepción de  datos.  Si se detecta un bit nivel bajo en la posición del bit de stop se pone el indicador de error de encuadre (frame  error) FERR RCSTA. Tanto este indicador como el noveno bit RX9D de los datos están en una cola de dos posiciones al igual que los  datos recibidos, de manera que al leer RCREG se actualizan FERR y RX9D con nuevos valores, por lo cual estos bits deberán ser leídos  antes de leer RCREG para no perder su información.  De acuerdo a lo anterior, la inicialización del módulo de recepción es como sigue:  1.

 Inicializar el baud rate escribiendo al registro SPBRG el divisor adecuado y opcionalmente al bit BRGH . 

2.

 Habilitar el puerto serie asíncrono limpiando el bit SYNC y poniendo el bit SPEN. 

3.

 Si se van a usar interrupciones, poner el bit RCIE (PIE). 

4.

 Si se desea recepción de datos de 9 bits se deberá poner el bit RX9 (RCSTA). 

5.

 Habilitar la recepción poniendo el bit CREN (RCSTA) 

6.

 El bit RCIF se pondrá cuando la recepción de un dato se complete y se generará una interrupción si RCIE está puesto. 

7.

 Leer el registro RCSTA para obtener el noveno bit (si se están recibiendo datos de 9 bits) o para determinar si ha ocurrido un  error de recepción. 

8.

 Leer los 8 bits del dato recibido leyendo el registro RCREG. 

9.

 Si ocurrió algún error este se limpia al limpiar el bit CREN, el cual deberá volver a ponerse si se desea continuar la recepción. 

ConfigPIC permite seleccionar algunos parámetros para configurar el módulo USART del pic, y generar el código de ayuda  Veamos un ejemplo. En este caso usando el módulo Usart del PIC16F628A y la interrupción que genera el mismo al recibir un dato  haremos un ejemplo donde esperamos dato desde PC, lo recibimos y lo reenviamos inmediatamente:  Hardware necesario: 

 

58   

Código:

 

 

59   

 

  Comparadores analógicos + Ejemplo  En esta entrega analizaremos los módulos de comparación analógica y tensión de referencia. Estos módulos están presentes en  el PIC16F628A pero no en el microcontrolador PIC16F84A, por lo que se trata de un tema completamente nuevo en esta serie. Como  verás a continuación, es un tema muy importante y extenso, por lo que seguramente deberemos dividirlo en 3 o 4 entradas.  El Módulo Comparador:  Dispone de dos comparadores analógicos C1 y C2 cuyas entradas pueden ser seleccionadas entre los pines RA0 a RA3 y cuyas salidas  pueden utilizarse para lectura digital interna o bien conectarse a dos pines de salida: RA4 y RA5. También podría ser posible emplear un  nivel de tensión configurable y generado por otro bloque, el denominado Módulo de Referencia de Tensión.  El multiplexado para la selección de las entradas a comparar y las salidas a generar depende del registro de control de comparación  CMCON (0x1F).  Existen 8 configuraciones posibles de entradas y salidas de comparación que se seleccionan con los 3 bits menos significativos (CM2‐ CM1‐CM0). En ese mismo registro se pueden leer los estados en la salida de cada uno de los comparadores C1 y C2 y si se desea invertir  o no la lógica del resultado de la comparación que aparece a la salida.  Registro CMCOM 

  Bit 7.  C2OUT: Bit de salida del Comparador 2.  Cuando C2INV = 0: 



Si C2Vin+>C2Vin‐ = 1 



Si C2Vin+C2Vin‐ = 0 



Si C2Vin+C1Vin‐ = 1 



Si C1Vin+C1Vin‐ = 0 



Si C1Vin+ 

Bit5.  C2INV: Bit de inversión de la salida del Comparador 2. 



1 = C2 Salida invertida. 



0 = C2 Salida no invertida. 

Bit 4.  C1INV: Bit de inversión de la salida del Comparador 1. 



1 = C1 Salida invertida. 



0 = C1 Salida no invertida. 

Bit 3.  CIS: Selector de pin de entrada al Comparador.  Cuando CM = 001: 



1 = C1Vin‐ conectado a RA3. 



0 = C1Vin‐ conectado a RA0. 

60   

Cuando CM = 010: 



1 = C1Vin‐ conectado a RA3. C2Vin‐ conectado a RA2. 



0 = C1Vin‐ conectado a RA0.C2Vin‐ conectado a RA1. 

Bit 2‐0.  CM: bits de selección de configuración de los Comparadores. 

             

61   

Modo de Trabajo de los Comparadores:  Si la entrada analógica VIN+ es mayor que la entrada analógica VIN‐, entonces la salida del comparador será un estado digital alto  Si la entrada analógica VIN+ es menor que la entrada analógica VIN‐, entonces la salida del comparador será un estado digital bajo 

  Las áreas sombreadas de la salida del comparador en la figura representan la incertidumbre debido a tensiones de desviación y tiempo  de respuesta.  Referencias de Comparación:  La referencia de tensión para la comparación puede ser:  Externa: se conectará a cualquiera de los pines de entrada externos del comparador y esa tensión deberá estar comprendida entre VDD y  VSS  Interna: se puede emplear una referencia de tensión generada a nivel interno por parte de un módulo interno específico presente dentro  del microcontrolador cuando se configuran los bits CM con la combinación 110  Módulo de Referencia de Tensión para Comparación:  Se trata de un divisor resistivo a partir de la tensión de alimentación del microcontrolador.  Registro VRCON (9Fh): 

  VR Selección de la tensión de referencia:  Si VRR = 1: Vref = (VR .Vdd) / 24  Si VRR = 0: Vref = (Vdd . 1/4) + (VR  . Vdd) / 24  Interrupciones del Módulo de Comparación:  El módulo de comparación puede generar una interrupción por activación del flag CMIF (Flag de Interrupción del Comparador) presente  en el registro PIR1. El flag CMIF se pondrá a 1 si se produce un cambio en la salida de cualquiera de los dos comparadores  (C1OUT o C2OUT) desde la última lectura que se realizó del registro CMCON.  El flag debe ponerse a cero por software pero además debe realizarse previamente una operación de lectura (o escritura) del registro  CMCON para que deje de darse la discrepancia entre el valor actual y el valor leído. Para que se produzca la interrupción deben  encontrarse activadas la máscara particular (CMIE en PIE2), la de periféricos (PEIE) y la global (GIE).  Característica especial del Módulo Comparador:  Si un comparador se encuentra activo y se sitúa al microcontrolador en modo de bajo consumo (SLEEP), el comparador permanecerá  activo y las interrupciones si están activadas mediante sus máscaras serán funcionales y podrán sacar al micro de su modo de bajo  consumo si cambia la salida de alguno de los comparadores desde la última lectura. 

62   

ConfigPIC permite seleccionar la configuración del módulo comparador analógico y tensión de referencia, generando el código de  configuración.  A modo de ejemplo conectaremos un potenciómetro al comparador 1, fijando una tensión de referencia interna a 3.59 Volt e invirtiendo  la salida del comparador. Cuando la tensión sobre el pin RA0 (C1Vin‐) sea mayor a 3.59 Volt haremos titilar un led 10 veces a modo de  alarma.  Hardware necesario: 

  Diagrama de Flujo: 

     

63   

Código:

 

 

64   

 

  Introducción Módulo CCP  El primer módulo que veremos en detalle es el Módulo CCP. Los microcontroladores PIC16F628A/648Adisponen de un módulo de  Captura/Comparación/PWM que en conjunto con los temporizadores, permite realizar en forma sencilla las tareas de medición de  tiempo y frecuencia, y generación de señales digitales. Con tres modos de funcionamiento que veremos en profundidad a partir de esta  entrega.  Módulo CCP  Los microcontroladores PIC16F628A/648A disponen de un módulo de Captura/Comparación/PWM que en conjunto con los  temporizadores, permite realizar en forma sencilla las tareas de medición de tiempo y frecuencia, y generación de señales digitales.  El módulo CCP tiene 3 modos de funcionamiento, que se describen a continuación: 



Modo captura: Permite capturar el valor que tiene en registro TMR1 cuando ocurre un evento especial en la terminal RB3/CCP1. 



Modo comparación: Permite comparar el valor de 16 bits del TMR1 con un valor previamente definido en los registros CCPRL1H y  CCPR1L 



Modo PWM: Permite generar señales digitales moduladas en ancho de pulso 

A continuación se da un breve resumen de los registros relacionados con cada módulo:  El registro principal de este módulo se compone de dos registros de 8 bits, denominados CCPR1H (16h) (parte más significativa) y CCPR1L  (15h) (parte menos significativa). La operación del módulo se controla mediante el registro CCP1CON (17h) y el disparo de evento  especial, el cual es generado al alcanzarse la igualdad en un registro de comparación reseteará el Timer 1.  Selección del modo de operación:  La selección del modo en que trabajara el módulo CCP se realiza mediante los cuatro bits menos significativos del registro CCP1CON, es  decir, mediante los bits CCP1M3:CCP1M0 (CCP1CON) de acuerdo a lo siguiente: 



0000 Captura/Comparación/PWM deshabilitados 



0100 Captura cada transición de bajada 



0101 Captura cada transición de subida 



0110 Captura cada cuarta transición de subida 



0111 Captura cada 16 transiciones de subida 



1000 Comparación, pone salida cada coincidencia 



1001 Comparación, limpia salida cada coincidencia 



1010 Comparación, genera interrupción cada coincidencia (Se setea bit CCP1IF, salida inalterada) 



1011 Comparación, dispara evento especial (Se setea bit CCP1IF , resetea TMR1(TMR1IF inalterado) ) 



11xx Modo PWM 

El Modo de Captura:  En el modo de captura el registro CCPR1(CCPR1H:CCPR1L) captura el valor de 16 bits registro TMR1 cuando ocurre un evento en la  patitaRB3/CCP1. El evento en cuestión puede especificarse previamente como alguno de los siguientes: 

65   



Cada transición de bajada 



Cada transición de subida 



Cada cuarta transición de subida 



Cada dieciseisava transición de subida 

Además de que el valor de TMR1 es capturado, la bandera de solicitud de interrupción CCP1IF es activada, la cual deberá ser limpiada por  software para poder detectarla si se está consultando por poleo.  El tipo de acción que se desea detectar en esta patita se configura mediante los bits de control CCP1M3:CCP1M0 (CCP1CON). Si  ocurre otro evento de captura antes de que haya sido leído el registro CCPR1, el valor capturado anterior se perderá, ya que con la nueva  captura este registro es reescrito.  En la figura siguiente se muestra un diagrama de bloques en donde se ilustra la manera en que trabaja el módulo CCP en modo de  captura: 

  El preescalador del CCP:  El valor del preescalador se configura mediante los bits CCP1M3:CCP1M0. Sin embargo, al realizar un cambio en la configuración del  preescalador se puede generar una interrupción falsa, para evitar lo anterior se deberá apagar el módulo CCP (limpiando el  registroCCP1CON) previamente al cambio de valor del preescalador.  Este preescalador es independiente al preescalador del Timer 1 (el cual puede usarse como ya se explicó con sus posibles divisores de  1/1, 1/2, 1/4, 18).  Configuraciones:  Se debe configurar el CCP1 como entrada a través del registro TRISB.  El Timer1 debe estar en modo temporizador o modo contador sincronizado  Al cambiar el modo de captura hay que tener inhabilitadas las interrupciones y borrar el flag para evitar interrupciones espúreas.  Si el pin RB3/CCP1 es configurado como salida, se deberá tener en cuenta que una escritura al puerto B puede causar una condición de  captura.   Ejemplo:  Para ejemplificar el uso del módulo CCP en modo captura vamos a realizar la medida del periodo de una onda cuadrada para así  determinar su frecuencia. La forma de trabajar va a ser la siguiente:  Configuramos CCP modo captura con cada transición de subida del pin RB3/CCP1 con Timer1 modo temporizador 1/1.  Al llegar un flanco ascendente, reseteamos Timer1 y esperamos al siguiente flanco ascendente, en el cual se guarda el valor capturado y  lo enviamos a la PC para poder determinar la frecuencia de la señal. Lo que hemos capturado es la cantidad de ciclos de reloj  transcurridos en un ciclo de la señal a medir. Con este valor y el Tosc al cual trabaja el microcontrolador podemos determinar el periodo  de la señal.  Periodo(s)=(4/20MHz).CCPR1  Frecuencia(Hz)=1/Periodo 

66   

Con un cristal de 20 MHz podemos medir desde aprox. 77Hz hasta los 500kHz, claro que a más frecuencia más error en las mediciones.  Por ejemplo, con algunos ensayos que he realizado a 1kHz se tiene un error de +‐1Hz, 10kHz +‐5Hz, 100kHz +‐ 0.5kHz, 200kHz +‐ 2kHz,  etc.  Para determinar la frecuencia adjunto un programita hecho en Visual Basic que toma 10 valores enviados desde el microcontrolador,  calcula un promedio del periodo y determina la frecuencia. Se hace de este modo para reducir el error cometido a altas frecuencias  (descargalo de acá) 

  Hardware necesario: 

           

67   

Código: 

 

68   

 

  Modo Captura   En la entrega de hoy veremos cómo utilizar el modo comparador. En este modo, el microcontroladorPIC16F628A aprovecha el registro de  16 bits CCPR1 (CCPR1H:CCPR1L) y el registro de 16 bits TMR1. Cuando estos valores coinciden se dispara una interrupción que podemos  aprovechar para realizar alguna acción en nuestro proyecto. Se trata de otra entrega muy importante en esta serie de entradas.    El Modo Comparador:  En el modo de comparación el registro de 16 bits CCPR1 (CCPR1H:CCPR1L) se compara constantemente con el valor del registro de 16  bits TMR1. De manera que cuando sus valores coinciden además de activarse la bandera para solicitar interrupción CCP1IF  (PIR1), puede ocurrir en la patita RB3/CCP1 (previa configuración) alguna de las siguientes acciones: 



RB3/CCP1 Se pone en alto 



RB3/CCP1 Se pone en Bajo 



RB3/CCP1 no cambia 

La acción que ocurra en esta patita se configura mediante los bits de control CCP1M3:CCP1M0 (CCP1CON). En la figura siguiente se  muestra un diagrama de bloques en donde se ilustra la manera en que trabaja el módulo CCP en modo comparador, 

  Configuraciones:  El pin RB3/CCP1 debe configurarse como salida limpiando el bit TRISB  El Timer 1 debe estar corriendo en modo temporizador (o en modo contador sincronizado)  Al limpiar el registro CCP1CON el latch de salida de la patita RB3/CCP1 se forza a su valor “default” de cero.  En el modo “interrupción software” no se realiza ninguna acción en el pin RB3/CCP1.  El modo “Special Event Trigger” ocurre inmediatamente al igualarse el par de registros TMR1H, TMR1L al par de  registros CCPR1H,CCPR1L. El par de registros TMR1H, TMR1L no se resetean hasta el próximo flanco ascendente del clock de Timer1.  Esto permite que el registro CCPR1 sea un registro de periodo programable para el Timer1  Ejemplo:  En este programa se hace uso del modo de comparación para realizar la conmutación de una señal cada vez que transcurre un tiempo, el  cual se ajusta al oprimir un pulsador de incremento o uno de decremento. 

69   

Hardware necesario: 

  Código: 

 

70   

 

  Modo PWM  Hoy veremos el Modo PWM (Modulación de Ancho de Pulso). Este importante modo es el que nos permite, por ejemplo, modificar la  intensidad con la que brilla un diodo LED o generar una onda de salida con frecuencia variable, permitiendo algunas aplicaciones que  a priori parecen imposibles, como “hacer hablar” a un PIC. Por lo pronto, antes de llegar a semejante nivel de sofisticación veremos los  principios básicos del PWM y algunos ejemplos.    Modo PWM (Modulación de Ancho de Pulso)  Con este modo de trabajo se consiguen impulsos lógicos cuya anchura del nivel alto es de duración variable, que son de enorme  aplicación en el control de dispositivos tan populares como los motores y triacs.  El pin RB3/CCP1 esta configurado como salida y cambia entre los niveles 0 y 1 a intervalos de tiempos variables, logrando un pulso cuyo  nivel alto tiene un ancho variable dentro del intervalo del periodo de trabajo: 

 

Modo PWM  La base de tiempos es el Timer2 más dos bits adicionales para tener los 10.  El periodo se determina con el registro PR2, ya que cuando TMR2=PR2: 



Se borra el TMR2 



Se pone a “1” el pin CCP1 



Se pasa el valor del CCPR1L al CCPR1H (para evitar glitch) 

71   

  De esta manera, de acuerdo a la figura anterior, el siguiente valor de comparación para TMR2 en el comparador de 10 bits es el Ciclo de  Trabajo, el cual al alcanzarse limpiará la patita CCP1.  El ciclo de trabajo se determina con el contenido del CCPR1L y los dos bits de CCP1CON (CCP1X y CCP1Y).  Periodo del PWM:  PeriodoPWM=(PR2+ 1).4.Tosc.TMR2 Preescaler  FrecuenciaPWM=1/PeriodoPWM  Ciclo de Trabajo del PWM:  El ciclo de Trabajo se especifica escribiendo un valor de 10 bits al registro CCPR1L (los 8 bits más significativos (msb)) y los dos bits menos  significativos (lsb) a CCP1CON:  CTPWM=(CCPR1L:CCP1CON).Tosc.TMR2 Preescaler  Como se puede ver en la figura anterior, el valor que determina la duración de C.T. del PWM no es el cargado en CCPR1L, sino  en CCPR1H, el cual sólo se actualiza en el momento en que TMR2 alcanza el valor de PR2 (es decir, cada vez que se completa un periodo).  Por ello, aunque CCPR1L puede ser escrito en cualquier momento, el Ciclo de Trabajo solo se actualiza hasta que termina el periodo que  está en transcurso.  No hay otra manera de escribir al registro CCPR1H, ya que este es un registro de sólo lectura.  El número de divisiones que se pueden tener en un Ciclo de Trabajo será 2^n, donde n es el número de bits usados, por lo tanto su  duración máxima será:  CTPWM=2^n.Tosc.TMR2 Preescaler  Sin embargo, dependiendo del valor de Ciclo de trabajo máximo (CT_PWM) deseado, no será posible realizar las 2^n divisiones y por lo  tanto no se podrán usar los n bits de resolución. O al revés, si se elige una resolución deseada n no será posible tener cualquier Ciclo de  Trabajo máximo (CT_PWM) Deseado.  De la ecuación anterior se puede despejar cual es la resolución máxima: 

72   

ResolucionPWM=log(CTPWM/Tosc.TMR2 Preescaler)/ log (2)  Veamos con un ejemplo, si fijamos PR2 en 100 y usamos preescaler 1/4 con un oscilador de 20 MHz, tendremos un PWM de periodo  80.8us. El ciclo de trabajo no puede superar este valor por lo que despejando de las ecuaciones anteriores, CCPR1L:CCP1CON no  puede ser mayor a 404. Aquí se ve claramente que no se pueden usar los 10 bits de resolución, sino “8.66” bits. Caso contario el  pinRB3/CCP1 nunca será reseteado.  En la siguiente tabla se resumen diversas elecciones de resolución n y la correspondiente frecuencia F_PWM máxima, así como el valor  dePR2 con el que se logra (para un frecuencia del cristal de 20 Mhz): 

  Secuencia de configuración del PWM:  A continuación se resumen los pasos para realizar la configuración inicial del PWM:   Establecer el periodo del PWM escribiendo al registro PR2. 



Establecer el Ciclo de Trabajo del PWM escribiendo al registro CCPR1L y a los bits CCP1CON. 



Configurar como salida el pin CCP1, limpiando el bit TRISB. 



Configurar el preescalador del Timer 2 y habilitar el Timer 2, escribiendo al registro T2CON. 



Configurar el módulo CCP1 para operación PWM. Poniendo en alto los bits CCP1CON . 

   Como ejemplo generaremos dos frecuencias distintas seleccionables mediante la acción de un pulsador conectador a RB0. Una de las  señales será de 500Hz y la otra de 2kHz, con ciclo de trabajo de 50%.  Con oscilador de 4MHz y preescaler 1/16 tendremos:  Señal de 500Hz PR2=124 (0x7C) CCPR1L&2bits=250(0xFA) CCPR1L=0x3E & 2bits=10  Señal de 2kHz PR2=30 (0x1E) CCPR1L&2bits=62 (0x3E) CCPR1L=0x0F & 2bits=10  Hardware necesario: 

     

73   

Código:  

  Veamos otro ejemplo:  En este se fija la frecuencia de PWM en 2 kHz y se varía el ciclo de trabajo con 2 pulsadores de control conectados a RB0 y RB1. Solo se  modifica en byte alto del CT, ósea el registro CCPR1L con lo que CT se varía de 4 en 4.     

74   

Hardware necesario: 

  Código: 

 

75   

 

  Registro de desplazamiento 74LS164N  En alguna oportunidad hemos hablado de la importancia de los registros de desplazamiento a la hora de controlar displays. Es que  gracias a estos integrados se puede evitar al microcontrolador la tarea de actualizar constantemente el estado de los mismos, ya que el  registro de desplazamiento se encarga de mantener encendidos los segmentos que sean necesarios. En esta entrega veremos cómo  realizar ese control con el popular chip 74LS164.    Control de Displays con 74LS164  Aquí realizo un nuevo ejemplo de manejo de varios displays de 7 segmentos. En este caso realizaremos el control de 3 displays con la  ayuda del registro de desplazamiento 74LS164. Las ventajas que conlleva el uso de este CI es que no necesitaremos multiplexar la señal  enviada a los displays, algo que limita mucho al microcontrolador, ya que debe refrescarlos continuamente. Y, obviamente, la desventaja  es que necesitaremos un 74LS164 por cada display.  Hardware: (los pines 7 y 14 del 74LS164 van a GND y 5V, y se debe agregar una resistencia a cada línea que une el 74LS164 con el display) 

         

76   

Con este circuito se pueden manejar 3 displays + los 3 puntos. El primer bit que ingresa será empujado por los demás. Ejemplo para  enviar 12.7: 

  Código: 

 

77   

 

78   

 

  Como hacer Cartel de LEDs 7×32.  Con esta entrega finalizamos la segunda parte de este tutorial.  A lo largo de 25 entradas hemos visto todo lo necesario para poder  programar prácticamente cualquier aplicación utilizando los populares microcontroladores PIC16F84A y PIC16F628A. Nos despedimos  con la explicación de lo que para muchos es un proyecto muy interesante: la creación de un cartel de LEDs que pasa mensajes.    Cartel de Leds en ASM  Para mostrar un ejemplo sencillo vamos a usar una tabla para guardar el mensaje a mostrar y una sola variable (8 bits) para indicar el  largo y control de la posición a enviar. Por ello el largo del mensaje estará restringido a 255 bytes que se reducen en 6 por la posición de  la tabla en la memoria de programa.  La forma de guardar cada letra del mensaje será la siguiente: 

  Cada byte indica una columna de la letra, donde un 0 es led apagado y 1 led encendido.  Nota: Es una forma de hacerlo, la cual la aprendí del amigo BrunoF en uno de sus tantos aportes  Luego el mensaje puede ser mayor al cartel utilizado para mostrarlo así que es necesario efectuar un desplazamiento del mensaje sobre  el cartel o lo que es lo mismo desplazar el cartel sobre el mensaje.  Para ello se utilizará una variable que indica la posición inicial dentro del mensaje, en la cual comienza a mostrarse en el cartel. Como  deseamos que el mensaje sea rotativo el problema se presenta en las últimas posiciones donde se debe mostrar la parte final del  mensaje y empezar a mostrar el inicio. Lo que hacemos es dividir en 2 la forma de mostrar el mensaje, cuando Posición Inicial + Largo del  Cartel sea menor a Largo del mensaje y cuando sea mayor: 

79   

  Bueno, más o menos se ha explicado como vamos a trabajar con el mensaje, ahora se debe entender como va a funcionar el  multiplexado de los leds. Vamos a realizar la multiplexación por filas, ósea que vamos a seleccionar una fila y vamos a actualizar sus  valores por medio de registros de desplazamientos. El tiempo de actualización no debe superar los 20ms!  Para actualizar usaremos una variable que indique que fila ha de actualizarse, por ejemplo para actualizar la fila uno la variable FilaActual  será 00000001. Ahora para saber que valores tenemos que mandar a los registros de desplazamiento iremos tomando cada una de las  columnas (PosicionEnviar) a actualizar, aremos un AND con FilaActual y determinaremos si enviar un 1 o un 0.  ( PosicionEnviar (AND) FilaActual ) = FilaActual? 



Si ‐> Enviamos un 1 



No‐> Enviamos un 0 

Hardware para simulación: 

           

80   

Código: 

 

81   

82   

 

83   

  Consideraciones para construcción real:  Para la construcción real se debe agregar la parte de “potencia” dado que el PIC y según el registro de desplazamiento que se utilice no  son capaces de manejar las corrientes necesarias, para ello se colocan transistores para el control de las filas y se agrega  el ULN2803/2003 en serie a los registros de desplazamiento, una forma de hacerlo sería la siguiente: 

  Y cambiar rutina de efectivizar a: 

           

84   

Otra forma: 

 

Otra forma  Pero deben tener en cuenta que para encender un led se debe enviar al registro de desplazamiento un cero. 

85   

Lenguaje ensamblador desde cero Lo primero que hay que saber para este lenguaje, es que cada línea de código, es una instrucción que realiza el CP o un paso que realiza el CP. A diferencia de otros lenguajes, como por ejemplo el C, una línea de instrucción, puede llevar uno o más pasos que el CP debe realizar. Más adelante entenderán el porqué. A esto último dicho, nos explica el porqué de un programa escrito en ASM (assembler) lleva menos línea de instrucción que el mismo programa realizado en otro lenguaje. Esto se traduce que, cuanto menos líneas de código, menor consumo de la memoria de programa. Nota: Entendemos por el mismo código, al realizar un software para realizar una dicha tarea. Una tarea que debe realizar nuestro microcontrolador, puede ser escrito en diferentes lenguajes, y es el programa que se utilizó quien lo traduce a formato hex (1 y 0). Ahora, ¿Qué es el CP? El CP o PC es el Contador de Programa. Es el encargado de leer cada instrucción y realizar la acción solicitada por el software. Para dar un ejemplo un poco más claro, digamos que el CP, es una persona. Esta persona se le da un papel que tiene diferentes tareas a realizar. Estas tareas, están una debajo de la otra y lee línea por línea y hace lo que le dice esa línea. Cada línea, posee una instrucción que se debe hacer. Cuando terminó de hacer esa instrucción, continúa con la línea de abajo. Supongamos que tenemos un papel que dice:      

Levantar la mano izquierda. Bajar la mano izquierda. Saltar tres veces en el mismo lugar. Levantar la mano derecha. Saltar una vez en el mismo lugar. Bajar la mano derecha.

El CP, hará esas tareas sin negarse y lo hará fielmente a lo que está escrito. Por lo que, si hace una tarea mal, es porque le pusimos una o más instrucciones mal. Si bien, el CP hará lo que nosotros le pidamos, el CP nos pide que respetemos algunas cosas. Estas cosas, dependerán de cada microcontrolador y que debemos saber para poder programar en forma correcta al PIC.

¿Cómo es la estructura del lenguaje ASM? Es muy fácil, posee 4 columnas bien diferenciadas y que no es problema acordarse.  La primera columna se llama ETIQUETA y sirve para darle el nombre a una posición de la memoria del programa al que se necesita apuntar. Los que no se den cuenta, ya lo harán.  La segunda columna, se llama INSTRUCCIÓN y lo que justamente hace, es una instrucción a realizar por el CP.  La tercera columna, se llama OPERANDO y es el operando de una instrucción, o sea, de la segunda columna. Hay instrucciones que no tienen operando y las veremos más adelante.

 Y la cuarta columna, se llama OBSERVACIONES y sirve solo para el programador, o sea, el usuario que está programando el PIC. En otras palabras, a nosotros. Siempre comienza con ; (punto y coma) Si no sirve para el PIC, ¿Para qué complicarla más? Todo lo contrario, es para ayudar al programador de que no se olvide que intentó hacer. Todos los lenguajes, desde los más básicos hasta los más avanzados, tienen esta características ya que en el pondremos que es lo que queremos hacer o explicar el programa. Si bien, estas observaciones se utilizan en la cuarta columna, no es obligación colocarla en esta columna, si no que puede ir al margen de la planilla en dónde estamos programando. Y es aquí dónde explicaremos la porción de una rutina para entenderlo más adelante. Bien, veremos a continuación, como se escriben las columnas: ETIQUETAS

INSTRUCCIÓN

OPERANDO

;OBSERVACIONES

O, podemos verlo así: ;OBSERVACIONES ;OBSERVACIONES ;OBSERVACIONES (y la cantidad que necesitemos) ETIQUETAS

INSTRUCCIÓN

OPERANDO

;OBSERVACIONES

Antes de empezar a ver las instrucciones, debemos concentrarnos en los registros.

¿Qué son los registros? Los registros, son posiciones de memoria el cual se utilizan para ir configurando el pic mientras se corre el programa, cambiar de bancos para acceder a otras partes de memorias, son banderas que nos van diciendo que está pasando con distintas operaciones, son habilitaciones o deshabilitaciones para módulos que trae el PIC. Por ejemplo, conversor Analógico/Digital, PWM. Estos registros, tienen una ancho de bit de acuerdo al PIC, que hay de 8 bit, 16 bit y 32 bit. Excepto la palabra configuración y que la veremos más adelante. El tamaño de los registro depende del tipo de microcontrolador. Cada registro, posee un nombre, y cada bit o un grupo de bit, se puede utilizar para lo descripto anteriormente (habilitar/deshabilitar, etc.). A continuación, veremos una posición de la RAM y sus 4 bancos. Este, es del PIC16F877

Como notarán, en las cuatro columnas, hay nombres. Estos nombres son todos los registros que posee este PIC. Verán que hay registros que se repiten. No quiere decir que están duplicados, triplicados o cuadriplicados, si no que se puede acceder a ellos no importa en qué banco estemos trabajando. (Ya lo entenderán, no se preocupen). Cada vez que se programe el PIC y se necesite trabajar con uno de estos registros, se debe acceder al banco que esté dicho nombre. Es por eso, que esta tabla es muy importante a la hora de trabajar.

Aprovechando que subí esta tabla del pic, cuando de ejemplos de programación, será sobre este pic. Microchip provee en forma gratuita estos Datasheet. Y hay uno por cada PIC. Por lo que si no tienen este Datasheet, descárguenlo de la página de Microchip. Cuando empecemos a programar, lo necesitarán. Uno de los registros muy utilizado, es el registro de trabajo W, el cual, se utiliza para mover un dato/valor de un registro a otro, cargar valores en un registro, y con la ayuda de la ALU puede hacer operaciones matemáticas. Observen con atención el diagrama de bloque dónde se encuentra W

Ahora bien, si W es un registro, ¿dónde está ubicado, ya que en el mapa de memoria no lo

encuentro? El registro W no está implementado en la memoria RAM, ni en la posición 0x00 ni en otra posición. W es un registro independiente que tiene un bus directo con la ALU (un camino privado). La ALU es la única entidad que puede leer o escribir este registro de trabajo. El direccionamiento indirecto hace uso de los registros FSR e INDF. INDF es completamente ajeno a W. Un direccionamiento indirecto usa el registro FSR como apuntador al contenido de otros registros. Cualquier instrucción que hace uso de INDF (0x00) como dirección invoca un direccionamiento indirecto. Los microcontroladores PIC, poseen tres tipos de memorias.

 Memoria de Programa: Es la ubicación física dónde se guarda el firmware que hemos creado, o sea, nuestro programa. Y tiene un ciclo de 100.000 de lectura y/o escrituras antes de estropearse y es del tipo FLASH.  Memoria de datos de uso general: Es la memoria RAM del PIC. Recordemos, que los registros están sobre la memoria RAM y la memoria de uso general, comienza después de los registros.  Memoria de datos EEPROM: Puede almacenar datos más de 40 años sin energía y 1.000.000 de ciclos de escritura y lectura El PIC 16F877, tiene una memoria de programa de 8Kb por un ancho de 14 Byte, o sea que cada posición de memoria tiene 14 bytes (B'11111111111111', o H'3FFF') Cada línea de instrucción ocupa una posición en la memoria de programa, así que, podemos poner hasta 8.192 instrucciones. La RAM de uso general (más los registros) trae 368 bytes con un ancho de 8 bytes (B'11111111', o H'FF'). Esto quiere decir, que tenemos 368 posiciones para nuestro uso. La EEPROM trae 256 bytes con un ancho de 8 bytes. Tenemos 256 posiciones para nuestro uso. Ahora, vamos a estudiar el registro STATUS y luego continuaremos con las instrucciones.

Registro STATUS Si entendieron hasta acá, se acordará que los registros poseen un ancho de 8 bytes. Cada byte, puede contener un 1 o 0. Vemos ahora en detalle el registro STATUS:

Este registro, tiene 3 Bytes dedicado para las operaciones matemáticas, 3 bytes dedicado al cambio de banco de memoria y 2 bytes dedicado para saber qué o quién produjo un Power Up (despertar del micro). Y se puede leer y escribir en él (cambiar datos). Los analizamos desde el más significativo (MSB) hasta el menos significativo (LSB).

BIT 7: Se llama IRP y sirve para el direccionamiento indirecto para cambiar el banco de memoria. 1 = Banco 2 y 3 0 = Banco 0 y 1

BIT 6 y BIT 5 Se llaman RP1 y RP0 respectivamente. Sirve para el direccionamiento directo para cambiar de banco de memoria.

00 = Banco 0 01 = Banco 1 10 = Banco 2 11 = banco 3

BIT 4 Se llama TO (neg). Este bit se utiliza para saber quién despertó al PIC. 1 = Después que despierta (Power up) o por las instrucciones CLRWDT o SLEEP, se pone a 1 este bit. 0 = Se pone a 0 cuando el Watchdog o en castellano perro guardián (WDT) despierta al PIC.

BIT 3 Se llama PD (neg). Este bit se utiliza para saber si el pic estaba durmiendo. 1 = Después de que despierta (Power up) o por la instrucción CLRWDT, se pone a 1 0 = Se pone a 0 cuando se ejecuta la instrucción SLEEP

BIT 2 Se llama Z y al igual que los dos bytes anteriores, es una bandera. Nos indica el resultado de una operación aritmética y lógica. 1 = La operación aritmética o lógica dio como resultado 0 0 = La operación aritmética o lógica no dio como resultado 0

BIT 1 Se llama DC. Digit carry/borrow (dígito llevar/prestar). Es afectado por las instrucciones ADDWF; ADDLW; SUBLW; SUBWF (Para la resta, la polaridad es inversa). 1 = Hubo un acarreo del 4to bit menos significativo al 5to bit. 0 = No hubo un acarreo del 4to bit menos significativo al 5to bit.

BIT 0 Se llama C carry/borrow. Es afectado por las mismas instrucciones que afectan al bit DC. 1 = Hubo un acarreo del bit más significativo (Bit 7) o sea cuando se excede de H'FF' 0 = No hubo acarreo del bit más significativo

Breve introducción de las instrucciones Cada instrucción tiene un ancho de 14 Bits, es por eso que la memoria de programa tiene el mismo ancho. Justamente para poder alojar cada instrucción. Las instrucciones, están divididas en tres grupos. Los cuales son:  Byte-Oriented operation (Byte-Orientando a la operación) Cada instrucción de este grupo está compuesta por:  OPCODE (Código)  DESTINATION (Destino)  FILE REGISTER ADDRESS (Dirección del archivo de registro) El OPCODE o código, es el código de cada instrucción y que es única para cada instrucción. Está formada por los bit del 13 al 8.

El DESTINATION o el destino, indica en dónde se va a guardar el dato.Por ejemplo, si hacemos una suma, tenemos dos opciones dónde guardarlo, una puede ser el registro W y la otra opción puede ser otro registro cualquiera o una posición de la RAM. Está formada por el bit 7. La constante que nos indica esto es la letra d. Si esta letra es 0, la operación se guardará en el registro W. En cambio si vale 1, la operación se guardará en el registro o posición de memoria que estemos trabajando al momento de usar una instrucción. Hay instrucciones, como veremos más adelante, que no es necesario indicar dónde queremos guardar la operación, ya que se hace en forma automática. Y hay otras instrucciones que si no se indica el destino, nos puede dar un error al compilar o el compilador lo elegirá el y por ende, nos puede ejecutar mal el programa. Y por último, tenemos el FILE REGISTER ADDRESS que se carga con la dirección del registro a ser guardado. Está formada por los bit 6 al 0. La constante que nos indica esto, es la letra f  Bit-Oriented operation (Bit-Orientando a la operación) Cada instrucción de este grupo está compuesta por:  OPCODE (Código): igual al primer grupo. Está formado por los bits 13 al 10.  BIT ADDRESS (Bit de dirección): Se utiliza para direccionar la operación. Está formado por los bits 9 al 7. Como pueden observar, se sacrificó bit del opcode para dárselo al bit address. La constante que nos indica esto es la letra b.  FILE REGISTER ADDRESS (Dirección del archivo de registro): Es igual al primer grupo. Está formado por los bit 6 al 0. Igual que en el primer grupo la constante que nos indica esto es la letra f.

 Literal and Control operation (Control y Literal de la operación) Cada instrucción de este grupo, está compuesta por:  OPCODE: Es igual que en el primer grupo. Está compuesta por los bits 13 al 8. Excepto para las instrucciones CALL y GOTO que está compuesta por los bit 13 al 11 (prestar mucha atención a esto, cuando veamos estas dos instrucciones entenderán la importancia).  LITERAL: Que puede ser un valor, por ejemplo para sumar, para restar, para cargar al registro W, en fin, un número decimal, binario o hexadecimal. O puede ser un valor de dirección a dónde apuntar para las instrucciones CALL y GOTO. Está compuesta por los bits 7 al 0. Excepto para las instrucciones CALL y GOTO que está compuesta por los bit 10 al 0 (prestar mucha atención a esto, cuando veamos estas dos instrucciones entenderán la importancia).

A continuación, vemos las 35 instrucciones agrupadas por los tres grupos:

Si alcanzan a ver en la imagen, verán que algunas instrucciones afectan al registro STATUS y otras no.

Las instrucciones Les voy a arruinar el momento de alegría. Las instrucciones hay que estudiarlas de memoria. Si, leyeron bien, de memoria. Lo que tienen que saber sobre las instrucciones, es como se escriben, que hace cada instrucción y lo más importante que bit del REGISTRO afecta. Vamos a ir viéndolo por orden alfabético. Y otra cosita más, como es de esperarse, están en INGLES o son abreviaturas pero en INGLES. Recordemos que: .123 o D'123' es en decimal; 0x7B o 7Bh o H'7B' es en Hexadecimal; B'01111011' es en binario.

ADDLW Suma un valor designado por el programador al registro W Código: ADDLW

.128

Si W tenía cargado un valor = .5, después de la instrucción W tiene cargado el valor .133 Para recordar, ADD es sumar, L es Literal y W es el registro W Afecta a:  Z Se pone a 1 si la operación es 0  DC Se pone a 1 si hubo un acarreo del bit 3 al 4  C Se pone a 1 si hubo desbordamiento, o sea, cuando se supera H'FF'

ADDWF Suma el valor del registro W con el valor de un registro cualquiera. El destino de esta suma, lo elige el programador. Código: ADDWF

TEMP,W

Si W tenía guardado .133 y la posición de la RAM llamada TEMP tenía el valor cargado con .2, W vale .135 y TEMP continúa valiendo .2 Ahora si hubiera puesto así: Código: ADDWF

TEMP, F

TEMP valdría .135 y W valdría .133 Para recordar, F, es File Register Address. NOTA: Para indicar la dirección de dónde se guarda, también se puede poner 0 o 1 en vez de W o F. 0, corresponder guardarlo en el registro W y 1 en el registro TEMP (para este caso). Afecta a:  Z Se pone a 1 si la operación es 0  DC Se pone a 1 si hubo un acarreo del bit 3 al 4  C Se pone a 1 si hubo desbordamiento, o sea, cuando se supera H'FF'

ANDWF Realiza la operación AND entre W y un registro designado por el programador. El destino de esta operación lo elige el programador. Código: ANDWF

TEMP, F

Si antes de la instrucción W vale B'11100011' y TEMP vale B'00111010' Después de la instrucción TEMP vale B'00100010' y W vale B'11100011' Afecta a: Z Se pone a 1 si la operación es 0

BCF Pone a 0 el bit de un registro. El bit debe ser indicado por el programador. Ejemplo: Código: BCF

TEMP, 2

Antes de la instrucción TEMP vale B'11111111'. Después de la instrucción TEMP vale B'11111011' Para recordar, Bit Clear es borrar File es archivo o registro No afecta ningún bit del registro Status.

BSF Pone a 1 el bit de un registro. El bit debe ser indicado por el programador: Código: BSF

TEMP, 0

Antes de la instrucción TEMP vale B'01110110'. Después de la instrucción TEMP vale B'01110111' Para recordar, Bit Set es poner a 1 File Archivo o registro No afecta a ningún Bit del registro Status.

BTFSC Salta un línea si el bit de un registro es cero. El bit debe ser indicado por el programador. Ejemplo: Código: BTFSC TEMP, 5 BCF

PORTA, 0

BSF

PORTB, 0

Caso 1: TEMP vale B'00011110'. El CP analizará solo el Bit 5 del registro TEMP, como es 0, salta la instrucción BCF PORTA, 0 y ejecuta la siguiente línea que es BSF PORTB, 0 y continua haciendo la instrucción. Caso 2: TEMP vale B'00111000'. El CP analizará solo el Bit 5 del registro TEMP, como es 1 no salta la instrucción y hará la instrucción BCF PORTA,0 y luego continua con la instrucción BSF PORTB,0 Para recordar Bit Test es chequear File Skip es salto Clear No afecta a ningún Bit del registro Status.

BTFSS Salta una línea si el bit de un registro es 1. EL bit debe ser indicado por el programador. Código: BTFSS TEMP, 3 ADDWF PORTC ANDWF NODO

Caso 1: TEMP vale B'01101100'. El CP analizará solo el Bit 3 del registro TEMP, como es 1, salta la instrucción ADD PORTC y ejecuta la siguiente línea que es ANDWF NODO y continúa haciendo la instrucción. Caso 2: TEMP vale B'11110000'. El CP analizará solo el Bit 3 del registro TEMP, como es 0 no salta la instrucción y hará la instrucción ADD PORTC y luego continúa con la instrucción AND NODO. Para recordar Bit Test es chequear File Skip es salto Set No afecta a ningún Bit del registro Status. Normalmente, continuando las instrucciones BTFSS y/o BTFSC va un GOTO o CALL pero no la he puesto porque aún no se explicaron estas instrucciones.

CALL Se dirige a una dirección de la memoria de programa designado por el programador. En otras palabras, se utiliza para dirigirse a una rutina o tarea. Su principal ventaja es que una vez que finalizó la tarea, vuelve al punto siguiente desde dónde se llamó. Código: CALL

ESC_PORTB

Para recordar, CALL es llamada. No afecta ningún bit del registro Status.

GOTO Se dirige a una dirección de la memoria de programa designado por el programador. En otras palabras, se utiliza para saltar instrucciones que no queremos que se ejecuten. A diferencia de la instrucción CALL, no hay forma de volver cuando se ejecuta la instrucción. Código: GOTO

INICIO

Para recordar GO TO es ir a. No afecta a ningún bit del registro Status.

Extendiendo la explicación… En la siguiente imagen, vemos el diagrama de bloques del PC o CP.

El PC es de 13 bits en este caso(8kwords). 14 son los bits de cada "word" o instrucción que se graban en cada posición de la FLASH (memoria de programa). El PC se reparte en: sus 8 bits de menor peso en el registro PCL, y los 5 restantes en el registro PCLATH. Los PICs al tener un set de instrucciones reducido no puede en una sola instrucción meter todos los bits necesarios para direccionar toda su memoria. EL program counter son 2 registros, el PChigh y PCLow. Cuando haces un CALL o un GOTO, solo se rellenan 11 bits (los 8 del PClow y 3 del PChigh) y los dos restantes los rellenas con el PCLATH (para completar los 13bits). El STACK (pila) tiene toda la dirección, no solo parcial. Si haces un call desde la página 0 a la página 3 y luego un return el código SI volverá a la página 0, pero el PCLATH sigue apuntando a la página 3, entonces si usas otro goto o call, debes tener en cuenta de modificar el PCLATH. Entonces, dijimos que: El PC = ProgramCounter o CP = Contador de Programa, tiene 13 bits; del 0 al 12. Al ejecutar un call o un goto, se copian del 0 al 10, y los otros 2 bits se copian del registro PCLATH. El pclath solo estará allí para esa situación. En un return o retfie la microelectrónica del PIC, pega la dirección del PC que estaba guardada. Lo vemos con un ejemplo 1. STACK = vacío PC = 0x00A0 PCLATH = 0b000011000 Ejecutas un CALL 0x230 2. El STACK tiene en su posición 0 la dirección 0x00A0. PC = 111000110000

3. Se ejecuta la subrutina y en ese punto el PC ya quedó en PC = 111000110111 4. Viene un RETURN. La microelectrónica del PIC copiará el stack tal cual en el program counter + 1 Valor STACK 0x00A0 + 1 --> PC = 0x00A1 5. EL código sigue ejecutándose en la página 0 pero hay que tener en cuenta que el PCLATH apunta a la página 3 por ello si harás otro CALL o GOTO, deberás cambiar de nuevo el PCLATH si la subrutina no está en la página 3. Vamos a entrar a todo detalle en el Program Counter(PC) para que se vayan todas las dudas ya que es muy importante. Vayamos al tema del PC, computed goto(lo que algunos llaman "tabla"), call, returns y goto. El Program Counter (PC) está conformado en esta familia de uC (y refiriéndonos a la familia 16F, las otras poseen más o menos bits implementados) por 13 bits repartidos entre dos registros: PCH y PCL. El PCL es legible/escribible directamente a través del registro físico PCL(valga la redundancia). En cambio, el PCH no es directamente accesible. No puede ser leído, y sólo puede ser grabado mediante un buffer que contiene el valor temporalmente (oh! aquí aparece nuestro famoso PCLATH). Entonces, recordar: El PCLATH es sólo un buffer temporal que almacena los 5 bits de mayor peso del PC para ser escritos cuando se ejecute una instrucción que lo requiera. Ahora, hay dos situaciones posibles en las que el PC debe ser cargado de manera distinta: una es cuando queremos trabajar con tablas y otra cuando realizamos un call o un goto que no esté en el mismo banco.

1era situación: Tabla(Comuted Goto) La tabla es una situación de uso del PC en la que se afecta directamente al registro PCL. Cuando se afecte directamente al PCL mediante una instrucción, es necesario que el usuario asegure que PCLATH tenga sus 5 bits pre-cargados adecuadamente. Hago un ejemplo:

Mal: org 0x000 movlw 0x01 call tabla

org 0x300 tabla addwf PCL,F retlw 0x03 retlw 0x01 retlw 0x0F

Bien: org 0x000 movlw 0x03 movwf PCLATH movlw 0x01 call tabla

org 0x300 tabla addwf PCL,F retlw 0x03 retlw 0x01 retlw 0x0F

Mejor: org 0x000 pageselw tabla movlw 0x01 call tabla

org 0x300 tabla addwf PCL,F retlw 0x03 retlw 0x01 retlw 0x0F

Pageselw es una instrucción del MPASM que genera dos instrucciones: un movlw literal y un movwf PCLATH. El valor del literal es automáticamente seleccionado por el ensamblador según la etiqueta(o posición de memoria) que se le especifique. En el caso anterior pageselw tabla generaría estas dos instrucciones:

movlw 0x03 movwf PCLATH Si no aseguramos que los 5 bits del PCLATH estén correctamente seteados al momento de afectar al PCL mediante alguna instrucción (generalmente es la addwf, pero puede usarse subwf y muchas otras) entonces el programa saltará a una posición indeseada.

2da situación: CALL y GOTO En esta familia de uC, cada instrucción es codificada en 14 bits. En el caso de las instrucciones CALL y GOTO, su estructura es la siguiente: F2 F1 F0 K10 K9 K8 K7 K6 K5 K4 K3 K2 K1 K0 Donde las F indican cuál instrucción es la que debe ejecutarse (100 para la CALL 101 para la GOTO), y las k corresponden a la dirección a la cual queremos llamar (con un CALL) o saltar (con un GOTO). Aquí se ve claramente un problema. Podemos ver que un CALL o un GOTO sólo almacenan 11 bits de la dirección a la cual debe ir. 11 bits es un máximo 2048 posiciones. ¿Qué pasa cuando un uC posee más de 2k de memoria Flash entonces? Por ejemplo, un 16F877A posee 8k de memoria Flash. ¿Cómo haría para llamar a una subrutina que está más allá de la posición 2047 dela flash? La solución nuevamente se encuentra en el PCLATH(y es nuevamente el usuario el que tiene el deber de pre-cargar el valor adecuado). Entonces, dijimos que el PC contiene 13 bits de longitud. 13 bits son hasta 8kwords(una word es en esta familia un conjunto de 14 bits que conforman una instrucción la cual se aloja en la memoria FLASH del uC). Un CALL o un GOTO sólo contienen los 11 bits de menor peso de la dirección a la cual ir, por lo que los 2 bits restantes deberán ser pre-cargados en los bits 4 y 3 del registro PCLATH por el usuario programador. Cuando se ejecuta una instrucción CALL o GOTO, es imprescindible que el registro PCLATH esté correctamente precargado. La instrucción a la que el uC irá estará conformada por 13 bits y ellos serán: PCLATH, 4 PCLATH, 3 K10 K9 K8 K7 K6 K5 K4 K3 K2 K1 K0 Cabe mencionar que el uC carga a PC con el valor pasado por los 11 bits de K, y a PC con el valor de los bits PCLATH. El registro PCLATH no es modificado de ninguna manera. Sólo se leen esos dos bits. Por ejemplo, en un uC de 8kWords hay 4 páginas. Una página cada 2048 words. Si se está en una página y se quiere ir a otro es necesario precargar antes dichos bits del PCLATH para poder hacerlo. El usuario no debe preocuparse por precargar el PCLATH en dos situaciones: Si el uC no posee más de 2kWords de memoria Flash; O si en el código creado por el usuario, no se utiliza la memoria FLASH más allá de la posición 2047(0x7FF). Si ocurre al menos uno de esos dos casos, es suficiente con asegurar que los bits PCLATH se encuentren ambos en cero. Vamos con un par de ejemplos:

Mal:

Bien:

Mejor:

org 0x000 ;Esto es página0 call cruzo

org 0x000 ;Esto es página 0 movlw 0x08 movwf PCLATH call cruzo

org 0x000 ;Esto es página 0 pagesel cruzo ;automáticamente seleccionar banco call cruzo

org 0x800 ;Esto ya es el página1 cruzo retlw 0xFF org 0x800 ;Esto ya es el página 1 cruzo org 0x800 ;Esto ya es el página 1 retlw 0xFF cruzo retlw 0xFF

Pagesel es una instrucción del MPASM que genera dos instrucciones: un bcf/bsf PCLATH,3 y un bcf/bsf PCLATH,4. El software ensamblador selecciona automáticamente la instrucción bcf o bsf según el banco en el cual se encuentra la etiqueta(o posición de memoria) que se le especifique. En el caso anterior pagesel cruzo generaría estas dos instrucciones: bsf PCLATH, 3 bcf PCLATH, 4 Ya que la subrutina cruzo se encuentra en la página1. Finalmente, cuando se ejecuta una instrucción CALL, se carga en el STACK el valor de la posición actual más 1(es decir, se guarda en el STACK el valor PC+1). Se guardan los 13 bits, por lo que durante las instrucciones RETURN, RETLW y RETFIE no es necesario precargar al PCLATH. Para más información, ver el esquema sección 2.3 del Datasheet de los PIC16F87XA que habla de cómo cargar al PC según cada situación.

CLRF Borra el contenido de un registro seleccionado por el programador. La forma en que lo hace, pone en 0 los 8 bit del registro. Este registro, puede ser cualquiera de la posición de la RAM. Ejemplo: Código: CLRF

PORTB

Antes de la instrucción PORTB vale B'11000111'. Después de la instrucción PORTB vale B'00000000' Para recordar CLeaR es limpio File es archivo o registro. Afecta a:Z Se pone a 1

CLRW Borra al registro W. La forma en que lo hace, pone en 0 los 8 bit del registro. Ejemplo: Código: CLRW

Antes de la instrucción W vale B'00000111'. Después de la instrucción W vale B'00000000'.

Para recordar CLeaR es limpiar Work es trabajo. Afecta a:Z Se pone a 1

CLRWDT Borra al WDT. La forma en que lo hace, pone en 0 al mismo. Ejemplo: Código: CLRWDT

Antes de la instrucción WDT vale B'11111110'. Después de la instrucción vale B'0000000'. Para recordar CLeaR es limpiar Watchdog es perro guardián Timer es contador. Afecta a:  TO (neg) Se pone a 1  PD (neg) Se pone a 1

NOTA: El WDT o el contador perro guardián, sirve para destrabar al PIC. Cada vez que se desborda, o sea, cada vez que pasa de H'FF' a H'00', produce un reset, y como es un reset, se dirige a la posición 0h de la memoria de programa. La forma de trabajar con él, es ir poniendo en lugares estratégicos la instrucción ya explicada, de esta manera evitamos el desborde del contador. Si el CP se traba en algún bucle o algo similar, al no limpiar el contador, el WDT desbordará y llevará al CP a la posición 0h de la memoria de programa. Muchas veces se evita de usar esta herramienta por no tener que calcular por todo el programa dónde y cuándo limpiar al WDT. Es recomendable su uso.

COMF Realiza el complemento de un registro. Código: COMF

TEMP, F

Si TEMP tenía guardado B'00111101' luego de ejecutar la instrucción TEMP vale B'11000010'. Nótese, que aquí también podemos elegir el destino y esto nos deja guardarlo en el registro W si así lo requerimos. Para recordar COMplement es complemento File es registro. Afecta a:Z Se pone a 1 si la operación da 0

DECF Decrementa en una unidad, o lo que es lo mismo, resta 1 el contenido de un registro Código: DECF

DECENA, W

Si antes de la instrucción DECENA vale .255, después de la instrucción W vale .254 y DECENA vale .255 Si por el contrario, hubiéramos elegido el destino F, después de la instrucción DECENA vale .254 Para recordar DECrement es decremento File es registro. Afecta a:Z se pone a 1 si la operación es 0

DECFSZ Decrementa en uno, o lo que es lo mismo, resta en 1 el contenido de un registro y cuando este vale 0, el CP salta una instrucción

Código: LOOP DECFSZ GOTO BCF

TEMP

LOOP PORTB, 0

El CP descontará en 1 el registro TEMP y evalúa el valor, si no es cero, ejecuta línea siguiente que es GOTO LOOP, el cual se dirige de nuevo a la línea LOOP DECFSZ TEMP el cual volverá a descontar en 1 y evalúa el valor, si es cero salta la línea GOTO LOOP y ejecuta la instrucción BCF PORTB. Esta última línea, el programador pondrá la instrucción que necesite ejecutar. Este pequeño programa que acabamos de ver, es un temporizador o un retardo que tardará en salir del bucle dependiendo de la frecuencia de reloj y el valor cargado en TEMP. NOTA: Esta instrucción, también hay que elegirle el destino. En el caso que no se exprese, como en este caso, el MPLAB dará por sentado que el resultado se guardará en el registro F y no en W. Para recordar DECrement es decremento File es registro Skip es salto Zero que es cero. No afecta ningún bit del registro STATUS.

INCF Incrementa en 1, o suma 1, el contenido de un registro elegido por el programador. Código: INCF

INDF, F

Si antes de la instrucción INDF vale H'29', después de la instrucción INDF vale H'2A'. Nótese que también podemos elegir el destino. Si hubiéramos elegido W, después de la instrucción W vale H'2A' y INDF vale H'29'. Para recordar INCrement es incremento File es registro. Afecta a:Z se pone a 1 si el resultado es 0

INCFSZ Incrementa en 1, o suma en 1, el contenido de un registro elegido por el programador y cuando este es 0, el CP salta una instrucción. Código: VOLVER

INCFSZ

CONTADOR

GOTO

VOLVER

INCF

PORTA

El CP incrementará en 1 el registro CONTADOR y evalúa el valor, si no es cero, ejecuta línea siguiente que es GOTO VOLVER, el cual se dirige de nuevo a la línea VOLVER INCFSZ CONTADOR el cual volverá a incrementar en 1 y evalúa el valor, si es cero salta la línea GOTO VOLVER y ejecuta la instrucción INCF PORTA. Esta última línea, el programador pondrá la instrucción que necesite ejecutar. Este pequeño programa que acabamos de ver, es un temporizador o un retardo que tardará en salir del bucle dependiendo de la frecuencia de reloj y el valor cargado en CONTADOR. Normalmente, se utiliza el retardo con DECFSZ pero este también es válido. NOTA: Esta instrucción, también hay que elegirle el destino. En el caso que no se exprese, como en este caso, el MPLAB dará por sentado que el resultado se guardará en el registro F y no en W. Para recordar INCrement es incremento File es registro Skip es salto Zero es cero. No afecta ningún bit del registro STATUS.

IORLW Realiza la operación OR entre W y un literal elegido por el programador. El resultado se guarda en W. La operación es W OR L. Si antes de la instrucción W vale B'01110100' y el literal elegido es B'00011111', después de la instrucción W vale B'01111111'. Para recordar Inclusive es inclusivo OR es la operación binaria OR Literal es literal W es el registro trabajo. Afecta a:Z se pone a 1 si la operación da 0

IORWF Realiza la operación lógica OR entre el registro W y un registro elegido por el programador. La operación es W OR F. Código: IORWF

PORTC, F

Si antes de la instrucción W vale B'01111111' y PORC vale B'00001111' después de la instrucción PORTC vale B'01111111' y W vale B'01111111'. Nótese que podemos elegir el destino y la otra opción, como ya se dieron cuenta por las instrucciones pasadas, puede ser W. Para recordar Inclusive es inclusivo OR es la operación binaria OR W es el registro trabajo y File es registro. Afecta a: Z se pone a 1 si el resultado es 0

MOVLW Carga al registro W con un literal elegido por el programador para luego hacer una operación matemática o moverlo a otro registro como veremos más adelante. Sin duda alguna, una de las instrucciones más usadas en la programación ASM. Código: MOVLW

.255

Si antes de la instrucción W vale .15, después de la instrucción W vale .255. Para recordar MOVe es mover Literal es literal W es el registro trabajo. Como es de esperar, no afecta ningún bit del registro STATUS.

MOVF Mueve el contenido de un registro a otro registro elegido por el usuario. Código: MOVF

RETARDO, W

Si antes de la instrucción W vale H'2A' y RETARDO vale H'FF', después de la instrucción W vale H'FF'. Nótese que aquí podemos elegir el destino, y tenemos la posibilidad de elegir el destino al propio registro RETARDO. Al principio parece innecesario, pero se puede tomar como una verificación, ya que se ve afectado el registro STATUS bit Z. Para recordar MOVe es mover y File es registro. Afecta a:Z Se pone a 1 si la operación es 0 Anteriormente, habíamos dicho que esta instrucción se la puede tomar como verificación, para saber si se guardó con el mismo valor que tenía, el bit Z se pone a 1 si el valor es igual al que tenía cargado.

MOVWF Mueve el contenido del registro W a un registro cualquiera elegido por el programador. Sin duda alguna, esta instrucción, es otra muy usada en la programación ASM

Código: MOVWF

ADCON0

Si antes de la instrucción W vale B'10000001' y ADCON0 vale 0x0, después de la instrucción ADCON0 vale 0x81. Para recordar MOVe es mover W es el registro W y File es registro. No afecta ningún bit del registro STATUS.

NOP No realiza ninguna operación. Solo consume un ciclo de instrucción. Código: NOP

Para recordar No es no y OPeration es operación. No afecta ningún bit del registro STATUS.

RETFIE Carga al CP con el valor de la parte alta de la pila para volver al lugar dónde se encontraba el CP antes de atender la interrupción. Al mismo tiempo, pone a 1 el bit GIE para activar de nuevo las interrupciones. Código: RETFIE

Para recordar RETurn es retornar From es de la IntErrupt es interrupción. No afecta ningún bit del registro STATUS.

RETLW Carga al CP con el valor de la parte alta de la pila para volver al lugar dónde se encontraba el CP desde dónde se llamó a la subrutina y al retornar, lo hace con un literal cargado en W especificado por el programador. Esta instrucción, se utilizan en las tablas (para más detalle, ver la explicación del GOTO y CALL). Ejemplo: Código: RETLW

'L'

En este ejemplo, el MPLAB, carga en W el código ASCII correspondiente a la letra L Extendiendo el ejemplo: Código: PAGESELW MOVFW

TABLA contador

CALL

TABLA

CALL

LCD_DATO

;CONFIGURA AL PCLATH PARA VOLVER AL LUGAR CORRECTO ;CARGA A W LA POCICIÓN A LEER EN LA TABLA POR EJEMPLO 3 ;LLAMA A LA RUTINA TABLA ;LLAMA A LA RUTINA PARA MOSTRA AL LCD

NOP ; ; TABLA ADDWF

PCL,F

;SUMA AL PCL CON EL CONTENIDO DE W POR EJEMPLO 3

RETLW

'1'

;RETORNA CON 1 ASCII

RETLW

'2'

;RETORNA CON 2 ASCII

RETLW

'3'

;RETORNA CON 3 ASCII

RETLW

'T'

;RETORNA CON 4 ASCII

Este es un ejemplo sencillo de cómo utilizar RETLW. Para interpretar este código empezamos desde PAGESELW, supongamos que el CP está en esta instrucción (que está explicado que hace) luego pasa a la instrucción MOVFW contadory suponemos que tiene cargado 3 en decimal, por lo que W pasará a tener 3 en decimal. El CP continua con CALL TABLA, el CP saltará por encima a todas las demás instrucciones y se dirige a la etiqueta TABLA y ejecuta la instrucción ADDWF PCL,F En el código hablamos que le suma 3 al PCL, por lo que saltará al RETLW '3' cargando a W con el código ASCII 3. Retorna justo debajo del CALL TABLA, o sea retorna a CALL LCD_DATO y ejecuta la rutina correspondiente, cuando termina, regresa al NOP (que puede ser cualquier instrucción que necesite el programador. Si en cambio, contador hubiera tenido cargado 4 en decimal cuando llegue a la tabla y le sume al PCL este apuntará a RETLW 'T' cargando en W el código correspondiente ASCII. Para recordar RETurn es retornar Literal es literal W es el registro de trabajo W No afecta ningún bit del registro STATUS.

RETURN Carga al CP con el valor de la parte alta de la pila para volver al lugar dónde se encontraba el CP cuando se llamó a la rutina o subrutina. La diferencia con RETLW es que RETURN regresa sin cambiar a W. Este se utiliza para terminar una rutina y no se necesite ningún dato. Por ejemplo en la rutina CALL LCD_DATO no nos sirve que vuelva con ningún valor ya que es una rutina para enviar datos a un LCD, así que esta rutina tendrá implementada RETURN Por ejemplo: Código: RETURN

No afecta ningún bit del registro STATUS Para recordar RETURN es retornar.

RLF Rota hacia la izquierda los bit de un registro seleccionado por el programador. El destino de la operación se puede elegir. Cada rotación equivale a multiplicar por 2 si el bit C del registro STATUS es 0. Código: RLF

PORTC, F

Si antes de la instrucción PORTC vale B'00001000', después de la instrucción vale B'00010000'. Si se hubiera elegido como destino W, PORTC después de la instrucción continua valiendo B'00001000' y W vale B'00010000' Para recordar Rotate es rotar Left es izquierda File es el registro. Afecta a:C se pone a 1 si hubo acarreo

RRF Rota hacia la derecha los bits de un registro seleccionado por el programador. El destino de la operación se puede elegir. Cada rotación equivale a dividir por 2 si el bit C del registro STATUS es 0. Código: RRF

PORTB, F

Si antes de la instrucción PORTB vale B'10000000' después de la instrucción PORTB vale B'0100000'. Si se hubiera elegido como destino W, PORTB después de la instrucción continua valiendo

B'10000000' y W vale B'01000000' Para recordar Rotate es rotar Right es derecha File es el registro. Afecta a:C se pone a 1 si hubo acarreo

Extendiendo la explicación de las instrucciones RRF y RLF A la hora de utilizar estas dos instrucciones, hay que prestarle atención al bit C del registro STATUS. La razón de esto, es porque la rotación se hace a través del bit C. Supongamos que tenemos lo siguiente: BIT C = 0 TEMP = B'00010000' Ejecutamos la instrucción RRF y TEMP vale B'00001000'. O si ejecutamos la instrucción RLF TEMP vale B'00100000' Pero si ahora tenemos: BIT C = 1 TEMP = B'00010000' Ejecutamos la instrucción RRF y TEMP vale B'10001000'. O si ejecutamos la instrucción RLF TEMP vale B'00100001' Vemos como rota los bit dependiendo del valor del bit C. Pero anteriormente, habíamos dicho que estas dos instrucciones afectan al bit C. La actualización del bit C, lo hace después de la rotación. Lo vemos con un ejemplo: Código: MOVLW B’10001001’ MOVWF temp BCF STATUS, C RLF temp, F

; PONEMOS A 0 AL BIT C ; ROTAMOS A LA IZQUIERDA

Al ejecutar este programa, nos dará lo siguientes resultados: TEMP = B'00010010' BIT C = 1 Y para ver la diferencia vemos lo siguiente: Código: MOVLW B’00000001’ MOVWF temp BCF STATUS, C RLF temp, F

; PONEMOS A 0 AL BIT C ; ROTAMOS A LA IZQUIERDA

Al ejecutar este programa, nos dará lo siguientes resultados: TEMP = B'00000010' BIT C = 0

Algo que me había olvidado de mencionar pero que MIGSANTIAGO del foro de TODOPIC estuvo atento es que estás dos instrucciones, nos sirve para enviar datos en forma serial utilizando el bit C que lo veremos más adelante. Recordemos que, para utilizar estas instrucciones para multiplicar o dividir, debemos asegurarnos de que el bit C, esté en 0.

SLEEP Pone al microcontrolador en bajo consumo. Código: SLEEP

Para recordar SLEEP es dormir. Afecta a:  TD se pone a 1  PD se pone a 1

SUBLW Resta el contenido de W con un literal de hasta 8 bit (.255). El resultado se guarda en W. Código: SUBLW

.20

Si antes de la instrucción W vale .23 después de la instrucción W vale .3 Para saber si el resultado es negativo o positivo, hay que chequear el bit C del registro Status. Si hay acarreo, el resultado es negativo, y por el contrario, si no hay acarreo es positivo. Para recordar SUBtraction es restar Literal es literal y W es el registro W. Afecta a:  Z se pone a 1 si el resultado es 0  DC se pone a 0 si hay acarreo del bit del 4 al 5 bit del registro (recordemos que en la resta, es

distinto a la suma, por eso, se pone a 0 si hubo acarreo).  C se pone a 0 si hubo acarreo (recordemos que en la resta, es distinto a la suma, por eso, se pone

a 0 si hubo acarreo).

SUBWF Resta el contenido de un registro seleccionado por el programador con el contenido del registro W. La fórmula es F - W = d. d es la dirección elegida por el programador en dónde se guardará el resultado que puede ser el registro W o el registro elegido por el programador. Código: SUBWF

MINUENDO, W

Si antes de la instrucción W vale .55 y MINUENDO vale .56, después de la instrucción, MINUENDO vale .56 y W vale .1 Para recordar SUBtraction es resta W es el registro W y File es el registro elegido. Afecta a:  Z se pone a 1 si el resultado es 0  DC se pone a 0 si hubo un acarreo del 4 bit al 5 bit (recordemos que en la resta, es distinto a la

suma, por eso, se pone a 0 si hubo acarreo).  C se pone a 0 si hubo acarreo del 7 bit. (recordemos que en la resta, es distinto a la suma, por eso,

se pone a 0 si hubo acarreo).

SWAPF Intercambia los bits de un mismo registro elegido por el programador. Los 4 bit de menor peso, pasan a ser lo 4 bits de mayor peso, y los 4 bits de mayor peso, pasan a ser los 4 bits de menor peso. El destino puede ser seleccionado. Cabe pensar que puede ser una instrucción de muy poco uso, pero todo lo contrario si se utilizan con las interrupciones. Microchips recomienda su utilización a la hora de salvar el contexto y restaurarlo en una interrupción ya que no modifica el registro STATUS. Cuando trabajemos con las interrupciones, se verá que es muy recomendable salvar el registro STATUS y W en la RAM para luego restaurarlos. Si utilizamos la instrucción MOVF, es afectado el bit Z, perdiendo su estado original en el momento de la interrupción. Esto se soluciona, utilizando la instrucción SWAPF. No se preocupen si no lo entiende por ahora. Lo entenderán cuando veamos ejemplo de interrupciones. Código SWAPF

STATUS, W

Si antes de la instrucción W bale H'55' y el registro STATUS vale B'00100100', después de la instrucción el registro STATUS vale H'24' y el registro W vale B'01000010' Para recordar SWAP es intercambiar NIBBLE es porción File es el registro. No afecta ningún bit del registro STATUS. XORLW Realiza la operación lógica XOR entre un literal o valor y el registro W. El resultado queda guardado en el registro W. Código: XORLW

B'11000101'

Si antes de la instrucción W vale B'11111000', después de la instrucción W vale B'00111101'. Para recordar XOR es la operación lógica XOR Literal es un valor W es el registro W. Afecta a:Z se pone a 1 si la operación es 0

XORWF Realiza la operación XOR entre un registro elegido por el programador y el registro W. La operación es F XOR W = d. El resultado se puede elegir dónde será guardado. Código: XORWF

PORTB, F

Si antes de la instrucción PORTB vale B11111110' y W vale B'00000001', después de la instrucción W vale .1 y PORTB vale B'11111111'. Para recordar XOR es la operación lógica XOR W es el registro W y File es el registro elegido. Afecta a:Z se pone a 1 si la operación es 0 Una vez que vimos todas las instrucciones y asumiendo que ya se la saben de memoria (tiempo tuvieron de sobra) y si no lo han hecho, es hora de hacerlo, empezamos a escribir programas muy sencillos. Pero, ¿cómo? Si se están haciendo esta pregunta, es hora de leer desde el primer mensaje. Tienen que acordarse las posiciones de las cuatro columnas. Recuerden que vamos a escribir los programas en el MPLAB, por lo que si aún no lo tienen, es hora de descargarlo de la página de Microchip en forma gratuita e instalarlo en la PC. Lamentablemente, este programa trabaja solo bajo Windows, por los que tienen Mac o Linux, no lo podrán hacer si no es por un emulador de Windows y aun así, no sé si funcione correctamente. Empezaremos bien desde el principio y para ello, voy a explicar cosas nuevas. Todo programa tiene un encabezado que se repite en cada programa nuevo y que varía según el PIC a utilizar y las

prestaciones del programa a escribir. Muchas de las personas crean plantillas nuevas para ahorrarse el trabajo. Yo soy una de ellas y aquí les doy una plantilla que pueden utilizar sin problemas y modificarlas según su necesidad. He aquí la plantilla que también está adjuntado. LIST P=16F877A INCLUDE __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC ; ;--------------------------------------------------------------;VARIABLES. ;--------------------------------------------------------------; CBLOCK H'20' ENDC ; RESET ORG H'00' GOTO INICIO ORG H'04' ;VECTOR INTERRUPCIÓN INTERRUP ; INICIO ; END

Primera línea: LIST P=16F877A Esta línea, sirve solo para el MPLAB y le indica que el PIC a utilizar es el 16F877A. Se debe actualizar según sea necesario.

Segunda línea: INCLUDE Esta línea sirve a la hora de compilar ya que dentro de este archivo que viene incluido dentro del MPLAB, le indica al ensamblador dónde están ubicados cada registro y el nombre de cada bits del PIC a utilizar así, nos ahorra de hacerlo nosotros mismos. Si desean abrir el archivo, lo pueden hacer con el notepad o cualquier editor de texto. Se debe actualizar según sea necesario.

Tercera línea: __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC Línea muy importante pero se puede omitir. Aquí se configura la palabra de configuración del PIC y que está en el Datasheet del pic correspondiente. En mi caso, yo la omito y luego lo configuro desde el ICPROG a la hora de pasar el archivo .hex al pic. Es por eso que esta línea está incompleta para el pic a utilizar pero completa para el PIC 16F84. Vemos en más detalle esta línea: __CONFIG Directiva para el ensamblador de que debe generar la palabra de configuración correspondiente de acuerdo a:

_CP_OFF la protección de lectura del PIC deshabilitado. _PWRTE_ON Reset de encendido habilitado _WDT_OFF Perro guardián deshabilitado. _XT_OSC Oscilador a cristal. El carácter& sirve para unir una directiva con otra.

Cuarta línea: ; ;--------------------------------------------------------------;VARIABLES. ;--------------------------------------------------------------; Este no es más que un pequeño encabezado. El ensamblador omitirá estas líneas y solo porque empieza con ";". Recuerden que, toda línea que empiece con ";" es comentario y el ensamblador la omitirá. Justo por debajo de este encabezado, ponemos las variables. ¿Aqué le llamo variables? Aposiciones de memorias o nombre de bit que yo quiera darle personalmente. Por ejemplo, dentro del archivo P16F877A.INC a la posición de memoria 0x05 le llama PORTA pero si yo quiero llamarlo PUERTO_A, es aquí dónde le indico al ensamblador. ¿Cómo se hace? Es muy fácil y con la instrucción "EQU" PUERTO_A EQU H’05’ Si al Bit RA6 lo quiero llamar LED6 lo hacemos así: LED6 EQU 6 Supongamos que quiero encender el LED 6 que está en el Puerto a bit 6, y este se activa con un 1 lógico, ponemos esta instrucción: BSF PUERTO_A, LED6 Y el ensamblador lo traducirá así: BSF 0X05, 0X06

Quinta línea: CBLOCK

H'20'

ENDC A estas dos líneas las unifique porque van juntas. Entre ellas van los nombres de cada posición de la RAM que nosotros queramos nombrar, o cada Registro que queramos renombrar. Recuerden que los registros están implementados en la RAM y que la posición de la RAM que puede utilizar el usuario para guardar cosas, empieza desde una posición que está indicada en el Datasheet. Para el caso de 16F877 empieza desde la posición 0x20 como lo ven en la figura siguiente.

La directiva CBLOCK H'20' indica que empezamos a nombrar posiciones de memoria desde la ubicación 0x20. Por ejemplo CBLOCK H’20’ temperatura demora1 demora2 ENDC La posición 0x20 se llama temperatura, la posición 0x21 se llama demora1 y así sucesivamente. También existe otra forma de nombrar o renombrar posiciones de memoria o registro, y ya lo vimos que es con la directiva EQU. Por ejemplo: temperatura EQU H'20' demora1 EQU H'21' demora2 EQU H'22'

Sexta línea: RESET ORG H'00' GOTO INICIO ORG H'04' ;VECTOR INTERRUPCIÓN INTERRUP He unificado estas líneas porque por lo general así se escribe en la mayoría de nuestros programas. Vemos con más detalles estas líneas. RESET ORG H’00’ Aquí es en dónde empieza el CP cuando se enciende al PIC. Y estos se debe, porque cuando hay un reset por el pin MCLR o un reset interno producido por, encendido del PIC o, por ejemplo, del perro guardián, el vector reset se ubica en la posición 0x00 de la memoria de programa. Como pueden apreciar, hemos llamado a la posición 0x00 con el nombre de RESET, ya que la primer columna es una etiqueta. Las etiquetas sirven para nombrar posiciones de memoria de programa. ORG H’00’ indica que se empieza a escribir desde la posición 0x00 por lo que la siguiente instrucción, quedará alojada en la posición 0x00. ORG es una directiva, y solo sirve para el ensamblador. Esta línea, SIEMPRE debe estar y no se puede modificar, salvo la etiqueta. Siguiente línea es GOTO INICIO, esta instrucción queda alojada en la posición 0x00 y es un salto a la etiqueta INICIO. Este salto tiene que estar, porque en las siguientes posiciones de memoria de programa, está la interrupción, externa e interna del PIC. Por eso es necesario hacer el salto. Siguiente línea nos encontramos con ORG H’04’, como se dieron cuenta, es una directiva. Esta posición de memoria, indica el vector de interrupción. Cuando estén habilitadas las interrupciones y una de ella se activa, el CP apuntará aquí, a la posición 0x04. Siguiente línea nos encontramos con la etiqueta INTERRUP. Si trabajamos con las interrupciones, aquí es donde escribiremos lo que necesitamos hacer con ellas.

Séptima línea: ; INICIO ; Vemos la etiqueta INICIO. Aquí vendrá el CP cuando haya un reset gracias al GOTO INICIO ubicado en la posición 0x00 de la memoria de programa. De esta manera, saltamos un montón de instrucciones que no debemos ejecutar antes. Como por ejemplo las interrupciones si hubiese. Por ende, a partir de esta etiqueta, estará nuestro programa principal. Configuraremos los puertos, las interrupciones y empezaremos a darle trabajo al CP.

Octava línea: END Esta es una directiva y solo sirve para el ensamblador indicando que después de esta directiva, se terminó el programa. Instrucciones que estén por debajo de esta línea, no serán tenido encuentra. Y esta directiva es obligatoria colocarla.

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF