Microcontroladores PIC

15,440 views

Published on

Introducción a los Microcontroladores PIC

Published in: Education
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
15,440
On SlideShare
0
From Embeds
0
Number of Embeds
20
Actions
Shares
0
Downloads
432
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Microcontroladores PIC

  1. 1. Voy a contar en muy poco tiempo el proceso de auto-aprendizaje que yo he seguidode los microcontroladores PIC, con un enfoque eminentemente práctico que permitaa cualquiera entender las características principales de los microcontroladores PIC degama media y mejorada, y eventualmente usar un microcontrolador para cualquierdiseño de complejidad pequeña o media.Asimismo esta introducción puede considerarse el primer paso para conocer enprofundidad el amplísimo mundo de los controladores de una forma rápida; desdeaquí se podrá profundizar con la información que provee el fabricante sobre el usode funcionalidades más avanzadas o con cualquier otra gama de microcontroladores,según sean las necesidades del interesado.Dada la cantidad de información y el carácter práctico de esta introducción, serecomienda una vez concluida ésta, que la persona interesada instale los paquetessoftware que se usan para programar los PIC por sí mismo, y también que se trate dehacer programas similares a los que se van a presentar con pequeñas variaciones, yaque la práctica hace que se afiancen mejor los conocimientos. A mi Padre. Aún con el dolor de perderte siempre recordaré tu alegría Papá. Tu hijo 1
  2. 2. 03.- ¿ Qué es un microcontrolador ? 04.- Familias de microcontroladores05.- Gamas de los PIC de 8 bits 06.- Características de los PIC07.- Periféricos y auto-control 08.- PIC16F690 en BLOQUES09.- MAPA DE MEMORIA 10.- STATUS11.- MPLAB IDE y PICkit2 12.- Placa de desarrollo ++13.- Nuestro primer programa (ASM) 14.- INSTRUCCIONES PARA BITS15.- INSTRUCCIONES PARA BYTES 16.- INSTRUCCIONES CON LITERAL Y DE CONTROL17.- TABLA DE INSTRUCCIONES 18.- Macros19.- PROGRAMA BLINK.ASM 20.- PROGRAMA ROTATE.ASM21.- Puertos polivalentes 22.- Diagrama del A/D23.- Selección del canal A/D 24.- Configurar el A/D25.- Programa A/D A2D.ASM 26.- Rebotes de tecla27.- Eliminación de rebotes 28.- Subrutina Delay29.- OPTION_REG 30.- Interrupciones31.- INTCON - INTERRUPT CONTROL REGISTER 32.- Timer033.- INTERRUPT.ASM 34.- FILTER.ASM35.- GREYCODE.ASM 36.- 1DIGITO.ASM37.- 2DIGITOS.ASM 38.- 7SEGMENT.ASM39.- 7SEG_INTERR.ASM 40.- PWM.ASM41.- Configuración 42.- ‘C’ Led_blink.c43.- ‘C’ básico 1 44.- ‘C’ básico 245.- Display7seg_int.c 46.- Fichero de listado.lst47.- Humid.c 48.- LCDs49.- LCD_rutinas_16F690_PORT-C.c - 1 50.- LCD_rutinas_16F690_PORT-C.c - 251.- Humid_LCD.c 52.- PWM_LCD.c53.- LCD_EasyPIC.c 54.- Timer1_Cal_quartz.c PIC18F132055.- Debugging: Teclado.c 56.- Watchdog: Test_WDT.c57.- Encoder_check.c 58.- Photodiode_PCB_controller.c59.- P18F2420_ADconverter.c 1 60.- P18F2420_ADconverter.c 261.- P18F2420_ADconverter.c 3 62.- P18F2420_ADconverter.c 463.- P18F2420_ADconverter.c 5 64.- P18F2420_ADconverter_callertable.txt 2
  3. 3. Un controlador es un dispositivo que se emplea para el gobierno y/o lamonitorización de uno o varios procesos. Hace unas décadas, los controladores seconstruían exclusivamente con componentes de lógica discreta, posteriormente seemplearon los microprocesadores, que se rodeaban con chips de memoria y E/Ssobre una tarjeta de circuito impreso. En la actualidad, todos los elementos delcontrolador se han podido incluir en un chip, el cual recibe el nombre demicrocontrolador.El microcontrolador es un sencillo pero completo computador contenido en elcorazón (chip) de un circuito integrado. Un microcontrolador es un circuito integradode alta escala de integración que incorpora la mayor parte de los elementos queconfiguran un controlador.Un microcontrolador dispone normalmente de los siguientes componentes:· Procesador o CPU (Unidad Central de Proceso).· Memoria para el programa tipo ROM/PROM/EPROM o FLASH.· Memoria RAM y EEPROM para contener los datos.· Líneas de E/S digitales para comunicarse con el exterior (puertos).· Generador de impulsos de reloj que sincronizan el funcionamiento de todo elsistema.· Osciladores, contadores y temporizadores.· Diversos módulos para el control de periféricos (puertos serie y paralelo,conversores Analógico/Digital y Digital/Analógico, etc.). 3
  4. 4. Hoy en día prácticamente todos los microcontroladores se fabrican con tecnología CMOS(Complementary Metal Oxide Semiconductor) por su alta capacidad de integración, su bajo consumoy su alta inmunidad al ruido.Entre los más conocidos podemos citar:• 8048 de Intel. Es el ‘padre’ de los microcontroladores actuales.• 8051 de Intel. Es antiguo (~1980) muy popular ya que es producido por varios fabricantes, y suarquitectura se sigue usando para productos nuevos, por ejemplo por ATMEL.• 68HC11 de Motorola y Toshiba, precursor de la familia 68xxx de Motorola mucho más potente.• PIC de MicroChip que posee una amplísima gama. Fueron los primeros microcontroladores conarquitectura RISC (Reduced Instruction Set Computer). Trataremos de éstos a lo largo de estapresentación.• AVR de ATMEL, nombre genérico de otra amplia gama de microcontroladores muy potentes yrápidos: AT90Sxx, ATtinyxx, ATmegaxx. Todos ellos pueden trabajar en C con herramientas libres.La mayoría de éstos microcontroladores tienen una arquitectura de buses Von Newman (o Princeton)y conjunto de instrucciones grande (CISC – Complex Instruction Set Computer); frente a los PIC’s queposeen una arquitectura de buses Harvard y un conjunto reducido de instrucciones (RISC). Laarquitectura Von Newman (muy común en casi todos los procesadores como los PC’s) tanto lasinstrucciones del programa como los datos llegan a la CPU a través de un solo bus, mientras que en laarquitectura Harvard hay dos buses, uno para las instrucciones de programa y otro para los datos;esto permite tener distinto número de líneas (ancho del bus) para las instrucciones del que tiene elbus de datos; en el caso de los PICs el bus de instrucciones tiene 12, 14 ó 16 bits y el de datos es de 8bits; dado que la memoria de programa (FLASH-ROM) está integrada en el chip no existe acceso albus de instrucciones desde el exterior, la interacción con el mundo se hace a través del bus de datos.Programar los PIC en ensamblador es algo más fácil que para otros tipos porque sólo tienen 35instrucciones (RISC) frente a por ejemplo las 130 de los AVR; en cualquiera de los dos casos suele sermás fácil y rápido programar en alto nivel (C o BASIC). 4
  5. 5. Además de la división según la arquitectura de 8, 16 ó 32 bits, la familia de 8 bits deMicroChip se divide en gamas según la evolución que han tenido los microcontroladores.Esta clasificación es muy dinámica, tanto que actualmente MicroChip habla de tres rangos,en vez de los cinco (históricos) dados en la primera tabla; las gamas enana y baja se hanfusionado (baseline), así como las gamas alta y mejorada se integran en la alta (highperformance) aunque realmente la antigua gama alta (PIC17Fxxx) ha desaparecido.Esta tabla es pues inexacta y se menciona sólo por dar información histórica, asimismo dadola rapidísima evolución del mercado de microcontroladores PIC, los números que se indicancorresponden a un momento en el tiempo y por tanto varían al irse introduciendo nuevosproductos con mayores prestaciones.Los nombres de los PIC’s que se dan corresponden a los microcontroladores que tienenmemoria FLASH (de ahí la ‘F’ del nombre), aunque también existen otros identificativos paradistintos tipos de memoria PROM que MicroChip llama OTP (One Time Programming) otambién con memoria ROM que se crea en el proceso de la fabricación. La gran ventaja de lamemoria FLASH es que puede borrarse y regrabarse muchas veces y es por tanto muyadecuada para el desarrollo o para las actualizaciones en el mismo chip físico.En la columna de ‘Instrucciones’ tenemos el tamaño de la palabra de la memoria deprograma donde se almacenan las instrucciones que ejecuta el microcontrolador, vemosque para las gamas media y alta las instrucciones tienen respectivamente 14 y 16 bits.Nosotros trabajaremos sólo con dispositivos con memoria FLASH de las gamas media y alta.Usaremos un sistema de desarrollo llamado PicKit2 Low Pin Count Demo Board, con unPIC16F690; mientras no se especifique lo contrario nos referiremos a ese sistema dedesarrollo y tipo de PIC. Para los programas en C usaremos también el sistema de desarrolloEASYPIC.Es interesante destacar que la gama PIC18Fxxxx posee un número mayor de instrucciones yun mapa de memoria diferente para permitir la programación de estos dispositivos en C; dehecho MicroChip sólo provee un compilador C para la gama alta; afortunadamente otrosvendedores han desarrollado compiladores para todas las gamas, aunque con las lógicaslimitaciones debidas al hardware. Nosotros usaremos el compilador de Mikroelektronika(www.mikroe.com) del que tenemos licencias, es fácil de usar, tiene buenas librerías y sepuede descargar una versión limitada gratuitamente. 5
  6. 6. La tecnología CMOS es muy rápida y como no necesita resistencias de polarización, prácticamente sólo consumeenergía en las transiciones o si tiene que proporcionar corriente a las cargas que pueda tener en el circuito.Puede funcionar con un rango de voltajes de 2 a 5.5 V. Para aplicaciones con baterías el PIC puede detener elreloj (modo sleep) y dado que la RAM es estática el consumo es virtualmente cero en dicho modo.El procesador RISC con arquitectura Harvard facilita implementar un esquema pipeline, o sea que la lectura de lasiguiente instrucción se hace *durante* la ejecución de la instrucción actual lo que permite una mayor velocidadde ejecución en casi todos los casos. Sólo cuando se ejecuta un salto en el programa se tiene que desechar lainstrucción leída, por lo que las instrucciones de salto requieren el doble de tiempo que las otras. De cualquiermanera cada instrucción necesita 4 ciclos de reloj para ejecutarse, y según hemos visto las de salto requieren 8ciclos de reloj para su ejecución. Así pues si un PIC tiene un reloj de 8 MHz, como máximo ejecuta a unavelocidad de 2 MIPS (Mega Instrucciones por Segundo) y como máximo los PIC de gama alta alcanzan 10 MIPS a40 MHz; los procesadores de ATMEL ejecutan una instrucción por ciclo de reloj llegando a 20 MIPS.Los PIC tienen un solo registro llamado W (Working register) conocido también como acumulador, quelógicamente tiene 8 bits. El bus de direcciones de acceso a la memoria es de 7 bits, por lo que sólo se puedeacceder a 128 bytes simultáneamente; para los PICs que tienen más memoria esta se organiza en bancos de 128bytes o menores; para cambiar de banco de memoria hay que ejecutar ciertas instrucciones, lo que introducecierta complejidad y propensión a tener fallos en los programas. Esta es posiblemente la característica menos‘agradable’ de los PIC y siempre debe tenerse en cuenta, al menos trabajando en ensamblador; en C elcompilador se encarga de ello aunque por un precio en la eficiencia, ya que se hacen muchas operaciones deselección de banco de memoria que no son necesarias. La nomenclatura que usa McroChip para referirse a lasceldas de memoria es un tanto confusa ya que a veces se refiere a ellas como ‘registros’ y otras como ‘file’(nombre ciertamente desafortunado …); los microcontroladores de ATMEL tienen 16 auténticos registros queson independientes de la memoria, siendo éste el concepto más usual de registro.El control de periféricos se hace simplemente escribiendo en una determinada celda de memoria genéricamentellamada SFR (Special Function Register). Por ejemplo, si quiero poner a nivel lógico alto todas las patillas delpuerto A, tendré que escribir FFh en la dirección de memoria 5, ya que esta es la dirección asignada para leer y/oescribir en el puerto A. Por tanto para controlar los dispositivos del PIC se usa exactamente la misma instrucciónque para almacenar un dato en memoria, solo que para ciertas posiciones de memoria (SFR’s) estaremosaccediendo a un dispositivo físico que nos conecta con el mundo real; esto es lo que significa que los periféricosestá mapeados en la memoria./******** Continua en la diapositiva siguiente ********/ 6
  7. 7. Este PIC tiene un oscilador interno a 8 MHz de tipo RC, poco estable (+-1%) con un divisor hasta 32kHz; también puede trabajar con un cuarzo o resonador externo hasta 20 Mhz. El modo defuncionamiento se selecciona en el momento de la programación del dispositivo y no puedecambiarse durante la ejecución (aunque con el oscilador interno se puede seleccionar el factor dedivisión).El PIC posee dos memorias permanentes, la FLASH con palabras de 14 bits contiene el programagrabado en el chip en el momento de la programación o ‘quemado’ (burn) del dispositivo y laEEPROM el la que se puede almacenar datos durante la ejecución. La FLASH permite más de 100.000escrituras, mientras que la EEPROM más de 1.000.000, aunque por velocidad y durabilidad nuncadebe usarse como RAM. La retención de datos en ambos casos es mayor de 40 años.Los comparadores permiten generar una interrupción o cambiar el estado de un SFR (registro enmemoria) según el valor de un voltaje analógico sea mayor o menor de una referencia que puede serinterna o externa.Temporizadores: Timer0 de 8 bits con pre-scaler, Timer1 de 16 bits puede trabajar como contador,con pre-scaler y oscilador independiente, y el Timer2 de 8 bits con pre y post-scaler. El módulo ECCP+(Enhanced Capture Compare) trabaja con los temporizadores para medir tiempos con muchaprecisión y también controla un generador de PWM (Pulse Width Modulation) con 10 bits deresolución y 1, 2 ó 4 salidas.EUSART es el Enhanced Universal Synchronous Asynchonous Receiver Transmitter, soporta RS485,RS232, LIN e I2C; es capaz de auto-detectar la velocidad y puede generar una interrupción con el bitde start.El módulo ICSP (In-Circuit Serial Programming) es el que nos permite programar el dispositivo sinnecesidad de retirarlo de su PCB (con algunas condiciones). Para algunos PICs también permite hacerdebugging en la PCB.Al entrar en modo sleep se detiene el oscilador, se vuelve a la ejecución después de un reset o unainterrupción; cada vez que se re-inicia el PIC el módulo PWRT (Power-up Timer) espera el arranquedel reloj antes de empezar la ejecución y el OST (Oscillator Start-up Timer) permite incrementar laespera hasta la estabilización completa del mismo (1024 periodos). El POR (Power-on Reset) generauna señal limpia de reset independientemente de la pendiente de subida de la alimentación; el BOR(Brown-out Reset) generará un reset si la tensión de alimentación baja de un cierto nivel pre-establecido. El módulo watchdog (WDT) es un temporizador totalmente independiente de laejecución del programa que generará un reset pasado un cierto tiempo, que es configurable, sin quela ejecución de programa haya ‘limpiado’ este temporizador; normalmente se usa para evitar que elprocesador se quede ‘colgado’ o ejecutando un bucle sin fin indeseado. 7
  8. 8. Vemos aquí el diagrama de bloques del PIC16F690 cada salida o entrada estámarcada con un cuadrado con una X, y en la diapositiva anterior veíamos también laasignación de los 20 pines del dispositivo. Observamos que tenemos del orden de 50salidas/entradas, lo que obviamente nos lleva a concluir que no todos los módulospodrán usarse simultáneamente en una determinada aplicación. Así por ejemplo lapatilla RA3/MCLR/Vpp puede funcionar como línea 3 del puerto A, o como masterclear (reset) o se usa para introducir el voltaje de programación del dispositivo (Vpp)que es de unos 12 voltios. En la configuración del dispositivo tenemos que decidir siesta patilla se usará como puerto general RA3 o como reset, y en cualquier caso lacircuitería conectada a esta patilla deberá tener en cuenta que se le puede aplicar unvoltaje alto (hasta 13.5 V) si se quiere tener la posibilidad de programar el dispositivoen su placa de aplicación (in-circuit).De izquierda a derecha y arriba hacia abajo tenemos: la memoria de programa 4k x14 bits; el contador de programa PC; la pila subrutinas de 8 niveles; el bus de datosde 8 bits; la RAM 256 bytes; los puertos de propósito general A, B y C; el bus deprograma de 14 bits; la unidad de procesamiento aritmético/lógico ALU con susregistros asociados; el descodificador de instrucciones; el módulo de control;oscilador interno; la unidad generadora de tiempos; los temporizadores 0, 1 y 2; elmódulo de comunicaciones serie asíncronas EUSART; el módulo decaptura/comparación mejorado ECCP+; puerto de comunicaciones síncronas SSI; elmódulo conversor A/D de 10 bits con 12 entradas y una referencia; módulo decomparadores; y la memoria EEPROM de 256 bytes. 8
  9. 9. Vemos aquí la memoria RAM organizada en 4 bancos, de 128 bytes cada uno. Los PICsólo pueden acceder a un banco a la vez. El motivo de estas limitaciones es que loscódigos de las instrucciones de ensamblador (conocidos como opcodes) tienen sólo7 bits para especificar la dirección de la celda de memoria; en los PIC de gama altacuyas instrucciones son de 16 bits los bancos son de 256 bytes, y pueden tener hasta16 bancos o sea 3.9 kB de RAM. Todas las celdas con nombre son los llamados SFR(Special Function Registers) que están relacionadas directamente con el hardware;las celdas marcadas en gris son inexistentes para el PCI16F690; si por error se accedea ellas se lee siempre 0 y si se escribe en ellas el hardware lo ignora.Vemos también que el número total de bytes de la RAM es de 96 en banco 0, y 80 enlos bancos 1 y 2; lo que nos da un total de 256 bytes para almacenamiento general.El SFR STATUS está presente en todos los bancos y vemos que su dirección (FileAddress) es 3. STATUS es el registro que contiene los bits de estado de la CPU ytambién 2 bits llamados RP1 y RP0 que son los que nos permiten establecer el bancoal que estamos accediendo. (Ver diapositiva siguiente para más detalles).Las posiciones F0 a FF en el banco 1, las 170 a 17F en el banco 2 y las 1F0 a 1FF en elbanco 3, están mapeadas a las 16 posiciones 70 a 7F en el banco 0; esto es que seacual sea el banco que tengamos seleccionado siempre leeremos lo mismo en éstas16 posiciones del final del banco. Esto es muy útil para almacenar datos que deberánser accesibles en varias partes del programa y no tendremos que hacer cambios debanco para acceder a ellos. Asimismo esta zona de memoria es fundamental a lahora de trabajar con las interrupciones, ya que dado que la interrupción puede llegaren cualquier momento, necesitamos un área de memoria donde guardar el estadodel procesador, incluyendo la información del banco en el que se esté trabajandoinmediatamente antes de ejecutar la interrupción y luego volver a el mismo estadoantes de retomar la ejecución normal del programa. 9
  10. 10. Este es un ejemplo de cómo se especifica el significado de los bits de un SFR (STATUS en estecaso) en el datasheet del PIC.El indicativo ‘R/W-0’ que aparece encima de algunos bits, significa que el bit es legible (R) yescribible (W) y que su valor después de un reset de la alimentación es 0. Observe otroscasos como R/W-x o R-1 que se explican en la leyenda.De este registro son especialmente importante los bits de acarreo (C carry) y cero (Z) quenos indican si la última operación ejecutada produjo rebosamiento (overflow) o dio comoresultado 0 respectivamente.Los bits RP0 y RP1 son los que seleccionan los bancos de memoria RAM.Entre los dispositivos contenidos en los PIC posiblemente los puertos son los más usados.Cada puerto tiene como mínimo dos SFR’s asociados: uno para las lecturas del propio puertoPORTx y otro denominado TRISx que determina para cada bit si se usará como entrada osalida digital. El nemónico TRISx proviene de TRi-State logic ya que cada patilla de lospuertos tiene un driver tri-state, o sea que además de los estados alto ‘1’ o bajo ‘0’, tiene untercer estado conocido como de alta impedancia, lo que significa que la línea del puertoqueda libre o flotante. Por tanto si activamos un bit de la palabra TRISA, estaremosactivando el estado de alta impedancia en el driver de esa línea y por tanto podremos leer elestado que ponga en ella la circuitería exterior, o sea, esa línea queda configurada comouna línea de entrada. Inversamente si ponemos un 0 en un bit de la palabra TRISA, estamosactivando su línea correspondiente como línea de salida.Podemos escribir en el SFR TRISx en cualquier momento de la ejecución del programa, perológicamente si por error se activa como salida una línea conectada a una salida de lacircuitería externa se puede producir un corto-circuito de los dos drivers (el del PIC y el de lacircuitería externa) que podría ocasionar averías; es importante por lo tanto que elprogramador defina correctamente las líneas de entrada y salida de todo el dispositivo. 10
  11. 11. Lógicamente antes de trabajar con los PIC’s hay que instalar el software (gratuito) MPLAB yPICkit2 que son el programa ensamblador y el programador/debugger de MicroChip queusaremos. En la web de www.MicroChip.com existe una cantidad ingente de información,sobre estos programas, datasheets, application notes, etc. Una vez instalados conectamos elPICkit2 con un cable USB, si todo está bien el dispositivo será reconocido y queda listo paratrabajar. MPLAB es muy potente y entre sus muchas cualidades está la de tener unsimulador, que en caso de no disponer de un PIC real, se puede usar para aprender o hacerdesarrollos y pruebas.En MPLAB pulsamos File->Open ‘Hello World.asm’ vemos que se abre una ventana con elfichero de texto que usa distintos colores para resaltar la sintaxis; luego Programmer->SelectProgrammer->PICkit2 y ejecutamos Project->Quick Build Hello World.asm (deberá estarseleccionada la ventana con este programa fuente para que esta opción esté activada).Debemos chequear también que el sistema ha reconocido el PIC que tenemos conectado,clickar en Configure->Select Device y comprobar que aparece el PIC16F690 en nuestro caso.Si queremos que aparezcan los números de línea en la ventana del texto del programa,hacer click con el botón derecho sobre la ventana y seleccionar ‘Properties’, luego en lapestaña de ‘ASM File Types’ marcar ‘Line Numbers’ o cualesquiera otra opción a nuestrogusto. Después una vez que la compilación ha terminado correctamente, podremos escribirel programa en el PIC, para esto ejecutar Programmer->Program en MPLAB, o en PICkit2Programmer seleccionar File->Import HEX, y pulsar el botón Write.En la ventana PICkit2 Programmer podemos pulsar el botón Read y vemos que el dispositivotiene las primeras posiciones de la memoria de programa (FLASH) escritas, todos los bits queno están escritos aparecen como 1, y dado que el PIC tiene 14 bits por palabra, enhexadecimal vemos 3FFF en todas las demás posiciones de memoria. Si pulsamos ‘On’ en lazona de VDD PICkit 2, aplicaremos la tensión que aparece a la derecha (5.0 V en nuestrocaso) a la tarjeta de desarrollo, e inmediatamente veremos que el programa grabado seejecuta. En este caso muy simple el programa tiene sólo 5 instrucciones tal y como puedeverse en la ventana del PICkit2 programmer, y al ejecutarse enciende el LED conectado a lapatilla 0 del puerto C. 11
  12. 12. Vemos en la diapositiva el dispositivo PICkit2 de MicroChip conectado a placa dedesarrollo ‘Low Pin Count’ que ha sido modificada por el autor para probar lasdistintas funcionalidades del microcontrolador. La tarjeta de desarrollo originalcontiene el PIC, los 4 LEDs rojos, el potenciómetro y el pulsador; se han añadido lostransistores T1 y T2 junto con los displays de 7 segmentos; el sensor de humedad; eldisplay LCD y el MOSFET T3 para controlar el pequeño motor de corriente continua.Disponemos también de otras tarjetas de demostración con un PIC16F887 SMD de44 pines. Ambos tipos de tarjetas son muy convenientes para ser usadas enaplicaciones pequeñas que no requieran mucha circuitería extra, o como un móduloque se puede integrar en un sistema mayor a través de los conectores adecuadospara aplicaciones más grandes.A lo largo de esta introducción veremos programas para medir y/o controlar todos ycada uno de estos dispositivos. A veces usaremos también alguna placa dedesarrollo de MikroElektronika, llamadas EasyPIC que son mucho más grandes ytienen por tanto mayor número de dispositivos y posibilidades. Para la mayoría delos programas en C usaremos los EasyPIC, aunque también algunas aplicaciones parala placa de desarrollo modificada para ilustrar el uso del programador PICkit2 conprogramas desarrollados con mikroC.La mayoría de los programas en ensamblador que veremos a continuación son losdesarrollados por MicroChip para ilustrar la forma de programar los PICs con MPLAB,y como se pueden cargar los programas en la propia placa de aplicación sinnecesidad de sacar el PIC del circuito, esto es lo que se conoce como ICSP (In-CircuitSerial Programming); que ya habíamos mencionado como una de las grandesventajas de los PIC. 12
  13. 13. Este pequeño programa está escrito en lenguaje ensamblador de los PICs, cabe destacar:•Todo lo que esté detrás de un punto y coma se considera comentario.•Las líneas que empiezan con # son directivas para el preprocesador, también en general las que empiezan por‘__’ y algunas palabras especiales como org o end que son palabras reservadas. Ninguna directiva producecódigo ejecutable, pero pueden modificar la forma en que el compilador lo produce.•La directiva ‘#include’ carga una serie de definiciones específicas para el PIC con el que estamos trabajando,contenidas en el fichero p16F690.inc en un cierto directorio de MPLAB. Esto nos permite usar en el programanombres para las posiciones de memoria y los SFR (Special Function Registers) que hacen el programa máslegible y fácil de entender. Si no pusiéramos esta directiva el compilador se quejaría, ya que no sabría quesignifica STATUS, PORTC, RP0, etc.•La directiva __CONFIG se usa para especificar los bits de configuración del PIC, éstos bits se escriben en elmomento de la escritura de la memoria de programa y configuran dispositivos como el oscilador, el watchdog,los retardos de arranque, el detector de voltaje bajo (brown-out), etc. Nota: no confundir la palabra deconfiguración (CONFIG ver datasheet pg. 174) con un SFR, ya que esta palabra sólo se escribe en el momento delburning del dispositivo y no puede cambiarse durante la ejecución.•La directiva ‘org x’ establece que el código que sigue debe ensamblarse a partir de la dirección ‘x’. En este caso 0es la dirección por la que siempre empiezan los PIC’s a ejecutar después de un reset.•La palabra ‘Start’ sin indentar es una etiqueta, o sea es un identificativo para esa posición del programa a la quepodremos dirigirnos con la orden ‘goto Start’. La sintaxis más usada añade dos puntos ‘:’ al final de las etiquetaspero MPLAB puede trabajar de las dos formas.•El comando ‘bsf f,b’ significa ‘Bit Set File la_celda_f, el_bit_b’; al ejecutarse pone a 1 (set) el bit b de la celda f,en nuestro caso es el bit 5 (RP0) de la celda 3 (STATUS), y por tanto a partir de ese momento accederemos albanco 1 de la memoria RAM. (Pregunta: ¿ por qué sabemos que el bit RP1 es 0 ?).•El comando ‘bcf f,b’ significa ‘Bit Clear File la_celda_f, el_bit_b’; al ejecutarse pone a 0 (clear) el bit b de la celdaf, en nuestro caso es el bit 0 de la celda 87h (TRISC), y por tanto la línea 0 del puerto C se activa como salida.•Luego seleccionamos el banco 0: bcf STATUS,RP0.•Finalmente activamos el bit 0 del puerto C: bsf PORTC,0. Pone un 1 en el bit bajo de la celda 07 (PORTC). Dadoque este puerto tiene un LED enchufado (a través de una resistencia) el LED se encenderá.•El comando ‘goto $’ salta sobre sí mismo de forma que ya no se ejecuta nada más. El goto es un salto a ladirección especificada, y ‘$’ significa la posición actual, también puede usarse con incrementos, por ejemplo‘goto $-1’ salta al comando anterior.•‘End’ es una directiva que le indica al compilador que no siga compilando, o sea fin del programa. 13
  14. 14. Ya hemos visto las instrucciones BSF y BCF en el ejemplo anterior.Pregunta: ¿ sobre qué banco actúa la instrucción: BCF 0x71,2?R: En principio en general el banco depende de las instrucciones de selección debanco que se hayan ejecutado antes, y por tanto en esa parte de programa que se hadado como ejemplo no aparece ninguna operación de selección de banco, luegoparece que no podríamos determinarlo con la información que tenemos. Sinembargo la dirección 0x71 está en la zona de memoria mapeada en todos losbancos, o lo que es lo mismo independiente del banco; luego la respuesta correctaes en todos los bancos.Las instrucciones BTFSC y BTFSS (Bit Test File Skip if Clear o Set) nos permitenejecutar o no la siguiente instrucción en función del valor del bit que se testea. Notarque la lógica de estas instrucciones es un poco confusa ya que la siguienteinstrucción no se ejecuta cuando la condición es verdadera, sino falsa; ya que lainstrucción está formulada negativamente (skip = no ejecutar), podríamos decir:‘test bit, no ejecutar si clear’. 14
  15. 15. Casi todas estas instrucciones tienen un sufijo ‘,d’ que es opcional y determina el destino delresultado de la operación; ‘d’ puede valer 1 ó 0 según el destino sea la celda de memoria oel acumulador (W) respectivamente. Realmente esto es un ‘truco’ para mantener bajo elnúmero de instrucciones (arquitectura RISC) pero a la vez cada una de estas instruccionespuede ejecutarse de una forma o de otra. Por defecto d=1, o sea que si no se especifica ‘d’ eldestino es la posición de memoria. En los ‘include’ de MPLAB están definidas f=1 y w=0, parahacer el código más fácil de entender; esto nos permite por ejemplo usar: incf Contador,f ; Contador = Contador + 1; equivalente a ‘incf Contador’ incf Contador,w ; W = Contador + 1, la variable Contador no cambiaEl funcionamiento de cada instrucción está dado en la columna ‘Function’ y no hay muchomás que añadir; cabe quizás mencionar que la operación NOP se puede usar para introducirun pequeño retardo, pero hay que considerar que este retardo depende de la velocidad dereloj lógicamente. Como todas las instrucciones simples NOP se ejecuta en 4 ciclos de reloj.También son interesantes los comandos DECFSZ y INCFSZ que se usan para hacer bucles; porejemplo para ejecutar 100 veces determinado grupo de instrucciones podríamos hacer: movlw .100 ; NOTA: esta es la manera por defecto deintroducir números en decimal movwf ContadorLoop100: < grupo de instrucciones a ejecutar ….> decfsz Contador goto Loop100 ; si el Contador es != 0vuelve a ejecutar el LoopLos PIC son atípicos en el sentido de que muchas de éstas operaciones hay que aplicarlasforzosamente sobre la memoria, y no existe la posibilidad de aplicarlas directamente alacumulador (W), como por ejemplo: COMF, DECF, INCF, RLF, RRF o SWAPF. 15
  16. 16. Estas instrucciones nos permiten introducir datos fijos (literal) en contraposición alos datos que podemos almacenar en la memoria, que pueden cambiar durante laejecución de un programa.Los PIC de gama media tiene una pila de subrutinas de 8 niveles, y de 31 niveles paralos de gama alta. Una subrutina es una porción de código a la que se puede llamardesde varias posiciones en el programa, y una vez acabada la ejecución de lasubrutina, la ejecución vuelve a la instrucción siguiente a la de la llamada a la rutina.A su vez dentro de una rutina, se puede llamar a otra subrutina y así sucesivamentehasta un máximo de 8 niveles (ó 31 para la gama alta). Normalmente hay que teneren cuenta que si se usan interrupciones tendremos que reservar tantos niveles comose usen en el programa más los de la rutina de interrupciones más uno, que es elnivel que usa la propia interrupción. La llamada a una rutina se hace con CALL<etiqueta>, y el retorno desde las rutinas se hace al ejecutar RETURN o ‘RETLW xx’;desde la rutina de servicio de la interrupción hay que usar RETFIE.Nota: TOS significa ‘Top Of Stack’, es un puntero a la pila donde se almacenan lasposiciones de retorno de las rutinas. PC significa ‘Program Counter’ y es la direcciónde la instrucción de programa que se está ejecutando.El comando CLRWDT es el que resetea el contador del watchdog (WDT), evitando lare-inicialización del procesador si el watchdog está activado y se ha consumido eltiempo de gracia.Los comandos OPTION y TRIS se mantienen por compatibilidad con PIC’s antiguos,no son ya necesarios y las próximas versiones no los incorporarán. 16
  17. 17. Notes1: When an I/O register is modified as a function of itself (e.g., MOVF PORTA, 1), the value used will bethat value present on the pins themselves. For example, if the data latch is ‘1’ for a pin configured asinput and is driven low by an external device, the data will be written back with a ‘0’.2: If this instruction is executed on the TMR0 register (and where applicable, d = 1), the prescaler willbe cleared if assigned to the Timer0 module.3: If the Program Counter (PC) is modified, or a conditional test is true, the instruction requires twocycles. The second cycle is executed as a NOP.Esta es la tabla completa de las 35 instrucciones de los PIC de gama media.Los tiempos de ejecución son casi siempre 1 ciclo, equivalente a 4 periodos del reloj; para lasoperaciones que requieren un salto son dos ciclos.Es importante observar los bits del registro de estado (STATUS) que se ven afectados por lasoperaciones; las operaciones aritméticas (ADD, SUB) afectan a C, Z y DC; las operacioneslógicas sólo a Z, las de rotación sólo al C y cabe destacar que las operaciones INCFSZ, DECFSZ,MOVxx o SWAPF no afectan a ningún bit de STATUS, excepto MOVF que afecta a Z.Observe en la columna del ‘opcode’ o código de la instrucción que la dirección de memoria(o file) tiene 7 bits, esto es lo que determina que el tamaño de los bancos de memoria seade 128 bytes ya que esto es lo máximo que podemos direccionar con los 7 bits de lainstrucción. Análogamente las direcciones de salto de GOTO y CALL tienen 11 bits, lo quenos permite un rango de salto de 2048 (lo que se conoce como una página), para saltos amás distancia hay que hacer uso del SFR PCLATH, que nos permite acceder a todas laspáginas que tenga la memoria de programa del dispositivo.Al principio es útil tener esta tabla a mano para entender los programas y al escribirnuestros primeros programas en ensamblador. 17
  18. 18. Además de las 35 instrucciones mencionadas anteriormente, MicroChip ha introducido estaserie de instrucciones especiales (en realidad macros) para facilitar la programación. Las‘macros’ son instrucciones del pre-procesador (no confundir con las instruccionesejecutables simples) que especifican una equivalencia del nombre de la macro con el cuerpode la definición de dicha macro y están soportadas por MPLAB; así por ejemplo podríamosdefinir en un programa:#define SALTA GOTOesta sentencia define la macro ‘SALTA’ como ‘GOTO’; las macros son sustituidas antes de lacompilación por su equivalente, luego en este caso si tenemos una sentencia en el programa‘SALTA Posicion3’, es equivalente a ‘GOTO Posicion3’.MicroChip introduce estas macros en los ficheros ‘#include p16F690.inc’ que acompañan alMPLAB y que además contienen los nombres de los SFRs de cada tipo de microcontroladorcomo ya habíamos mencionado. Todas estas instrucciones se obtienen en realidad comouna combinación de las instrucciones simples que realmente son las que ejecuta elmicrocontrolador, por este motivo estas instrucciones rompen la regla de que ‘todas’ lasinstrucciones de los PIC se ejecutan en 4 u 8 ciclos de reloj, ya que por ejemplo BNZ puedetardar 12 ciclos; otras sin embargo no son más que nombres más adecuados a los ‘pocoafortunados’ BTFSC o BTFSS.En los PIC de gama alta la mayoría de estas instrucciones son instrucciones reales, y ademásse han introducido otras muchas hasta un total de 83 por lo que ya no pueden considerarseestrictamente RISC, pero este juego de instrucciones extendido está indicado y fue diseñadopara permitir la programación de estos dispositivos en lenguajes de alto nivel,particularmente el C. Algunas de las instrucciones extendidas hay que activarlas en laconfiguración del dispositivo. 18
  19. 19. Entre las líneas 31 y 34 tenemos la declaración de dos variables Delay1 y Delay2usando la directiva ‘cblock’, que le indica al compilador que necesitamos un bloquede datos a partir de la posición de memoria 0x20. En realidad en este caso lo únicoque estamos haciendo es asignar a los símbolos Delay1 y Delay2 los valores 0x20 y0x21 respectivamente, pero si tenemos un bloque de memoria con más elementoses más cómodo que el compilador se encargue de asignarle sus posicionesconsecutivas.El programa es simple: primero inicializa el puerto C, enciende el LED, espera uncierto tiempo en un doble bucle y apaga el LED, vuelve a esperar la misma cantidadde tiempo y salta a la sentencia que enciende el LED para repetir todo el procesodesde ese punto.Preguntas:•¿ Por qué no se inicializan las variables Delay1, Delay2 ? ¿ es esto correcto ? R: nopero sólo afecta al primer bucle, por lo que es casi irrelevante.•Hay dos partes en el código que son idénticas y por tanto este programa se puedeestructurar mejor creando una subrutina. Se propone como ejercicio.•También se puede re-diseñar la rutina del ejercicio anterior para que acepte unavariable que determine el retardo total. De esta forma se hace mucho más fácilhacer más rápido o lento la velocidad de parpadeo; se puede también cambiar larelación encendido/apagado o incluso modificarlo durante la ejecución del programapara que poco a poco vaya acelerando y vuelta a empezar. 19
  20. 20. Esencialmente el programa (Rotate.asm) es muy similar al anterior. Ahora definimostodo el puerto C como de salida y usamos la variable Display para almacenar el valorde los bits que pasamos a los cuatro diodos LED y para realizar la rotación, tal ycomo puede verse en las líneas 60 a 64.¿ Se podría usar PORTC como variable en vez de Display ? La respuesta es sí, y en lamayoría de los casos funcionaría bien; pero podría darse un efecto colateralindeseado, ya que si por ejemplo la línea 3 del puerto está cortocircuitada la lecturaencubierta que se hace durante la rotación (rrf PORTC,f) nos devolvería 0 al intentaractivar la línea 3 y por tanto la rotación se pararía en dicho punto.Ejercicio: Hay un error intencionado en el programa, relacionado con un comentario.¿ Cual es ?Respuesta en la siguiente diapositiva. 20
  21. 21. Vemos aquí el diagrama hardware de dos líneas más o menos típicas de los puertos quepodemos encontrar en los PIC. La complejidad que podemos observar se debe a lasmúltiples conexiones posibles de algunos pines; en el caso de la derecha se trata del pin RC7(PORTC.7) y como vemos está conectado al conversor A/D y hay varios drivers y dos flip-flops para el control de la línea. El flip-flop de PORTC es el que proporciona el dato desalida, mientras el flip-flop TRISC controla la habilitación del driver de salida. Vemos tambiénque la lectura digital de este pin sólo puede hacerse si no está habilitada su línea deselección de modo analógico, ya que si el modo analógico está seleccionado para esta líneasiempre leeremos 0 lógico. También observamos que para esta línea se puede seleccionar lafunción SDO, en cuyo caso el nivel lógico a la salida es independiente del valor escrito en elflip-flop del PORTC.En el diagrama de la izquierda, que corresponde a la patilla RA2 (PORTA.2), vemos queademás de los flip-flops para PORTA y TRISA, tenemos WPUA e IOCA; éstos SFRs controlan lafuncionalidad de weak-pull-up y la de interrupt-on-change que posee este pin;análogamente existen WPUB e IOCB con las mismas funcionalidades para el puerto B.También vemos que tiene funciones relativas al TMR0 y tiene la capacidad de generarinterrupciones desde dispositivos externos (INT).Una característica que afecta a todas las líneas de los puertos de los PIC es que *siempre*usan una secuencia de lectura-modificación-escritura (Read-Modify-Write o RMW), lo quesignifica que cualquier instrucción que especifique un registro ejecuta un ciclo RMW, estoes, el registro es leído, los datos modificados, y el resultado es almacenado de acuerdo conla instrucción. En otras palabras: una operación de lectura se lleva a cabo en el registroincluso si la instrucción aparentemente “sólo” escribe en dicho registro. Esto puede tenerresultados indeseados en la interacción con el hardware, que el programador siempre debede tener en cuenta. En los PIC de gama alta existe un tercer registro (LATA, LATB, etc) quepuede leer el dato del latch no el del puerto de salida.Respuesta al ejercicio de la diapositiva anterior: ‘movlw 13’ no da 1 centésima de segundo,ya que 13h es 19d y por tanto el tiempo es un 50% mayor. 21
  22. 22. Vemos que tiene 14 entradas posibles, que se selecciona con los 4 bits CHS<3:0> de lapalabra ADCON0. La entrada seleccionada se digitaliza con 10 bits (0 .. 1024 niveles)comparada con la tensión de referencia. Esta tensión de referencia se puede seleccionar conel bit VCFG, bien la tensión de alimentación o una tensión menor aplicada a la patilla RA1. ElSFR que controla casi todo esto es:ADCON0 – A/D CONTROL REGISTER (ADDRESS: 1Fh)--------------------------------------------------------------------------------------| R/W-0 | R/W-0 | R/W-0 | R/W-0 | R/W-0 | R/W-0 | R/W-0 | R/W-0 |--------------------------------------------------------------------------------------| ADFM | VCFG | CHS3 | CHS2 | CHS1 | CHS0 |GO/DONE|ADON |--------------------------------------------------------------------------------------bit 7bit 0bit 7 ADFM: A/D Result Formed Select bit 1 = Right justified (ADRESH contains the two most significant bits) 0 = Left justified (ADRESH contains the eight most significant bits)bit 6 VCFG: Voltage Reference bit 1 = VREF pin 0 = VDDbit 5-2 CHS<3:0>: Analog Channel Select bits 0000 = Channel 00 (AN0); 0001 = Channel 01 (AN1); ………… 1011 = Channel 11 (AN11) 1100 = CVREF 1101 = VP6  Esta es una referencia de voltaje interna de 0.60 V 1110 = Reserved. Do not use. 1111 = Reserved. Do not use.bit 1 GO/DONE: A/D Conversion Status bit 1 = A/D conversion cycle in progress. Setting this bit starts an A/D conversion cycle. This bit is automatically cleared by hardware when the A/D conversion has completed. 0 = A/D conversion completed/not in progressbit 0 ADON: A/D Enable bit 1 = A/D converter module is enabled 0 = A/D converter is shut off and consumes no operating current 22
  23. 23. La selección de canal es muy sencilla, hay un bit para cada canal en los SFR ANSEL y ANSELH.Notar que para el PIC16F690 por defecto todos los canales están en modo analógicodespués de un reset.IMPORTANTE: hay grandes diferencias en la forma de seleccionar los canales analógicos deun modelo de PIC a otro y es *imprescindible* consultar la documentación para el correctocontrol de las entradas.Un aspecto importante del control del convertidor A/D es la velocidad de conversión, que seestablece con el SFR ADCON1; este SFR tiene sólo 3 bits del 6 al 4 con el siguientesignificado:ADCON1 – A/D CONTROL REGISTER 1 (ADDRESS: 9Fh)— ADCS2 ADCS1 ADCS0 — — — —bit 7 bit 0bit 7 Unimplemented: Read as ‘0’bit 6-4 ADCS<2:0>: A/D Conversion Clock Select bits 000 = FOSC/2 001 = FOSC/8 010 = FOSC/32 x11 = FRC (clock derived from a dedicated internal oscillator = 500 kHz max) 100 = FOSC/4 101 = FOSC/16 110 = FOSC/64bit 3-0 Unimplemented: Read as ‘0’ 23
  24. 24. These steps should be followed for an A/D conversion:1. Configure the A/D module: • Configure analog/digital I/O (ANSx) • Select A/D conversion clock (ADCON1<6:4>) • Configure voltage reference (ADCON0<6>) • Select A/D input channel (ADCON0<5:2>) • Select result format (ADCON0<7>) • Turn on A/D module (ADCON0<0>)2. Configure A/D interrupt (if desired): • Clear ADIF bit (PIR1<6>) • Set ADIE bit (PIE1<6>) • Set PEIE and GIE bits (INTCON<7:6>)3. Wait the required acquisition time.4. Start conversion: • Set GO/DONE bit (ADCON0<1>)5. Wait for A/D conversion to complete, by either: • Polling for the GO/DONE bit to be cleared (with interrupts disabled); OR • Waiting for the A/D interrupt6. Read A/D Result register pair (ADRESH:ADRESL), clear bit ADIF if required.7. For next conversion, go to step 1 or step 2 asrequired. The A/D conversion time per bit isdefined as TAD. A minimum wait of 2 TAD isrequired before the next acquisition starts. 24
  25. 25. Este programa configura el conversor A/D para leer la entrada PORTA(0) = AN0 = RA0comparada con la tensión de alimentación (referencia Vdd); el reloj de digitalización es deFosc/16.Nótese el uso de NOP’s para introducir un pequeño retardo desde la activación del A/Dhasta el inicio de la conversión. Este retardo se necesita para que se estabilice el voltaje a laentrada del módulo A/D.Aquí introducimos una manera más cómoda de selección de bancos de memoria: en vez deponer explícitamente los bits RP0 y RP1 de la palabra STATUS, usamos la directiva ‘banksel<nombre_registro>’, el pre-compilador introducirá los comandos BSF o BCF necesarios paraseleccionar el banco en el que se encuentra el registro nombrado.Advertencia: el uso de BANKSEL siempre pone todos los bits de selección de banco al valornecesario, esto puede ser ineficiente ya que la mayoría de las veces no es necesariocambiarlos todos. Por otra parte el compilador siempre genera un warning cuandoaccedemos a cualquier posición de memoria fuera del banco 0, tal y como puede verse en lafigura referido a la línea 63 del programa donde se accede a TRISA que está en el banco 1, yaunque tengamos la directiva BANKSEL en la línea anterior … Esto es claramente mejorablepor parte de los desarrolladores de MPLAB, si bien es cierto que no siempre se puedeasegurar que en alguna otra parte del programa haya un salto a la línea 63 y podría darse elcaso de que se accediera a otro banco. Es responsabilidad del programador asegurarse deque este problema no se presenta.Al ejecutar este programa sobre la tarjeta de desarrollo podemos cambiar el valor delvoltaje en RA0 usando el potenciómetro en la placa y veremos como los 4 LEDs presentanlos bits más significativos de la conversión, siendo equivalente a la presentación en binariodel valor del voltaje/Vdd * 16, ya que se trata de los 4 bits más significativos. Es interesantemover el potenciómetro cerca de la transición entre 7 y 8 por ejemplo y veremos como elruido afecta a las conversiones, ya que observaremos cambios en la lectura debidonormalmente a interferencias. 25
  26. 26. Este programa (rebotes.asm) demuestra que si no se toman precauciones, lasoperaciones manuales de pulsación de teclas producen rebotes, es decir elinterruptor se activa y desactiva más veces de las que deseamos.A la entrada del puerto A<3> tenemos una resistencia de pull-up y un pulsador atierra. Notar cómo a la hora de configurar la patilla 3 del puerto A como entradadigital, no basta con hacer el TRISA<3> igual a 1, sino que en general también serequiere deshabilitar la entrada analógica correspondiente en el registro ANSEL.Preguntas: ¿ Son correctos los comentarios del programa ? ¿ Cuándo se actualiza lacuenta, al pulsar o al soltar la tecla ? R: Los comentarios de las líneas 31 y 36 estánintercambiados, por lo se la cuenta se incrementa al soltar la tecla.Ejercicio: modificar el programa para que cuente cambios de estado de la tecla, osea en cada pulsación debería contar 2 veces, uno al pulsar y otro al soltar la tecla. 26
  27. 27. Esta versión del programa llamada Debounce.asm, espera a detectar la tecla estable5 veces, con un retardo de 1 ms entre cada testeo.La eliminación de los rebotes también se puede hacer por métodos ‘hardware’ tal ycomo puede verse en las dos figuras de la diapositiva; en la primera por filtrado(paso bajo) y en la segunda usando un flip-flop tipo RS. Obviamente usando lapotencia de microcontrolador nos ahorramos la colocación de esta circuiteríaexterna y simplificamos nuestro diseño.Observar como se puede comprobar si una variable (Counter en este caso) alcanzaun determinado valor en las líneas 73 y siguientes. 27
  28. 28. Entre los programas fuente que acompañan la presentación encontramos 3 que sonmuy similares: Vsrotate.asm, Reversible.asm, y Function.asm. Los dos primeros noañaden nada nuevo por lo que se deja al lector para su compilación y estudio; enambos casos se lee el A/D y se establece una rotación de los LEDs con un retardoque es función del valor leído del A/D. Así moviendo el potenciómetro los LEDs sedesplazan a mayor o menor velocidad. En el programa Reversible.asm también sepuede cambiar el sentido de desplazamiento del LED encendido al pulsar elinterruptor de la tarjeta. Finalmente Function.asm realiza la misma función perointroduce una subrutina para manejar el tiempo de retardo, como podemos ver en ladiapositiva desde la línea 116 hasta las 123.Una llamada a la rutina aparece en la línea 85; vemos que el acumulador (W) se usapara pasar un ‘parámetro’ a la rutina, en este caso es el número de bucles desegundo nivel que realizaremos; cuanto mayor sea el valor de W mayor será elretardo generado.También es posible que una rutina ‘devuelva’ algún valor; en ese caso puede usarseW o si son más de un valor pueden usarse variables creadas al efecto. 28
  29. 29. Entre otras funciones el SFR OPTION_REG controla al temporizador Timer0. La señalde reloj que alimenta al Timer0 puede derivarse por división del reloj principal opuede introducirse al PIC por una línea de entrada. Con el bit T0CS podemosseleccionar como fuente para el Timer0 la patilla 2 del puerto A, y de esta forma eltemporizador estaría funcionando como un contador; en cuyo caso el bit T0SEpermite seleccionar si la cuenta se hace en el flanco de bajada o el de subida.El Timer0 comparte su pre-scaler con el watchdog (WDT), en función del valor del bitPSA se usará para uno o el otro pero nunca simultáneamente para los dos.Finalmente los tres bits bajos PS<2:0> seleccionan el valor de división del pre-scaler,note que los valores de división son distintos para el TIMER-0 y el WDT.El Timer0 tiene 8 bits, y por tanto cuenta desde 0 a 255, al siguiente pulso vuelve a 0y se genera una interrupción (ver diapositiva siguiente). 29
  30. 30. Una interrupción es una señal que recibe el controlador para atender un suceso detectado por el hardware periférico. En losPIC existen numerosos periféricos que pueden generar interrupciones: como los timers, el cambio de estado en una línea deun puerto, el conversor analógico/digital, los comparadores, el módulo de comunicaciones serie, el módulo de comparación ycaptura, la EEPROM, etc. Asimismo un sistema externo al microcontrolador puede también generar una interrupción a travésde un determinado flanco en la línea de interrupción externa (RA2/INT en el PIC16F690).Para que una interrupción afecte al microcontrolador, deberán están habilitadas las interrupciones en general (INTCON<GIE>ver diapositiva siguiente); para los periféricos del microcontrolador deberá también estar habilitadas las interrupciones deperiféricos (PEIE), así como las interrupciones del periférico en particular que la genera (ADIE, RCIE, TXIE, TMR1IE, etc.). Paralos sistemas externos, el timer 0 ó los puertos, deberá estar habilitada INTE, T0IE o RABIE respectivamente. Si no se dan estascondiciones de habilitación, la interrupción no afecta a la ejecución. Si por el contrario se recibe una interrupción que estáhabilitada el controlador termina de ejecutar la instrucción actual (en algunos casos puede haber más retardo – latencia),pone GIE a 0 para deshabilitar cualquier otra interrupción, y ejecuta un salto a la dirección 4 donde se debe encontrar la rutinade servicio de las interrupciones. Una vez acabada la rutina de servicio de interrupciones se ejecuta el retorno a la instrucciónsiguiente a la que se terminó de ejecutar cuando se recibió la interrupción, usando para ello la instrucción RETFIE que vuelve ahabilitar GIE. Dentro de la rutina de servicio de interrupciones se debe salvar el contexto de ejecución del programa principal(WREG y STATUS/banco de trabajo), y este contexto deberá recuperarse justo antes de volver de la interrupción, para que laejecución normal pueda continuar tal y como se había quedado. Para esto es necesario reservar 2 celdas de memoria en lazona común de todos los bancos (Ejercicio: razone por qué debe ser en la zona común y no en el banco 1 por ejemplo.) quenos permitan almacenar el working register W y la palabra STATUS. Este código nos permite realizar estas operaciones:cblock 0x70 W_TEMP STATUS_TEMPendcMOVWF W_TEMP ;Copy W to TEMP registerSWAPF STATUS,W ;Swap status to be saved into W, SWAPF doesn’t change any flagCLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register::(ISR) ;Insert user code here:SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into WMOVWF STATUS ;Move W into Status register (sets bank to original state)SWAPF W_TEMP,F ;Swap W_TEMPSWAPF W_TEMP,W ;Swap W_TEMP into WRETFIE ; TOS -> PC ; 1 -> GIEPregunta: parece más sencillo ejecutar ‘movf W_TEMP,w’ al final en vez de dos SWAPF … ¿Por qué no se usa ‘movf’ ? R:Porque movf altera el valor del flag Z en STATUS.Una vez dentro de la rutina de servicio de interrupciones podemos saber que dispositivo ha generado la interrupción mirandolos flags de INTCON, PIR1 y PIR2; sólo un flag puede estar a 1, y este flag debe ser puesto a 0 por el software de la ISR. 30
  31. 31. INTCON es el registro (SFR) de control de las interrupciones. Como hemos visto unainterrupción es una señal generada por algún dispositivo interno o externo al PIC yque requiere una acción inmediata; el registro INTCON nos permite habilitar o no lasinterrupciones que pueda generar cada dispositivo.Relativos al Timer0 tenemos dos bits el T0IE que permite habilitar la interrupción delTimer0; y T0IF es un flag que nos indica que el Timer0 ha llegado al final de sucuenta. Este flag deberá ser limpiado por el software antes de que ocurra elsiguiente overflow. Este flag se actualizará independientemente de que lasinterrupciones estén habilitadas.Además de este registro INTCON, existen los registros PIE1 y PIE2 que son los‘Peripheral Interrupt Enable registers’ ; en ellos se puede habilitar la interrupción delos dispositivos internos (periféricos) como el A/D, USART, Timer1, Timer2, etc.En los PIC de gama alta se pueden definir la prioridad de las interrupciones comoalta o baja; lógicamente existen dos vectores de interrupción en las posiciones 0x08y 0x18 respectivamente, y muchas otras posibilidades de configuración. 31
  32. 32. Vemos en este sencillo programa que el uso del temporizador lógicamente puedesimplificar la generación de retardos o en general el control del tiempo. Insertadoen el programa se ha incluido un diagrama simplificado del Timer0.En la línea 36 seleccionamos un factor de división de 256 de la frecuencia deentrada; en este caso la señal seleccionada es el ciclo de instrucción delmicrocontrolador, que a su vez es Tosc*4 ya que cada instrucción requiere 4 ciclos dereloj para su ejecución. En total pues el periodo de la señal que alimenta altemporizador es 1024*Tosc. En nuestro caso el oscilador es de 8 MHz por lo que elperiodo del Timer0 es: Timer0 = 1024 * 1/8 us = 128 usel flag de overflow se activará cada 256 impulsos recibidos, dando un total de:32.768 ms.En la línea 42 el programa espera sin hacer nada ‘útil’; normalmente el procesadorpodría dedicarse a cualquier otra cosa mientras el temporizador lleva la cuenta deltiempo transcurrido. Nótese que el flag T0IF se debe poner a cero en el software. Eneste programa usamos el flag de fin de cuenta del TIMER-0 pero no tenemoshabilitadas las interrupciones, y por tanto no hemos definido la rutina de servicio delas mismas; en la diapositiva siguiente vemos un ejemplo con interrupciones.Pregunta: de nuevo hay un pequeño error en el programa, ¿ cual es ? ¿ qué efectotiene ? R: En la línea 38 no accedemos al banco correcto y por tanto en el primerbucle Display no está inicializado correctamente. 32
  33. 33. Programa de ejemplo de uso de interrupciones ‘interrupt.asm’; este programa usa las interrupcionesque se generan con el overflow del Timer0. En la rutina de servicio de las interrupciones carga en elvalor de conversión en el registro del TMR0 por lo que acelera o decelera la rotación del encendidode los LEDs en la placa de desarrollo.Nótese en la línea 52 que la primera instrucción es ahora un salto al principio del programa normal,ya que la rutina de servicio de las interrupciones (ISR) empieza forzosamente en la posición 4.Observe entre las líneas 61 y 66 como se puede averiguar que periférico ha generado la interrupciónmirando los flags en INTCON y PIR1, y como se limpia por software el flag en la línea 70.‘T0Semaphore’ es una posición de memoria que se usa para transmitir información entre la ISR y elprograma principal; es un flag que indica que el temporizador ha terminado la cuenta.En el trozo de programa visualizado en la diapositiva (que es el programa original de MicroChip) hayun error tipográfico en las sentencias de chequeo de los flags, ¿ puede señalarlo ?Asimismo hay otro error más grave que hace que no se espere correctamente el final de la conversióndel A/D, ¿ puede identificar el error ? Es posible que este error pasara desapercibido porque a efectosprácticos no se nota en la ejecución normal del programa, ¿ puede explicar porqué no se nota ?Estos dos errores están corregidos en versión de ‘interrupt.asm’ que acompaña al curso.Por otra parte el programa está preparado para que el sentido de rotación de los LEDs cambie cuandose pulsa la tecla SW1 de la tarjeta de desarrollo. Sin embargo esto no funciona cuando el PICkit2 estácontrolado por MPLAB, y sin embargo funciona correctamente si está controlado por el programaPICkit2 Programmer; esto se debe a que el switch está conectado a RA3/MCLR/Vpp y esta línea, quees el Master Clear o reset, no queda liberada cuando usamos MPLAB. Puede comprobarse con unvoltímetro que RA3 está continuamente a nivel lógico bajo y por ello no responde a la pulsación de latecla. 33
  34. 34. Programa ‘Filter.asm’. Este programa ilustra el uso del llamado acceso indirecto a la memoria, para ello los PICsusan dos SFR que son accesibles en todos los bancos: FSR (04h) y INDF (00h), ‘File Select Register’ e ‘INDirect File’respectivamente. FSR es lo que se conoce como un ‘puntero’ y no es más que una posición de memoria cuyocontenido nos indica donde accederemos al operar con INDF; es decir que si escribimos el valor 34h en FSR yluego leemos INDF, estaremos leyendo la celda de memoria 34h; en general cualquier operación que hagamossobre INDF se realizará sobre la celda de memoria a la que apunte FSR. El banco al que accedemos vienedeterminado por “STATUS.IRP” que vale 0 para los bancos 0 y 1, y vale 1 para los bancos 2 y 3; la razón por la quesólo se necesita 1 bit de selección de banco es que ahora el puntero (FSR) tiene 8 bits, en vez de los 7 que secodifican en las instrucciones de acceso a memoria ‘normales’, y por tanto el bit más alto de FSR es el queselecciona si accedemos al banco 0 o al 1 si IRP=0, o al 2 o al 3 si IRP=1. Por ejemplo el siguiente código pone a 0una serie de posiciones de memoria: MOVLW 0x20 ;initialize pointer MOVWF FSR ;to RAMNEXT CLRF INDF ;clear INDF register INCF FSR ;inc pointer BTFSS FSR,4 ;all done? GOTO NEXT ;no clear nextPregunta: ¿ cuantas posiciones de memoria inicializa este pequeño programa ? R:16Observe las instrucciones de las líneas 36 a 39 como pueden reservarse varias posiciones contiguas en lamemoria añadiendo ‘:x’ para reservar ‘x’ celdas de memoria dentro del bloque. Por ejemplo para acceder a lasdos celdas reservadas con ‘Delay:2’, se puede usar ‘Delay’ y ‘Delay+1’ , y el preprocesador las sustituirá por lasdirecciones correctas.Observe en el programa como se limpian las 8 celdas de memoria ‘Queue:8’ en la rutina FilterInit. Por otra parteen la rutina ‘Filter’ se almacena el dato de entrada (que viene en W) en la posición de memoria donde apuntaFSR. El programa realiza el ‘filtrado’ sumando las últimas 8 lecturas y calculando su valor medio; note que lasuma puede ser mayor de 8 bits, por lo que se almacena en un entero de 16 bits y para dividir por 8 se usan 3pares de rotaciones, tal y como puede verse en las líneas 120 y siguientes. El resultado vuelve a tener 8 bits y sedevuelve en W (y también en la variable Round).Pregunta: Vemos en las líneas 102 a 104 como se resta un valor de 8 bits de la variable de 16 bits ‘RunningSum’;los PIC realizan la substracción como una adición del número complementario. ¿ Es correcto entonces el uso delbit de acarreo (Carry) que se hace en la línea 103 y 104 ? Razone la respuesta y ponga algún ejemplo numérico.R: Sí es correcto, si hay carry significa que la operación SUBWF no tuvo overflow. Ej. 3 – 1 se calcula como 3 +255 = 2 + C; mientras que 1 – 3 se calcula como 1 + 253 = 254 (=-2) sin acarreo. 34
  35. 35. Programa ‘GreyCode.asm’. En este programa hacemos uso de una funcionalidad de los PICs que seconoce como GOTO computado (computed goto), esto es que se puede ejecutar un saltomodificando el registro especial PCL que contiene la parte baja del contador de programa (PC);además el programa ilustra como se puede usar el registro PCLATH que nos permite modificar los bitsaltos del PC y que es necesario a la hora de hacer saltos (GOTO’s o CALL’s) a otras páginas dememoria distinta de la que estamos.Tal y como puede verse en la figura, para el PIC16F690 que tiene una memoria de programa de 8kwords, hace falta el PC tenga 13 bits; PCL contiene los 8 bits bajos y PCH (que *no* está mapeado enningún registro) contiene los 5 bits altos. Podemos modificar PCH usando el SFR PCLATH, que se cargaen PCH de forma automática al hacer cualquier operación en PCL. También si hacemos un salto o unallamada a subrutina los dos bits más altos de PCLATH se transfieren automáticamente a la parte altade PC; de esta forma se pueden hacer saltos entre páginas de código.En esta rutina lo que hacemos es un GOTO computado, sumándole a PCL el valor de entrada a larutina que es W. La instrucción ‘retlw XX’ carga el valor del literal XX en W y retorna; en nuestro casosupongamos que la tabla empieza en la posición 81 (que coincide con el número de la línea) y que elvalor de entrada a la rutina es W=3; entonces al ejecutar ‘addwf PCL,f’ el programa saltará a la línea84 donde se retorna al programa principal con W cargado con el valor que se encuentra en la posición3 de la tabla. El primer valor de la tabla se corresponde con el índice 0; en este caso la tabla tiene 16elementos con el código Gray de los números del 0 al 15.Cuando el salto que se hace usando PCL pueda superar una frontera de 256*i, hay que modificarPCLATH antes de modificar PCL para que el salto se haga dentro de la tabla, si no podríamos saltarhacia atrás en vez de a la zona de la tabla; esto es lo que se muestra entre las líneas 71 y 79. Otraforma más simple de evitar esta complejidad es asegurarnos de que la tabla no atraviesa ningunafrontera de 256 bytes, usando ORG 0x100 por ejemplo. Aquí también se ilustra como leer el byte altoy bajo de una dirección de programa usando las palabras reservadas ‘high’ y ‘low’.Este es el último de los programas ejemplo que acompañan al PICkit2, a partir de ahora veremosejemplos desarrollados por el autor, que son un poco más complejos pero también más cercanos aaplicaciones prácticas. 35
  36. 36. El programa ‘1digito.asm’ ilustra como se pueden usar las tablas para representar los números del 0al 15 en formato hexadecimal. En la tarjeta de desarrollo modificada por el autor tenemos 2 displaysde 7 segmentos conectados al puerto C; los 7 segmentos a,b,c,d,e,f, y g están conectados a través deresistencias a RC0, RC1, …, RC6 respectivamente y el punto decimal está conectado al bit 7 (RC7). Elcátodo común de los displays está conectado al colector de sendos transistores cuyas bases estáncontroladas por el puerto B<6:7>; siendo la línea 6 (RB6) el dígito menos significativo. La figura de ladiapositiva siguiente representa un esquema similar (aunque no igual). Esta conexión permite lamultiplexación de la representación de cada nibble secuencialmente (Ver diapositiva siguiente.)En este programa contamos las pulsaciones de la tecla, en la variable ‘Counter’, igual que se hizo en elejemplo ‘rebotes.asm’. En la tabla ‘SevenSeg’ convertimos el valor de la cuenta en el código para surepresentación en formato de 7 segmentos y de esta manera no necesitamos usar un descodificadordel tipo 7447 o 4511 y además nos permite extender la funcionalidad de éstos que sólo puedenrepresentar del 0 al 9. La tabla es fácil de crear, por ejemplo para el número ‘1’ tendremos queencender los segmentos b y c, por tanto tendremos que activar las líneas 1 y 2 del puerto C cuyo valorseria: 0000 0110b ó en hexadecimal 0x06 que es la entrada que vemos en la segunda línea de la tablaque corresponde al número ‘1’, ó en la figura para el ‘5’: 0110 1101 = 0x6D.En la línea 32 activamos el transistor de la cifra baja de las dos que tenemos, y queda activadocontinuamente durante todo el programa, por lo tanto cuando activamos el puerto C con un valor dela tabla aparecerá el dígito correspondiente en la cifra derecha del display; dado que RB7 quedadesactivado siempre la cifra alta nunca se activa.Pregunta: ¿ Qué sucede si eliminamos las líneas 35 y 42 donde se llama a la rutina SevenSeg ? ¿Veremos algo reconocible en el display ? R: No; veremos que se encienden unos segmentos difícilesde interpretar.Observe como en las líneas 70 a 73 comprobamos que la tabla no atraviesa ninguna frontera depágina y por tanto podemos hacer el GOTO computado sin mayor complicación (Comparar con larutina de la diapositiva anterior). Estas líneas no generan ningún código ya que son sólo directivaspara el preprocesador; si al compilar obtenemos el error ‘Tabla de SevenSeg cruza una frontera depágina’ tendremos que mover la rutina a otro sitio del programa, normalmente esto no suponeningún problema. 36
  37. 37. El programa ‘2digitos.asm’ es similar al anterior: va contando pulsaciones de la tecla en lavariable ‘Counter’, pero ahora usamos los dos dígitos del display de 7 segmentos. Dado quelos dígitos están conectados en paralelo al puerto C tenemos que multiplexar, activandocada dígito durante un cierto tiempo y luego hacemos la misma operación con el otro dígito.Si estas operaciones se realizan con la suficiente rapidez, no se aprecia ningún parpadeo tansolo veremos que la luminosidad es menor que cuando se activaba un dígitopermanentemente.Para conseguir esto hemos desarrollado la rutina ‘Representa’, que recibe como parámetrode entrada el valor del registro de trabajo (W), y desde esta rutina se llama dos veces a‘SevenSeg’, una para los 4 bits bajos (nibble bajo) y otra para el nibble alto. Además se llamaa la rutina ‘TiempoEncendido’ para mantener el dígito durante unos 30 us encendido. Paraque esta rutina funcione correctamente tenemos que hacer llamadas a ella de formacontinua, ya que si no observaríamos un molesto parpadeo o incluso los dígitos podríandesaparecer si hubiese un periodo del orden de una décima de segundo sin que seactivaran. Vemos pues que mientras el programa espera la pulsación de la tecla siempretiene la llamada a ‘Representa’ dentro del bucle de comprobación, tal y como puede verseentre las líneas 41 a 45 del programa.Introducimos en este programa también la directiva ‘DT x’ que es equivalente a ‘retlw x’,pero que nos permite poner las tablas más o menos grandes de una forma mucho máscompacta tal y como puede verse entre las líneas 74 a 78. El uso de esta directiva (o de‘retlw’) *no* se recomienda para los PIC de gama alta, ya que para éstos las instruccionesson de 16 bits pero el PC cuenta bytes, por lo que las tablas serían mayores y hay que hacerotras operaciones con PCL; además para la gama alta existen otras instrucciones quetrabajan directamente con las tablas: TBLRD* y TBLWT*, que lee o escribe en la posiciónapuntada por TBLPTR que es un SFR triple con 21 bits útiles. 37
  38. 38. El programa ‘7segment.asm’ usa los dos dígitos del display de 7 segmentos de formacompleta, para representar los 10 bits del resultado de la conversión A/D. Además ilustra laforma de hacer que la conversión se realice mientras el reloj principal del microcontroladorestá parado (modo SLEEP), y como consecuencia el resultado es menos ‘ruidoso’. Sepropone como ejercicio comprobar la mejora del ruido de conversión; simplementecomentar la línea 68 (SLEEP) y quitar el comentario de las líneas 70 a 76.Se ha modificado la rutina ‘RepresentaAD’ para que use los puntos decimales de los 2displays para representar los dos bits altos de los 10 bits del resultado del conversor A/D, ylos 8 bits bajos se presentan en hexadecimal en las dos cifras del display. Así por ejemplopodemos tener en el display ‘ 9.A. ’ lo que significa 0x39A, o ‘ E 2. ’ lo que significa 0x1E2.Observe también en el programa como se configura el PIC para habilitando lasinterrupciones de periféricos (PEIE), pero no habilitamos las interrupciones en general(GIE=0). Esto puede parecer inútil pero nos permite ‘despertar’ al micro cuando el A/Dacaba la conversión, sin necesidad de tener una rutina de servicio de interrupciones. Estecódigo realiza esta función: movlw b01110000‘ ;F(RC) para poder usar SLEEP movwf ADCON1 banksel PIE1 bsf PIE1,ADIE banksel INTCON bsf INTCON,PEIE; activa INT del A/D para despertar del SLEEP bcf INTCON,GIE; desactiva INT general para que no salte a 0004 38
  39. 39. El programa ‘7seg_interr.asm’ hace lo mismo que el anterior, pero esta vez usandolas interrupciones del TMR0 y del conversor A/D. Vemos en la diapositiva la rutina deservicio de interrupciones (ISR): las líneas 32 a 34 salvan el contexto del programaprincipal; las líneas 35 a 40 determinan la fuente de la interrupción y saltan a laparte específica para cada periférico, en nuestro caso del TMR0 en las líneas 42 a 59,o del A/D en las líneas 68 a 83; después retoma el contexto del programa principalentre las líneas 60 a 64, para finalmente volver al programa principal re-activando lasinterrupciones con la orden RETFIE en la línea 65.Puede observarse en el programa que activamos el modo SLEEP para hacer lamedida del voltaje analógico sin interferencias; es muy importante en este casonotar que durante la conversión también TMR0 se para, ya que está ligado aloscilador principal que también deja de oscilar. Por tanto si estuviéramos haciendouna cuenta de tiempo basado en TMR0 se acumularían retrasos, y si cometiéramosel error de activar el modo SLEEP sin arrancar la conversión, el microcontrolador separaría indefinidamente ya que ningún periférico generaría interrupciones en esecaso. Si se necesitara mantener un reloj y usar el modo SLEEP, se podría usar elTimer 1, que posee un oscilador independiente, en el que normalmente se coloca uncuarzo de 32 kHz, tal y como se representa en la parte superior de la diapositiva, quepermite mantener un reloj de tiempo real, independiente del oscilador principal ydel modo de trabajo usado en todo momento. 39
  40. 40. El programa ‘PWM.asm’ ilustra como se puede usar el módulo ECCP+ (EnhancedCapture/Compare/PWM+) del PIC 16F690 para controlar el brillo de los LEDs o cualquierotra función pseudo-analógica conectada a los pines 2, 3, 4 ó 5 del puerto C. La resolucióndel PWM es como máximo de 10 bits, y usa Timer2 (8 bits), más dos bits del pre-scaler nospermite controlar el ancho del pulso y el periodo; la relación pulso/periodo es el ciclo detrabajo o duty-cycle. En la diapositiva se puede ver una aplicación half-bridge estándar, half-bridge controlando un circuito full-bridge, y una aplicación full-bridge usando las 4 salidasdel PIC; en este último caso el PIC puede introducir un tiempo muerto entre las activacionesde dos transistores en la misma columna.Puede observarse que el número de SFRs que es necesario usar es bastante grandeincluyendo los relativos al timer2: PIR1, TMR2, T2CON, CCPR1L, CCPR1H, CCP1CON,PWM1CON, PIE1, PR2, etc. La estructura y uso de estos registros se puede consultar en ladatasheet del dispositivo; aunque dada la complejidad asociada se recomienda que parausar el módulo PWM se usen las librerías de mikroC ya que éstas simplifican notablementeel trabajo; más adelante veremos un programa en C con similar funcionalidad pero menoscomplejo.El programa lee el conversor A/D y programa el duty cycle del PWM en función de la lectura;observamos que el brillo de los LEDs 3 y 4 de la tarjeta de desarrollo varía de forma continuaal mover el potenciómetro RP1; si queremos controlar un dispositivo que requiera máspotencia tendremos que usar un transistor como driver.Otra aplicación común del módulo ECCP+ es la de generar pitidos o alarmas; basta conectarun altavoz y variando la frecuencia y/o el ciclo de trabajo podremos cambiar el tono y elmatiz del sonido de alarma.Note que no podemos leer el A/D en modo SLEEP porque si se activa este modo se parará eloscilador principal, que es el origen del reloj del TMR2; por lo que en general cuandoestamos usando el módulo PWM no podemos usar el modo SLEEP. 40
  41. 41. En diapositivas anteriores hemos mencionado determinadas opciones que sólo puedenestablecerse cambiando la configuración del microcontrolador. Todos los PIC tienen una ovarias palabras de configuración que sólo pueden ser escritas en el momento de lagrabación (burn) del dispositivo. A veces a los bits de configuración se les llama fusibles(fuses) por su similitud con los chips PAL (Programmable Array Logic) en los queefectivamente se ‘quemaban’ determinadas conexiones internas del dispositivo. En los PIClos bits de configuración pueden re-escribirse tantas veces como el programa, ya quepueden considerarse parte de dicha memoria de programa, y estarían localizados enposiciones más allá de la memoria de usuario donde se almacena el programa (dirección2007h para el PIC16F690) y que sólo puede ser escrita en el momento de la programacióndel chip. Como hemos dicho para dispositivos con memoria FLASH los bits de configuraciónse pueden escribir tantas veces como el programa, por lo que el nombre de fusibles es pocoafortunado.Los bits de configuración se pueden programar (poner a ‘0’) o dejar no-programado (se leecomo ‘1’) para seleccionar varias configuraciones del dispositivo tal y como puede verse enla diapositiva. Observe que podemos entre otras opciones, seleccionar el modo del relojprincipal, habilitar el watchdog, el master reset MCLR o la protección del código o los datosescritos en el chip.En otras posiciones de memoria de esta área tenemos también la identificación del tipo dedispositivo que normalmente es reconocido por las herramientas de escritura y gracias a ellose puede evitar escribir el código escrito para un tipo en un chip distinto.Desde un punto de vista práctico las herramientas de escritura normalmente proporcionanun menú de opciones de configuración en función del chip que usemos; tanto en MPLAB(ver la figura) como con mikroC podemos seleccionar la configuración cuando definimos unfichero de proyecto que incluye el código fuente de nuestro programa. 41
  42. 42. Vemos aquí un programa en C (Led_blink.c) tal y como se ve en la ventana de mikroC PRO justo después decompilar correctamente; en la ventana de mensajes nos dice cuanta RAM y ROM usa el programa. Si tenemosconectado el EASYPIC a nuestro ordenador, presionando F11 se escribirá el programa en el PIC y empezará laejecución de forma inmediata. Este programa ilustra algunas ventajas de la programación en C, frente a laprogramación en ensamblador. Desglosaremos en detalle este primer programa:•Todo lo está entre /* y */ es un comentario que puede extenderse en varias líneas, igual que lo que sigue a //.•En todo programa C hay una función ‘main()’ que es el comienzo del programa.•Lo que está entre llaves ‘, sentencias; -’ es un bloque de sentencias. Al principio de un bloque puede aparecer ladeclaración de las variables y su tipo. A casi todos los efectos cuando creamos un bloque es sintácticamenteequivalente a una sola sentencia.•Los tipos de variables en mikroC son: char, int, float, void, (y double). Los tipos enteros pueden tener prefijoscomo: short, long y unsigned. En la línea 7 declaramos la variable ‘n’ como un entero corto.•En la línea 8 tenemos la primera sentencia que genera código, hace todos los puertos de salida. Vemos que enuna línea puede haber varias sentencias; análogamente podríamos tener una sola sentencia en varias líneas, yaque una sentencia no termina hasta que aparece el ‘;’.•En la línea 9 inicializamos los puertos. Note que no tenemos que hacer ningún cambio de banco, ya que elcompilador se encarga de esa complicación por nosotros.•La línea 10 es necesaria para poder usar las líneas conectadas al A/D como digitales (ver datasheet).•Bucle “while (condición) ,sentencias;-”, mientras la condición sea verdadera se repite el bloque de sentencias.•Las condiciones se construyen con los operadores relacionales: >, >=, <, <=, ==, != . Las condiciones simples sepueden unir con los operadores lógicos: &&, || y ! que significan AND, OR y NOT respectivamente. En Ccualquier expresión o asignación es falsa si su resultado es 0, y verdadera en caso contrario. Un error comúnentre principiantes es escribir “while (n=3) ….”, esa condición es *siempre* verdadera porque lo que hace esasignar el valor 3 a n y dado que el resultado es != 0, el bucle será un bucle sin fin; normalmente se quiereexpresar “while (n==3) …”, que ejecutará el bucle mientras n valga 3.•En C es muy común expresar “x = x +1”, condensado como “x++”. Cuando el operador incremento “++” precedea la variable, el incremento se hace *antes* de ejecutar la sentencia, y si aparece como sufijo el incremento sehace después. Así por ejemplo si a=3 y ejecutamos “b=a++;”, b valdrá 3 y a 4; pero si ejecutamos “b=++a;”, b y avaldrán 4. Análogamente existe el operador decremento ‘--’.•El bucle “for (sentencia1; condición; sentencia3) , bloque -”, es equivalente a: “sentencia1; while (condición) {bloque; + sentencia3; -” . Note que tanto la sentencia1 como la sentencia3 pueden ser una serie de sentenciassimples separadas por comas; por ejemplo: “for (k=7, n=0; n-k != 0; n++, k--) ,…-”•Delay_ms(x) es una función de librería que nos proporciona un retardo de ‘x’ milisegundos.•La construcción “if (condición) {bloque-verdadero} else {bloque-falso-” se ejecuta sólo uno de los bloques enfunción de la condición. Se pueden encadenar tantos “if … else if … else if …” como se quieran.•Los operadores sobre los bits (bitwise) son: <<, >>, ~, &, | y ^; siendo respectivamente desplazamiento a laizquierda, derecha, complemento, AND, OR, y XOR. 42
  43. 43. 1. El tipo de las variables determina su tamaño en memoria y el rango en valores de la variable. ‘char’ tiene 8 bits y va de 0 a 255. ‘int’ es el tipo por defecto, tiene 16 bits y rango de -32768 a +32767; ‘short int’ o sólo ‘short’ tiene 8 bits y rango de -128 a +127; ‘long int’ o sólo ‘long’ tiene 32 bits y rango de -231 a +231-1. Para ‘unsigned short’, ‘unsigned’ y ‘unsigned long’ los rangos van de 0 a 255, 65535 y 4294967295 (=232-1) respectivamente. ‘float’ es un número en coma flotante de 32 bits y rango +-6.8 E+38 y para números pequeños +-1.17 E-38. ‘double’ en mikroC es idéntico a float, en otras implementaciones tiene 64 bits. ‘void’ sólo se usa para funciones y significa que la función no devuelve ningún valor o no tiene parámetros de entrada. ‘const’ es un modificador que indica al compilador que la variable no va a cambiar durante la ejecución. ‘volatile’ indica que la variable puede ser cambiada por procesos ajenos al programa (HW).2. La directiva del pre-compilador ‘#define xx yy’ crea el parámetro xx con el valor yy. Un parámetro queda fijado en el momento de la compilación y no cambia nunca.3. Todas las variables simples se almacenan en 1, 2 ó 4 celdas de memoria; un array es una serie de datos del mismo tipo que ocupan lugares contiguos en memoria, por ejemplo: int x[3]; declara x como un array de 3 elementos x*0+, x*1+ y x*2+ que ocupan un bloque de memoria de 6 bytes. En C ‘x’ es también un puntero constante a ese bloque de memoria; un puntero es una variable que contiene la *dirección* de un objeto (variable, array, matriz, cadena o estructura) en la memoria. En general se declara así: int *p; ‘p’ no es un entero sino un puntero a una variable de tipo entero. Si ahora ejecutamos p=x; x[0] es también *p, de estas dos maneras estamos accediendo a la misma posición en memoria, ya que ‘*’ como operador unario significa ‘contenido de’; análogamente x*1+ == *(p+1), y x*2+ == *(p+2). Por otra parte ‘&’ como operador unario sobre una variable significa ‘dirección de’ la variable, luego también es cierto que: &x*0+ == p. Un ‘string’ o cadena es un array de caracteres; toda cadena termina con el carácter ‘0’, por ejemplo: char s*+=“hola”; es una cadena de 5 caracteres que son: ‘h’ ‘o’ ‘l’ ‘a’ ‘0’, y ‘s’ es un puntero constante a la posición que ocupa la ‘h’. Una matriz es una tabla de datos: int tabla[2][5]; tiene 2 filas y 5 columnas.4. Una estructura es un conjunto de datos agrupados, normalmente relacionados en el mundo real. Por ejemplo struct PERSONA { char Nombre[8], Apellidos[20]; int edad; } Pepe; define la estructura de datos Pepe de 30 bytes con dos cadenas y un entero. Normalmente es mejor definir un tipo de estructura genérico por ejemplo: typedef struct {char Nombre[8], Apellidos[20]; int edad; } PERSONA; y después podemos usar ‘PERSONA’ como un tipo definido por el usuario y declarar: PERSONA Pepe, *p; donde estaríamos declarando la estructura Pepe igual que antes, y también declaramos ‘p’ como un puntero a estructura de tipo PERSONA. Para acceder a los componentes de la estructura se usa ‘.’, de forma que Pepe.Nombre o Pepe.edad; también si hacemos: p=&Pepe; podremos acceder con : p->Nombre o p->edad.5. En mikroC todos los SFRs se pueden acceder como variables o como estructuras compuestas de 8 bites (B0, B1,…,B7) o campos (F0,F1,…,F7). Así podemos escribir: PORTB|=0x80; o PORTB.F7=1; para poner a 1 la línea 7 del puerto B. También siempre podremos referenciar cualquier bit con nombre: INTCON.GIE=1; 43
  44. 44. 1. Los operadores aritméticos (+ - * / %) operan sobre dos datos de tipo simple. El operador % nos da el resto de la división entera. En general el resultado es del tipo de mayor tamaño. Por ejemplo si tenemos: char c; int i,x; y hacemos: x=i+c; ‘c’ se convierte a entero antes de la operación y el resultado es un entero de 16 bits. A veces podemos especificar explícitamente la conversión de tipo usando la técnica de ‘type cast’ sobre una expresión de la forma ‘(tipo)(expresión)’, por ejemplo: x= i + (int)(c);2. Análogamente los operadores orientados a bits o lógicos también operan sobre dos datos y son: rotar a la izquierda <<, rotar a la derecha >>, AND &, OR | y XOR ^; complementar ~ opera sobre un solo dato. Si tenemos short j=0xF1; int i=0x281; y hacemos X= j|i; X valdrá 0x2F1, ó i>>2 vale 0xA0.3. C nos permite simplificar expresiones del tipo: x = x (operador) y; para cualquier operador aritmético o lógico, por su sintaxis equivalente: x (operador)= y; así tenemos que x *= 3; es equivalente a: x = x*3;4. Los operadores incremento ‘++’ o decremento ‘--’ se aplican sobre variables de carácter entero o punteros, y según vayan como sufijo o prefijo realizan la operación después o antes de usar la variable. Estos operadores se usan mucho en C y permiten hacer sentencias muy concisas. Cuando se aplican sobre punteros, este pasa a apuntar al elemento siguiente (o anterior) en la memoria *independientemente* del tamaño del objeto al que apunta. Por ejemplo si declaramos: int *p; y p apunta a la posición de memoria 0x70, ++p apuntará a la posición 0x72 ya que el tamaño de un entero es de 2 bytes.5. Los operadores condicionales permiten comparar dos expresiones aritmético-lógicas mientras que los operadores AND, OR y NOT (&& , || y !) operan con expresiones condicionales. La construcción: (condición) ? Expresión_1 : Expresión_2; devuelve la expresión 1 si la condición es verdadera y la 2 si es falsa. Así por ejemplo podemos hacer: max = (a > b) ? a : b;. En C toda expresión (incluyendo las aritméticas) puede considerarse una condición, en ese caso la condición es verdadera si el resultado de la expresión es distinto de 0 y falsa en caso contrario.6. Las construcciones: if (condición) { bloque1 } else { bloque2}; while (condición) { bloque3 }; y for (sentencia1; condición; sentencia3) { bloque4 }; ya fueron descritas anteriormente. La construcción: do { bloque } while (condición); siempre se ejecuta al menos una vez ya que la condición sólo se comprueba al final de la ejecución del bloque. En un bloque repetitivo al ejecutar una sentencia ‘break;’ se produce la salida inmediata del bloque. La sintaxis de switch es: switch (espresión) , case valor1: sentencias; …; break; case valor2: sentencias; …; break; ……; default: sentencias; …; break; - y permite ejecutar una serie de sentencias en los distintos casos que se enumeren.7. Las funciones son subrutinas que pueden recibir una serie de variables de entrada, realizan una serie de operaciones y pueden devolver un valor del tipo de la función. Antes de usar cualquier función, ésta debe haber sido declarada o definida. En C las funciones reciben copias de las variables de entrada, por tanto si una función cambia el valor de estas variables cambia sólo la copia, no la variable original; sin embargo si la función trabaja con el puntero a una variable puede cambiar el contenido de la variable original. mikroC provee una gran cantidad de funciones agrupadas en librerías que nos permiten trabajar con todos los módulos de todos los PIC de forma sencilla, estas funciones están documentadas en la ayuda de mikroC. A veces la declaración de las funciones de librería requiere un fichero ‘header’ que se debe incluir en nuestro programa con la sentencia ‘#include <librería.h>’, como ‘math.h’, ‘string.h’, etc. 44
  45. 45. Este programa ‘Display7seg_int.c’ muestra el resultado de la conversión del A/Dmultiplexado en los dos dígitos del display de 7 segmentos, similar al programa enensamblador ‘7seg_interr.asm’ que hemos visto anteriormente. Nótese que en el programano hay ninguna referencia al modelo de PIC; para mikroC tenemos que declarar el modelode PIC, la velocidad y cualquier parámetro de inicialización en un fichero de proyecto, eneste caso ‘Display7seg_int.mcppi’. Observamos aquí el programa completo y vemos que alusar la función de librería ‘ADC_Read(int chan)’, la de ‘Delay_ms()’ y las capacidades dellenguaje C, ocupa menos de 30 líneas.En las líneas 11 y 12 tenemos la tabla de conversión de los dígitos de 0 a 15 para surepresentación en formato de 7 segmentos. Todas las variables que se declaran fuera de unbloque de sentencias son visibles en todas las funciones que siguen a la declaración, sonpues variables globales; frente a las variables que sólo existen en un bloque llamadaslocales.La interrupción es una función que no devuelve ningún valor, ni lógicamente aceptaparámetros. Se activa con cada fin de cuenta del timer 0; entre las líneas 18 a 20 escribe elcódigo de los 7 segmentos para cada dígito y lo mantiene hasta la siguiente interrupción.En el programa principal se lee el conversor A/D mediante la función de la librería ‘unsignedADC_Read(unsigned short canal)’ y usamos los 8 bits bajos para generar las cifrashexadecimales de los dígitos y usamos los dos bits superiores para activar los puntosdecimales de los dos dígitos. De esta forma podemos representar los 10 bits del resultado dela conversión.Una vez que hayamos compilado el programa, cargaremos el fichero ‘.hex’ con el PICkit2 y loejecutamos en el sistema de desarrollo modificado para comprobar su correctofuncionamiento.Pregunta: ¿ Cómo se podría aumentar el brillo de los segmentos de los displays ?Existe la posibilidad de que la interrupción del TMR0 llegue entre las líneas 37 y 38, ¿ quéefecto tendría ? ¿ se podría evitar ? (Ver diapositiva siguiente) 45

×