Guia Pics Completa

  • October 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Guia Pics Completa as PDF for free.

More details

  • Words: 32,916
  • Pages: 142
María Aranda Elcuaz

Universidad Pública de Navarra

Índice general Título

__Página

INTRODUCCIÓN…………………………………………………………………………..5 MEMORIA………………………………………………………………………………….8 Capítulo 1: Microcontroladores: Características y aplicaciones generales……………..9 1.1. Definición………………………………………………………………………9 1.2. Recursos comunes a todos los microcontroladores…………………………….9 1.2.1. Arquitectura básica....………………………………………………...9 1.2.2. Procesador CPU………………………………………………………9 1.2.3. Memoria……………………………………………………………..10 1.2.4. Puertas de Entrada y Salida....………………………………………12 1.2.5. Reloj Principal………………………………………………………12 1.3. Recursos especiales…………………………………………………………...12 1.4. Lenguajes de programación…………………………………………………...13 1.5. Fabricantes…………………………………………………………………….14 1.6. Aplicaciones…………………………………………………………………..14 Capítulo 2: Microcontroladores PIC…………………………………………………………15 2.1. Características relevantes……………………………………………………..15 2.2. Las gamas PIC………………………………………………………………...17 2.2.1. Gama baja…………………………………………………………...17 2.2.2. Gama media…………………………………………………………18 2.2.3. Gama alta y gama mejorada………………………………………...18 2.3. 16F87X: características generales…………………………………………….19 2.3.1. Organización de la memoria………………………………………...19 2.3.1.1. Memoria de programa……………………………………..19 2.3.1.2. Direccionamiento y paginado……………………………..19 2.3.2. Banco de registros y memoria de datos……………………………..20 2.3.2.1. Direccionamiento de datos………………………………...21 2.3.3. Registros con funciones especiales………………………………….21 2.3.3.1. Registro de estado…………………………………………22 2.3.3.2. Registro de opciones………………………………………22 2.3.3.3. Registro de interrupciones………………………………...23 2.3.3.4. Otros registros especiales………………………………….24 2.3.4. Palabra de configuración e identificación…………………………...25 2.4. Recursos comunes e interrupciones en los 16F87X…………………………..26 2.4.1. Diagramas de conexionado………………………………………….26 2.4.2. Recursos comunes…………………………………………………..28 2.4.2.1. Oscilador principal………………………………………...28 2.4.2.2. Perro guardián WDT………………………………………29 1

María Aranda Elcuaz

Título

Universidad Pública de Navarra

__Página

2.4.2.3. Temporizador TMR0……………………………………...29 2.4.2.4. Reset………………………………………………………30 2.4.2.5. Modo de reposo Sleep…………………………………….31 2.4.3. Interrupciones……………………………………………………….31 2.5. Periféricos……………………………………………………………………..33 2.5.1. Puertas de Entrada y salida………………………………………….33 2.5.2. Conversor Analógico Digital………………………………………..34 2.5.3. Temporizador TMR1………………………………………………..37 2.5.4. Temporizador TMR2………………………………………………..38 2.5.5. Módulos de captura/comparación/modulación de anchura de pulsos…………………………………………………………..39 2.5.5.1 Modo de captura…………………………………………...39 2.5.5.2 Modo de comparación……………………………………...40 2.5.5.3 Modulación por anchura de pulsos (PWM)………………..40 2.5.6. Puerta serie síncrona (SSP)………………………………………….41 2.5.6.1 Modo SPI…………………………………………………..41 2.5.6.2 Modo I2C…………………………………………………..42 2.5.7. Interfaz de comunicaciones serie (USART-SCI)…………………...43 2.5.8. Lectura y escritura de la memoria de datos EEPROM……………...46 2.5.8.1. Lectura de la memoria de datos…………………………...47 2.5.8.2. Escritura de la memoria de datos………………………….47 2.6 Repertorio de instrucciones de la gama media………………………………...47 Capítulo 3: Herramientas de trabajo…………………………………………………………53 3.1. Placa de pruebas PICDEM 2 PLUS…………………………………………..53 3.2. Software de programación……………………………………………………54 3.2.1. Cómo usar MPLAB…………………………………………………55 3.2.1.1. Creación de proyectos…………………………………….55 3.2.1.2. Compilación del programa………………………………..56 3.2.1.3. Programación……………………………………………...57 3.3. Lenguaje C…………………………………………………………………….58 3.3.1. Operadores y expresiones…………………………………………...58 3.3.2. Directivas del pre-procesador…...…………………………………..59 3.3.2.1. Control de memoria……………………………………….59 3.3.2.2. Directivas del C estándar………………………………….60 3.3.2.3. Especificación de dispositivos…………………………….60 3.3.2.4. Librerías incorporadas…………………………………….60 3.3.3. Funciones……………………………………………………………62 3.3.3.1. Funciones de I/O serie RS232……………………………..62 3.3.3.2. Funciones de I/O discreta………………………………….63 3.3.3.3. Funciones de retardos……………………………………..64 3.3.3.4. Funciones de control de procesador……………………….65 3.3.3.5. Contadores/Temporizadores………………………………65 3.3.3.6. Funciones de entrada A/D…………………………………66 3.3.3.7. Funciones CCP…………………………………………….66 3.3.3.8. Funciones para el manejo de la Eeprom interna…………..67 3.3.4. Definición de datos………………………………………………….67 2

María Aranda Elcuaz

Título

Universidad Pública de Navarra

__Página 3.3.5. Definición de una función…………………………………………..68 3.3.6. Estructura de un programa en C…………………………………….68

Capítulo 4: Prácticas…………………………………………………………………………...70 4.1. Entradas digitales……………………………………………………………...70 4.1.1. Control de tiempos: Parpadeo de un led…………………………….70 4.1.1.1. Organigrama………………………………………………70 4.1.1.2. Solución en ensamblador………………………………….70 4.1.1.3. Solución en C……………………………………………...72 4.1.2. Encendido de un led a través de un pulsador……………………….73 4.1.2.1. Organigrama………………………………………………73 4.1.2.2. Solución en ensamblador………………………………….73 4.1.2.3. Solución en C……………………………………………...74 4.2. LCD y Memoria Eeprom……………………………………………………...76 4.2.1. Envío de mensajes al LCD………………………………………….76 4.2.1.1. Organigrama………………………………………………76 4.2.1.2. Solución…………………………………………………...77 4.2.2. Programación de la Eeprom………………………………………...78 4.2.2.1. Organigrama………………………………………………79 4.2.2.2. Solución…………………………………………………...80 4.3. Entradas Analógicas: Potenciómetro…………………………………………82 4.3.1. Organigrama………………………………………………………...82 4.3.2. Solución……………………………………………………………..83 4.4. PWM………………………………………………………………………….85 4.4.1. Primer acercamiento al PWM………………………………………85 4.4.1.1. Organigrama………………………………………………86 4.4.1.2. Solución…………………………………………………...86 4.4.2. PWM con entradas analógicas……………………………………...87 4.4.2.1. Organigrama………………………………………………87 4.4.2.2. Solución…………………………………………………...88 4.5. Comunicación Serie PIC-PC…………………………………………………90 4.5.1. Un ejemplo sencillo…………………………………………………91 4.5.1.1. Organigrama………………………………………………91 4.5.1.2. Solución…………………………………………………...92 4.5.2. PWM a distancia. Versión 1………………………………………...93 4.5.2.1. Organigrama………………………………………………94 4.5.2.2. Solución…………………………………………………...94 4.5.3. PWM a distancia. Versión 2………………………………………...97 4.5.3.1. Organigrama………………………………………………97 4.5.3.2. Solución…………………………………………………...98 Capítulo 5: Comunicaciones CAN…………………………………………………………..101 5.1. Introducción………………………………………………………………….101 5.1.1. El CAN y su historia……………………………………………….101 5.1.2. Aplicaciones……………………………………………………….101 5.2. Características del bus CAN…………………………………………………102 3

María Aranda Elcuaz

Título

Universidad Pública de Navarra

__Página

5.3. Arquitectura de capas………………………………………………………..102 5.3.1. Capa física…………………………………………………………103 5.3.2. Capa de enlace de datos……………………………………………104 5.4. Mensajes y tipos de tramas…………………………………………………..104 5.4.1. Trama de datos……………………………………………………..105 5.4.2. Trama remota………………………………………………………106 5.4.3. Trama de error……………………………………………………..107 5.4.4. Espacio entre tramas……………………………………………….108 5.4.5. Trama de sobrecarga……………………………………………….108 5.5. Acceso múltiple y arbitraje de acceso al bus………………………………...109 5.6. Especificaciones……………………………………………………………..110 5.7. Protocolos CAN de alto nivel………………………………………………..110 5.8. Implementación de microcontroladores CAN……………………………….110 5.8.1. Stand-Alone CAN Controller……………………………………...111 5.8.2. Integrated CAN Controller………………………………………...111 5.8.3. Single-Chip CAN Node....................................................................112 ANEXOS…………………………………………………………………………………113 Anexo 1: Librerías C……………………………………………………………………..114 1.1. LCD………………………………………………………………….114 1.2. PIC 16F877…………………………………………………………..118 Anexo 2: Modulación PWM……………………………………………………………..122 Anexo 3: Presentación comunicaciones CAN………...………………………………127 BIBLIOGRAFÍA…………………………………………………………………………141

4

María Aranda Elcuaz

Universidad Pública de Navarra

INTRODUCCIÓN

5

María Aranda Elcuaz

Universidad Pública de Navarra

Introducción La energía eólica es la energía renovable más competitiva dentro del mercado energético y España es un país puntero, puesto que es el 2º fabricante mundial y el 3º en potencia instalada (6202 MW en 2003). Además Navarra fue la comunidad pionera en España y hasta 2001 la 1ª comunidad en potencia instalada. Hoy en día, todavía se puede decir que el sector de la energía eólica es relativamente nuevo, aún con ciertas incógnitas en sus equipos, rendimientos, etc. En consecuencia, el empleo de los sistemas de monitorización suponen una herramienta imprescindible para poder conocer las evoluciones reales de las distintas magnitudes físicas y así dar fiabilidad al funcionamiento general de los aerogeneradores. Son de aplicación para estas tareas cualquier elemento comercial de medida como registradores, osciloscopios, sensores programables, etc. Sin embargo, por las características especiales de trabajo, es decir, a gran altura, en movimiento, etc, resulta muchas veces interesante disponer de potentes herramientas de medida y análisis de reducido tamaño y robustez. La empresa INGETUR, fabricante de turbinas de gran potencia, solicitó a su departamento de investigación y desarrollo el diseño de una herramienta portátil de pequeñas dimensiones y sencillo manejo para la monitorización de magnitudes físicas en los aerogeneradores. Dicha herramienta debía ser configurable y debía permitir la conexión directa al bus CAN de comunicaciones, con el que trabajan estas máquinas, para así poder realizar un seguimiento de las magnitudes físicas tales como presiones hidráulicas, temperaturas, posiciones de elementos, etc. Con todas estas premisas de desarrollo y configuración se llegó a la conclusión de que la mejor forma de implementar este dispositivo era hacerlo mediante microcontroladores, puesto que son dispositivos programables caracterizados principalmente por su reducido tamaño, sencillez de programación y gran diversidad de aplicaciones de control de sistemas. Para realizar este dispositivo es necesario seguir una serie de pautas o fases que se detallan a continuación. La primera fase comprende un estudio general de los microcontroladores. En esta etapa se definen con detalle todas las características fundamentales y sus aplicaciones principales, así como los lenguajes de programación de los mismos. Todo ello para tener un conocimiento exhaustivo de los microcontroladores en general y de los microcontroladores PIC de la casa MICROCHIP en particular, centrando el estudio en una familia de gama media muy comercial en estos días. Otro de los objetivos de este trabajo era la de recoger en un documento aquella información necesaria y suficiente que permita una introducción cómoda en el entorno de los microcontroladores PIC. Para ello, se ha estructurado la memoria de este proyecto en tres capítulos teóricos y un cuarto capítulo con ejercicios prácticos. El estudio teórico recoge toda la información práctica asociada a los fundamentos del hardware y del software, mientras que los ejercicios prácticos tienen la función de simplificar el proceso de aprendizaje de la programación en entorno C. Además, tal como se han quedado 6

María Aranda Elcuaz

Universidad Pública de Navarra

finalmente dichos ejercicios, podrían servir de base para futuras prácticas de cursos específicos de empresa o universitarios. Los primeros capítulos de la memoria están dedicados a los fundamentos teóricos de los microcontroladores, tal y como se comenta en el párrafo anterior. El primer capítulo describe de manera general los microcontroladores hablando de sus recursos comunes, aplicaciones y fabricantes. El segundo capítulo está dedicado a la gama media de los microcontroladores PIC, especialmente a la familia 16F87X. Aquí se hace un estudio detallado de todos sus recursos y aplicaciones, la organización de la memoria, sus periféricos, etc. Finalmente, en el tercer capítulo se describen las herramientas necesarias para llevar acabo la programación de los PICS. Se describe la placa de pruebas que se empleará en el capítulo de prácticas, el software necesario para su programación de manera práctica y finalmente se realiza un resumen de las directivas empleadas por el compilador CCS que trabaja en lenguaje C. El cuarto, y último capítulo dedicado a los microcontroladores desarrolla un total de seis prácticas que parten desde un nivel cero con el trabajo con entradas y salidas digitales, pasando por el manejo de la memoria EEPROM y la pantalla LCD, las entradas analógicas, la modulación por anchura de pulsos (PWM) y finalmente las comunicaciones de estos microcontroladores vía serie (RS232). La segunda fase comprende un estudio del bus CAN y sus aplicaciones. En esta etapa se describe el funcionamiento de la red CAN para después poder realizar pruebas en este tipo de red con microcontroladores. La memoria de este proyecto dedica un capítulo a este estudio, preparando además una presentación en PowerPoint que servirá para poder ofrecer un curso interno en la empresa con el objetivo de que sus empleados conozcan los detalles que entraña este tipo de comunicaciones. En este capítulo se describen las características fundamentales de este tipo de comunicaciones, se habla de su estructura interna, los tipos de tramas que se envían, especificaciones y protocolos CAN. Asimismo termina haciendo referencia a la implementación CAN en los microcontroladores. La principal línea de continuación en proyectos futuros es la preparación de software específico de comunicación CAN. A partir de este software se podrá finalizar el desarrollo del dispositivo monitor que dio origen al presente proyecto final de carrera. Además de todo lo comentado anteriormente, en este proyecto se añaden al final del mismo una serie de anexos. El primero vendrá relacionado con la programación de los dispositivos, exponiendo dos librerías empleadas por el compilador. Seguidamente, se añade un capítulo que describe los principios de modulación por anchura de pulsos y finalmente, un capítulo dedicado a las comunicaciones en red CAN. Se trata de una presentación en PowerPoint que describe los principios básicos de este tipo de bus.

7

María Aranda Elcuaz

Universidad Pública de Navarra

MEMORIA

8

María Aranda Elcuaz

Universidad Pública de Navarra

Capítulo 1. Microcontroladores: Características y aplicaciones generales 1.1 Definición Recibe el nombre de controlador el dispositivo que se emplea para el gobierno de uno o varios procesos. Por ejemplo, el controlador que regula el funcionamiento de un horno dispone de un sensor que mide constantemente su temperatura interna y, cuando traspasa los límites prefijados, genera las señales adecuadas que accionan los actuadores que intentan llevar el valor de la temperatura dentro del rango estipulado. Aunque el concepto de controlador ha permanecido invariable a través del tiempo, su implementación física ha variado frecuentemente. Hace tres décadas, los controladores se construían exclusivamente con componentes de lógica discreta, posteriormente se emplearon los microprocesadores, que se rodeaban con chips de memoria y E/S sobre una tarjeta de circuito impreso. En la actualidad, todos los elementos del controlador se han podido incluir en un chip, el cual recibe el nombre de microcontrolador. Realmente consiste en un sencillo pero completo computador contenido en el corazón (chip) de un circuito integrado.

1.2 Recursos comunes a todos los microcontroladores Al estar todos los microcontroladores integrados en un chip, su estructura fundamental y sus características son muy parecidas. Todos deben disponer de los bloques esenciales: procesador, memoria de datos e instrucciones, líneas de entrada y salida, oscilador de reloj y módulos controladores de periféricos. Sin embargo, cada fabricante intenta enfatizar los recursos idóneos para las aplicaciones a las que se destintan preferentemente.

1.2.1 Arquitectura básica Aunque inicialmente todos los microcontroladores adoptaron la arquitectura clásica de Von Neumann, en el momento presente se impone la arquitectura Harvard. La arquitectura de Von Neumann se caracteriza por disponer de una sola memoria principal donde se almacenan datos e instrucciones de forma indistinta. A dicha memoria se accede a través de un sistema de buses único (direcciones, datos y control). La arquitectura Harvard dispone de dos memorias independientes: una, que contiene sólo instrucciones y otra, sólo datos. Ambas disponen de sus respectivos sistemas de buses de acceso y es posible realizar operaciones de acceso (lectura o escritura) simultáneamente en ambas memorias

1.2.2 Procesador Es el elemento más importante del microcontrolador y determina sus principales características, tanto a nivel hardware como a nivel de software. Se encarga de direccionar 9

María Aranda Elcuaz

Universidad Pública de Navarra

la memoria de instrucciones, recibir el código OP de la instrucción en curso, su decodificación y la ejecución de la operación que implica la instrucción, así como la búsqueda de los operandos y el almacenamiento del resultado. Existen tres orientaciones en cuanto a la arquitectura y funcionalidad de los procesadores actuales: CISC: Computadores de Juego de Instrucciones Complejo: Disponen de más de 80 instrucciones máquina en su repertorio, algunas de las cuales son muy sofisticadas y potentes, requiriendo muchos ciclos para su ejecución. RISC: Tanto la industria de los computadores comerciales como la de los microcontroladores están decantándose hacia la filosofía RISC (Computadores de Juego de Instrucciones Reducido). En estos procesadores el repertorio de instrucciones máquina es muy reducido y las instrucciones son simples y, generalmente, se ejecutan en un ciclo. La sencillez y rapidez de las instrucciones permiten optimizar el hardware y el software del procesador. SISC: En los microcontroladores destinados a aplicaciones muy concretas, el juego de instrucciones, además de ser reducido, es “específico”, o sea, las instrucciones se adaptan a las necesidades de la aplicación prevista. Esta filosofía se ha bautizado con el nombre de SISC (Computadores de Juego de Instrucciones Específico).

1.2.3 Memoria En los microcontroladores la memoria de instrucciones y datos está integrada en el propio chip. Una parte debe ser no volátil, tipo ROM, y se destina a contener el programa de instrucciones que gobierna la aplicación. Otra parte de memoria será tipo RAM, volátil, y se destina a guardar las variables y los datos. La RAM en estos dispositivos es de poca capacidad pues sólo debe contener las variables y los cambios de información que se produzcan en el transcurso del programa. Por otra parte, como sólo existe un programa activo, no se requiere guardar una copia del mismo en la RAM pues se ejecuta directamente desde la ROM. Según el tipo de memoria ROM que dispongan los microcontroladores, la aplicación y utilización de los mismos es diferente. Se describen las cinco versiones de memoria no volátil que se pueden encontrar en los microcontroladores del mercado. 1º. ROM con máscara Es una memoria no volátil de sólo lectura cuyo contenido se graba durante la fabricación del chip. El elevado coste del diseño de la máscara sólo hace aconsejable el empleo de los microcontroladores con este tipo de memoria cuando se precisan cantidades superiores a varios miles de unidades. 2ª. OTP El microcontrolador contiene una memoria no volátil de sólo lectura “programable una sola vez” por el usuario. OTP (One Time Programmable).

10

María Aranda Elcuaz

Universidad Pública de Navarra

La versión OTP es recomendable cuando es muy corto el ciclo de diseño del producto, o bien, en la construcción de prototipos y series muy pequeñas. 3ª EPROM Los microcontroladores que disponen de memoria EPROM (Erasable Programmable Read OnIy Memory) pueden borrarse y grabarse muchas veces. La grabación se realiza, como en el caso de los OTP, con un grabador gobernado desde un PC. Si, posteriormente, se desea borrar el contenido, disponen de una ventana de cristal en su superficie por la que se somete a la EPROM a rayos ultravioleta durante varios minutos. Las cápsulas son de material cerámico y son más caros que los microcontroladores con memoria OTP que están hechos con material plástico. 4ª EEPROM Se trata de memorias de sólo lectura, programables y borrables eléctricamente EEPROM (Electrical Erasable Programmable Read OnIy Memory). Tanto la programación como el borrado, se realizan eléctricamente desde el propio grabador y bajo el control programado de un PC. Es muy cómoda y rápida la operación de grabado y la de borrado. Los microcontroladores dotados de memoria EEPROM una vez instalados en el circuito, pueden grabarse y borrarse cuantas veces se quiera sin ser retirados de dicho circuito. Para ello se usan “grabadores en circuito” que confieren una gran flexibilidad y rapidez a la hora de realizar modificaciones en el programa de trabajo. Se va extendiendo en los fabricantes la tendencia de incluir una pequeña zona de memoria EEPROM en los circuitos programables para guardar y modificar cómodamente una serie de parámetros que adecuan el dispositivo a las condiciones del entorno. 5ª FLASH Se trata de una memoria no volátil, de bajo consumo, que se puede escribir y borrar. Funciona como una ROM y una RAM pero consume menos y es más pequeña. A diferencia de la ROM, la memoria FLASH es programable en el circuito. Es más rápida y de mayor densidad que la EEPROM. La alternativa FLASH está recomendada frente a la EEPROM cuando se precisa gran cantidad de memoria de programa no volátil. Es más veloz y tolera más ciclos de escritura/borrado. Las memorias EEPROM y FLASH son muy útiles al permitir que los microcontroladores que las incorporan puedan ser reprogramados “en circuito”, es decir, sin tener que sacar el circuito integrado de la tarjeta. Así, un dispositivo con este tipo de memoria incorporado al control del motor de un automóvil permite que pueda modificarse el programa durante la rutina de mantenimiento periódico, compensando los desgastes y otros factores tales como la compresión, la instalación de nuevas piezas, etc. La reprogramación del microcontrolador puede convertirse en una labor rutinaria dentro de la puesta a punto.

11

María Aranda Elcuaz

Universidad Pública de Navarra

1.2.4 Puertas de Entrada y Salida La principal utilidad de las patitas que posee la cápsula que contiene un microcontrolador es soportar las líneas de E/S que comunican al computador interno con los periféricos exteriores.

1.2.5 Reloj principal Todos los microcontroladores disponen de un circuito oscilador que genera una onda cuadrada de alta frecuencia, que configura los impulsos de reloj usados en la sincronización de todas las operaciones del sistema. Generalmente, el circuito de reloj está incorporado en el microcontrolador y sólo se necesitan unos pocos componentes exteriores para seleccionar y estabilizar la frecuencia de trabajo. Dichos componentes suelen consistir en un cristal de cuarzo junto a elementos pasivos o bien un resonador cerámico o una red R-C. Aumentar la frecuencia de reloj supone disminuir el tiempo en que se ejecutan las instrucciones pero lleva aparejado un incremento del consumo de energía.

1.3 Recursos especiales Cada fabricante oferta numerosas versiones de una arquitectura básica de microcontrolador. En algunas amplía las capacidades de las memorias, en otras incorpora nuevos recursos, en otras reduce las prestaciones al mínimo para aplicaciones muy simples, etc. La labor del diseñador es encontrar el modelo mínimo que satisfaga todos los requerimientos de su aplicación. De esta forma, minimizará el coste, el hardware y el software. Los principales recursos específicos que incorporan los microcontroladores son: 1. Temporizadores o “Timers”: Se emplean para controlar periodos de tiempo y para llevar la cuenta de acontecimientos que suceden en el interior. 2. Perro guardián o “Watchdog”: Es un temporizador que cuando se desborda y pasa por 0 provoca un reset automáticamente en el sistema. 3. Protección ante fallo de alimentación o “Brownout”: Se trata de un circuito que genera un reset cuando el voltaje de alimentación VDD es inferior a un voltaje mínimo establecido. 4. Estado de reposo o de bajo consumo: Es un estado del sistema donde se detiene el reloj principal y sus circuitos asociados con el objetivo de ahorrar energía en periodos de tiempo donde el microcontrolador se mantiene en espera de instrucciones.

12

María Aranda Elcuaz

Universidad Pública de Navarra

5. Conversor A/D: Procesa señales analógicas convirtiéndolas en señales digitales. 6. Comparador analógico: Algunos modelos de microcontroladores disponen internamente de un Amplificador Operacional que actúa como comparador entre una señal fija de referencia y otra variable que se aplica por una de las patitas de la cápsula. La salida del comparador proporciona un nivel lógico 1 ó 0 según una señal sea mayor o menor que la otra. 7. Modulador de anchura de impulsos o PWM: Son circuitos que proporcionan en su salida impulsos de anchura variable, que se ofrecen al exterior a través de las patitas del encapsulado. 8. Puertas de comunicación: Con objeto de dotar al microcontrolador de la posibilidad de comunicarse con otros dispositivos externos, otros buses de microprocesadores, buses de sistemas, buses de redes y poder adaptarlos con otros elementos bajo otras normas y protocolos. Algunos modelos disponen de recursos que permiten directamente esta tarea, entre los que destacan: - UART, adaptador de comunicación serie asíncrona. - USART, adaptador de comunicación serie síncrona y asíncrona - Puerta paralela esclava para poder conectarse con los buses de otros microprocesadores. - USB (Universal Serial Bus), que es un moderno bus serie para los PC. - Bus I2C, que es un interfaz serie de dos hilos desarrollado por Philips. - CAN (Controller Area Network), para permitir la adaptación con redes de conexionado multiplexado desarrollado conjuntamente por Bosch e Intel para el cableado de dispositivos en automóviles.

1.4 Lenguajes de programación Se han desarrollado todo tipo de lenguajes para los microcontroladores, pero los más usados son el Ensamblador, el BASIC y el C. Los programas escritos en Ensamblador son compactos y rápidos, sin embargo, utiliza nemónicos inteligibles y si no están bien confeccionados resultarán de gran tamaño y lentos. Los lenguajes de alto nivel como el BASIC y el C son más fáciles de comprender y por tanto de diseñar. Pero como toda máquina digital, el microcontrolador es capaz de entender exclusivamente el lenguaje binario grabado en la memoria. Los compiladores son programas que se encargan de traducir el programa de trabajo escrito en cualquier lenguaje a código máquina para luego grabarlo en la memoria del microcontrolador y ejecutarlo.

13

María Aranda Elcuaz

Universidad Pública de Navarra

1.5 Fabricantes En la actualidad, gran parte de los fabricantes de circuitos integrados disponen de su propia línea de microcontroladores. Así tendremos Intel, que ha ido siempre por delante presentando nuevos productos, así por ejemplo el 8048 se considera el primer microcontrolador de 8 bits y lo fabricó Intel en la década de los 70. Otra de las principales empresas del mundo de los dispositivos programables es Motorola y los microcontroladores PIC de la empresa americana Microchip han sido conocidos en los últimos años. Su popularidad avanza día a día, siendo incluidos en la mayoría de proyectos debido a su bajo coste, reducido consumo, pequeño tamaño, fácil programación y abundancia de herramientas económicas de soporte. Otras empresas como Hitachi, Texas, Toshiba y Zilog abarcan pequeñas partes del mercado. Todos los microcontroladores que se fabrican en el presente son buenos y el mejor no siempre es el mismo. Cambian el modelo y fabricante según la aplicación y las circunstancias que lo envuelven.

1.6 Aplicaciones Cada vez existen más productos que incorporan un microcontrolador con el fin de aumentar sustancialmente sus prestaciones, reducir su tamaño y coste, mejorar su fiabilidad y disminuir el consumo. Algunos fabricantes de microcontroladores superan el millón de unidades de un modelo determinado producidas en una semana. Este dato puede dar una idea de la masiva utilización de estos componentes. Los microcontroladores están siendo empleados en multitud de sistemas presentes en la vida diaria, como pueden ser juguetes, horno microondas, frigoríficos, televisores, computadoras, impresoras, módems, el sistema de arranque de nuestro coche, etc. Y otras aplicaciones como instrumentación electrónica, control de sistemas en una nave espacial, etc. Una aplicación típica podría emplear varios microcontroladores para controlar pequeñas partes del sistema. Estos pequeños controladores podrían comunicarse entre ellos y con un procesador central, probablemente más potente, para compartir la información y coordinar sus acciones, como, de hecho, ocurre ya habitualmente en cualquier PC.

14

María Aranda Elcuaz

Universidad Pública de Navarra

Capítulo 2. Microcontroladores PIC Para la realización de estas prácticas se ha elegido la familia PIC de microchip por diversos motivos: 1. Por la cantidad de información disponible sobre estos microcontroladores, y es que para las aplicaciones más habituales la elección de una versión adecuada de PIC es la mejor solución. 2. Por su sencillez de manejo, tienen un juego de instrucciones reducido, de 35 en la gama media. 3. Por su precio, que es comparativamente inferior al de sus competidores 4. Por su velocidad y promedio de parámetros en consumo, tamaño, etc. 5. Porque posee gran variedad de herramientas, tanto de software como de hardware, baratas y fáciles de utilizar. Una de las razones del éxito de los PIC se basa en su utilización. Cuando se aprende a manejar uno de ellos, conociendo su arquitectura y su repertorio de instrucciones, es muy fácil emplear otro modelo.

2.1 Características relevantes 1º La arquitectura del procesador sigue el modelo Harvard: En esta arquitectura, la CPU se conecta de forma independiente y con buses distintos con la memoria de instrucciones y con la de datos y así permitir su acceso simultaneo. Bus de datos MEMORIA DE DATOS

Bus de Instrucciones MEMORIA DE INSTRUCCIONES

CPU

12

8

Figura 2.1.a 2º Se aplica la técnica de segmentación (“pipe-line”) en la ejecución de las instrucciones: La segmentación permite al procesador realizar al mismo tiempo la ejecución de una instrucción y la búsqueda del código de la siguiente. De esta forma se puede ejecutar cada instrucción en un ciclo (un ciclo de instrucción equivale a cuatro ciclos de reloj) excepto las instrucciones de salto que ocupan dos ciclos al no conocer la dirección de la siguiente instrucción hasta que no se haya completado la de bifurcación. Figura 2.1.b de la página siguiente.

15

María Aranda Elcuaz

Universidad Pública de Navarra CLK

ciclo

BI3

BI2

BI1

EI3

EI2

EI3

Fin INSTR0 Fin INSTR1 Fin INSTR2

Figura 2.1.b 3º El formato de todas las instrucciones es de la misma longitud: Las instrucciones de los microcontroladores de la gama baja tienen una longitud de 12 bits. Las de la gama media tienen 14 bits y más las de la gama alta. Esta característica es muy ventajosa en la optimización de la memoria de instrucciones y facilita enormemente la construcción de ensambladores y compiladores. 4º Procesador RISC (Computador de Juego de instrucciones reducido): Los modelos de la gama baja disponen de un repertorio de 33 instrucciones, 35 los de la gama media y casi 60 los de la alta. 5º Todas las instrucciones son ortogonales: Cualquier instrucción puede manejar cualquier elemento de la arquitectura como fuente o como destino. 6º Arquitectura basada en un banco de registros: Esto significa que todos los objetos del sistema (puertas de E/S, temporizadores, posiciones de memoria, etc.) están implementados físicamente como registros. 7º Diversidad de modelos de microcontroladores con prestaciones y recursos diferentes: La gran variedad de modelos de microcontroladores PIC permite que el usuario pueda seleccionar el más conveniente para su proyecto. 8º Herramientas de soporte potentes y económicas: La empresa Microchip y otras que utilizan los PIC ponen a disposición de los usuarios numerosas herramientas para desarrollar hardware y software. Son muy abundantes los programadores, los simuladores software, los emuladores en tiempo real, Ensambladores, Compiladores C, Intérpretes y Compiladores BASIC, etc.

16

María Aranda Elcuaz

Universidad Pública de Navarra

2.2 Las gamas PIC Para resolver aplicaciones sencillas se precisan pocos recursos; en cambio, las aplicaciones grandes requieren numerosos y potentes. Siguiendo esta filosofía, Microchip construye diversos modelos de microcontroladores orientados a cubrir, de forma óptima, las necesidades de cada proyecto. Así, hay disponibles microcontroladores sencillos y baratos para atender las aplicaciones simples y otros complejos y más costosos para las de mucha envergadura. Con las cuatro gamas de PIC se dispone de gran diversidad de modelos y encapsulados, pudiendo seleccionar el que mejor se acople a las necesidades de acuerdo con el tipo y capacidad de las memorias, el número de líneas de E/S y las funciones auxiliares precisas. Sin embargo, todas las versiones están construidas alrededor de una arquitectura común, un repertorio mínimo de instrucciones y un conjunto de opciones muy apreciadas, como el bajo consumo y el amplio margen del voltaje de alimentación.

2.2.1 Gama Baja La gama baja de los PIC encuadra nueve modelos fundamentales en la actualidad. A muchos de estos microcontroladores de gama baja se les llama “enanos” porque solamente disponen de 8 patillas. La memoria de programa puede contener 512, 1 k. y 2 k palabras de 12 bits, y ser de tipo ROM, EPROM aunque también hay modelos con memoria OTP. La memoria de datos puede tener una capacidad comprendida entre 25 y 73 bytes. Sólo disponen de un temporizador (TMR0), un repertorio de 33 instrucciones y un número de patitas para soportar las E/S comprendido entre 12 y 20. El voltaje de alimentación admite un valor muy flexible comprendido entre 2 y 6,25 V, lo cual posibilita el funcionamiento mediante pilas corrientes teniendo en cuenta su bajo consumo (menos de 2 mA a 5 V y 4 MHz ). Al igual que todos los miembros de la familia PIC16/17, los componentes de la gama baja se caracterizan por poseer los siguientes recursos. 1. Sistema POR (POWER ON RESET): Todos los PIC tienen la facultad de generar un auto reset al conectarles la alimentación. 2. Perro guardián (Watchdog): Existe un temporizador que produce un reset automáticamente si no es recargado antes de que pase un tiempo prefijado. Así se evita que el sistema quede "colgado" dado en esa situación el programa no recarga dicho temporizador y se genera un reset. 3. Código de protección: Cuando se procede a realizar la grabación del programa, puede protegerse para evitar su lectura.

17

María Aranda Elcuaz

Universidad Pública de Navarra

4. Líneas de E/S de alta corriente: Las líneas de E/S de los PIC pueden proporcionar o absorber una corriente de salida comprendida entre 20 y 25 mA, capaz de excitar directamente ciertos periféricos. 5. Modo de reposo (bajo consumo o SLEEP): Ejecutando una instrucción (SLEEP), la CPU y el oscilador principal se detienen y se reduce notablemente el consumo. Y por otro lado, conviene nombrar dos restricciones importantes de la gama baja y es que la pila solo dispone de dos niveles, lo que supone no poder encadenar más de dos subrutinas y además no admiten interrupciones.

2.2.2 Gama Media En esta gama sus componentes añaden nuevas prestaciones a las que poseían los de la gama baja, haciéndoles más adecuados en las aplicaciones complejas. Admiten interrupciones, poseen comparadores de magnitudes analógicas, convertidores A/D, puertos serie y diversos temporizadores. Algunos modelos disponen de una memoria de instrucciones del tipo OTP que resulta mucho más económica en la implementación de prototipos y pequeñas series. Otros en cambio, disponen de una memoria de instrucciones tipo EEPROM, que, al ser borrables eléctricamente, son mucho más fáciles de reprogramar que las EPROM, que tienen que ser sometidas a rayos ultravioleta durante un tiempo determinado para realizar dicha operación. El PIC elegido para realización de las prácticas, el 16F877, pertenece a esta gama y en los sucesivos capítulos, las explicaciones se centrarán en él.

2.2.3 Gama Alta y Gama Mejorada En la actualidad, esta gama esta formada por tres modelos. Los dispositivos PIC17C4X responden a microcontroladores de arquitectura abierta pudiéndose expansionar en el exterior al poder sacar los buses de datos, direcciones y control. Así se pueden configurar sistemas similares a los que utilizan los microprocesadores convencionales, siendo capaces de ampliar la configuración interna del PIC añadiendo nuevos dispositivos de memoria y de E/S externas. Esta facultad obliga a estos componentes a tener un elevado número de patitas comprendido entre 40 y 44. Admiten interrupciones, poseen puerto serie, varios temporizadores y mayores capacidades de memoria, que alcanza los 8k palabras en la memoria de instrucciones y 454 bytes en la memoria de datos. En 2003, Microchip lanzaba varios modelos de microcontroladores de gran potencia y velocidad, y se destinan a aplicaciones muy avanzadas. Con un patillaje que llega desde las 28 hasta las 84 patillas, la memoria de código alcanza las 64k palabras y una frecuencia de 40 MHz.

18

María Aranda Elcuaz

Universidad Pública de Navarra

2.3 16F87X: Características generales 2.3.1 Organización de la memoria Los microcontroladores PIC 16F87X poseen dos bloques de memoria separados, la memoria de programa y los bancos de registros. Las posiciones de la memoria de datos son de 1 byte cada una y las de la memoria de programa de 14 bits. Para direccionar los datos hacen falta 7 bits para elegir posición dentro de un determinado banco y 2 bits más para seleccionar el banco, ya que pueden existir cuatro bancos de registros. 2.3.1.1 Memoria de programa La memoria de instrucciones puede tener una capacidad mínima de 4k palabras de 14 bits hasta una máxima de 8k palabras de la misma longitud. Durante la fase de búsqueda, la dirección de la instrucción la proporciona el contador de programa, el cual normalmente se auto incrementa en la mayoría de las instrucciones, excepto en las de salto. Al tener cada posición de memoria un tamaño de 14 bits, en las instrucciones del programa están implícitas las direcciones de los registros o memoria de datos. En una sola palabra se agrupa el código de la instrucción y su dirección. De los 14 bits, 7 se utilizan para indicar su dirección, lo que da un máximo direccionable en la memoria de datos de 128 bytes por banco de registros. 2.3.1.2 Direccionamiento y paginado En los PICs 16F87X, el contador de programa (CP) del microcontrolador tiene un tamaño de 13 bits, con lo que es posible direccionar un tamaño total de memoria de programa hasta un máximo de 8k x 14 bits organizada en páginas de un tamaño de 2k x 14 bits. Para manejar microcontroladores de 4 u 8k bytes de memoria de programa, ha de recurrirse a la paginación, cada página tiene una capacidad de 2k, y éstas a su vez, se dividen en 8 subpaginas de 256 bytes. El contador del programa, al estar formado por 13 bits, está compuesto por dos secciones tal y como se muestra en la figura 2.3.1.2. El byte bajo viene del registro de PCL que puede ser leído y escrito. Los bits superiores (PC<12:8>), están alojados en el registro PCH, sobre el que no se puede leer ni escribir, pero se puede acceder a él indirectamente a través del registro PCLATH.

Figura 2.3.1.2: Contador de programa

19

María Aranda Elcuaz

Universidad Pública de Navarra

2.3.2 Banco de registros y memoria de datos Los registros son de 8 bits y están formados por cuatro bancos como se puede ver en la figura 2.3.2:

Figura 2.3.2: Banco de registros del PIC 16F877 En las primeras posiciones de dichos bancos se encuentran los registros de funciones especiales, seguidos a continuación por los registros de proposición general o memoria de datos. La memoria de datos SRAM en los PIC 16F877 es de 368 bytes. La memoria de trabajo o acumulador (w) de 1 byte en la SRAM es un registro de almacenamiento temporal. Este registro no puede ser accedido de forma directa, pero su contenido sí puede moverse a otro registro al que sí puede accederse directamente. Cada operación aritmética que se realiza utiliza el registro w. 20

María Aranda Elcuaz

Universidad Pública de Navarra

La memoria de datos EEPROM de 256 bytes en el PIC16F877 puede almacenarse de forma indefinida cualquier dato que se desee retener cuando se apague la alimentación. Esta memoria es de 8 bits y no forma parte del espacio normal direccionable, y sólo es accesible en lectura y escritura a través de dos registros. 2.3.2.1 Direccionamiento de los datos Para direccionar la memoria de datos se emplean tres modelos de direccionamiento, el Inmediato, el Directo y el Indirecto. Cuando una instrucción utiliza un dato inmediato, su valor (literal) lo contiene su código OP y en la ejecución se carga en el registro W para su posterior procesamiento. En el direccionamiento directo consiste en codificar el nombre del o de los registros en cuestión directamente en la instrucción, pero primero hay que situarse en el banco adecuado. Si el dato no se halla en el banco 0, se emplean los bits 6 y 5 del registro FSR (Registro de Selección de Banco), que se denominan RAI y RA0, respectivamente. En las instrucciones con direccionamiento indirecto se usa como operando el registro INDF, que ocupa la posición 0 del banco 0. En tal caso, se accede a la posición que apunta el contenido del registro FSR ubicado en la posición 04 del área de datos. Sus 5 bits de menos peso apuntan la dirección del dato y los bits 6 y 5 seleccionan el banco. No tiene implementado el bit 7, que siempre se lee como 1. El registro INDF no se halla implementado físicamente. Cada vez que se le referencia, se utiliza el contenido del registro FSR para direccionar al operando.

Figura 2.3.2: Direccionamiento directo e indirecto

2.3.3 Registros con funciones especiales Los registros de funciones especiales o registros de control tienen como cometido gobernar el funcionamiento de los recursos del microcontrolador. 21

María Aranda Elcuaz

Universidad Pública de Navarra

2.3.3.1 Registro de estado (Status) Ocupa las posiciones 03h, 83h, 130Bh y 183Bh del PIC. Es uno de los registros más importantes, cuyos bits controlan funciones vitales del microcontrolador. En la figura 2.3.3.1 se muestra la estructura y la misión de cada uno de sus bits.

Figura 2.3.3.1: Registro de Estado El bit IRP hace la selección de bancos para el direccionamiento indirecto, tal y como se ha visto en el punto anterior y los bits RP1:RP0 lo hacen para el direccionamiento directo. Los bits TO y PD, no se pueden escribir, son banderas que indican la causa por la que se ha producido el reset del PIC y permiten actuar en consecuencia: Z es la bandera de cero, DC bandera de acarreo en el 4º bit de menor peso y C bandera de acarreo en el 8º bit. 2.3.3.2 Registro de opciones (Option_reg) El registro de opciones se encuentra en las posiciones 81h y 181h, puede ser leído y escrito y contiene varios bits para la configuración de las asignaciones del pre divisor al TMR0 o al WDT, la interrupción externa, el TMR0 y las resistencias internas de polarización del puerto B. RBPU es el bit de conexión de las resistencias de polarización del Puerto B; INTDEG selecciona el tipo de flanco para la interrupción por RB0/INT, según esté a 0 o a 1 será ascendente o descendente. T0CS selecciona la fuente de reloj para el TMR0 y T0SE el tipo de flanco activo para el TMR0. PSA indicará la asignación del divisor de frecuencias al WDT o al TMR0.

22

María Aranda Elcuaz

Universidad Pública de Navarra

Finalmente, los bits PS2:PS0 asignan la tasa del valor del divisor de frecuencias, y difiere dependiendo del predivisor que se haya asignado al TMR0 o al WDT. Los detalles de todo lo comentado sobre este registro se encuentran en la siguiente figura:

Figura 2.3.3.2: Registro de opciones 2.3.3.3 Registro de interrupciones (INTCON)

Figura 2.3.3.3: Registro de interrupciones 23

María Aranda Elcuaz

Universidad Pública de Navarra

Puesto que los microcontroladores PIC de la gama media admiten interrupciones, requieren un registro encargado de su regulación. La operatividad de sus bits se entenderá mejor cuando se explique la operatividad de las interrupciones. En la figura 2.3.3.3 de la página anterior se ofrece la estructura y la misión de los bits del registro INTCON. El bit GIE concede o cancela la activación global de las interrupciones. PEIE, TOIE, INTE y RBIE activan o desactivan las interrupciones en periféricos, TMR0, interrupciones externas y del puerto B respectivamente. El resto de bits son banderas de estado. 2.3.3.4 Otros registros especiales Los registros PIE1 y PIE2 contienen los bits que autorizan o prohíben las interrupciones producidas por los periféricos internos del PIC y que no están incluidos en el registro INTCON. Los registros PIR1 y PIR2 contienen una serie de bits que actúan como banderas de señalización de la causa que origina la interrupción, esté permitida o no. Para ver mayor detalle de estos registros ver las figuras siguientes:

Figura 2.3.3.4: Registros PIE1, PIR1 y PCON

24

María Aranda Elcuaz

Universidad Pública de Navarra

2.3.4 Palabra de configuración e identificación La palabra de configuración en los PIC de la gama media se compone de 14 bits que se escriben durante el proceso de grabación del dispositivo. Dichos bits ocupan la posición reservada de la memoria de programa 2007h. Como se puede comprobar en la figura 2.3.4, los bits CP1:CP0 son los bits de protección de código, BODEN activa o desactiva el fallo en la alimentación, PWRTE activa el temporizador, WDTE activa el perro guardián, los bits FOSC1:FOSC0 seleccionan el tipo de oscilador.

Figura 2.3.4: Palabra de configuración También existen cuatro posiciones reservadas en la memoria de programa destinadas a contener las Palabras de identificación (ID). En estas palabras solo se emplean los 4 bits de menos peso, en donde se almacena el número de serie, códigos de identificación, numeraciones secuénciales o aleatorias, etc. También se escribe su contenido en el proceso de grabación del dispositivo.

25

María Aranda Elcuaz

Universidad Pública de Navarra

2.4 Recursos comunes e interrupciones En la siguiente tabla se muestran las características más relevantes de los PIC 16F87X: Características 16F873 16F874 16F876 16F877 Frecuencia Máxima DC-20Mhz DC-20Mhz DC-20Mhz DC-20Mhz Memoria de programa 4KB 4KB 8KB 8KB FLASH Palabra de 14 bits Posiciones RAM de datos 192 192 368 368 Posiciones EEPROM de 128 128 256 256 datos Ports E/S A, B y C A, B, C, D y E A, B y C A, B, C, D y E Nº de Pines 28 40 28 40 Interrupciones 13 14 13 14 Timers 3 3 3 3 Módulos CCP 2 2 2 2 Comunicaciones Serie MSSP, USART MSSP,USART MSSP,USART MSSP, USART Comunicación Paralelo PSP PSP Líneas de entrada en 5 8 5 8 Convertidor A/D de 10 bits 35 35 35 35 Juego de Instrucciones instrucciones instrucciones instrucciones instrucciones Longitud de la instrucción 14 bits 14 bits 14 bits 14 bits

Todos estos elementos que se muestran en la tabla serán analizados y explicados en los puntos sucesivos de este capítulo.

2.4.1 Diagramas de conexionado del 16F877

Figura 2.4.1a: Diagrama de conexionado del PIC 16F877

26

María Aranda Elcuaz

Universidad Pública de Navarra

En la figura anterior se muestra el diagrama de conexionado de un PIC 16F877. A continuación se nombran las funciones de todas las patitas: - MCLR/VPP: Reset externo. Por esta patita se aplica también la tensión / VPP usada en la grabación del programa. - RA0/AN0: E/S digital o entrada analógica - RA1/AN1: E/S digital o entrada analógica - RA2/AN2/VREF: E/S digital, entrada analógica o salida de la tensión de referencia - RA3/AN3/ VREF: E/S digital, analógica o entrada externa de VREF - RA4/TOCKI: E/S digital o entrada del reloj para TMR0 - RA5/AN4/SS: E/S digital, analógica o selección del puerto serie sincrono - RB0/INT-RB7: E/S digitales del Puerto B. RB0/INT puede actuar como entrada de interrupción externa. RB4-RB7 pueden provocar interrupción cuando cambian de estado - RE0/RD/AN5: E/S digital del Puerto E. Señal de lectura del Puerto paralelo esclavo. Entrada analógica. - RE1/WR/AN6: E/S digital. Señal de escritura del Puerto paralelo esclavo. Entrada analógica. - RE2/CS/AN7: E/S digital. Señal de activación del Puerto paralelo esclavo. Entrada analógica. - VDD: Entrada del positivo de la alimentación - OSC1/CLKIN: Entrada al cristal cuarzo o reloj externo - OSC2/CLKOUT: Salida del cristal. En modo R-C por esta patita sale ¼ FOSC1 - RC0/T1OSO/T1CL1: E/S digital del Puerto C. Conexión del oscilador externo para el temporizador TMR1 o entrada de reloj para el TMR1 - RC1/T1OSI/CCP2: E/S digital del Puerto C. Conexión del oscilador externo para TMR1 o salida del modulo 2 de captura/comparación - RC2/CCP1: E/S digital del Puerto C. Salida del modulo 1 de captura/comparación - RC3/SCK/SCL: E/S digital. E/S de reloj para el Puerto serie sincrono (SSP) de los módulos SPI a I2C - RC4/SDI/SDA: E/S digital. Entrada de datos serie en el modo SPI. E/S de datos serie en modo I2C - RC5/SD0: E/S digital del Puerto C. Salida de datos serie en el modo SPI - RC6/TX/CK: E/S digital. Transmisión serie asincrona. Entrada de reloj para comunicación serie sincrona - RC7/RX/DT: E/S digital. Recepción serie asincrona. Línea de datos en la comunicación serie sincrona. - RD0/PSP0-RD7/PSP7: E/S digitales del Puerto D. Este Puerto puede trabajar como Puerto paralelo esclavo para interconexión con un bus de datos de 8 bits de otro microprocesador Una vez explicado el funcionamiento de cada patita del PIC16F877, en la página siguiente, en la figura 2.4.1b se muestra su arquitectura interna, un diagrama de bloques donde se muestran los periféricos y las líneas de entrada y salida.

27

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 2.4.1b: Arquitectura interna del 16F877

2.4.2 Recursos comunes En la gama media existen muchos recursos que son comunes a la mayoría de los modelos y que son conocidos por la gama baja. 2.4.2.1 Oscilador principal Para la generación de los impulsos de reloj internos los PIC16F87X disponen de cuatro alternativas, debiendo el usuario seleccionar el más adecuado y programar adecuadamente los bits FOSC1 y FOSC0 de la palabra de configuración, que establecen la configuración entre las siguientes: - LP: - XT: - HS: - RC:

Oscilador de cristal de cuarzo o resonador cerámico de baja potencia Cristal o resonador cerámico Oscilador de cristal o resonador de alta velocidad Oscilador formado por una red resistencia condensador

28

María Aranda Elcuaz

Universidad Pública de Navarra

En la figura siguiente se ofrece un circuito para las alternativas que usan cristal de cuarzo o resonador.

Figura 2.4.2.1a: Esquema para configuraciones LP, XT y HS Cuando no se requiere una gran precisión en la generación de impulsos de reloj, se puede emplear una red RC mucho más económica. En este caso, la frecuencia de oscilación viene determinada por los valores de resistencia y de los condensadores exteriores, así como de la temperatura de funcionamiento.

Figura 2.4.2.1b: Esquema para configuración RC 2.4.2.2 Perro guardián (WDT) El Perro guardián vigila que el programa no se "cuelgue" y dejen de ejecutarse las instrucciones secuénciales del mismo tal como lo ha previsto el diseñador. Para realizar esta labor de vigilancia, el perro guardián da un paseo por la CPU cada cierto tiempo y comprueba si el programa se ejecuta normalmente; en caso contrario, el perro provoca un reset, reinicializando todo el sistema. Este temporizador está controlado por un oscilador interno independiente, con una temporización nominal de 18 ms, que puede aumentarse asignando el divisor de frecuencia al perro guardián, con el cual, trabajando en el rango mayor, puede alcanzar hasta 2,3 segundos. Para evitar que se desborde el WDT y genere un reset, hay que recargar o refrescar su cuenta antes de que llegue el desbordamiento. Este refresco, que en realidad consiste en ponerle a 0 para iniciar la temporización, se consigue por software con las instrucciones CLRWDT y SLEEP. 2.4.2.3 Temporizador TMR0 El TMR0 en los PIC16F87X es un contador ascendente de 8 bits, que puede funcionar con reloj interno o externo y ser sensible al flanco ascendente o descendente. Se le puede

29

María Aranda Elcuaz

Universidad Pública de Navarra

asigna el divisor de frecuencia, y además posee la posibilidad de generar una interrupción cuando se desborda. El TMR0 se comporta como un registro de propósito especial ubicado en la posición 1 del área de datos. Para trabajar con TMR0 se pueden utilizar las siguientes fórmulas en el caso que los impulsos de reloj provengan del oscilador interno con un periodo de Tosc. Tiempo = 4 · Tosc · (Valor cargado en TMR0) · (Rango del Divisor) Valor a cargar en TMR0 = (tiempo / 4 · Tosc) · (Rango del Divisor) En la figura 2.4.2.3 se ofrece el diagrama de bloques del TMR0 y el preescaler que comparte con el WDT. Obsérvese que existe un bloque que retrasa dos ciclos y cuya misión consiste en sincronizar el momento del incremento producido por la señal T0CKI con el que producen los impulsos del reloj interno. Cuando no se usa el Divisor de frecuencia, la entrada de la señal de reloj externa es la misma que la salida de dicho Divisor.

Figura 2.4.2.3: Diagrama de bloques del TMR0 2.4.2.4 Reset El reset de los microcontroladores puede ser originado por las siguientes causas: 1ª Conexión de la alimentación (POR: Power-On-Reset) 2ª Activación de la patita MCLR (Master Clear Reset) durante una operación normal. 3ª Activación de MCLR en el estado de Reposo o SLEEP. 4ª Desbordamiento del Perro guardián. Como se aprecia en el esquema de la figura 2.4.2.4 de la página siguiente, cualquiera de estas posibilidades introduce un nivel bajo en la entrada S del flip-flop y pone en marcha un temporizador propio que, al cabo de 18 ms, origina un flanco ascendente en la salida Q que supone la generación del reset interno. El bloque temporizador de la figura produce un retraso en la generación del reset para dar tiempo a que se estabilice la tensión VDD de alimentación y la frecuencia del oscilador principal. Este temporizador está gobernado por un oscilador RC independiente.

30

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 2.4.2.4: Diagrama de bloques del circuito de Reset Los bits TO y PD del Registro de Estado toman el valor correspondiente según la causa que haya provocado el reset. TO 0 0 1 1 u

PD 0 1 0 1 u

Estado tras el RESET WDT en el modo “SLEEP” WDT en el modo normal MCLR en el modo SLEEP Conexión de la alimentación (POR) MCLR en el modo normal

2.4.2.5 Modo de reposo (Sleep) Este modo especial de funcionamiento ocasiona un consumo muy bajo y se entra en él con la ejecución de la instrucción SLEEP. Con esta instrucción ocurren las siguientes acciones: 1. Si el perro guardián está activado, se refrescara su valor (se borra) pero sigue funcionando normalmente. 2. El oscilador principal del sistema deja de funcionar. 3. Los puertos de E/S mantienen el mismo estado que tenían antes de ejecutar SLEEP. 4. Los bits TO y PD del registro de estado toman los valores 1 y 0, respectivamente. Para salir del estado de Reposo hay dos posibilidades: 1ª Se activa la patita MCLR y se genera un reset. 2ª El Perro guardián que estaba activo cuando se ejecuto SLEEP se desborda y genera un reset. Para conocer la causa por la que se ha salido del Estado de Reposo se analizan los bits TO y PD.

2.4.3 Interrupciones Una interrupción consiste en una detención del programa en curso para realizar una determinada rutina que atienda la causa que ha provocado la interrupción. Es como una 31

María Aranda Elcuaz

Universidad Pública de Navarra

llamada a subrutina, que se origina por otra causa que por una instrucción del tipo CALL. Tras la terminación de la rutina de interrupción, se retorna al programa principal en el punto en que se abandono. Las causas que originan una interrupción pueden ser externas, como la activación de una patita con el nivel lógico apropiado, e internas, como las que pueden producirse al desbordarse un temporizador, como el TMR0. En las aplicaciones industriales, las interrupciones son un producto muy potente para atender los acontecimientos físicos en tiempo real. Las interrupciones evitan que la UCP explore continuamente el nivel lógico de una patita o el valor de un contador. Los PIC16F87X tienen cuatro posibles fuentes de interrupción: 1ª. Interrupción externa provocada al activar la patita RB0/INT 2ª. Desbordamiento del TMR0 3ª. Cambio de estado en las líneas del Puerto B 4ª. Cambio de estado en el comparador analógico En la figura siguiente se ofrece el esquema lógico que controla la generación de la interrupción, cuando aparece un nivel alto en su línea INT de salida.

Figura 2.4.3: Lógica de control para la generación de la interrupción Cada causa de interrupción esta controlada mediante dos líneas o señales. Una de ellas actúa como una bandera de señalización que indica si se ha producido o no el acontecimiento, mientras que la otra es el permiso o prohibición de la interrupción en si. El valor que se aplica a las señales de entrada del circuito de gobierno de las interrupciones proviene del que tengan los bits de los registros INTCON, PIR1 y PIE1. El bit GIE de activación global del permiso de interrupción, situado en el registro INTCON, se borra automáticamente cuando se reconoce una interrupción para evitar que se produzca otra cuando se atiende a la inicial. Al retornar de la interrupción, el bit GIE se vuelve a activar.

32

María Aranda Elcuaz

Universidad Pública de Navarra

2.5 Periféricos 2.5.1 Puertos de entrada y salida Las patitas de comunicación de los microcontroladores se agrupan en conjuntos llamados puertos porque dejan entrar y salir la información al procesador o pines. Dichos puertos deben soportar las líneas que precisan los distintos periféricos que hay integrados en la cápsula. Cuantos más periféricos dispone el modelo, exige más líneas de comunicación y mayor numero de patitas, con más multiplexado de señales. Los Puertos de E/S de los PIC16F87X disponen de versiones con 40 patitas y 5 puertos de E/S. Tienen Conversor A/D, 4 temporizadores, modulo CCP, Puerto Serie SSP, interfaz Serie SCI, Puerto Paralelo Esclavo y más capacidad en sus memorias. Puerto A: Consta de 6 patitas o líneas (RA0-RA5). Todas, menos RA4, pueden actuar como E/S digitales o como canales de entrada para el Conversor AD. La patita RA4, además de E/S digital puede funcionar como entrada de reloj externo para el TMR0. Puerto B: Las 4 líneas de mas peso del Puerto B (RB<3:0>) actúan como E/S digitales, según la programación del registro TRISB. Además pueden disponer de una carga pull-up interna si se programa la línea como entrada y el bit<7> (RBPO) del registro OPTION vale 0. Las líneas RB<7:4> funcionan como las anteriores, pero además pueden provocar una interrupción si se programan como entradas y se produce el cambio de nivel lógico en alguna de ellas. En tal caso se activa el bit <0> (RBIF) de INTCON. La interrupción se anula al borrar el bit <3> (RBIE) de INTCON o al hacer una nueva lectura del Puerto B. Puerto C: Es un puerto bidireccional de 8 bits, cada patita actúa como E/S digital, según la programación de TRISC. Además, también puede actuar como entrada o salida de diversos periféricos internos. Consultar el punto 2.4.1 donde se explican los diagramas de conexionado para ver la función de cada patita en el puerto C. Puerto D: Cada patita puede configurarse como E/S digital, según la programación del registro TRISD. También puede funcionar como Puerto Paralelo Esclavo para soportar la interconexión directa con el bus de datos de 8 bits de otro microprocesador. Para funcionar en este modo hay que poner a 1 el bit<4> (PSMODE) de TRISE. En tal caso, las líneas RE<2:0> del Puerto E pasan a soportar las señales de control CS, WR y RD, entre el Puerto D y el bus del microprocesador. Cada vez que el microprocesador realiza un ciclo de lectura o escritura sobre el Puerto D el bit <7> (PSPIF) del registro PIR1 se pone a 1.

33

María Aranda Elcuaz

Universidad Pública de Navarra

Puerto E: Este puerto que solo dispone de tres patitas esta disponible en el modelo, la nomenclatura de las líneas es: RE0/RD/AN5 RE1/WR/AN6 RE2/CS/AN7 Las 3 patitas pueden funcionar como E/S digitales, según la programación de los tres bits de menos peso del registro TRISE. También pueden actuar como señales de control (RD, WR y CS) para el flujo de datos entre un microprocesador y el Puerto D, cuando esta programada en el modo Esclavo. Deben programarse como entradas. Finalmente, también pueden realizar estas 3 patitas la función de canales de entradas analógicas para el Conversor A/D, según la programación del registro ADCON1. El registro TRISE, que se muestra en la figura siguiente sirve para configurar las líneas de E/S digitales del Puerto E, o bien, para actuar como Registro de Estado cuando el Puerto D funciona como Puerto Paralelo Esclavo.

Figura 2.5.1: Registro TRISE

2.5.2 Conversor analógico digital El módulo de conversión Analógico/Digital dispone de cinco entradas para los dispositivos de 28 pines y ocho para los otros dispositivos de la familia. Es un conversor analógico a digital de 8 bits con una tensión de referencia que puede ser interna (VDD) o externa (entra por la patita AN3/Vref). En cada momento la conversión solo se realiza con la entrada de uno de sus canales, depositando el resultado de la misma en el registro ADRES y activándose la bandera ADIF, que provoca una interrupción si el 34

María Aranda Elcuaz

Universidad Pública de Navarra

bit de permiso correspondiente esta activado. Además, al terminar la conversión el bit GO/DONE se pone a 0.

Figura 2.5.2a: Conversor AD con 8 canales para entradas analógicas El módulo de A/D tiene cuatro registros que son: ADRESH, ADRESL, ADCON0 y ADCON1. Para gobernar el funcionamiento del CAD se utilizan el ADCON0 y el ADCON1. El primero, que se muestra en la figura 2.5.2a, selecciona el canal a convertir con los bits CHS <2:0>, activa al conversor y contiene la bandera que avisa del fin de la conversión (ADIF) y el bit GO/DONE.

Figura 2.5.2b: Registro ADCON0 35

María Aranda Elcuaz

Universidad Pública de Navarra

El registro ADCON1 establece las entradas que son digitales y analógicas, así como el tipo de tensión de referencia (interna o externa). ADFM selecciona el formato del resultado de la conversión, con justificación izquierda o derecha. PCFG3:PCFG0 son los bits de configuración de los canales de entrada del conversor. Se utilizan para configurar las patillas como E/S digital o como entrada analógica de acuerdo con la tabla de la figura siguiente.

Figura 2.5.2c: Registro ADCON1 Finalmente, se describen de forma resumida los pasos para realizar una conversión en el CA/D: 1º. Se configura correctamente el CA/D programando los bits de los registros de control. 2º. Se autoriza o prohíbe la generación de interrupción al finalizar la conversión, cargando los bits del PIE1. 3º. Para iniciar la conversión se pone el bit GO/DONE = 1. Hay que tener en cuenta el tiempo que durara la conversión. 4º. Se detecta el final de la conversión bien porque se genera la interrupción, o bien porque se explora cuando el bit GO/DONE = 0. 5º. Se lee el resultado de la conversión en el registro ADRES.

36

María Aranda Elcuaz

Universidad Pública de Navarra

Los registros ADRESH:ADRESL contienen los 10 bits resultado de la conversión A/D. Cuando se completa la conversión A/D, el resultado se guarda en los registros y se pone a cero el bit GO/DONE y el flag de fin de conversión ADIF (PIR1<6>) se pone a 1. Después de que el conversor A/D se ha configurado como se quiere, la selección del canal debe realizarse antes de hacer la adquisición. Los canales de entrada analógica deben tener los correspondientes bits del registro TRIS seleccionados como entradas.

2.5.3 Temporizador TMR1 El TMR1 es un Temporizador/Contador ascendente de 16 bits, por lo que esta implementado mediante dos registros específicos TMR1H y TMR1L, que contienen el valor del conteo en cada momento. El valor de registro TMR1H-TMR1L evoluciona desde 0000h hasta FFFFh, en cuyo instante activa la bandera TMR1IF y vuelve a 0000h. Como fuente de los impulsos de reloj existen tres alternativas: 1ª. Generación interna (4 TOSC) 2ª. Generación mediante un oscilador externo controlado por cristal que se conecta a las patitas RC0/T1OSO/T1CKI y RC1/T1OSI/CCP2. El oscilador se activa poniendo a 1 el bit T1OSCEN del registro T1CON. El bit TMR1CS del registro T1CON selecciona entre el reloj interno o externo. 3ª. Trabaja en modo contador de eventos, cuando los impulsos externos a contar se aplican a la patita RC0/T1OSO/T1CKI. La fuente de los impulsos de reloj aplica a un Divisor de Frecuencias que los divide por 1, 2, 4 u 8, según el valor de los bits <1:0> (TICKPS) del registro T1CON. El reloj externo puede estar sincronizado o no con el interno, según el bit T1SYNC de T1CON. El interno siempre es síncrono. T1OSCEN habilita el oscilador, #TlSYNC es el bit de control de sincronización de la señal de entrada, TMR1CS selecciona la fuente de reloj y TMR1ON activa el temporizador TMR1. Figuras 2.5.3a y 2.5.3b.

Figura 2.5.3a: Esquema del TMR1 El periodo en T1CKI es preciso que tenga una duración mínima de 4.TOSC. En el modo de Reposo cuando funciona en modo síncrono, el TMR1 deja de incrementarse pues se desconecta el circuito de sincronismo. En forma asíncrona el TMR1 sigue contando durante el modo de reposo, por eso se puede emplear como un reloj de tiempo real y para sacar del modo de Reposo al sistema. También en modo asíncrono se 37

María Aranda Elcuaz

Universidad Pública de Navarra

puede usar como base de tiempos en operaciones de Captura y Comparación. El modulo CCP pone a 0 el TMR1 cuando se produce una Captura o una Comparación.

Figura 2.5.3b: Registro T1CON

2.5.4 Temporizador TMR2 El TMR2 solo esta incorporado en unos pocos modelos de la gama media porque se trata de un temporizador de 8 bits diseñado para usarse conjuntamente con el circuito de Modulación de Anchura de Impulsos (PWM). Se incrementa al ritmo de los impulsos que se le aplican (4.T OSC), que pueden ser divididos por 1, por 4 o por 16 mediante un Predivisor. Cuando el valor de TMR2 coincide con el del PR2 (Registro de Periodo) se genera un impulso en la salida EQ y TMR2 pasa a 00h. PR2 es un registro específico de lectura y escritura que cuando hay un Reset se carga con el valor FFh. Los impulsos producidos por EQ se aplican a un Post-divisor que puede dividirlos hasta 1:16, activando su salida la bandera TMR2IF. El registro T2CON regula los principales parámetros de este temporizador.

Figura 2.5.4a: Diagrama de bloques del TMR2 38

María Aranda Elcuaz

Universidad Pública de Navarra

El reset borra al Predivisor y al Post-divisor. También lo hace al TMR2 cuando se ha generado como consecuencia del WDT, POR o MCLR. Cada vez que se escribe sobre el TMR2 o el T2CON se borran el Predivisor y el Post-divisor. La salida EQ se puede utilizar como señal de reloj para el modulo de interfaz serie SSP.

Figura 2.5.4b: Registro T2CON

2.5.5 Módulos de captura/comparación/modulación de anchura de pulsos CCP Los microcontroladores PIC16F87X disponen de dos de estos módulos, llamados CCP1 y CCP2, que se controlan con los registros CCP1CON y CCP2CON, respectivamente. Realizan tres funciones: 1ª. Capturan información de 16 bits procedente del TMR1. 2ª. Comparan el valor de un registro con el del TMR1. 3ª. Modulan o controlan el intervalo de tiempo en el que bascula de 1 a 0 una patita del microcontrolador. Los módulos CCP1 y CCP2 son idénticos, excepto en ciertas funciones especiales de disparo. Ambos constan de dos registros CCPRxH y CCPRxL. 2.5.5.1 Modo de Captura En este modo el registro CCPRxH/L de 16 bits captura el valor contenido en el TMR1, siempre que ocurra uno de los siguientes acontecimientos en la patita Rcy/CCPx del Puerto C, que previamente ha tenido que configurarse como entrada en el registro TRISC: a) b) c) d)

Un flanco ascendente Un flanco descendente Cada 4 flancos ascendentes Cada 16 flancos ascendentes

Al realizarse una captura se activa la bandera CCPxIF del registro PIR1 o PIR2 y si se programa adecuadamente el bit de permiso en PIE1 o PIE2, se genera una interrupción. Ya se puede leer el valor del registro CCPRx. 39

María Aranda Elcuaz

Universidad Pública de Navarra

Cuando se produce una captura y no se ha leído el contenido de CCPRx se borra y pasa a contener el nuevo. Si se van a modificar las condiciones en las que se va a efectuar la Captura conviene detener o desactivar el modulo CCP para que no se produzcan falsas interrupciones durante la operación. Una aplicación del modo de Captura puede ser la medición de los intervalos de tiempo que existen entre los impulsos que llegan a la patita Rcy/CCPx configurada como entrada. En este modo de trabajo TMR1 debe usarse como entrada de reloj externo sincronizado. 2.5.5.2 Modo de Comparación Cuando un modulo CCP trabaja de esta manera el contenido del registro CCPRxH/L se compara continuamente con el del TMR1, que debe trabajar en modo síncrono. Cuando coinciden ambos valores la patita Rcy/CCPx, que previamente se habrá configurado como salida, puede bascular a 1, a 0, o bien no variar, pero se activara el señalizador CCPxIF. En tal caso, si el bit de permiso esta activado se provoca una interrupción. Si se selecciona la función especial de disparo, el CCP1 pone a 0 al TMR1 con lo que CCPR1 funciona como un registro de periodos capaz de provocar interrupciones periódicamente. También el CCP2 pone a 0 el TMR1 e inicia una conversión en el Convertidor A/D, con lo que se pueden realizar periódicamente conversiones de analógicodigitales, sin el control del programa de instrucciones. 2.5.5.3 Modulo de Anchura de Pulsos (PWM) En este modo la patita Rcy/CCPx, que se ha programado como salida, bascula entre 0 y 1 a intervalos variables de tiempo. Cuando el valor de registro PR2 coincide con los 8 bits de más peso de TMR2 la patita mencionada pasa a 1 y TMR2 toma el valor 00 y reanuda la cuenta. El contenido de CCPRxL pasa a CCPRxH y se compara con TMR2. Cuando ambos coinciden la patita Rcy/CCPx pasa a 0 y se repite la secuencia. Variando el valor de PR2 y CCPRxL se varia el intervalo de tiempo que la patita esta a 1 y esta a 0, respectivamente. Tiempo a 1 = (PR2 + 1) . 4 . TOSC . PREDIVISOR Tiempo a 0 = DCI . TOSC . PREDIVISOR DCI representa el valor de los 8 bits del registro CCPRxL concatenado con los bits <5:4> de CCPxCON. Los 8 bits de TMR2 se concatenan con dos bits Q del reloj interno haciendo que cuente cada TOSC, en vez de cada 4 . TOSC. Todo ello sucede cuando se opera con una resolución de 10 bits, porque si se usa una de 8 bits, los dos bits de menos peso se ponen a 0. La figura 2.5.5.3 de la página siguiente representa cualquiera de los registros CCPICON o CCP2CON. Los bits 4 y 5 funcionan solamente en el modo PWM y son los dos bits de menos peso cuando se trabaja con una resolución de 10 bits. CCPxM3:CCPxM0 seleccionan el modo de trabajo.

40

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 2.5.5.3: Registro CPPxCON

2.5.6 Puerto serie síncrono (SSP) Se trata de un periférico diseñado para soportar una interfaz serie síncrono que resulta muy eficiente para la comunicación del microcontrolador con dispositivos tales como displays, EEPROM, ADC, etc. Tiene dos modos de trabajo: 1º. Interfaz Serie de Periféricos (SPI) 2º. Interfaz Inter-Circuitos (I2C) 2.5.6.1 Modo SPI Sirve para conectar varios microcontroladores de la misma o diferente familia, bajo el formato “maestro-esclavo”, siempre que dispongan de un interfaz compatible. En este modo se pueden emplear 3 o 4 señales de control: Salida de Datos (SDO), Entrada de Datos (SDI), Reloj (SCK) y Selección de Esclavo (SS). Dichas señales se corresponden con las patitas RC5, RC4, RC3 y RA5 respectivamente. Cada una de las señales debe programarse como entrada o salida según su condición, utilizando los bits de los registros TRIS. Cualquier función del modo SPI queda anulada poniendo con el valor opuesto a su condición el bit correspondiente de TRIS. Por ejemplo, si solo se quiere recibir datos, se programa la patita que soporta a SOD como entrada y así se anula su función. Con el registro de control SSPCON se eligen las diferentes opciones de trabajo: Modo Master (SCK es salida), Modo Esclavo (SCK es entrada), tipo de flanco de reloj, velocidad de SCK en Modo Master, etc. Cuando se recibe un dato útil, este se introduce en serie en SSPSR y pasa a SSPBUF en paralelo. El dato a transmitirse deposita en SSPBUF y de aquí pasa a SSPSR. Se puede recibir y transmitir datos simultáneamente. SSPSR es un registro de desplazamiento que funciona serie/paralelo/serie.

41

María Aranda Elcuaz

Universidad Pública de Navarra

Cuando se acaba de transmitir o recibir un dato completo se activa el bit BF (Buffer Lleno) del registro SSPSTAT. También lo hace la bandera SSPIF y si el bit de permiso esta activado se genera una interrupción. Cuando se recibe un dato durante una transmisión se ignora y se activa el bit WCOL del registro SSPCON que indica que se ha producido una “colisión”. (Para ver los detalles de funcionamiento de los registro SSPSTAT y SSPCON consultar el DATA SHEET del 16F87X que se puede encontrar en la página web de microchip.) En el caso que se reciba un nuevo dato en SSPSBUF sin haber leído el anterior se genera un error de desbordamiento.

Figura 2.5.6.1: Modo SPI 2.5.6.2 Modo I2C Este tipo de interfaz serie ha sido desarrollado por Philips y utiliza solo dos hilos trenzados y una masa común para la interconexión de los diversos dispositivos, que han tenido que ser diseñados para soportar este protocolo, asegurando una gran fiabilidad en la comunicación que llega a tolerar una velocidad máxima de 400 Kbps. Es capaz de interconectar hasta 128 dispositivos situados a gran distancia, por lo que resulta muy usado en edificios inteligentes, control de distribuciones de electricidad, agua y gas, piscifactorías, etc. El master es el que inicia y termina la transferencia general y provee de la señal de reloj. El esclavo es el dispositivo direccionado por el master, mediante 7 bits, lo que limita el número de componentes a 128.

42

María Aranda Elcuaz

Universidad Pública de Navarra

El inicio de la transmisión se determina con el bit de inicio (S) y el final con otro bit de stop (P). El bus serie de 2 hilos utiliza uno de ellos para transferir datos (SDA) y el otro para la señal de reloj (SCL). En el protocolo I2C cada dispositivo tiene asignada una dirección de 7 o de 10 bits que envía el master cuando comienza la transferencia con uno de ellos. Tras la dirección se añade el bit de recepción/transmisión o lectura/escritura (R/W). Los datos se transmiten con longitud byte y al finalizar cada uno se inserta un bit de reconocimiento ACK. Debe existir un modulo de arbitraje que gestione que solo hay un maestro en cada instante sobre el bus compartido. La figura muestra un esquema interno de funcionamiento del interfaz I2C.

Figura 2.5.6.2a: Modo I2C SSPBUF es el registro donde se almacena el byte a transmitir o el que se recibe. SSPSR es el registro desplazamiento serie de la línea E/S. SSPADD es el registro de direcciones que identifica el dispositivo (modo esclavo) o que lo direcciona (modo master). El registro de control SSPCON selecciona las diversas funciones del modo I2C.. Cada vez que se detecta un bit de inicio o un bit de stop es posible que se active la bandera SSPIF y en el caso de estar también activado el bit de permiso correspondiente generar una interrupción.

2.5.7 Interfaz de comunicaciones serie (USART-SCI) La interfaz de comunicaciones SCI proporciona las mismas prestaciones que una UART programable. Se puede configurar de dos modo diferentes: Asíncrono (full-duplex) La comunicación es bidireccional. La patita RC6/Tx/CK actúa como línea de transmisión y la RC7/Rx/DT como línea de recepción. Cada dato lleva un bit de inicio y otro de stop.

43

María Aranda Elcuaz

Universidad Pública de Navarra

Síncrono (semiduplex) Comunicación unidireccional. Una sola línea para los datos que se implementan sobre la patita RC7/Rx/DT. Existen dos modos, en el modo master la señal de reloj sale por la patita RC6/Tx/CK y en el modo esclavo entra por ella. En ambos modo los datos pueden ser de 8 o 9 bits, pudiendo emplear el noveno como bit de paridad, transmitiéndose o recibiéndose por el bit <0> de RXSTA y/o RCSTA. El registro específico TXSTA actúa como registro de estado y control del transmisor y el RCSTA hace lo mismo para el receptor. La velocidad en baudios se establecen por el valor cargado en el registro SPBRG y el bit BRGH del registro TXSTA, con el que se puede elegir la velocidad alta (1) o baja (0) en el modo asíncrono. BAUDIOS = FOSC / (n(x + 1)) n = 4 en el modo síncrono n = 16 en el modo asíncrono de alta velocidad n = 64 en el modo asíncrono de baja velocidad x = valor cargado en el registro SPBRG y siendo x = (FOSC / Baudios) / (n – 1)

Mediante la programación de los bits del registro TXSTA y RCSTA se configura el modo de trabajo. Así, SPEN configura RC7/Rx y RC6/Tx como líneas de comunicación serie. El transmisor se activa con el bit TxEN. El dato a transmitir se carga en TxREG y luego pasa al registro transmisor TSR, cuando se haya transmitido el bit de stop del dato anterior. Entonces se activa la bandera TxIF y si el bit de permiso esta activado se produce una interrupción. Activando Tx8/9 se inserta el noveno bit almacenado en el bit <0> (TxD8) de TXSTA. El bit TRMT indica si el transmisor esta vacío o no. El dato se recibe por RSR y cuando se completa se pasa al registro RCREG para su posterior lectura, activándose la bandera RCIF y si acaso la interrupción. Si se activa el bit RC8/9del RCSTA el noveno bit se deposita en el bit <0> (RCD8) del RCSTA. Los bits OERR y FERR indican error de desbordamiento y de trama, respectivamente. En la figura de la página siguiente se ofrece la asignación de funciones de los bits de los registros TXSTA y RCSTA que gobiernan al receptor y transmisor asíncronos, respectivamente. En modo síncrono el SCI trabaja en half duplex, no pudiendo emitir y transmitir a la vez. La señal de reloj la envía el transmisor (maestro) conjuntamente con los datos. Los principios y el funcionamiento de la emisión y la recepción sincronas son similares al 44

María Aranda Elcuaz

Universidad Pública de Navarra

modo asíncrono y únicamente hay que seleccionar esta forma de trabajo cargando adecuadamente los registros TXSTA y RCSTA.

Figura 2.5.6a: Registro TXSTA La figura superior muestra el registro TXSTA donde el bit 7, CSRC, es el bit de selección de reloj siendo solo importante en el modo síncrono donde se elige entre maestro o esclavo. El bit 6 habilita la transmisión de 8 o 9 bits, en general, es TXEN, quien habilita la transmisión. El bit SYNC selecciona el modo USART entre síncrono y asíncrono. Finalmente BRGH selecciona si el rango de baudios será de baja o alta velocidad en el modo asíncrono, TRMT es el bit de estado del registro de desplazamiento del transmisor y TX9D es el noveno bit de datos de transmisión. Se puede emplear como bit de paridad. La figura 2.5.6b de la página siguiente muestra el registro RCSTA donde el bit 7, SPEN, es el bit de habilitación del puerto serie. El bit 6 habilita la recepción de 8 o 9 bits y SREN, bit 5, habilita la recepción única y CREN, bit 4, la recepción continua. Los bits 1 y 2 son bits de error y finalmente, RX9D es el noveno bit de datos de recepción.

45

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 2.5.6b: Registro RXSTA

2.5.8 Lectura y escritura de la memoria de datos EEPROM En la familia de microcontroladores 16F87X tanto la memoria EEPROM de datos como la memoria de programa FLASH puede ser modificada sin necesidad de utilizar un programador exterior. Se dispone de seis registros de SFR para leer y escribir sobre la memoria no volátil, estos registros son: EECON1, EECON2, EEDATA, EEDATH, EEADR y EEADRH. Para direccionar las 256 posiciones de la memoria EEPROM del PIC16F876 y 16F877 basta con 8 bit, por ello para escribir o leer solo hacen falta el registro EEADR para direccionar la posición y el registro EEDATA para colocar el dato leído o escrito. Sin embargo para poder escribir o leer datos en la memoria FLASH que puede tener hasta 8K palabras de 14 bits hacen falta dos registros para direccionar la posición de memoria, por ello se utiliza el registro EEADR concatenado con el registro EEADRH que contiene la parte alta de la palabra de direccionamiento de memoria. De forma similar se utilizan los registros EEDATA concatenado con el registro EEADRH que contiene los 6 bit de mayor peso de las palabras de 14 bits. Además para controlar el proceso de lectura y escritura de la memoria EEPROM y FLASH se dispone de dos registros: el EECON1 y el EECON2.

46

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 2.5.8 Registro EECON1 2.5.8.1 Lectura de la memoria de datos Para leer un dato de la EEPROM, el registro EEADR es cargado con la dirección de la EEPROM donde se encuentra el dato y luego el microcontrolador copia el dato de dicha posición a EEDATA. A continuación hay que poner a 0 el bit EEPGD (EECON1<7>), para apuntar a la memoria de datos EEPROM. Una vez que se ponga a 1 la bandera RD (EECON1<0>), el dato estará disponible en el registro EEDATA, donde permanecerá hasta la siguiente escritura o lectura. 2.5.8.2 Escritura de la memoria de datos La escritura, que es en realidad una programación, es más compleja por razones de seguridad. Antes de escribir un dato en la EEPROM, debe ponerse a 1 la bandera de activación de escritura WR (EECON1<1>). Para transferir el dato desde el registro EEDATA a la dirección de la EEPROM a la que apunta EEADR, debe ejecutarse una secuencia obligatoria indicada por el fabricante. Posteriormente, cuando se ha realizado con éxito la operación de la bandera EEIF (PIR1<7>) se pone a 1. Si no lo hace, el almacenamiento ha sido incorrecto y no se ha realizado.

2.6 Repertorio de instrucciones de la gama media Habiendo escogido los diseñadores de PIC la filosofía RISC, su juego de instrucciones es reducido, siendo éstas, además, sencillas y rápidas, puesto que casi todas se ejecutan en un único ciclo de máquina (equivalente a 4 del reloj principal). Sus operandos son de gran flexibilidad, pudiendo actuar cualquier objeto como fuente y como destino. Para comprender estas instrucciones, ante todo es conveniente tener clara la estructura interna del microcontrolador, puesto que las instrucciones la referencian, y puesto que en cualquier micro la comprensión de la nomenclatura de sus componentes es esencial. De

47

María Aranda Elcuaz

Universidad Pública de Navarra

este modo se expone la tabla siguiente para ayudarle a comprender las abreviaturas, y seguidamente las 35 instrucciones para la gama media.

Abreviatura

Descripción

PC

Contador de Programa que direcciona la memoria de instrucciones. Tiene un tamaño de 11 bits en la gama baja, de los cuales los 8 de menos peso configuran el registro PCL que ocupa el registro 0x02 del área de datos.

TOS

Cima de la pila, con 2 niveles en la gama baja y 8 en la media

WDT W F

D Dest TO PD b k

x

label

Perro guardián (Watchdog) Registro W, similar al acumulador Suele ser un campo de 5 bits (fffff) que contiene la dirección del banco de registros, que ocupa el banco 0 del área de datos. Direcciona uno de esos registros. Bit del código OP de la instrucción, que selecciona el destino. Si d=0, el destino es W, y si d=1 el destino es f. Destino (registro W o f) Bit “Time Out” del registro de estado Bit “Power Down” del registro de estado Suele ser un campo de 3 bits (bbb) que determinan la posición de un bit dentro de un registro de 8 bits Se trata, normalmente, de un campo de 8 bits (kkkkkkkk) que representa un dato inmediato. También puede constar de 9 bits en las instrucciones de salto que cargan al PC Valor indeterminado (puede ser un 0 o un 1). Para mantener la compatibilidad con las herramientas software de Microchip conviene hacer x = 0 Nombre de la etiqueta

[] () ® <> Î

Opciones Contenido Se asigna a Campo de bits de un registro Pertenece al conjunto

Z

Señalizador de cero en W. Pertenece al registro de estado

C

Señalizador de acarreo en el octavo bit del W. Pertenece al registro de estado

DC

Señaliza el acarreo en el 4 bit del W. Pertenece al registro de estado

Itálicas

Términos definidos por el usuario

48

María Aranda Elcuaz

ADDLW

Suma un literal

Universidad Pública de Navarra

ADDWF W + F

ANDLW

Sintaxis: [label] ADDLW k Operandos: 0 £ k £ 255 Operación: (W) + (k)Þ (W) Flags afectados: C, DC, Z Código OP: 11 111x kkkk kkkk Descripción: Suma el contenido del registro W y k, guardando el resultado en W.

Sintaxis: [label] ADDWF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: (W) + (f) Þ (dest) Flags afectados: C, DC, Z Código OP: 00 0111 dfff ffff Descripción: Suma el contenido del registro W y el registro f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Sintaxis: [label] ANDLW k Operandos: 0 £ k £ 255 Operación: : (W) AND (k)Þ (W) Flags afectados: Z Código OP: 11 1001 kkkk kkkk Descripción: Realiza la operación lógica AND entre el contenido del registro W y k, guardando el resultado en W.

Ejemplo:

Ejemplo:

Ejemplo:

ADDLW 0xC2

Antes: W = 0x17 Después: W = 0xD9

ADDWF REG,0

Antes: W = 0x17., REG = 0xC2 Después: W = 0xD9, REG = 0xC2

W AND literal

ADDLW 0xC2

Antes: W = 0x17 Después: W = 0xD9

ANDWF W AND F

BCF

Sintaxis: [label] ANDWF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: (W) AND (f) Þ (dest) Flags afectados: Z Código OP: 00 0101 dfff ffff

Sintaxis: [label] BCF f,b Operandos: 0 £ f £ 127, 0 £ b £ 7 Operación: 0 Þ (f) Flags afectados: Ninguno Código OP: 01 00bb bfff ffff

Sintaxis: [label] BSF f,b Operandos: 0 £ f £ 127, , 0 £ b £ 7 Operación: 1 Þ (f) Flags afectados: Ninguno Código OP: 01 01bb bfff ffff

Descripción: Realiza la operación lógica AND entre los registros W y f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Descripción: Borra el bit b del registro f

Descripción: Activa el bit b del registro f

Ejemplo: :

Ejemplo:

Ejemplo: :

ANDWF REG,0

Antes: W = 0x17., REG = 0xC2 Después: W = 0x17, REG = 0x02

Borra un bit

BCF REG,7

Antes: REG = 0xC7 Después: REG = 0x47

BSF

Activa un bit

BSF REG,7

Antes: REG = 0x0A Después: REG = 0x8A

BTFSC Test de bit y salto

BTFSS Test de bit y salto

CALL

Sintaxis: [label] BTFSC f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: Salto si (f) = 0 Flags afectados: Ninguno Código OP: 01 10bb bfff ffff

Sintaxis: [label] BTFSS f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: Salto si (f) = 1 Flags afectados: Ninguno Código OP: 01 11bb bfff ffff

Sintaxis: [label] CALL k Operandos: 0 £ k £ 2047 Operación: PC Þ Pila; k Þ PC Flags afectados: Ninguno Código OP: 10 0kkk kkkk kkkk

Descripción: Si el bit b del registro f es 0, se salta una instrucción y se continúa con la ejecución. En caso de salto, ocupará dos ciclos de reloj.

Descripción: Si el bit b del registro f es 1, se salta una instrucción y se continúa con la ejecución. En caso de salto, ocupará dos ciclos de reloj.

Descripción: Salto a una subrutina. La parte baja de k se carga en PCL, y la alta en PCLATCH. Ocupa 2 ciclos de reloj.

Ejemplo:

Ejemplo:

Ejemplo:ORIGEN CALL DESTINO

BTFSC REG,6 GOTO NO_ES_0 SI_ES_0 Instrucción NO_ES_0 Instrucción

BTFSS REG,6 GOTO NO_ES_0 SI_ES_0 Instrucción NO_ES_0 Instrucción

Salto a subrutina

Antes: PC = ORIGEN Después: PC = DESTINO

49

María Aranda Elcuaz

CLRF

Universidad Pública de Navarra

Borra un registro

CLRW Borra el registro W

CLRWDT

Sintaxis: [label] CLRF f Operandos: 0 £ f £ 127 Operación: : 0x00 Þ (f), 1 Þ Z Flags afectados: Z Código OP: 00 0001 1fff ffff

Sintaxis: [label] CLRW Operandos: Ninguno Operación: : 0x00 Þ W, 1 Þ Z Flags afectados: Z Código OP: 00 0001 0xxx xxxx

Descripción: El registro f se carga con 0x00. El flag Z se activa.

Descripción: El registro de trabajo W se carga con 0x00. El flag Z se activa.

Sintaxis: [label] CLRWDT Operandos: Ninguno Operación: 0x00 Þ WDT, 1 Þ /TO 1 Þ /PD Flags afectados: /TO, /PD Código OP: 00 0000 0110 0100 Descripción: Esta instrucción borra tanto el WDT como su preescaler. Los bits /TO y /PD del registro de estado se ponen a 1.

Ejemplo: :

Ejemplo: :

CLRF REG

Antes: W = 0x5A Después: W = 0x00, Z = 1

Antes: REG = 0x5A Después: REG = 0x00, Z = 1

COMF

CLRW

Complemento de f

Borra el WDT

Ejemplo: : CLRWDT Después: Contador WDT = 0, Preescales WDT = 0, /TO = 1, /PD = 1

DECF Decremento de f

DECFSZ Decremento y salto

Sintaxis: [label] COMF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: : (/ f), 1 Þ (dest) Flags afectados: Z Código OP: 00 1001 dfff ffff

Sintaxis: [label] DECF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: : (f ) – 1 Þ (dest) Flags afectados: Z Código OP: 00 0011 dfff ffff

Sintaxis: [label] DECFSZ f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: (f) -1 Þ d; Salto si R=0 Flags afectados: Ninguno Código OP: 00 1011 dfff ffff

Descripción: El registro f es complementado. El flag Z se activa si el resultado es 0. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f..

Descripción: Decrementa en 1 el contenido de f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Descripción: Decrementa el contenido del registro f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f. Si la resta es 0 salta la siguiente instrucción, en cuyo caso costaría 2 ciclos.

Ejemplo: :

Ejemplo: :

COMF REG,0

DECF CONT,1 Ejemplo:

Antes: REG = 0x13 Después: REG = 0x13, W = 0XEC

GOTO

Salto incondicional

Antes: CONT = 0x01, Z = 0 Después: CONT = 0x00, Z = 1

INCF

Incremento de f

DECFSC REG,0 GOTO NO_ES_0 SI_ES_0 Instrucción NO_ES_0 Salta instrucción anterior

INCFSZ Incremento y salto

Sintaxis: [label] GOTO k Operandos: 0 £ k £ 2047 Operación: k Þ PC <8:0> Flags afectados: Ninguno Código OP: 10 1kkk kkkk kkkk

Sintaxis: [label] INCF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: : (f ) + 1 Þ (dest) Flags afectados: Z Código OP: 00 1010 dfff ffff

Sintaxis: [label] INCFSZ f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: (f) -1 Þ d; Salto si R=0 Flags afectados: Ninguno Código OP: 00 1111 dfff ffff

Descripción: Se trata de un salto incondicional. La parte baja de k se carga en PCL, y la alta en PCLATCH. Ocupa 2 ciclos de reloj.

Descripción: Incrementa en 1 el contenido de f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Ejemplo: DESTINO

Ejemplo:

Descripción: Incrementa el contenido del registro f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f. Si la resta es 0 salta la siguiente instrucción, en cuyo caso costaría 2 ciclos.

ORIGEN

Antes: PC = ORIGEN Después: PC = DESTINO

GOTO

INCF CONT,1

Antes: CONT = 0xFF, Z = 0 Después: CONT = 0x00, Z = 1

Ejemplo:

INCFSC REG,0 GOTO NO_ES_0 SI_ES_0 Instrucción NO_ES_0 Salta instrucción anterior

50

María Aranda Elcuaz

IORLW

Universidad Pública de Navarra

W OR literal

IORWF

W AND F

MOVLW Cargar literal en W

Sintaxis: [label] IORLW k Operandos: 0 £ k £ 255 Operación: : (W) OR (k)Þ (W) Flags afectados: Z Código OP: 11 1000 kkkk kkkk

Sintaxis: [label] IORWF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: (W) OR (f) Þ (dest) Flags afectados: Z Código OP: 00 0100 dfff ffff

Sintaxis: [label] MOVLW f Operandos: 0 £ f £ 255 Operación: (k) Þ (W) Flags afectados: Ninguno Código OP: 11 00xx kkkk kkkk

Descripción: Se realiza la operación lógica OR entre el contenido del registro W y k, guardando el resultado en W.

Descripción: Realiza la operación lógica OR entre los registros W y f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Descripción: El literal k pasa al registro W.

Ejemplo:

Ejemplo:

Ejemplo:

IORLW 0x35

Antes: W = 0x9A Después: W = 0xBF

MOVF

IORWF REG,0

Antes: W = 0x91, REG = 0x13 Después: W = 0x93, REG = 0x13

Mover a f

MOVWF

Mover a f

Sintaxis: [label] MOVF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: (f) Þ (dest) Flags afectados: Z Código OP: 00 1000 dfff ffff Descripción: El contenido del registro f se mueve al destino d. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f. Permite verificar el registro, puesto que afecta a Z.

Sintaxis: [label] MOVWF f Operandos: 0 £ f £ 127 Operación: W Þ (f) Flags afectados: Ninguno Código OP: 00 0000 1fff ffff

Ejemplo:

Ejemplo:

MOVF REG,0 Después: W = REG

Descripción: El contenido registro W pasa el registro f.

MOVLW 0x5A

Después: REG = 0x4F, W = 0x5A

NOP

No operar

Sintaxis: [label] NOP Operandos: Ninguno Operación: No operar Flags afectados: Ninguno Código OP: 00 0000 0xx0 0000 del

MOVWF REG,0

Antes: REG = 0xFF, W = 0x4F Después: REG = 0x4F, W = 0x4F

Descripción: No realiza operación alguna. En realidad consume un ciclo de instrucción sin hacer nada.

Ejemplo:

CLRWDT

Después: Contador WDT = 0, Preescales WDT = 0, /TO = 1, /PD = 1

RETFIE Retorno de interrup.

RETLW Retorno, carga W

RETURN Retorno de rutina

Sintaxis: [label] RETFIE Operandos: Ninguno Operación: : 1 Þ GIE; TOSÞPC Flags afectados: Ninguno Código OP: 00 0000 0000 1001

Sintaxis: [label] RETLW k Operandos: 0 £ k £ 255 Operación: : (k)Þ (W); TOSÞPC Flags afectados: Ninguno Código OP: 11 01xx kkkk kkkk

Sintaxis: [label] RETURN Operandos: Ninguno Operación: : TOS Þ PC Flags afectados: Ninguno Código OP: 00 0000 0000 1000

Descripción: El PC se carga con el contenido de la cima de la pila (TOS): dirección de retorno. Consume 2 ciclos. Las interrupciones vuelven a ser habilitadas.

Descripción: El registro W se carga con la constante k. El PC se carga con el contenido de la cima de la pila (TOS): dirección de retorno. Consume 2 ciclos.

Descripción: El PC se carga con el contenido de la cima de la pila (TOS): dirección de retorno. Consume 2 ciclos.

Ejemplo:

Ejemplo:

Ejemplo:

RETFIE

Después: PC = dirección de retorno GIE = 1

RETLW 0x37

Después: PC = dirección de retorno W = 0x37

RETURN

Después: PC = dirección de retorno

51

María Aranda Elcuaz

RLF

Rota f a la izquierda

Universidad Pública de Navarra

RRF

Rota f a la derecha

Sintaxis: [label] RLF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: Rotación a la izquierda Flags afectados: C Código OP: 00 1101 dfff ffff

Sintaxis: [label] RRF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: Rotación a la derecha Flags afectados: C Código OP: 00 1100 dfff ffff

Descripción: El contenido de f se rota a la izquierda. El bit de menos peso de f pasa al carry (C), y el carry se coloca en el de mayor peso. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Descripción: El contenido de f se rota a la derecha. El bit de menos peso de f pasa al carry (C), y el carry se coloca en el de mayor peso. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Ejemplo:

Ejemplo:

RRF REG,0

Antes: REG = 1110 0110, C = 0 Después: REG = 1110 0110, W = 1100 1100, C = 1

RRF REG,0

SLEEP Modo bajo consumo Sintaxis: [label] SLEEP Operandos: Ninguno Operación: 0x00ÞWDT, 1 Þ / TO 0 Þ WDT Preescaler, 0 Þ / PD Flags afectados: / PD, / TO Código OP: 00 0000 0110 0011 Descripción: El bit de energía pone a 0, y a 1 el de descanso. WDT y su preescaler se borran. micro para el oscilador, llendo modo “durmiente”. Ejemplo: :

Antes: REG = 1110 0110, C = 1 Después: REG = 1110 0110, W = 01110 0011, C = 0

SLEEP

Preescales WDT = 0, /TO = 1, /PD = 1

SUBLW Resta Literal - W

SUBWF

Sintaxis: [label] SUBLW k Operandos: 0 £ k £ 255 Operación: ( k ) - (W) Þ (W) Flags afectados: Z, C, DC Código OP: 11 110x kkkk kkkk Descripción: Mediante el método del complemento a dos el contenido de W es restado al literal. El resultado se almacena en W.

Sintaxis: [label] SUBWF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: ( f ) – (W )Þ (dest) Flags afectados: C, DC, Z Código OP: 00 0010 dfff ffff Descripción: Mediante el método del complemento a dos el contenido de W es restado al de f. . Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Sintaxis: [label] SWAPF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: : (f <3: 0>)Û (f <7:4>) Flags afectados: Ninguno Código OP: 00 1110 dfff ffff

Ejemplos:

Ejemplo: :

Antes:W=1,C=?. Después: W=1, C=1 Antes:W=2,C=?. Después: W=0, C=1 Antes:W=3,C=?.Después:W=FF,C=0 (El resultado es negativo)

Ejemplos: SUBWF REG,1 Antes: REG = 0x03, W = 0x02, C = ? Después:REG=0x01, W = 0x4F, C=1 Antes: REG = 0x02, W = 0x02, C = ? Después:REG=0x00, W =0x02, C= 1 Antes: REG= 0x01, W= 0x02, C= ? Después:REG=0xFF, W=0x02, C= 0 (Resultado negativo)

XORLW

XORWF W AND F

SUBLW 0x02

W OR literal

Resta f – W

se El El al

Sintaxis: [label] XORLW k Operandos: 0 £ k £ 255 Operación: : (W) XOR (k)Þ (W) Flags afectados: Z Código OP: 11 1010 kkkk kkkk

Sintaxis: [label] XORWF f,d Operandos: d Î [0,1], 0 £ f £ 127 Operación: (W) XOR (f) Þ (dest) Flags afectados: Z Código OP: 00 0110 dfff ffff

Descripción: Se realiza la operación lógica XOR entre el contenido del registro W y k, guardando el resultado en W.

Descripción: Realiza la operación lógica XOR entre los registros W y f. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f.

Ejemplo: :

Ejemplo: :

XORLW 0xAF

Antes: W = 0xB5 Después: W = 0x1A

SWAPF

Intercambio de f

Descripción: Los 4 bits de más peso y los 4 de menos son intercambiados. Si d es 0, el resultado se almacena en W, si d es 1 se almacena en f. SWAPF REG,0

Antes: REG = 0xA5 Después: REG = 0xA5, W = 0x5A

La gama media tiene un total de 35 instrucciones, cada una de las cuales ocupan 14 bits.

XORWF REG,0

Antes: W = 0xB5, REG = 0xAF Después: W = 0xB5, REG = 0x1A

52

María Aranda Elcuaz

Universidad Pública de Navarra

Capítulo 3. Herramientas de trabajo Para la realización de las prácticas será necesario disponer de cierto material físico y algunos programas informáticos: Hardware necesario: - Tarjeta entrenadora Picdem 2 Plus de Microchip - In-Circuit Debugger ICD 2 - PIC 16F877 Software necesario: - Microchip MPLAB IDE con Plug-in de CCS instalado

3.1 Placa de pruebas: PICDEM 2 PLUS Sobre la placa de pruebas PICDEM 2 PLUS de Microchip se realizarán todas las prácticas propuestas en el capítulo 4; se presenta a continuación un listado de sus características generales:

1) Posee 3 módulos para la conexión de microcontroladores de 18, 28 y 40 pines que en ningún caso podrán ser utilizados al mismo tiempo. 2) Regulador de +5 V para entradas de corriente 9 V, 100 mA AC/DC, pila de 9V o +5 V de corriente continua regulada para la alimentación de la placa. 3) Conexión serie RS-232 y hardware asociado (MAX232A para ajustar niveles) para comunicar la tabla con distintos dispositivos externos como puede ser, por ejemplo, un ordenador. 4) Conector para el depurador y grabador en circuito ICD 2 5) Potenciómetro de 5 KΩ para entradas analógicas, conectado a RA0 a través de una resistencia de 470 Ω. 6) 3 pulsadores para impulsos externos (RA4 y RB0) y botón de reset. Si se presionan se ponen a 0, si no, permanecen a nivel alto. 7) Led verde de indicación de encendido 8) 4 Leds rojos conectados al Puerto B de cada uno de los microcontroladores 53

María Aranda Elcuaz

Universidad Pública de Navarra

9) Jumper J6 para la desconexión de los leds 10) Oscilador de 4 MHz 11) Conectores vacíos para otros osciladores 12) Cristal de 32.768 KHz para la operación de TMR1 13) Jumper J7 para la desconexión del oscilador RC 14) EEPROM 32k x 8 serie para comunicación I2C 15) Pantalla LCD con dos líneas de 16 caracteres cada una. Las líneas de control son RA3:RA1 y cuatro líneas de datos (RD3:RD0)

16) Buzzer 17) Área de conexión de hardware libre 18) Sensor de temperatura TC74 conectado a los micros a través de RC3 y RC4 compatible con la comunicación I2C En la siguiente tabla se puede ver un resumen de las conexiones de entrada y salida:

3.2 Software de programación MPLAB IDE es un conjunto de herramientas que permite el desarrollo completo de proyectos siguiendo las siguientes fases: 1) Editar el programa: Estas prácticas serán diseñadas en lenguaje C en el editor de textos de MPLAB, pero se pueden realizar en cualquier otro lenguaje, ya sea de bajo nivel como el ensamblador u otros de alto nivel como el Visual Basic etc. 2) Compilar o ensamblar el programa fuente, es decir, convertir a código máquina ejecutable el programa fuente editado en la fase anterior. Para poder compilar el programa será necesario tener instalado el Plug-in de CCS y para ensamblarlo habrá que emplear el programa MPASWIN que incluye MPLAB IDE. 3) Simular el programa: Antes de grabar el programa en la memoria del PIC, conviene comprobar si el funcionamiento del programa es correcto. Para ello se puede 54

María Aranda Elcuaz

Universidad Pública de Navarra

simular por software con el simulador que incluye MPLAB. No es una fase obligatoria, es opcional pero conveniente. 4) Grabación del PIC: Para la grabación del microcontrolador se utilizará el ICD2 conectado al PC.

3.2.1 Cómo usar MPLAB 3.2.1.1 Creación de proyectos MPLAB es un Entorno de Desarrollo Integrado (IDE) fácil de aprender y fácil de usar. La característica IDE proporciona a los desarrolladores de software para aplicaciones la flexibilidad para editar, compilar, emular, simular, desarrollar y depurar su propio software para las familias de microcontroladores PIC16/17 de Microchip. Para crear un nuevo proyecto se debe ir a Project>Project Wizard, tal y como se indica en la figura siguiente. Una vez ahí, se abrirá un asistente de creación de proyectos donde habrá que seguir unos pasos sencillos para la configuración del proyecto.

1) Selección del modelo de microcontrolador a emplear de una lista. En el caso de estas prácticas se elegirá el PIC16F877. 2) Selección del lenguaje y compilador a emplear así como la ubicación de este en el PC, en este caso, se utilizará el compilador de Ccs tal y como se indica en la figura.

55

María Aranda Elcuaz

Universidad Pública de Navarra

Si el programa se realiza en otro lenguaje habrá que seleccionar otro compilador. Por ejemplo si se ha realizado en lenguaje ensamblador, en este paso habrá que seleccionar “MPASM Assembler” que se encuentra en la carpeta donde se ha instalado el MPLAB IDE. 3) Dar un nombre al proyecto y elegir la carpeta donde se desea guardar.

4) Seleccionar los archivos de código fuente y las librerías necesarias para llevar a cabo el proyecto.

En caso de no haber creado todavía el código fuente, no habría más que crearlo en el editor de textos del propio programa o en cualquier otro editor de textos. En MPLAB sería File>New, una vez escrito se guarda pulsando File>Save. Después de seguir todos los pasos el programa realiza un resumen, ahí se pulsa Finalizar y se sale del asistente. En este punto cabe destacar que lo realizado hasta ahora es simplemente la creación del código fuente y la configuración de las aplicaciones que se van a emplear. El siguiente paso es la compilación. 3.2.1.2 Compilación del programa Una vez realizado el proyecto es tan sencillo como darle al botón de compilar tal y como se indica en la figura de la página siguiente. 56

María Aranda Elcuaz

Universidad Pública de Navarra

Si el programa no tiene fallos nos saldrá un mensaje de que se ha compilado con éxito “Build Sucedded”, si tiene algún error saldrá un mensaje e indicará en que línea o parte del programa se ha producido, habrá que corregirlo y volver a compilar. Una vez compilado correctamente se habrá generado en la carpeta previamente seleccionada un archivo de igual nombre al código fuente pero con extensión .hex. Este archivo es el mismo pero traducido a código máquina, de tal forma que el PIC pueda comprender las ordenes indicadas en el programa. Si el programa ha sido realizado en lenguaje ensamblador en vez de en lenguaje C simplemente en vez de aparecer la opción “Compile” aparecerá la opción “Assemble” y todo lo demás será exactamente igual a lo explicado para el lenguaje C. 3.2.1.3 Programación Una vez generado el archivo en código máquina solamente queda pasarlo del ordenador al microcontrolador. Para ello será necesario un programador que, en este caso, será el MPLAB ICD 2 de Microchip. Una vez conectado vía USB al ordenador y después a la tarjeta entrenadora Picdem 2 Plus. Habrá que seleccionarlo y conectarlo en el MPLAB IDE tal y como se ve en la figura: Programmer>Select Programmer>Mplab Icd 2

Una vez seleccionado habrá que pulsar el icono “Program tarjet device” y el programa quedará grabado en el PIC.

57

María Aranda Elcuaz

Universidad Pública de Navarra

3.3 Lenguaje C. En este punto de proyecto no se pretende explicar cómo se programa en este lenguaje, sino hacer un listado de las directivas y funciones permitidas por el compilador PCW de CCS, compilador específico para microcontroladores de la casa Microchip. Así pues, se parte de la idea de que el lector posee conocimientos básicos de este lenguaje u otros lenguajes de alto nivel.

3.3.1 Operadores y expresiones Una expresión de asignación tradicional es de la forma expr1 = expr1 operador expr2, pero también puede ser representada por otra más corta expr1 operador = expr2. En la siguiente tabla se resumen los operadores de asignación compuesta y su significado:

Los operadores aritméticos empleados para realizar operaciones matemáticas son:

La misión de los operadores relacionales es comparar dos operandos y dar un resultado entero, 1 si es verdadero y 0 si es falso:

58

María Aranda Elcuaz

Universidad Pública de Navarra

Los operadores lógicos, al igual que los operadores relacionales, devuelve 1 o 0 tras la evaluación de sus operandos. En la tabla siguiente se ilustran estos operadores:

Los operadores de manejo de bits permiten actuar sobre los operandos a nivel de bits y sólo pueden ser de tipo entero (incluyendo el tipo char). Son los que siguen:

Las expresiones empleadas se exponen en la siguiente tabla:

3.3.2 Directivas del preprocesador Todas las directivas del preprocesador comienzan con el carácter # seguido por un comando específico. Algunas de estas directivas son extensiones del C estándar. El C proporciona una directiva del preprocesador, que los compiladores aceptan, y que permite ignorar o actuar sobre los datos que siguen. El compilador de CCS admite cualquier directiva del preprocesador que comience con PRAGMA, lo que asegura la compatibilidad con otros compiladores. A continuación se describen algunas directivas del compilador que se emplearán para programar los microcontroladores PIC en estas prácticas. 3.3.2.1 Control de memoria #BIT identificador = x.y Esta directiva creará un identificador "id" que puede utilizarse como cualquier SHORT INT (entero corto; un bit). El identificador hará referencia a un objeto en la posición de memoria x más el bit de desplazamiento y. #BYTE identificador = X 59

María Aranda Elcuaz

Universidad Pública de Navarra

Esta directiva creará un identificador “id” que puede utilizarse como cualquier INT (un byte). El identificador hará referencia a un objeto en la posición de memoria x, donde x puede ser una constante u otro identificador. Si x es otro identificador, entonces éste estará localizado en la misma dirección que el identificador “id”. #RESERVE Permite reservar posiciones de la RAM para uso del compilador. #RESERVE debe aparecer después de la directiva #DEVICE, de lo contrario no tendrá efecto. 3.3.2.2 Directivas del C estándar #DEFINE identificador CADENA Se utiliza simplemente para reemplazar el identificador (ID) con CADENA #IF expresión_constante #ELSE #ENDIF El preprocesador evalúa la expresión_constante y si es distinta de cero procesará las líneas hasta el #ELSE o en su defecto hasta el #ENDIF. #INCLUDE #INCLUDE "Nombre_Fichero" Esta directiva hace que el compilador incluya en el fichero fuente el texto que contiene el archivo especificado en . 3.3.2.3 Especificación de dispositivos #FUSES opciones Esta directiva define qué fusibles deben activarse en el dispositivo cuando se programe. Esta directiva no afecta a la compilación; sin embargo, esta información es necesaria para algunos programadores de dispositivos. Algunas de las opciones más usadas son: LP, XT, HS, RC WDT, NOWDT PROTECT, NOPROTECT PUT, NOPUT (Power Up Timer) BROWNOUT, NOBROWNOUT SWAP 3.3.2.4 Librerías incorporadas #USE DELAY (CLOCK=frecuencia) Esta directiva indica al compilador la frecuencia del procesador, en ciclos por segundo, a la vez que habilita el uso de las funciones DELAY_MS() y DELAY_US(). 60

María Aranda Elcuaz

Universidad Pública de Navarra

#USE FAST_IO (puerto) Esta directiva afecta al código que el compilador generará para las instrucciones de entrada y salida. Este método rápido de hacer I/O ocasiona que el compilador realice I/O sin programar el registro de dirección. #USE I2C (master/slave, SDA=Pin, SCL=Pin opciones) La librería I2C contiene funciones para implementar un bus I2C. La directiva #USE I2C permanece efectiva para las funciones I2C_START, I2C_STOP, I2C_READ, I2C_WRITE e I2C_POLL hasta que se encuentre otra directiva #USE I2C. Las opciones son:

#USE RS232 (BAUD=baudios, XMIT=pin, RCV=pin...) Esta directiva le dice al compilador la velocidad en baudios y los pines utilizados para la I/O serie. Esta directiva tiene efecto hasta que se encuentra otra directiva RS232. La directiva #USE DELAY debe aparecer antes de utilizar #USE RS232. Esta directiva habilita el uso de funciones tales como GETCH, PUTCHAR y PRINTF. Las opciones son:

#USE STANDARD_IO (puerto) Esta directiva afecta al código que el compilador genera para las instrucciones de entrada y salida. El método estándar de hacer I/O causará que el compilador genere código para hacer que un pin de I/O sea entrada o salida cada vez que se utiliza. En los procesadores de la serie 5X esto necesita un byte de RAM para cada puerto establecido como I/O estándar. 61

María Aranda Elcuaz

Universidad Pública de Navarra

3.3.3 Funciones 3.3.3.1 Funciones de i/o serie rs232 c = GETC() c = GETCH() c = GETCHAR() Estas funciones esperan un carácter por la patilla RCV del dispositivo RS232 y retorna el carácter recibido. Es preciso utilizar la directiva #USE RS232 antes de la llamada a esta función para que el compilador pueda determinar la velocidad de transmisión y la patilla utilizada. La directiva #USE RS232 permanece efectiva hasta que se encuentre otra que anule la anterior. Los procedimientos de I/O serie exigen incluir #USE DELAY para ayudar a sincronizar de forma correcta la velocidad de transmisión. PUTC() PUTCHAR() Estas funciones envían un carácter a la patilla XMIT del dispositivo RS232. Es preciso utilizar la directiva #USE RS232 antes de la llamada a esta función para que el compilador pueda determinar la velocidad de transmisión y la patilla utilizada. La directiva #USE RS232 permanece efectiva hasta que se encuentre otra que anule la anterior. PUTS(string) Esta función envía cada carácter de string a la patilla XMIT del dispositivo RS232. Una vez concluido el envío de todos los caracteres la función envía un retorno de carro CR o RETURN (ASCII 13) y un avance de línea LF o LINE-FEED (ASCII 10). PRINTF([function], string, [values]) La función de impresión formateada PRINTF saca una cadena de caracteres al estándar serie RS-232 o a una función especificada. El formato está relacionado con el argumento que ponemos dentro de la cadena (string). Cuando se usan variables, string debe ser una constante. El carácter % se pone dentro de string para indicar un valor variable, seguido de uno o más caracteres que dan formato al tipo de información a representar. Si ponemos %% obtenemos a la salida un solo %. El formato tiene la forma genérica %wt, donde w es optativo y puede ser 1,2,...,9. Esto es para especificar cuántos carácteres son representados; si elegimos el formato 01,...,09 indicamos ceros a la izquierda, o también 1.1 a 9.9 para representación en punto flotante. t es el tipo de formato y puede ser uno de los siguientes:

62

María Aranda Elcuaz

Universidad Pública de Navarra

SET_UART_SPEED(baud) Esta función cambia la velocidad de transmisión de la UART (Universal Asynchronous Receiver Transmitter) en tiempo de ejecución. SETUP_ADC(mode) Esta función configura (permite establecer analógico/digital. Los modos son los siguientes:

los

parámetros)

del

conversor

ADC_OFF ADC_CLOCK_DIV_2 ADC_CLOCK_DIV_8 ADC_CLOCK_DIV_32 ADC_CLOCK_INTERNAL 3.3.3.2 Funciones de I/O discreta INPUT(pin) Devuelve el estado '0' o '1' de la patilla indicada en pin. El método de acceso de I/O depende de la última directiva #USE *_IO utilizada. El valor de retorno es un entero corto. OUTPUT_BIT(pin, value) Esta función saca el bit dado en value(0 o 1) por la patilla de I/O especificada en pin. El modo de establecer la dirección del registro, está determinada por la última directiva #USE *_IO. OUTPUT_HIGH(pin) Pone a 'uno' el pin indicado. El método de acceso de I/O depende de la última directiva #USE *_IO utilizada. OUTPUT_LOW(pin) Pone a 'cero' el pin indicado. El método de acceso de I/O depende de la última directiva #USE *_IO.

63

María Aranda Elcuaz

Universidad Pública de Navarra

SET_TRIS_A(value) SET_TRIS_B(value) SET_TRIS_C(value) SET_TRIS_D(value) SET_TRIS_E(value) Estas funciones permiten escribir directamente los registros tri-estado para la configuración de los puertos. Esto debe usarse con FAST_IO() y cuando se accede a los puertos de I/O como si fueran memoria, igual que cuando se utiliza una directiva #BYTE. Cada bit de value representa una patilla. Un '1' indica que la patilla es de entrada y un '0' que es de salida. 3.3.3.3 Funciones de retardos DELAY_CYCLES(count) Esta función realiza retardos según el número de ciclos de instrucción especificado en count; los valores posibles van desde 1 a 255. Un ciclo de instrucción es igual a cuatro periodos de reloj. DELAY_MS(time) Esta función realiza retardos del valor especificado en time. Dicho valor de tiempo es en milisegundos y el rango es 0-65535. Es preciso utilizar la directiva #use delay(clock=frecuencia) antes de la llamada a esta función, para que el compilador sepa la frecuencia de reloj. DELAY_US(time) Esta función realiza retardos del valor especificado en time. Dicho valor es en microsegundos y el rango va desde 0 a 65535. Es necesario utilizar la directiva #use delay antes de la llamada a esta función para que el compilador sepa la frecuencia de reloj. 3.3.3.4 Funciones de control del procesador DISABLE_INTERRUPTS(level) Esta función desactiva la interrupción del nivel dado en level. El nivel GLOBAL prohíbe todas las interrupciones, aunque estén habilitadas o permitidas. Los niveles de interrupción son:

ENABLE_INTERRUPTS(level) Esta función activa la interrupción del nivel dado en level. Queda a cargo del técnico definir un procedimiento o rutina de atención, para el caso que se produzca la interrupción 64

María Aranda Elcuaz

Universidad Pública de Navarra

indicada. El nivel GLOBAL permite todas las interrupciones que estén habilitadas de forma individual. SLEEP() Esta función pone al micro en un estado de REPOSO. 3.3.3.5 Contadores/Temporizadores GET_RTCC() GET_TIMER0() GET_TIMER1() i=GET_TIMER2() Estas funciones devuelven el valor de la cuenta de un contador en tiempo real. RTCC y Timer0 son el mismo. Timer1 es de 16 bits y los otros son de 8 bits. RESTART_WDT() Esta función reiniciará el timer del watchdog. Si habilitamos el timer del watchdog, debe llamarse periódicamente a RESTART_WDT() para prevenir el reseteo del procesador. SET_RTCC(value) SET_TIMER0(value) SET_TIMER1(value) SET_TIMER2(value) Estas funciones activan el timer o temporizador al valor especificado. RTCC y Timer0 son el mismo. Timer1 es de 16 bits y los otros son de 8 bits. SETUP_TIMER_1(mode) Esta función inicializa el timer1. Los valores de mode deben ordenarse juntos, tal como se muestra en el ejemplo. El valor del timer puede leerse y puede escribirse utilizando GET_TIMER1() y SET_TIMER1(). Los valores de mode son:

SETUP_TIMER_2(mode, period, postscale) Esta función inicializa el timer2; mode especifica el divisor del reloj del oscilador. Period es un número comprendido entre 0-255, y determina el momento en el que el valor del reloj se resetea a 0. postscale es un número de 0 a 15, que determina cuántos reset del timer se han producido antes de una interrupción. 0 significa 1 reset, 1 significa 2 reset, y

65

María Aranda Elcuaz

Universidad Pública de Navarra

así sucesivamente. El valor del timer puede leerse y puede escribirse utilizando GET_TIMER2() y SET_TIMER2(). Los valores de mode son: -

T2_DISABLED T2_DIV_BY_1 T2_DIV_BY_4 T2_DIV_BY_16

3.3.3.6 Funciones de entrada A/D SETUP_ADC_PORTS(value) Esta función configura los pines del ADC para que sean analógicos, digitales o alguna combinación de ambos. SETUP_ADC(mode) Esta función prepara o configura el conversor A/D. Los modos de funcionamiento son: - ADC_OFF - ADC_CLOCK_DIV_2 - ADC_CLOCK_DIV_8 - ADC_CLOCK_DIV_32 - ADC_CLOCK_INTERNAL SET_ADC_CHANNEL(canal) Especifica el canal a utilizar por la función READ_ADC(). El número de canal empieza en 0. Es preciso esperar un corto espacio de tiempo después de cambiar el canal de adquisición, antes de que se puedan obtener lecturas de datos válidos. i=READ_ADC() Esta función lee el valor digital del conversor analógico digital. Deben hacerse llamadas a SETUP_ADC() y SET_ADC_CHANNEL() en algún momento antes de la llamada a esta función. 3.3.3.7 Funciones CCP SETUP_CCP1(mode) SETUP_CCP2(mode) Estas funciones inicializa el contador CCP. Para acceder a los contadores CCP se utilizan las variables CCP_1 y CCP_2. Los valores para mode son: CCP_OFF CCP_CAPTURE_FE CCP_CAPTURE_RE 66

María Aranda Elcuaz

Universidad Pública de Navarra

CCP_CAPTURE_DIV_4 CCP_CAPTURE_DIV_16 CCP_COMPARE_SET_ON_MATCH CCP_COMPARE_CLR_ON_MATCH CCP_COMPARE_INT CCP_COMPARE_RESET_TIMER CCP_PWM CCP_PWM_PLUS_1 (sólo si se utiliza un ciclo de trabajo de 8 bits) CCP_PWM_PLUS_2 (sólo si se utiliza un ciclo de trabajo de 8 bits) CCP_PWM_PLUS_3 (sólo si se utiliza un ciclo de trabajo de 8 bits) SET_PWM1_DUTY(value) SET_PWM2_DUTY(value) Estas funciones escriben los 10 bits de value al dispositivo PWM para establecer el ciclo de trabajo. Se puede usar un valor de 8 bits si no son necesarios los bits menos significativos. 3.3.3.8 Funciones para el manejo de la Eeprom interna READ_EEPROM(address) Esta función lee un byte en la dirección (address) de Eeprom especificada. La dirección puede ser 0-63. WRITE_EEPROM(address, value) Esta función escribe un byte de datos en la dirección de memoria Eeprom especificada. Value es el byte de datos a escribir.

3.3.4 Definición de datos Si TYPEDEF se pone delante de la definición de un dato, entonces no se asigna espacio de memoria al identificador a menos que sea utilizado como un especificador de tipo en otras definiciones de datos. Si delante del identificador ponemos CONST entonces, el identificador es tratado como constante. Las constantes deben ser inicializadas y no pueden cambiar en tiempo de ejecución. typedef

[calificador_tipo] [especificador_tipo] [identificador]

Especificadores de tipo: unsigned unsigned int int char long long int

define un número de 8 bits sin signo define un número de 8 bits sin signo define un número de 8 bits sin signo define un número de 8 bits sin signo define un número de 16 bits sin signo define un número de 16 bits sin signo 67

María Aranda Elcuaz

signed signed int signed long float short short int

Universidad Pública de Navarra

define un número de 8 bits con signo define un número de 8 bits con signo define un número de 16 bits con signo define un número de 32 bits en punto flotante define un bit define un bit

3.3.5 Definición de una función El formato de la definición de una función es como sigue: [calificador_tipo] identificador ([[especificador_tipo identificador]) { [cuerpo de la función] } El calificador_tipo para una función pueden ser void o un especificador de tipo (véase la lista de la página anterior) La definición de una función puede ir precedida por una de las siguientes directivas del preprocesador (calificadores de función) para identificar una característica especial de la función: #separate #inline #int_... Cuando utilizamos una de las directivas mencionadas y la función tiene un prototipo (declaración anterior a la definición de la función, y colocada al principio del fichero fuente) hay que incluir la misma #directiva en el prototipo y en la definición de la función. Una función que tiene un parámetro de tipo char aceptará una constante de cadena. El compilador generará un bucle que llama a la función una vez para cada carácter de la cadena.

3.3.6 Estructura de un programa en C Para crear un programa es necesario seguir los siguientes pasos: 1. Especificaciones del programa (qué se tiene que hacer) 2. Hacer organigrama 3. Escribir el código fuente 4. Compilar 5. Grabar el programa en el microcontrolador Como etapas previas a la escritura del código fuente, es importante tener muy claro que es lo que se pretende hacer, por eso, será conveniente realizar un listado con las órdenes necesarias para que el programa se lleve acabo, y realizar un organigrama o diagrama de flujo con el orden de las mismas, las condiciones, etc. De forma generalizada, la estructura de un programa en C tiene el siguiente aspecto: declaraciones globales prototipos de funciones

68

María Aranda Elcuaz

Universidad Pública de Navarra

main() { variables locales; bloque de sentencias; llamadas a las funciones; } funcion_1() { variables locales a funcion_1; bloque de sentencias; llamada a otra/s funciones; } funcion_n() { … }

69

María Aranda Elcuaz

Universidad Pública de Navarra

Capítulo 4. Prácticas 4.1 Entradas Digitales El objetivo de esta práctica es tener una primera toma de contacto con todos los elementos que se irán empleando a lo largo de los distintos ejercicios planteados en este capítulo. Para ello se van a realizar distintos ejemplos que trabajan con entradas digitales cuyo resultado se visualizará mediante unos leds. El trabajo con entradas digitales es, posiblemente, el ejercicio más sencillo que se puede plantear. Además, se realizará una comparación entre el diseño de los programas en lenguaje C y lenguaje ensamblador para demostrar la eficiencia del ensamblador frente a la comodidad del C.

4.1.1 Control de tiempos: Parpadeo de un led Diseñar un programa que encienda y apague el led de la placa de entrenamiento PICDEM 2 PLUS conectado al bit 0 del puerto B del microcontrolador cada 65 milisegundos. 4.1.1.1 Organigrama

Inicio Puerto B: Salida Inicialización de registros Encender Led Retardo 65 ms Apagar Led Retardo 65 ms

4.1.1.2 Solución en ensamblador Para el correcto diseño de este programa habrá que seguir estos tres simples pasos: 1º) Configurar el puerto B como salida 2º) Cambiar el estado de los leds de encendido a apagado 3º) Generar una rutina de retardo entre ambos estados 70

María Aranda Elcuaz

Universidad Pública de Navarra

Para generar una rutina de retardo correcta habrá que tener en cuenta la fórmula dada en el apartado 2.4.2.3 de la memoria: Tiempo = 4 · Tosc · (Valor cargado en TMR0) · (Rango del Divisor) Valor a cargar en TMR0 = (tiempo / 4 · Tosc) · (Rango del Divisor) Como en la placa PICDEM se tiene un cristal que trabaja a una frecuencia de 4 MHz, el valor de Tosc será de 0,25 microsegundos. Por otra parte, el rango del divisor será el máximo, es decir, 1:256. Y por último, para llegar a los 65 milisegundos habrá que cargar al TMR0 con 255: Tiempo = 4 · 0,25us · 255 · 256 = 0,06528 s = 65,28 ms Aquí se observa ya la primera desventaja del lenguaje ensamblador. Como se puede observar el resultado no es del todo exacto, será una aproximación. En el lenguaje C, tal y como se verá en el siguiente punto, existe una función que directamente introduce un retardo de 65 ms, el resultado no sólo es más exacto sino que también es más directo ya que no será necesario realizar ningún cálculo previo. Nota: Una vez que el TMR0 se desborda se enciende la bandera que se encuentra en el bit 2 del registro INTCON, bandera que habrá que no se apaga sola, por tanto habrá que apagarla por software. Dicho todo esto el programa que da solución al problema planteado en ensamblador quedaría de la siguiente manera: <1a-ensamblador.asm> LIST P=16F877 INCLUDE"P16F877.INC" #define #define

INIC

BANK1 bsf STATUS,5 BANK0 bcf STATUS,5

;Macro para abreviar el BANCO 1 ;Macro para abreviar el BANCO 0

org

0

BANK1 clrf movlw movwf BANK0 clrf

;Selección del Banco 1 TRISB ;Se configura todo el puerto B como salida b'11010111' ;Se configura el registro OPTION_REG ;OPTION:TMR0:Preescaler 256 ;Selección del Banco 0 PORTB ;Apaga todos los leds del puerto B

PARPA bsf call bcf call goto

PORTB,0 RETAR PORTB,0 RETAR PARPA

RETAR clrf TMR0 LOOP btfss INTCON,2 goto LOOP bcf INTCON,2 return end

;Posición 0 de la memoria de programa

;Enciende el led RB0 ;Llama a la rutina de RETARDO ;Apaga el led RB0 ;Llama a la rutina de RETARDO ;Comienza de nuevo el ciclo PARPA ;TMR0=0 y empieza su incremento ;Se ha desbordado? ;No, repite el proceso ;Si, se pone el flag a 0 ;retorna al programa principal ;fin de programa

71

María Aranda Elcuaz

Universidad Pública de Navarra

Inicialmente en el programa se llama a la librería del microcontrolador donde tiene configuradas las direcciones de todos los registros del PIC y después se pasa al programa principal donde se distinguen tres fases bien diferenciadas. La primera fase configura el puerto B como salida y el registro de opciones para la correcta configuración del temporizador TMR0. En la segunda fase estaría el programa principal, enciende y apaga el leds y llama a la rutina de retardos y finalmente, en la tercera fase se expone la rutina del retardo. Por último, cabe destacar que en este programa no se ha definido la palabra de configuración, y no importa siempre que se defina desde el programa MPLAB donde habrá que seleccionar el oscilador adecuado y deshabilitar el resto de las opciones. 4.1.1.3 Solución en C Para el correcto diseño de este programa en lenguaje C habrá que seguir exactamente los mismos pasos seguidos anteriormente en el lenguaje ensamblador: 1º) Configurar el puerto B como salida 2º) Cambiar el estado de los leds de encendido a apagado 3º) Generar una rutina de retardo entre ambos estados Sin embargo, como se ve a continuación, el lenguaje C es mucho más breve y más fácil de comprender. Por lo tanto, a la hora de pensar el diseño de un programa será más rápido y sencillo realizarlo en C que en ensamblador. //Programa 1a-c.c – Parpadeo de un led cada 65 ms// #include <16F877.h> #fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP #use delay(clock=4000000) #use fast_io(B) void main() // Programa principal { set_tris_b(0); // Configura el puerto B como salida while (1) // Bucle infinito { output_B(1); // Enciende el led RB0 delay_ms(65); // Retardo de 65ms output_B(0); // Apaga todos los leds delay_ms(65); // Retardo de 65ms } } // Fin del programa

De este programa no queda mucho por comentar, la presentación es muy clara y se han añadido los comentarios correspondientes tras cada función en el propio programa. A simple vista parece que el programa planteado en C ocupa mucho menos que el programa diseñado en ensamblador, pero en la realidad no es así, una vez traducidos a código máquina, el programa en C ocupa 312 bytes mientras que el programa en lenguaje ensamblador ocupa 103 bytes. Si empleásemos un programa para desensamblar el código en C y traducirlo a ensamblador se podría ver como en realidad para realizar el mismo trabajo se necesitan

72

María Aranda Elcuaz

Universidad Pública de Navarra

más instrucciones. La flexibilidad del C tiene su precio en cuanto a tamaño de código y tiempo de ejecución.

4.1.2 Encendido de un led a través de un pulsador Diseñar un programa en c y ensamblador que encienda el led RB1 después de presionar el pulsador RA4. 4.1.2.1 Organigrama Inicio PIN A4: Entrada Puerto B: Salida Inicialización de registros

Chequeo pulsador

¿Han pulsado?

No

Apagar led

Sí Retardo para evitar rebotes Encender led

4.1.2.2 Solución en ensamblador Para dar solución a este problema se deben seguir los siguientes pasos: 1º) Configurar el 4º bit del Puerto A como entrada 2º) Configurar el Puerto B como salida 3º) Generar un pequeño retardo para evitar rebotes después de presionar el pulsador y así no confundir al microcontrolador El programa queda resuelto en lenguaje ensamblador de la siguiente manera: <1b-esamblador.asm> LIST P=16F877 INCLUDE"P16F877.INC" #define #define

BANK1 bsf STATUS,5 BANK0 bcf STATUS,5

;Macro para abreviar el BANCO 1 ;Macro para abreviar el BANCO 0 73

María Aranda Elcuaz

INIC

org

0

BANK1 clrf movlw movwf movlw

TRISB b'00001000' TRISA b'11010010'

movwf OPTION_REG BANK0 WAIT

clrf PORTB btfsc PORTA,4 goto call

WAIT RETAR

PULSA bsf PORTB,1 btfss PORTA,4 goto call

PULSA WAIT

RETAR clrf TMR0 LOOP btfss INTCON,2 goto LOOP bcf INTCON,2 return end

Universidad Pública de Navarra ;Posición 0 de la memoria de programa ;Seleccion del Banco 1 ;Configura el puerto B como Salida ; ;Configura el pulsador en RA4 como Entrada ;Se configura el registro ;OPTION:TMR0:Preescaler 8 ; ;selección del Banco 0 ;Apaga los LEDS borrando el puerto B ;Lee el interruptor y espera a que sea "0". Han ;pulsado? ;No han pulsado, va a la etiqueta WAIT ;Si han pulsado, llama a la rutina de RETARDO ;Bit 1 del PUERTO B "1". Enciende el LED ;Lee el interruptor y espera a que sea "1". Han ;soltado? ;No, va a la etiqueta PULSAR ;Si, va a la etiqueta WAIT ;TMR0=0 y empieza su incremento ;Se ha desbordado? ;No, repite el proceso ;Si, se pone el flag a 0 ;retorna al programa principal ;fin de programa

De la misma manera que en el problema anterior, inicialmente se configura el puerto B como salida, así como el registro de opciones para el TMR0. Posteriormente llega el programa principal donde se lee el estado del pulsador y se actúa en consecuencia. Finalmente una rutina de retardo que es llamada desde el programa principal, esta vez, debido a que será necesario un retardo para que los posibles rebotes que se puedan producir al presionar el pulsador no confundan al microcontrolador. 4.1.2.3 Solución en c Para conseguir una solución en lenguaje C habrá que pensar en introducir en el programa una secuencia condicional que revise los dos estados del pulsador y actúe en consecuencia tras hacer todas las configuraciones que sean necesarias. El problema planteado podría tener el siguiente diseño: <1b-c.c> #include <16F877.h> #fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP #use delay(clock=4000000) #use fast_io(A) #use fast_io(B) #byte port_a=0X05 #byte port_b=0X06 void main() { set_tris_a(0xFF); //Puerto A como entrada set_tris_b(0x00); //Puerto B como salida port_b=0; for(;;) //Bucle infinito 74

María Aranda Elcuaz

Universidad Pública de Navarra

{ if(!input(PIN_A4)) //Si se ha pulsado hacer... { delay_us(50); //meter un tiempo para los rebotes output_high(PIN_B0); //encender led } else //Si no { output_low(PIN_B0); //apagar el led } } }

Como conclusión, cabe indicar que la solución a estos problemas no es exclusiva; se ha puesto una posible solución y por supuesto, habrá otras distintas igualmente válidas. El objetivo de esta práctica era doble: 1º) Que el alumno tome contacto con las prácticas con dos simples ejemplos, conociendo ya de forma práctica el microcontrolador, la placa de pruebas y los lenguajes de programación. 2º) Una muestra de que el lenguaje C en el caso de este proyecto tiene más ventajas que inconvenientes: Se ha comprobado que el lenguaje C ocupa un mayor espacio en la memoria del PIC que el programa en lenguaje ensamblador. Los microcontroladores tienen una capacidad de memoria limitada pero cada día salen al mercado nuevos modelos con mayor capacidad y no por ello aumentan su tamaño. Además por muy extensas que puedan llegar a ser las prácticas aquí planteadas, al compilar el programa se comprueba que el tamaño de código no llega en ningún caso a ocupar un 80% de la memoria del PIC. También es cierto que los tiempos de demora en lenguaje C son superiores a los del lenguaje ensamblador, pero en estos ejemplos las soluciones obtenidas se plantean para ser observadas por el propio ojo humano, con lo cual, estos tiempos de demora tampoco son excesivamente importantes. En contraposición, se piensa que el lenguaje C es más comprensible y puede ahorrar al diseñador tiempo de trabajo. Por todo esto, se toma la determinación a partir de este punto de resolver las prácticas únicamente en lenguaje C.

75

María Aranda Elcuaz

Universidad Pública de Navarra

4.2 LCD y Memoria Eeprom En la práctica anterior ya se ha visto como se utilizaba la librería del PIC 16F877, librería que se puede encontrar en el Anexo 1. Esta librería contiene el nombre y la dirección de todos los registros del PIC así como la definición de una serie de funciones que facilitarán el manejo de temporizadores, entradas analógicas y otra serie de recursos que se irán viendo a lo largo del resto de prácticas. El caso de las pantallas LCD es un poco especial porque no todas son iguales y aunque así lo fueran no tienen porque estar conectadas a la placa de la misma manera. Ya se ha visto en el apartado 3.1 la conexión de la pantalla en la placa PICDEM 2 PLUS, consultando el archivo “lcd.c” que se puede encontrar en la carpeta donde se instaló el compilador se observa que las conexiones de la pantalla definidas no son exactamente iguales por eso habrá que modificarlo con las conexiones de la placa PICDEM. Al archivo modificado se le ha llamado “lcd-picdem.c” y se puede encontrar también en el Anexo 1. Entonces, para poder emplear la pantalla LCD habrá que incluir dicho archivo en la cabecera del programa. El objetivo de esta práctica es conocer las conexiones del LCD, cómo funciona, su librería LCD y aprender a manejar las funciones incluidas en ella y además la grabación en la memoria EEPROM del PIC que se verá en el punto siguiente.

4.2.1 Envío de mensajes al LCD Tras leer y comprender el archivo “lcd-picdem.c”, crear un programa que muestre en la pantalla LCD los siguientes mensajes solamente una vez: 1. Un saludo centrado, por ejemplo: Hola 2. Escribir el abecedario letra a letra en toda la pantalla y llenar los huecos finales con números. Entre letra y letra meter una pausa de 0,5 s. 3. Terminar con una despedida centrada en la segunda línea. 4.2.1.1 Organigrama

Inicio Definir vector Inicializar variables y LCD Enviar mensaje 1 Retardo 5000 ms

76

María Aranda Elcuaz

Universidad Pública de Navarra

Borrar Pantalla

Situar cursor Enviar carácter Retardo 0,5 s

¿Último carácter?

No

Sí Borrar pantalla Situar cursor Enviar menaje 3 Retardo 5000 ms

4.2.1.2 Solución Para que este programa funcione correctamente primero habrá que inicializar la pantalla con su correspondiente función en el programa principal. Los mensajes primero y tercero son simples, bastará una función para enviarlos y el suficiente retardo para que la vista de cualquier persona sea capaz de percibirlo. Sin embargo, el segundo mensaje será un poco más complicado, primeramente habrá que definir un vector de caracteres que contenga el abecedario y todos los números a enviar. Posteriormente, y ya en el programa principal, habrá que generar un bucle para ir moviéndose a lo largo de toda la pantalla y asimismo meter el retardo solicitado de 0,5s entre el envío del primer carácter y el segundo. Dicho todo esto el programa pedido quedaría de la siguiente manera: <2lcd.c> #include <16F877.h> #use delay(clock=4000000) #include //Archivo de config de la pantalla #fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP char vector[]={' ','a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5', '6'}; 77

María Aranda Elcuaz

Universidad Pública de Navarra

void main() { int i,j=1; lcd_init(); lcd_putc(" Hola delay_ms(5000);

//Inicia la pantalla ");

lcd_putc("\f");

//Envía Hola //Pausa de 5 segundos //Borra Pantalla

for(i=1;i<33;i++) //Recorre las 32 posiciones del LCD { if(j==1) //Si esta en la linea 1 { lcd_gotoxy(i,j); //Ir a la posición i,j } else { lcd_gotoxy((i-16),j); //Sino a la posición i-16,j } printf(lcd_putc,"%c", vector[i]); //Escribir el carácter i delay_ms(500); //Pausa de 0,5s if(i==16) { j=2; //Después del carácter 16 pasar a la //2 línea } } //Fin del bucle lcd_putc("\f"); lcd_gotoxy(1,2); lcd_putc(" Adios! delay_ms(5000);

");

//Vuelve a borrar pantalla //Y coloca el cursor en la segunda //línea //Envia Adios //Pausa de 5 segundos

}

Como se puede comprobar en este ejercicio se desarrollan la mayoría de funciones definidas para el LCD: - Inicialización de la pantalla (lcd_init()) - Posicionamiento del cursor (lcd_gotoxy(x,y)) - Envío de comandos al LCD (lcd_putc(“\f”)) - Escritura en pantalla: - Constantes (lcd_putc(" Adios! ")) - Vectores (printf(lcd_putc,"%c", vector[i])) Es un ejercicio sencillo pero muy completo a la vez en lo que al funcionamiento del LCD se refiere.

4.2.2 Programación de la EEPROM Tal y como se ha visto en el punto 2.3.2 de este documento, la memoria de datos EEPROM posee 256 bytes en el PIC16F877 donde puede almacenar de forma indefinida cualquier dato que se desee retener cuando se apague la alimentación. Para recordar el funcionamiento interno de esta memoria basta consultar el punto 2.5.8 también en este documento.

78

María Aranda Elcuaz

Universidad Pública de Navarra

Para poner en práctica la programación de la memoria EEPROM, y aprovechando que se conoce ya como mostrar datos en la pantalla LCD de la placa de pruebas, se va a realizar un programa que controle el funcionamiento de una máquina de “Su turno” que se puede encontrar habitualmente en cualquier establecimiento comercial. Sobre el LCD se visualizará el número del turno actual (2 dígitos). Este se deberá incrementar a cada pulso aplicado por RA4. En la memoria EEPROM del PIC16F877 se almacenará el último número visualizado, de forma que, ante un fallo de alimentación por ejemplo, se reanude la cuenta en el último número. ¿Qué sucede al pulsar el reset?, ¿Se reinicia el programa? 4.2.2.1 Organigrama

Inicio Pin A4: Entrada Iniciar LCD Leer EEPROM No

Turno>99? Sí Turno = 1

Posicionar cursor Escribir LCD Chequeo Pulsador

¿Han pulsado? Sí

No

Retardo rebotes Incrementar turno Turno>99?

No

Sí 79

María Aranda Elcuaz

Universidad Pública de Navarra

Turno = 1

Escribir EEPROM

Situar Cursor Enviar turno al LCD 4.2.2.2 Solución Para diseñar este programa será necesario conocer las funciones para el manejo de la Eeprom que se pueden encontrar en el capítulo del lenguaje C. Por otra parte, se recomienda generar una rutina que coloque el cursor en todo momento para sobrescribir el número y que a su vez lo muestre a través de la pantalla LCD; A esta rutina se le podrá llamar cuando sea necesario. A continuación, se presenta una solución posible al problema planteado: <2eeprom.c> #include <16f877.h> #use delay(clock=4000000) #fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP #use fast_io(A) #include int turno; void Visualizar_Turno() //Rutina para mandar el turno al LCD { lcd_gotoxy(8,1); printf (lcd_putc,"%U", turno); } void main() { set_tris_a(0b00010000); lcd_init();

//PIN RA4 como entrada

// Comandos de inicialización del LCD.

lcd_putc("Turno: "); turno = read_eeprom(0); if((turno<1)||(turno>99)) { turno=1; } Visualizar_Turno();

//Lee la posición 0 de la EEPROM //Poner a 1 si está fuera del rango

//Ver el turno

while(1) { if(!input(PIN_A4)) { delay_ms(90); //Retardo para evitar rebotes 80

María Aranda Elcuaz

}

}

Universidad Pública de Navarra

turno++; //Incrementar turno if(turno>99) //Si es mayor de 99 volver a 1 { lcd_gotoxy(9,1); lcd_putc(" "); turno=1; } write_eeprom(0,turno); //Escribir el valor en la eeprom Visualizar_Turno(); //Visualizarlo en el LCD

}

En la cabecera del programa se hacen las configuraciones pertinentes y se incluyen los archivos necesarios para el correcto funcionamiento de las funciones incluidas en el programa principal tal y como se hacía hasta ahora. Después se expone la subrutina que escribirá el valor en la LCD cada vez que se pulse RA4 y que se llamará durante el programa principal. En el programa principal, tras configurar el PIN RA4 como entrada y la inicialización del LCD se lee la EEPROM para comprobar el último número que leyó la maquina antes de perder la alimentación si ese valor no está dentro del rango [01-99] se inicializa a 1 y se visualiza el turno por la LCD. Después siempre que se pulse RA4, incrementará el turno en una posición, se mostrará en la LCD y se grabará en la memoria EEPROM por si hay fallos en la alimentación. Al pulsar el botón de reset, evidentemente sí que se reinicia el programa aunque la placa de pruebas no parezca mostrar cambios. Si el contador no se pone a 01 es precisamente porque el último valor antes de presionar el pulsador del reset fue memorizado en la Eeprom.

81

María Aranda Elcuaz

Universidad Pública de Navarra

4.3 Entradas analógicas: Potenciómetro Como ya se ha comentado en el capítulo 2 de la memoria, el PIC16F877 posee 8 pines situados en las puertas A y E que pueden trabajar de manera analógica. Conectado al pin RA0 del microcontrolador, la placa de pruebas PICDEM 2 PLUS posee un potenciómetro con una resistencia R16 de 5 kΩ que puede oscilar entre 0 y +5V con ayuda de una ruleta. La figura siguiente indica la conexión del potenciómetro al microcontrolador:

Con la ayuda de este potenciómetro en esta práctica se pretende visualizar, a través del LCD de la placa de pruebas, el voltaje que cae en dicha resistencia en tiempo real según la posición en que se deje la ruleta que lo controla. 4.3.1 Organigrama Inicio Definir constantes y variables Iniciar pantalla

Situar cursor Encender ACD Seleccionar terminales analógicas

82

María Aranda Elcuaz

Universidad Pública de Navarra

Seleccionar canal Hacer conversión AD Escalar valores Enviar datos al LCD Retardo 10 ms

4.3.2 Solución Para la realización de este programa habrá que tener en cuenta varias cosas expuestas ya en el punto 2.5.2 pero que es conveniente recordar: Primero, el PIC 16F877 posee una resolución de hasta 10 bits para el resultado de la conversión A/D, si en el compilador no se pone nada, da por hecho que la resolución que se desea obtener es de 8 bits, si se prefiere una resolución de 10 bits habrá que especificarlo. En este caso una resolución de 8 bits será suficiente para obtener resultados satisfactorios y la instrucción #device adc no sería necesaria pero se ha querido poner igualmente. Segundo, habrá que configurar los puertos que se desean emplear de forma analógica, el conversor analógico digital y especificar el canal a utilizar que en este caso será el 0. Finalmente, cabe recordar que habrá que escalar la lectura obtenida. Se ha elegido una resolución de 8 bits, por lo tanto el fondo de escala será de 255. Por otro lado el rango de voltaje va desde 0 V hasta +5 V, por lo tanto bastará multiplicar el valor obtenido por 5 y dividirlo entre el fondo de escala. Para hacer esta operación se puede crear una subrutina que haga el cálculo y se le llame desde el programa principal. Un programa que podría dar solución al problema queda expuesto y explicado a continuación: #include <16F877.h> #device adc=8 #use delay(clock=4000000) #include #fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP const int escala = 255; const float v_max = 5.0; void calcula_voltaje (int val, float &voltaje) { voltaje=(val*v_max)/escala; } 83

María Aranda Elcuaz

Universidad Pública de Navarra

void main(void) { int valor; float voltaje; lcd_init(); lcd_putc('\f'); //Borra pantalla lcd_putc("voltios = "); lcd_gotoxy(16,1); lcd_putc("V"); for(;;) { lcd_gotoxy(11,1); setup_adc(adc_clock_div_32); //Enciende conversor setup_adc_ports(AN0); //Selecciona terminales set_adc_channel(0); // Selecciona canal

}

valor=read_adc(); // Conversión AD calcula_voltaje(valor,voltaje); printf(lcd_putc,"%1.2f",voltaje); delay_ms(10); }

Tras la cabecera de programa correspondiente se definen las constantes para el cálculo del voltaje y la subrutina que realiza el cálculo. Una vez en el programa principal, habrá que definir dos variables, la primera que será el valor obtenido en el conversor y la segunda el valor a mostrar por el LCD. Se inicializa la pantalla, se hacen las configuraciones pertinentes y una vez hecho todo esto ya se podrá leer el valor digital del conversor analógico digital, escalarlo y finalmente mostrarlo en pantalla.

84

María Aranda Elcuaz

Universidad Pública de Navarra

4.4 PWM Cuando se desea que el estado de un determinado pin del microcontrolador bascule entre 0 y 1 a intervalos variables de tiempo se emplea la modulación por anchura de pulsos. Para ver como funciona la PWM en detalle, además de lo dicho en capítulos anteriores de la memoria, se puede consultar el Anexo 2. En el microcontrolador puede generarse una salida PWM por el pin CCP1, que en este caso es RC2, utilizando TMR2, PR2 y el módulo CCP1. La secuencia es la siguiente: se incrementa TMR2, a su vez un comparador comprueba si el valor de TMR2 y el del registro de anchura de pulso (CCPR1L) son iguales. Cuando esto ocurre, el pin CCP1 pasa a nivel bajo. Al mismo tiempo un segundo comparador comprueba si son iguales TMR2 y PR2. Cuando lo son, CCP1 pasa a nivel 1 y TMR2 se pone a 0 para comenzar el siguiente periodo. Este proceso puede repetirse indefinidamente de forma automática, obteniendo de esta forma una salida modulada por anchura de pulso (PWM) en el pin CCP1. Gráficamente sería así:

PR2 CCPR1 TMR2

1

Para un primer acercamiento a la modulación por anchura de pulsos se plantea el siguiente ejercicio:

4.4.1 Primer acercamiento al PWM Con la ayuda de las dos siguientes fórmulas para el cálculo del valor a cargar en PR2 y en CCPR1L realizar un programa que trabaje con una frecuencia de 500 Hz y encienda el led RB1 cada 1ms inicialmente. Además se desea que presionando el pulsador RB0 el duty cambie a 1,5 ms y si se presiona RA4 el duty cambie a 250 ms. Variando el duty se conseguirán distintas intensidades para el led. Para el cálculo de PR2 se tiene que: T = (PR2+1)·4·Tosc·TMR2preescaler

85

María Aranda Elcuaz

Universidad Pública de Navarra

Para el cálculo del duty se tiene que: Duty = (CCPR1L:CCPCON1<5:4>)·Tosc·TMR2preescaler 4.4.1.1 Organigrama Inicio Configurar puertos Configurar CCP1 Elegir frecuencia Inicializar Duty

Comprobar pulsadores

RB0 ON?

No

Sí Cambiar duty a 1,5 ms

RA4 ON?

No

Sí Cambiar duty a 750 ms 4.4.1.2 Solución Para los cálculos de PR2 y CCPRL1 hay que tener en cuenta que el oscilador de la placa de pruebas PICDEM 2 PLUS trabaja a una frecuencia de oscilación de 4MHz y TMR2preescaler se le da el valor de 16. Con esto y despejando de las fórmulas dadas se obtiene que para una frecuencia de 500 Hz habrá que cargar PR2 con el valor 124. Por otro lado se trabajará con 8 bits por lo tanto los bits CCPCON1<5:4> se cargan con 00 y así despejando de la segunda fórmula dada se tendrá que los valores de CCPR1L serán de 62 para los 1 ms de salida, 94 cuando se pulsa RB0 y 16 al pulsar RA4. Teniendo esto y consultando las funciones a emplear en la modulación de anchura de pulsos en el capítulo 3.3.3 de la programación en lenguaje C se puede realizar ya el programa solicitado que podría quedar de la siguiente manera: 86

María Aranda Elcuaz

Universidad Pública de Navarra

<ejermod1.c> #include <16F877.H> #fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP #use Delay(Clock=4000000) #use fast_io(B) #byte PORTB=6 main() { PORTB=0b00000010;

}

setup_ccp1(CCP_PWM); setup_timer_2(T2_DIV_BY_16,124,1); set_pwm1_duty(62);

// Configura CCP1 como PWM // f=500Hz (T=2ms) // Duty=1ms de partida

while(1) { if(!input(PIN_B0) set_pwm1_duty(94);

// Duty=1,5ms

if(!input(PIN_A4)) set_pwm1_duty(16);

// Duty=250ms

}

En la cabecera tal y como se hacía hasta ahora se realizan las configuraciones necesarias para el PIC y para el empleo del puerto B como salida. Después se configura el led a utilizar y el CCP1 como PWM. Se carga la frecuencia de 500 Hz y el duty inicial para después entrar en un bucle infinito que cambie los dutys según se presione los distintos pulsadores. NOTA IMPORTANTE: CCP1 en este microcontrolador está situado en la patilla RC2, para obtener la salida en el led RB1 habrá que unirlos con un cable exterior. Trabajando con estos valores de frecuencias es imposible que el ojo humano perciba que el led se enciende y se apaga, en cambio, lo que sí se podrá observar es la intensidad de iluminación del led. A mayor tiempo de encendido el led mostrará mayor intensidad y viceversa.

4.4.2 PWM empleando entradas analógicas Trabajando a la misma frecuencia que se ha trabajado en el programa anterior (f = 500 Hz), ahora se va a seleccionar el duty con ayuda del potenciómetro conectado a RA0. Además para conocer con que duty se está trabajando en cada momento, habrá que mostrar dicho valor mediante la pantalla LCD que dispone la placa de pruebas. Para los cálculos de PR2 y CCPR1L emplear las fórmulas dadas en el ejercicio anterior. 4.4.2.1 Organigrama Inicio Definir constantes y variables

87

María Aranda Elcuaz

Universidad Pública de Navarra

Iniciar LCD Configurar CCP1 Seleccionar frecuencia Encender ADC Seleccionar terminales analógicos Seleccionar canal

Convertir AD Establecer Duty Escalar Duty Enviar datos al LCD

4.4.2.2 Solución Este ejercicio combina la mayor parte de lo visto hasta ahora ya que emplea entradas analógicas, trabaja con el LCD y además se introduce la modulación por anchura de pulsos. Tras la cabecera del programa habrá que generar una rutina que escale el duty tal y como se hacía para el voltímetro en la práctica 3. Habrá que realizar también las configuraciones pertinentes del LCD para mostrar resultados y finalmente todo lo que lleva relacionado el PWM consigo. Dicho todo esto, el programa solicitado podría tener la siguiente forma: <ejermod2.c> #include <16F877.H> #fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP #use Delay(Clock=4000000) #include #use fast_io(B) #byte PORTB=6 const float escala = 255; const float d_max = 1999; 88

María Aranda Elcuaz

Universidad Pública de Navarra

void calcula_duty (int val, float &duty) { duty=(val*d_max)/escala; } main() { int valor; float duty; PORTB=0b00000010; lcd_init(); lcd_gotoxy(1,1); lcd_putc(" f=500Hz->T=2ms "); lcd_gotoxy(1,2); lcd_putc("duty = us");

}

setup_ccp1(CCP_PWM); setup_timer_2(T2_DIV_BY_16,124,1);

// Configura CCP1 como PWM // f=500Hz (T=2ms)

setup_adc(adc_clock_div_32); setup_adc_ports(AN0); set_adc_channel(0);

// Selecciona Reloj // RA0 analogico

while(1) { valor=read_adc(); set_pwm1_duty(valor); calcula_duty(valor,duty); lcd_gotoxy(8,2); printf(lcd_putc,"%3.2f",duty); }

// Lee valor RA0 // Establece duty como valor // Escala el duty // Muestra el resultado

En este programa por lo tanto se tiene que observar la diferencia de intensidad en el led seleccionado según se mueve la ruleta, además de conocer en cada momento el duty con el que se está trabajando consultando el LCD. Se puede comprobar que cuando la ruleta se encuentra en el mínimo el led estará apagado y el duty será de 0 ms y cuando la ruleta se encuentre en su máximo el led permanecerá encendido a su máxima intensidad y el duty coincidirá con el valor del periodo de trabajo (2000 ms), puesto que el duty nunca podrá ser mayor que la frecuencia.

89

María Aranda Elcuaz

Universidad Pública de Navarra

4.5. Comunicación Serie PIC-PC (RS-232) Resulta de gran interés abrir las puertas de comunicación del microcontrolador para poder comunicarse no sólo con los elementos incluidos en la placa de pruebas dada sino también con elementos exteriores más potentes como puede ser un ordenador o cualquier elemento que sea poseedor también de un bus de comunicaciones. En esta práctica se pretende ver cómo el microcontrolador con ayuda de un cable serie y un sencillo programa informático de comunicación que incluye el propio Windows puede enviar datos al ordenador, éste los reconoce y a su vez puede enviar otros datos introducidos mediante el teclado que el microcontrolador también es capaz de reconocer. El programa informático al que se refiere en este documento es el HyperTerminal de Windows. Antes de comenzar con la práctica en sí conviene conocer las siguientes consideraciones: 1º) Para que dos dispositivos puedan transmitir datos entre sí será necesario que lo hagan a la misma velocidad, por lo tanto, al abrir el HyperTerminal habrá que asegurarse de poner las mismas configuraciones que de establezcan en el programa realizado en C. 2º) Para conectar el PC a un microcontrolador por el puerto serie se utilizan las señales Tx, Rx y GND. El PC utiliza la norma RS232, por lo que los niveles de tensión de los pines están comprendidos entre +15 y -15 voltios, los microcontroladores normalmente trabajan con niveles TTL (0-5v), será necesario por tanto intercalar un circuito que adapte los niveles:

3º) Ese circuito adaptador de niveles es en realidad un chip, que en el caso de la placa de prueba PICDEM 2 PLUS viene ya incrustado, se trata del chip MAX232 cuyo esquema se puede ver en la página siguiente. En el esquema se puede ver que lleva conectados 4 condensadores q serán necesarios para que las transmisiones se lleven a cabo. Además se observa como las patitas 13 y 14 están conectadas al puerto serie de la placa que comunicará como el ordenador y las patitas 11 y 12 están conectadas a las patitas RX (RC7) y TX (RC6) del microcontrolador. Todas estas observaciones realizadas en esta página junto con las nombradas en el apartado correspondiente de la programación en lenguaje C serán necesarias para llevar a cabo la práctica de manera satisfactoria.

90

María Aranda Elcuaz

Universidad Pública de Navarra

4.5.1 Un ejemplo sencillo Se propone a continuación un ejemplo sencillo y divertido para comprobar que efectivamente el microcontrolador y el ordenador son capaces de comunicarse entre sí. Para ello se creará un programa en C que pida el nombre del alumno en el HyperTerminal, espere una respuesta y después la muestre en el LCD de la placa de pruebas para así comprobar que el microcontrolador también es capaz de recibir la información. 4.5.1.1 Organigrama Inicio Declarar e iniciar variables Iniciar LCD Transmitir cadena a PC Escribir LCD

Recibir carácter RS232 Enviar carácter RS232 Situar cursor Escribirlo en la LCD

91

María Aranda Elcuaz

Universidad Pública de Navarra

4.5.1.2 Solución Si se han estudiado las funciones relacionadas con la comunicación serie el programa se diseña casi de manera inmediata como sigue: <1rs232.c> // Comunicación serie gestionada por software. #include <16f877.h> #use delay(clock=4000000) #use RS232(BAUD=9600, BITS=8, RESTART_WDT)

PARITY=N,

XMIT=PIN_C6,

RCV=PIN_C7,

#include main() { int x=1; char c; lcd_init(); puts("Escribe tu nombre: "); lcd_putc("Te llamas: "); while (1) { c = getc(); putc(c); lcd_gotoxy(x,2); lcd_putc(c); x++; if(x>16) { x=1; } } }

El programa como de costumbre empieza con la cabecera, donde es importante situar la directiva #use delay antes que la directiva del puerto serie para un funcionamiento correcto. En la directiva para el puerto rs232 la velocidad en baudios, la paridad y el número de bits pueden variar, en este ejercicio se han puesto los valores más empleados, aunque podrían ser otros sin afectar demasiado al funcionamiento del programa. Las patillas XMIT y RCV deben coincidir con los pines de transmisión serie definidos para cada microcontrolador. Una vez iniciada la pantalla, en el programa principal la función puts lo que hace es enviar la cadena de caracteres a la pantalla principal del Hyperterminal (programa que se recuerda debe estar configurado con las mismas opciones que se han definido en la directiva rs232) y la función put_lcd enviará lo que le sigue a la pantalla LCD. En este momento el programa queda esperando a recibir algo por el teclado. Una vez pulsada una tecla en el teclado, la función c=getc() hace que el microcontrolador reciba ese carácter y la siguiente función hace que se envíe en forma de 92

María Aranda Elcuaz

Universidad Pública de Navarra

eco a la pantalla del Hyperterminal. Después se coloca en la posición de pantalla correspondiente y las va escribiendo en el LCD.

4.5.2 PWM a distancia. Versión 1. Una vez visto el ejemplo anterior que explicaba de manera sencilla el funcionamiento del puerto serie se puede realizar cualquier ejemplo de mayor o menor complejidad que no debe entrañar ninguna dificultad para realizarlo por el alumno. Ya que en prácticas anteriores se ha visto el funcionamiento del PWM, aquí se va un poco más allá y se plantea un ejercicio de PWM a distancia. El programa deberá solicitar en el Hyperterminal las configuraciones necesarias de frecuencia y duty para mostrar el resultado en la pantalla del ordenador, lcd y el led RB1 tal y como se detalla a continuación: Inicialmente, ayudándose de la pantalla del Hyperterminal, se darán a elegir entre tres frecuencias posibles: -

Si se pulsa 1 se realizará la configuración para f = 500Hz Si se pulsa 2 se realizará la configuración para f = 2KHz Si se pulsa 3 se realizará la configuración para f = 20KHz Si se pulsa cualquier otra tecla se mostrará un mensaje de error y se volverá a pedir que se elija frecuencia

Además habrá que memorizar ese valor en la memoria Eeprom para posibles desconexiones de alimentación. Una vez establecida la frecuencia habrá que solicitar, también mediante la pantalla del Hyperterminal el duty con el que se quiere trabajar. -

Si se pulsa 1 se realizará la configuración para duty = 1,5ms Si se pulsa 2 se realizará la configuración para duty = 750us Si se pulsa cualquier otra tecla se mostrará un mensaje de error y se volverá a pedir que se elija duty

También en este caso habrá que memorizarlo en la memoria Eeprom y en ambos casos se deberá enviar también la frecuencia y duty seleccionados a la pantalla LCD. Por último ya que en cada caso se graba en la memoria Eeprom las configuraciones correspondientes, en el inicio del programa se deberá crear una secuencia que informe en la pantalla del Hyperterminal cuales eran las últimas configuraciones seleccionadas antes de la última desconexión y configurar con ellas el led. Nota de ayuda: Inicialmente este programa puede dar algunos errores debido a que el carácter que el PIC recibe viene dado en código ASCII y habrá que cambiarlo a número entero. Para solucionar esto no habrá que hacer grandes esfuerzos puesto que el compilador incluye en su librería stdlib.h una función que convierte el código ASCII a números enteros. Si se consulta esta librería rápidamente se descubre qué función realiza este

93

María Aranda Elcuaz

Universidad Pública de Navarra

trabajo. En el programa solicitado simplemente habrá que incluir esta librería y llamar a la función correspondiente cuando sea necesario. 4.5.2.1 Organigrama

Inicio Incluir librería LCD y RS232 Declarar variables Iniciar Pantalla y led Configurar CCP1 como PWM

Parte 1

Parte 2

Enviar cadenas para selección de frec al PC

Enviar cadenas para selección de duty al PC

Recibir respuesta vía RS232

Recibir respuesta vía RS232

Convertir ASCII a entero

Convertir ASCII a entero

Escribir EEPROM

Escribir EEPROM

Leer EEPROM Seleccionar frecuencia y duty Enviar datos al PC

No

¿Frecuencia correcta? Sí

No

¿Duty correcto? Sí

Seleccionar frecuencia (PR2)

Seleccionar duty (CCPR1L)

Mandar datos LCD

Mandar datos LCD

Mandar datos PC

Mandar datos PC

Parte 1 Parte 2

4.5.2.2 Solución Tras incluir en la cabecera las configuraciones y librerías necesarias, será necesario definir al menos 3 variables. Por un lado la cadena de caracteres que reconocerá que valor se ha introducido por teclado y por otro lado dos variables de entero largo que alberguen los valores recibidos convertidos a número entero. Después de la definición de las variables comienza el programa principal, que tras las configuraciones e inicio de pantalla debería leer la memoria Eeprom para mostrar los resultados de frecuencia y duty anteriores a la desconexión de la alimentación. Comienza el primer bucle, aquel que solicita una frecuencia hasta que el valor introducido es válido y seguirá tres pasos: 94

María Aranda Elcuaz

-

Universidad Pública de Navarra

Convierte el valor ASCII a número entero Memoriza el valor entero en la Eeprom Entra dentro de una condicional que configure PR2 como corresponda y muestre la selección por el led, la pantalla LCD y la pantalla del Hyperterminal

Cuando termina este bucle comienza otro exactamente igual, pero esta vez para la configuración del duty. Por lo tanto, una posible solución al problema planteado quedaría como sigue: #include <16f877.h> #fuses HS,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP #use delay(clock=4000000) #use RS232(BAUD=9600, BITS=8, RESTART_WDT)

PARITY=N,

XMIT=PIN_C6,

RCV=PIN_C7,

#use fast_io(B) #byte PORTB=6 #include #include <stdlib.h> char c[1]; long int k1,k2; main() { lcd_init(); lcd_gotoxy(1,1); PORTB=0b00000010; setup_ccp1(CCP_PWM);

// B1 será el led para la modulación // Configura CCP1 como PWM

//Esta parte hasta el bucle infinito comprueba la eeprom para saber con //que valores se trabajó anteriormente puts("La ultima vez se trabajo con:"); k1=read_eeprom(0); //Lee el valor de la última frecuencia seleccionada if (k1==1) { setup_timer_2(T2_DIV_BY_16,124,1); // f=500Hz (T=2ms) puts("Una frecuencia de 500 Hz"); } if (k1==2) { setup_timer_2(T2_DIV_BY_16,30,1); // f=2KHz (T=0,5ms) puts("Una frecuencia de 2 KHz"); } if (k1==3) { setup_timer_2(T2_DIV_BY_16,2,1); // f=20KHz (T=50us) puts("Una frecuencia de 20 KHz"); } k2=read_eeprom(1); // Lee el valor del último duty seleccionado if (k2==1) { set_pwm1_duty(94); // Duty=1,5ms puts("Y un duty de 1,5ms"); } if (k2==2) 95

María Aranda Elcuaz

Universidad Pública de Navarra

{ set_pwm1_duty(16); // Duty=750us puts("Y un duty de 750us"); } while(1) { parte1: puts("Pulsa 1, trabajar: "); puts("1. f=500Hz puts("2. f=2kHz puts("3. f=20kHz

2

o

3

segun

a

la

frecuencia

que

ahora

prefieras

(T=2ms=2000us)"); (T=0.5ms=500us)"); (T=50us)");

gets(c); k1 = atoi32(c); write_eeprom(0,k1);

//Convierte los ascii recibidos a numero entero. // Escribe k1 en la direccion 0 de la eeprom

lcd_gotoxy(1,1); if (k1==1) { setup_timer_2(T2_DIV_BY_16,124,1); // f=500Hz (T=2ms) puts("Has seleccionado la frecuencia de 500 Hz"); lcd_putc(" f=500Hz->T=2ms "); } if (k1==2) { setup_timer_2(T2_DIV_BY_16,30,1); // f=2KHz (T=0,5ms) puts("Has seleccionado la frecuencia de 2 KHz"); lcd_putc("f=2kHz->T=0.5ms "); } if (k1==3) { setup_timer_2(T2_DIV_BY_16,2,1); // f=20KHz (T=50us) puts("Has seleccionado la frecuencia de 20 KHz"); lcd_putc("f=20KHz->T=50us "); } if ((k1!=1)&(k1!=2)&(k1!=3)) { puts("Error: Frecuencia indebida, selecciona de nuevo"); goto parte1; } parte2: puts("Selecciona el duty pulsando 1 o 2: "); puts("1. Duty=1.5ms"); puts("2. Duty=750us"); gets(c); k2 = atoi32(c); //Convierte los ascii recibidos a un numero entero. write_eeprom(1,k2); // Escribe k2 en la direccion 1 de la eeprom lcd_gotoxy(1,2); if (k2==1) { set_pwm1_duty(94); puts("Has seleccionado el lcd_putc(" Duty = 1.5ms } if (k2==2) { set_pwm1_duty(16); puts("Has seleccionado el lcd_putc(" Duty = 750us

duty de 1.5ms"); ");

duty de 750us"); ");

// Duty=1,5ms

// Duty=750us

96

María Aranda Elcuaz

Universidad Pública de Navarra

} if ((k2!=1)&(k2!=2)) { puts("Duty incorrecto, selecciona de nuevo"); goto parte2; } puts(" "); } }

4.5.3 PWM a distancia. Versión 2. El programa realizado en el punto anterior es interesante pero demasiado largo y poco práctico debido a que solo se pueden seleccionar tres diferentes tipos de frecuencia y dos de duty. El problema está en que se emplea una función que escribe carácter a carácter y no por bloques. Si se sustituye la función de escritura por printf se soluciona dicho problema y se puede obtener un programa más corto y con un rango de elección de la configuración mucho más amplio. Así pues, en este programa se pide: 1º) Pedir por pantalla una frecuencia en Hz que esté dentro del rango admisible, si no es así, mostrar un mensaje de error y volver a solicitarla. 2º) Pedir por pantalla un duty que esté dentro del rango admisible, si no es así, mostrar un mensaje de error y volver a solicitarlo. 3º) Mostrar las configuraciones mediante el led, la pantalla LCD y en la pantalla del Hyperterminal mostrar además los valores obtenidos para PR2 y CPR1L. 4.5.3.1 Organigrama

Inicio Incluir librería LCD y RS232 Declarar variables Iniciar Pantalla y led Configurar CCP1 como PWM Seleccionar duty Enviar datos al PC Parte 1 Parte 2

97

María Aranda Elcuaz

Universidad Pública de Navarra

Parte 1

Parte 2

Enviar cadenas para selección de frec al PC

Enviar cadenas para selección de duty al PC

Recibir respuesta vía RS232

Recibir respuesta vía RS232

Convertir ASCII a entero

Convertir ASCII a entero

Calcular PR2

Calcular CCPR1L No

No

¿PR2 válido?

¿CCPR1L correcto?





Seleccionar frecuencia

Seleccionar duty

Mandar datos LCD

Mandar datos LCD

Mandar datos PC

Mandar datos PC

4.5.3.2 Solución El problema en este caso conlleva algún cambio más respecto al anterior. Habrá que definir una cadena de caracteres más larga y una vez introducida habrá que operar con ella para obtener los valores correspondientes de PR2 y CCPR1L, ya que esta vez no son inmediatos. #include <16f877.h> #fuses HS,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP #use delay(clock=4000000) #use RS232(BAUD=9600, BITS=8, RESTART_WDT)

PARITY=N,

XMIT=PIN_C6,

RCV=PIN_C7,

#use fast_io(B) #byte PORTB=6 #include #include <stdlib.h> char frec[5]; long int k1,K2,PR2,CCPR1L; 98

María Aranda Elcuaz

Universidad Pública de Navarra

main() { lcd_init(); lcd_gotoxy(1,1); lcd_putc("F=

Hz");

lcd_gotoxy(1,2); lcd_putc("Duty=

us");

PORTB=0b00000010; setup_ccp1(CCP_PWM);

// B1 led para la modulación // Configura CCP1 como PWM

puts("Ejercicio de PWM a distancia."); set_pwm1_duty(0);

// Frecuencia 0 de partida

while(1) { parte1: puts("Elige la frecuencia que prefieras trabajar en Hz y pulsa INTRO: "); gets(frec); k1 = atoi32(frec); //Convierte ascii a un numero entero. printf("%Lu" " Hz", k1); puts(" "); PR2=(62500/k1)-1; if ((PR2<0)|(PR2>255)) { puts("Frecuencia indebida, seleccione de nuevo una frecuencia"); goto parte1; } if ((PR2>0)&(PR2<256)) { setup_timer_2(T2_DIV_BY_16,PR2,1); printf(" por tanto, PR2=" "%Lu", PR2); puts(" "); } lcd_gotoxy(4,1); printf(lcd_putc,"%Lu",k1); parte2: puts("Elige el duty en us y pulsa INTRO: "); gets(frec); k2 = atoi32(frec); printf("%Lu" " us", k2); puts(" ");

//Devuelve el dato recibido

CCPR1L=k2/16; if ((CCPR1L<0)|(CCPR1L>255)) { puts("Duty incorrecto, repite el proceso"); goto parte2; } if ((CCPR1L>0)&(CCPR1L<256)) { set_pwm1_duty(CCPR1L); printf(" por tanto, CCPR1L=" "%Lu", CCPR1L); puts(" "); } lcd_gotoxy(7,2); printf(lcd_putc,"%Lu",k2); 99

María Aranda Elcuaz

Universidad Pública de Navarra

puts("Muy bien, ahora comprueba el resultado en la placa."); puts(" "); } }

100

María Aranda Elcuaz

Universidad Pública de Navarra

Capítulo 5. Comunicaciones CAN 5.1 Introducción 5.1.1 El CAN y su historia El CAN (Controller Area Network) es un bus de comunicaciones serie en tiempo real originalmente desarrollado en la automoción alemana a mediados de los años 80 por Robert Bosch. Su objetivo principal era hacer los automóviles más seguros, fiables y con un gasto de combustible más eficiente mientras se reducía el peso y la complejidad de los mismos. Algunos años importantes para el CAN son: - 1983: Comienzo del proyecto interno de Bosch para vehículos - 1987: Primeros controladores CAN desde Intel y Philips - 1991: Se publica la especificación 2.0 - 1992: Se establece la CiA (CAN in Automation) y el CAN comienza a emplearse en los automóviles de la casa Mercedes - 1993: se publica el estándar ISO 11898 - 1995: se añade la trama extendida a la ISO 11898 A pesar de que hoy en día el 80% de las aplicaciones CAN están en la industria automovilística, el protocolo CAN también se ha ido extendiendo a otros mercados:

5.1.2 Aplicaciones Como ya se ha comentado anteriormente, la mayor parte de las aplicaciones que posee el CAN están concentradas en la industria automovilística donde realiza el control del motor, de la mecánica del automóvil así como los sistemas de entretenimiento. Relacionado con la industria automovilística, el CAN se extiende al transporte público y otras máquinas móviles como aviones, helicópteros, trenes y los controles de tráfico y sistemas de información conductor/pasajero. Pero en general el CAN se aplica en cualquier sistema de control industrial: sistemas de control de plantas y maquinaria, redes entre máquinas, sistemas de supervisión… y en la automatización de edificios: control de ascensores, aire acondicionado, sistemas de calefacción y refrigeración, control de iluminación… En resumen, en cualquier sistema que precise control en tiempo real distribuido y con escaso flujo de datos.

5.2 Características del bus CAN El bus CAN es un bus serie de transmisión de datos en tiempo real que sigue la norma ISO 11898 y sus características son:

101

María Aranda Elcuaz

Universidad Pública de Navarra

1. La comunicación está basada en mensajes y no en direcciones, todos los nodos CAN son capaces de transmitir y recibir datos y varios pueden acceder al bus de datos simultáneamente. No hay sistema de direccionamiento de los nodos en el sentido convencional y los mensajes se envían según su prioridad: Un nodo emisor envía el mensaje a todos los nodos de la red, cada nodo, según el identificador del mensaje, lo filtra y decide si debe procesarlo inmediatamente o descartarlo. Este identificador es quien determina la prioridad que determina que mensaje accede primero al bus.

Figura 5.2a 2. Flexibilidad: Se pueden añadir nodos adicionales al bus sin necesidad de reprogramar todo el sistema para que se reconozcan los nuevos nodos. 3. Gran fiabilidad en la transmisión: - Detecta errores, los señaliza, envía mensaje de error y reenviará el mensaje corrupto una vez que el bus vuelva a estar activo - Distingue entre errores temporales y errores permanentes desconectando automáticamente los nodos defectuosos. - Puede operar en ambientes con condiciones extremas de ruido e interferencias. 4. La velocidad de transmisión depende de la longitud de la red. Cada red puede alcanzar los 1000 metros de longitud.

Figura 5.2.b

5.3 Arquitectura de capas La arquitectura del protocolo CAN está basada en capas y permite la interoperabilidad entre productos de diferentes manufacturas gracias a la creación del modelo de referencia 102

María Aranda Elcuaz

Universidad Pública de Navarra

OSI (Open System Interconection, ISO 7498). Este modelo implementa las dos capas inferiores del protocolo CAN, la capa física y la capa de enlace de datos.

5.3.1 Capa física La capa física es responsable de la transferencia de bits entre los distintos nodos que componen la red. Define aspectos como niveles de señal, codificación, sincronización y tiempos en que los bits se transfieren al bus. En la especificación original de CAN, la capa física no fue definida, permitiendo diferentes opciones para la elección del medio y niveles eléctricos de transmisión. Las características de las señales eléctricas en el bus fueron establecidas más tarde por el estándar ISO 11898 y su modelo de referencia OSI. Además, ahí se especifica tres niveles con distintas funciones cada uno. Los distintos niveles de la capa física son:

Figura 5.3.1.a Los nodos conectados al bus interpretan dos niveles lógicos denominados: Dominante: la tensión diferencial (CAN_H - CAN_L) es del orden de 2.0 V con CAN_H = 3.5V y CAN_L = 1.5V (nominales). Recesivo: la tensión diferencial (CAN_H - CAN_L) es del orden de 0V con CAN_H = CAN_L = 2.5V (nominales). La codificación de bits se realiza por el método NRZ (Non-Return-to Zero) que se caracteriza por que el nivel de señal puede permanecer constante durante largos periodos de tiempo y habrá que tomar medidas para asegurarse de que el intervalo máximo permitido entre dos señales no es superado. Esto es importante para la sincronización. No hay flanco de subida ni de bajada para cada bit, durante el tiempo de bit hay bits dominantes (“0”) y recesivos (“1”) y disminuye la frecuencia de señal respecto a otras codificaciones (como la codificación Manchester, por ejemplo).

103

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 5.3.1.b

5.3.2 Capa de enlace de datos La capa de enlace es responsable del acceso al medio y el control lógico y está dividida a su vez en dos niveles. El primero sería el LLC, Logical Link Control, que se dedica al filtrado de aceptación, la notificación de sobrecarga y a la gestión de recuperación. El segundo nivel es el MAC, Médium Access Control, dedicado al encapsulado y desencapsulado de datos, codificación de las tramas, gestión de acceso al medio, detección y señalización de errores, acuses de recibo… Todo esto se irá viendo en los puntos posteriores de este capítulo.

5.4 Mensajes y tipos de tramas Como se ha comentado en el apartado de características, el protocolo CAN está basado en mensajes no en direcciones. El nodo emisor transmite el mensaje a todos los nodos de la red sin especificar un destino y todos ellos escuchan el mensaje para luego filtrarlo según le interese o no. Existen distintos tipos de tramas predefinidas por CAN para la gestión de la comunicación: Trama de datos: Se utiliza normalmente para poner información en el bus y la pueden recibir algunos o todos los nodos. Trama de información remota: puede ser utilizada por un nodo para solicitar la transmisión de una trama de datos con la información asociada a un identificador dado. El nodo que disponga de la información definida por el identificador la transmitirá en una trama de datos. Trama de error: Se generan cuando algún nodo detecta algún error definido. Trama de sobrecarga: Se generan cuando algún nodo necesita más tiempo para procesar los mensajes recibidos. Espaciado entre tramas: Las tramas de datos (y de interrogación remota) se separan entre sí por una secuencia predefinida que se denomina espaciado nter.-trama. Bus en reposo: En los intervalos de inactividad se mantiene constantemente el nivel recesivo del bus. En un bus CAN los nodos transmiten la información espontáneamente con tramas de datos, bien sea por un proceso cíclico o activado ante eventos en el nodo. La trama de interrogación remota sólo se suele utilizar para detección de presencia de nodos o para 104

María Aranda Elcuaz

Universidad Pública de Navarra

puesta al día de información en un nodo recién incorporado a la red. Los mensajes pueden entrar en colisión en el bus, el de identificador de mayor prioridad sobrevivirá y los demás son retransmitidos lo antes posible.

5.4.1 Trama de datos

Figura 5.4.1.a Los mensajes de datos consisten en celdas que envían datos y añaden información definida por las especificaciones CAN:

Figura 5.4.1.b Inicio de trama (SOF): El inicio de trama es una celda de un solo bit siempre dominante que indica el inicio del mensaje, sirve para la sincronización con otros nodos. Celda de Arbitraje (Arbitration Field): Es la celda que concede prioridad a unos mensajes o a otros: -

En formato estándar tendrá 11 bits seguidos del bit RTR (Remote Transmisión Request) que en este caso será dominante.

Figura 5.4.1.c -

En formato extendido serán 11 bits de identificador base y 18 de extendido. El bit SRR substituye al RTR y será recesivo.

Figura 5.4.1.d 105

María Aranda Elcuaz

Universidad Pública de Navarra

Nota: La trama en formato estándar prevalece sobre la extendida Celda de control (Control Field): El campo de control está formado por dos bits reservados para uso futuro y cuatro bits adicionales que indican el número de bytes de datos. En realidad el primero de estos bits (IDE) se utiliza para indicar si la trama es de CAN Estándar (IDE dominante) o Extendido (IDE recesivo). El segundo bit (RB0) es siempre recesivo. Los cuatro bits de código de longitud (DLC) indican en binario el número de bytes de datos en el mensaje (0 a 8) Celda de Datos (Data Field): Es el campo de datos de 0 a 8 bytes. CRC: Código de redundancia cíclica: Tras comprobar este código se podrá comprobar si se han producido errores. Celda de reconocimiento (ACK): es un campo de dos bits que indica si el mensaje ha sido recibido correctamente. El nodo transmisor pone este bit como recesivo y cualquier nodo que reciba el mensaje lo pone como dominante para indicar que el mensaje ha sido recibido. Fin de trama (EOF): Consiste en 7 bits recesivos sucesivos e indica el final de la trama. Espaciado entre tramas (IFS): Consta de un mínimo de 3 bits recesivos.

5.4.2 Trama remota Los nodos tienen habilidad para requerir información a otros nodos. Un nodo pide una información a los otros, el nodo que tiene dicha información envía una comunicación con la respuesta que puede ser recibida además por otros nodos si están interesados.

Figura 5.4.2.a Un mensaje de petición remota tiene la siguiente forma:

Figura 5.4.2.b 106

María Aranda Elcuaz

Universidad Pública de Navarra

En este tipo de mensajes se envía una trama con el identificador del nodo requerido, a diferencia con los mensajes de datos, el bit RTR toma valor recesivo y no hay campo de datos. En caso de que se envíe un mensaje de datos y de petición remota con el mismo identificador, el de datos ganará el acceso al bus puesto que el RTR lleva valor dominante.

5.4.3 Trama de error Las tramas de error son generadas por cualquier nodo que detecta un error. Consiste en dos campos: Indicador de error ("Error Flag") y Delimitador de error. El delimitador de error consta de 8 bits recesivos consecutivos y permite a los nodos reiniciar la comunicación limpiamente tras el error. El Indicador de error es distinto según el estado de error del nodo que detecta el error:

Figura 5.4.3.a Si un nodo en estado de error "Activo" detecta un error en el bus interrumpe la comunicación del mensaje en proceso generando un "Indicador de error activo" que consiste en una secuencia de 6 bits dominantes sucesivos. Esta secuencia rompe la regla de relleno de bits y provocará la generación de tramas de error en otros nodos. Por tanto el Indicador de error puede extenderse entre 6 y 12 bits dominantes sucesivos. Finalmente se espera el campo de delimitación de error formado por los 8 bits recesivos. Entonces la comunicación se reinicia y el nodo que había sido interrumpido reintenta la transmisión del mensaje. Si un nodo en estado de error "Pasivo" detecta un error, el nodo transmite un "Indicador de error pasivo" seguido, de nuevo, por el campo delimitador de error. El indicador de error de tipo pasivo consiste en 6 bits recesivos seguidos y, por tanto, la trama de error para un nodo pasivo es una secuencia de 14 bits recesivos. De aquí se deduce que la transmisión de una trama de error de tipo pasivo no afectará a ningún nodo en la red, excepto cuando el error es detectado por el propio nodo que está transmitiendo. En ese caso los demás nodos detectarán una violación de las reglas de relleno y transmitirán a su vez tramas de error. Tras señalar un error por medio de la trama de error apropiada cada nodo transmite bits recesivos hasta que recibe un bit también recesivo, luego transmite 7 bits recesivos consecutivos antes de finalizar el tratamiento de error. La regla de relleno de bits que aparece líneas arriba consiste en que cada cinco bits de igual valor se introduce uno de valor inverso tal y como se ve en la figura siguiente: 107

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 5.4.3.b Otro método para la detección de errores es el chequeo de la trama:

Figura 5.4.3.c El campo CRC contiene información adicional a la trama, éste se calcula con un polinomio generador de igual manera en el receptor y en el emisor. Esto permite detectar errores aleatorios en hasta 5 bits o una secuencia seguida de 15 bits corruptos. El campo ACK, en el caso del emisor será recesivo y el receptor deberá sobrescribirlo como dominante y el primero comprobará, mediante la monitorización, que el mensaje ha sido escuchado. Si no sucede así, la trama se considerará corrupta.

5.4.4 Espacio entre tramas El espacio entre tramas separa una trama (de cualquier tipo) de la siguiente trama de datos o interrogación remota. El espacio entre tramas ha de constar de, al menos, 3 bits recesivos. Esta secuencia de bits se denomina "íntermission". Una vez transcurrida esta secuencia un nodo en estado de error activo puede iniciar una nueva transmisión o el bus permanecerá en reposo. Para un nodo en estado error pasivo la situación es diferente, deberá espera una secuencia adicional de 8 bits recesivos antes de poder iniciar una transmisión. De esta forma se asegura una ventaja en inicio de transmisión a los nodos en estado activo frente a los nodos en estado pasivo.

5.4.5 Trama de sobrecarga Una trama de sobrecarga tiene el mismo formato que una trama de error activo. Sin embargo, la trama de sobrecarga sólo puede generarse durante el espacio entre tramas. De esta forma se diferencia de una trama de error, que sólo puede ser transmitida durante la transmisión de un mensaje. La trama de sobrecarga consta de dos campos, el Indicador de Sobrecarga, y el delimitador. El indicador de sobrecarga consta de 6 bits dominantes que pueden ser seguidos por los generados por otros nodos, dando lugar a un máximo de 12 bits dominantes. El delimitador es de 8 bits recesivos. 108

María Aranda Elcuaz

Universidad Pública de Navarra

Una trama de sobrecarga puede ser generada por cualquier nodo que debido a sus condiciones internas no está en condiciones de iniciar la recepción de un nuevo mensaje. De esta forma retrasa el inicio de transmisión de un nuevo mensaje. Un nodo puede generar como máximo 2 tramas de sobrecarga consecutivas para retrasar un mensaje. Otra razón para iniciar la transmisión de una trama de sobrecarga es la detección por cualquier nodo de un bit dominante en los 3 bits de "intermission". Por todo ello una trama de sobrecarga de 5 generada por un nodo dará normalmente lugar a la generación de tramas de sobrecarga por los demás nodos dando lugar, como se ha indicado, a un máximo de 12 bits dominantes de indicador de sobrecarga.

5.5 Acceso múltiple y arbitraje de acceso al bus

Figura 5.5.a CAN permite el acceso al bus de varios nodos a la vez. El proceso de arbitraje está basado en el CSMA/CD (Carrier Sense Multiple Access with Collision Detection): Cada nodo debe vigilar el bus en un periodo sin actividad antes de enviar un mensaje (Carrier Sense) y además, una vez que ocurre el periodo sin actividad cada nodo tiene la misma oportunidad de enviar un mensaje (Multiple Access). En caso de que dos nodos comiencen a transmitir al unísono se detectará la colisión. Al detectarse la colisión comienza el arbitraje. Cada nodo emisor envía los bits del identificador del mensaje y vigila el bus comprobando lo que emite. El nodo de mayor prioridad (con bits dominantes, “0”) accederá primero al bus y una vez pasado un tiempo de espera, diferente para cada nodo, se vuelve a intentar el acceso sin repetición de mensaje ni pérdidas de tiempo ya que esta contención es a nivel de bit. Es un modo no destructivo, los mensajes permanecen intactos a pesar de detectar colisiones y no conlleva retrasos en los mensajes de alta prioridad, prioridad que viene especificada en el identificador de mensaje. En la figura 5.5.b se ve un ejemplo de arbitraje en un bus CAN.

109

María Aranda Elcuaz

Universidad Pública de Navarra

Figura 5.5.b

5.6 Especificaciones del protocolo CAN Se puede hablar de tres especificaciones CAN 2.0 que se utilizan hoy en día: Protocolo CAN especificación 2.0 A: solo maneja mensajes estándar con identificador de 11 bits Protocolo CAN especificación 2.0 Pasivo: solo transmite mensajes estándar con identificador de 11 bits, pero comprueba si recibe mensajes estándar y mensajes extendidos con identificadores de 29 bits. Protocolo CAN especificación 2.0 Activo: transmiten y reciben mensajes estándar y mensajes extendidos

5.7 Protocolos de alto nivel El protocolo CAN especifica la forma de transmitirse la información y en que condiciones se realiza según el estándar ISO 11898. Para especificar la estructura de la información que se transmite y otros mecanismos para dotar de funcionalidad específica a los nodos se precisa protocolo adicional de más alto nivel. Ejemplos de protocolo de más alto nivel pueden ser CANopen y MCNet protocol

5.8 Implementación de controladores CAN Existen tres tipos de arquitecturas en microcontroladores: Stand-Alone CAN controller, Integrated CAN Controller y Single-Chip CAN Node.

110

María Aranda Elcuaz

Universidad Pública de Navarra

5.8.1 Stand-Alone CAN Controller Es la arquitectura más simple, para llevar a cabo una comunicación en una red CAN será necesario: 1. Un microcontrolador como puede ser el 16F877, con el que se ha venido trabajando a lo largo de todo este proyecto. 2. Un controlador CAN que introduzca el protocolo CAN, filtro de mensajes,… y todo el interface necesario para las comunicaciones. Un ejemplo de controlador CAN es el MCP2510 cuya DATA SHEET se puede encontrar en la página web de microchip. 3. Un transceiver CAN, esto es, un transmisor/receptor que puede ser por ejemplo el MCP2551 desarrollado por microchip.

Figura 5.8.1 Así pues, si de alguna manera se pretende trabajar en una red CAN con la placa de pruebas en la que se han desarrollado los ejercicios anteriores no sería factible a no ser que de alguna manera se le acoplasen el controlador y el transceptor CAN correspondiente. Microchip ha creado una placa de pruebas específica para este tipo de comunicaciones, que desarrolla además este tipo de arquitectura y que se puede conseguir también a través de la página web de microchip.

5.8.2 Integrated CAN Controller Este tipo de arquitectura consiste en un microcontrolador que incluya, no sólo sus características propias sino además un módulo CAN con las características de un microcontrolador CAN. El transceiver se sitúa de manera separada.

Figura 5.8.2 111

María Aranda Elcuaz

Universidad Pública de Navarra

5.8.3 Single-chip CAN Node

Figura 5.8.3 Se trata de un chip que incluye en su interior los tres elementos necesarios para llevar a cabo las comunicaciones en un entorno CAN.

112

María Aranda Elcuaz

Universidad Pública de Navarra

ANEXOS

113

María Aranda Elcuaz

Universidad Pública de Navarra

Anexo 1: Librerías 1.1 Librería LCD //////////////////////////////////////////////////////////////////////// lcd_picdem.c Driver para módulos LCD microcontrolados Funciones definidas: lcd_init()

Inicialización,llamar antes de cualquier otra función.

lcd_putc(c) Muestra c en la posicion siguiente del LCD. Caracteres de control: \f Borra display \n Sitúa cursor al comienzo de la línea 2 \b Retrocede el cursor una posición \t Avanza el cursor una posición \r Retrocede una posición la pantalla visible \v Avanza una posición la pantalla visible lcd_gotoxy(x,y) Sitúa escritura en posición del LCD (posición 1,1: arriba a la izquierda) lcd_getc(x,y)

Devuelve carácter en posición x,y del LCD

//////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// Conexión a 7 pines del MCU: 3 de control / interface de datos de 4 bits: Líneas de control asignadas RA1 enable RA2 rw RA3 rs Líneas RD0 RD1 RD2 RD3

de Datos D4 D5 D6 D7

//////////////////////////////////////////////////////////////////////// struct lcd_pines_control { // Estructura que se define para facilitar acceso boolean boolean boolean boolean

nada; enable; //y asociarlos a los 3 bits más bajos del PORTA rw; //se asigna luego a esta estructura el PORTA rs; //rs (1º) corresponde al menos significativo //a los pines de control del LCD int otros : 4; } lcd_control; struct lcd_pines_datos { // Se hace lo mismo con esta estructura para el PORTD int datos:4; //los 4 bits más bajos son los de datos int no_usados:4; } lcd_datos; #byte lcd_control = 5 #byte trisa = 0x85

//Se pone la estructura entera en el PORTA //Registro de dirección de datos

#byte lcd_datos = 8 #byte trisd = 0x88

//Lo mismo para los datos, en el PORTD //Registro de dirección de datos 114

María Aranda Elcuaz #define lcd_linea_dos 0x40

Universidad Pública de Navarra //Dirección de inicio para la 2ª línea en la //DDRAM

//////////////////////////////////////////////////////////////////////// -Prototipos de las funciones //////////////////////////////////////////////////////////////////////// void byte void void void void char void

lcd_init(); lcd_read_byte(); lcd_send_nibble(byte n); lcd_send_byte(byte address, byte n); lcd_gotoxy(byte x, byte y); lcd_putc(char c); lcd_getc(byte x, byte y); lcd_clr_line(char fila);

//////////////////////////////////////////////////////////////////////// Función que inicializa el LCD, se deberían cambiar bits para cambiar configuración //////////////////////////////////////////////////////////////////////// void lcd_init() { byte i; trisa&=0b11110001; //Se asigna salidas en RA1, RA2 y RA3, resto puerto //como estaba trisd&=0b11110000; // Lo mismo para RD0 a RD3 lcd_control.rs = 0; lcd_control.rw = 0; lcd_control.enable = 0; delay_ms(15); for(i=1;i<=3;++i) { lcd_send_nibble(3); delay_ms(5); } lcd_send_nibble(2); lcd_send_byte(0,0b00101000);//Se lcd_send_byte(0,0b00001100);//Se lcd_send_byte(0,0b00000001);//Se lcd_send_byte(0,0b00000110);//Se

envía envía envía envía

Function set 0 0 1 DL N F Display on/off 0 0 0 0 1 D C B Clear Display Entry Modeset 0 0 0 0 0 1 I/D S

//////////////////////////////////////////////////////////////////////// DL: datos 4 bits(0); 8 bits (1) N: 2 líneas (1); 1 línea (0) F: 5x10 (1); 5x8 (0) D: display on (1); off (0) C: cursor on (1); off (0) B: parpadeo pos.cursor (1); no (0) I/D: incremento en R/W (1) o decremento (0) S: acompaña desplaz.display (1); no (0) //////////////////////////////////////////////////////////////////////// } //////////////////////////////////////////////////////////////////////// Lee el byte señalado por el puntero, 1º parte alta, 2º parte baja Si al llamar a esta función rs=0, devuelve busy flag (+signif.) y dirección actual //////////////////////////////////////////////////////////////////////// byte lcd_read_byte() 115

María Aranda Elcuaz {

Universidad Pública de Navarra

byte low,high; trisa&=0b11110001;//Señales de control (salidas), el resto lo que sean trisd|=0b00001111;//Las de datos pasan a ser entradas, las demás igual

}

lcd_control.rw = 1; delay_cycles(1); lcd_control.enable = 1; delay_cycles(1); high = lcd_datos.datos; lcd_control.enable = 0; delay_cycles(1); lcd_control.enable = 1; delay_us(1); low = lcd_datos.datos; lcd_control.enable = 0; trisd&=0b11110000; // Dejamos RD0 a RD3 como salidas return( (high<<4) | low);

//////////////////////////////////////////////////////////////////////// Envía medio byte, los 4 bits más bajos de n Necesario poner rs y rw de modo adecuado y entrar con enable=0 //////////////////////////////////////////////////////////////////////// void lcd_send_nibble( byte n ) { lcd_datos.datos = n; delay_cycles(1); lcd_control.enable = 1; delay_us(2); lcd_control.enable = 0; } //////////////////////////////////////////////////////////////////////// -Envía un byte (n) al registro de instrucciones (si address=0) ó reg. de datos (address=1) -Utiliza lcd_send_nibble(n) enviando primero nibble alto del byte //////////////////////////////////////////////////////////////////////// void lcd_send_byte( byte address, byte n ) { lcd_control.rs = 0; while ( bit_test(lcd_read_byte(),7) );//Mientras esté ocupado el LCD, //espera lcd_control.rs = address; delay_cycles(1); lcd_control.rw = 0; delay_cycles(1); lcd_control.enable = 0; lcd_send_nibble(n >> 4); lcd_send_nibble(n & 0x0F); } //////////////////////////////////////////////////////////////////////// Sitúa el contador de direcciones en la DDRAM (para lectura o escritura posterior): x puede ir de 1 a 40, posición dentro de una línea (16 visibles) y puede ser 1 (línea 1) o 2 (línea 2) //////////////////////////////////////////////////////////////////////// void lcd_gotoxy( byte x, byte y) { byte posicion; if(y!=1) posicion=lcd_linea_dos; 116

María Aranda Elcuaz

Universidad Pública de Navarra

else posicion=0; posicion+=x-1; lcd_send_byte(0,0x80|posicion); //Las direcciones de la DDRAM empiezan //por 1xxxxxxx } //////////////////////////////////////////////////////////////////////// Envía un carácter c a la DDRAM del LCD, también algunos caracteres de control: //////////////////////////////////////////////////////////////////////// void lcd_putc( char c) { switch (c) { case '\f': lcd_send_byte(0,1); break; //Limpia la pantalla delay_ms(2); case '\n': lcd_gotoxy(1,2); break; //Coloca puntero en 1ª posicion de la 2ª línea case '\b': lcd_send_byte(0,0x10); break; //Retrocede una posición el cursor case '\t': lcd_send_byte(0,0x14); break; //Avanza una posición el cursor case '\r' : lcd_send_byte(0,0x18); break; //Retrocede una posición la pantalla visible case '\v' : lcd_send_byte(0,0x1C); break; //Avanza una posición la pantalla visible default : lcd_send_byte(1,c); break; //Si es una tira, los envía todos uno a uno } } //////////////////////////////////////////////////////////////////////// Devuelve el carácter situado en la posición x,y de la DDRAM //////////////////////////////////////////////////////////////////////// char lcd_getc( byte x, byte y) { char value;

}

lcd_gotoxy(x,y); lcd_control.rs=1; value = lcd_read_byte(); lcd_control.rs=0; return(value);

//////////////////////////////////////////////////////////////////////// Limpia la linea correspondiente y se situa al principio de la misma //////////////////////////////////////////////////////////////////////// void lcd_clr_line(char fila) { int j; lcd_gotoxy(1,fila); for (j=0;j<40;j++) lcd_putc(' '); }

lcd_gotoxy(1,fila);

117

María Aranda Elcuaz

Universidad Pública de Navarra

1.2 Librería 16F877 //////////// Standard Header file for the PIC16F77 device ////////////// #device PIC16F77 #nolist //////// Program memory: 8192x14 Data RAM: 367 Stack: 8 //////// I/O: 33 Analog Pins: 8 //////// C Scratch area: 77 ID Location: 2000 //////// Fuses: LP,XT,HS,RC,NOWDT,WDT,NOPUT,PUT,PROTECT,NOPROTECT //////// Fuses: NOBROWNOUT,BROWNOUT //////// ////////////////////////////////////////////////////////////////// I/O // Discrete I/O Functions: SET_TRIS_x(), OUTPUT_x(), INPUT_x(), // PORT_B_PULLUPS(), INPUT(), // OUTPUT_LOW(), OUTPUT_HIGH(), // OUTPUT_FLOAT(), OUTPUT_BIT() // Constants used to identify pins in the above are: #define #define #define #define #define #define

PIN_A0 PIN_A1 PIN_A2 PIN_A3 PIN_A4 PIN_A5

40 41 42 43 44 45

#define #define #define #define #define #define #define #define

PIN_B0 PIN_B1 PIN_B2 PIN_B3 PIN_B4 PIN_B5 PIN_B6 PIN_B7

48 49 50 51 52 53 54 55

#define #define #define #define #define #define #define #define

PIN_C0 PIN_C1 PIN_C2 PIN_C3 PIN_C4 PIN_C5 PIN_C6 PIN_C7

56 57 58 59 60 61 62 63

#define #define #define #define #define #define #define #define

PIN_D0 PIN_D1 PIN_D2 PIN_D3 PIN_D4 PIN_D5 PIN_D6 PIN_D7

64 65 66 67 68 69 70 71

#define PIN_E0 #define PIN_E1 #define PIN_E2

72 73 74

///////////////////////////////////////////////////////// Useful defines #define FALSE 0 #define TRUE 1 #define BYTE int #define BOOLEAN short int #define #define #define #define

getc getch fgetc getch getchar getch putc putchar 118

María Aranda Elcuaz

Universidad Pública de Navarra

#define fputc putchar #define fgets gets #define fputs puts //////////////////////////////////////////////////////////////// Control // Control Functions: RESET_CPU(), SLEEP(), RESTART_CAUSE() // Constants returned from RESTART_CAUSE() are: #define WDT_FROM_SLEEP 0 #define WDT_TIMEOUT 8 #define MCLR_FROM_SLEEP 16 #define NORMAL_POWER_UP 24 //////////////////////////////////////////////////////////////// Timer 0 // Timer 0 (AKA RTCC)Functions: SETUP_COUNTERS() or SETUP_TIMER0(), // SET_TIMER0() or SET_RTCC(), // GET_TIMER0() or GET_RTCC() // Constants used for SETUP_TIMER0() are: #define RTCC_INTERNAL 0 #define RTCC_EXT_L_TO_H 32 #define RTCC_EXT_H_TO_L 48 #define #define #define #define #define #define #define #define #define

RTCC_DIV_1 RTCC_DIV_2 RTCC_DIV_4 RTCC_DIV_8 RTCC_DIV_16 RTCC_DIV_32 RTCC_DIV_64 RTCC_DIV_128 RTCC_DIV_256

#define RTCC_8_BIT

8 0 1 2 3 4 5 6 7 0

// Constants used for SETUP_COUNTERS() are the above // constants for the 1st param and the following for // the 2nd param: ////////////////////////////////////////////////////////////////// WDT Watch Dog Timer Functions: SETUP_WDT() or SETUP_COUNTERS() (see above) // RESTART_WDT() // #define WDT_18MS 8 #define WDT_36MS 9 #define WDT_72MS 10 #define WDT_144MS 11 #define WDT_288MS 12 #define WDT_576MS 13 #define WDT_1152MS 14 #define WDT_2304MS 15 //////////////////////////////////////////////////////////////// Timer 1 // Timer 1 Functions: SETUP_TIMER_1, GET_TIMER1, SET_TIMER1 // Constants used for SETUP_TIMER_1() are: // (or (via |) together constants from each group) #define T1_DISABLED 0 #define T1_INTERNAL 0x85 #define T1_EXTERNAL 0x87 #define T1_EXTERNAL_SYNC 0x83 #define T1_CLK_OUT

8

#define #define #define #define

0 0x10 0x20 0x30

T1_DIV_BY_1 T1_DIV_BY_2 T1_DIV_BY_4 T1_DIV_BY_8

//////////////////////////////////////////////////////////////// Timer 2 119

María Aranda Elcuaz

Universidad Pública de Navarra

// Timer 2 Functions: SETUP_TIMER_2, GET_TIMER2, SET_TIMER2 // Constants used for SETUP_TIMER_2() are: #define T2_DISABLED 0 #define T2_DIV_BY_1 4 #define T2_DIV_BY_4 5 #define T2_DIV_BY_16 6 ////////////////////////////////////////////////////////////////// CCP // CCP Functions: SETUP_CCPx, SET_PWMx_DUTY // CCP Variables: CCP_x, CCP_x_LOW, CCP_x_HIGH // Constants used for SETUP_CCPx() are: #define CCP_OFF 0 #define CCP_CAPTURE_FE 4 #define CCP_CAPTURE_RE 5 #define CCP_CAPTURE_DIV_4 6 #define CCP_CAPTURE_DIV_16 7 #define CCP_COMPARE_SET_ON_MATCH 8 #define CCP_COMPARE_CLR_ON_MATCH 9 #define CCP_COMPARE_INT 0xA #define CCP_COMPARE_RESET_TIMER 0xB #define CCP_PWM 0xC #define CCP_PWM_PLUS_1 0x1c #define CCP_PWM_PLUS_2 0x2c #define CCP_PWM_PLUS_3 0x3c long CCP_1; #byte CCP_1 = 0x15 #byte CCP_1_LOW= 0x15 #byte CCP_1_HIGH= 0x16 long CCP_2; #byte CCP_2 = 0x1B #byte CCP_2_LOW= 0x1B #byte CCP_2_HIGH= 0x1C ////////////////////////////////////////////////////////////////// PSP // PSP Functions: SETUP_PSP, PSP_INPUT_FULL(), PSP_OUTPUT_FULL(), // PSP_OVERFLOW(), INPUT_D(), OUTPUT_D() // PSP Variables: PSP_DATA // Constants used in SETUP_PSP() are: #define PSP_ENABLED 0x10 #define PSP_DISABLED 0 #byte

PSP_DATA=

8

////////////////////////////////////////////////////////////////// SPI // SPI Functions: SETUP_SPI, SPI_WRITE, SPI_READ, SPI_DATA_IN // Constants used in SETUP_SSP() are: #define SPI_MASTER 0x20 #define SPI_SLAVE 0x24 #define SPI_L_TO_H 0 #define SPI_H_TO_L 0x10 #define SPI_CLK_DIV_4 0 #define SPI_CLK_DIV_16 1 #define SPI_CLK_DIV_64 2 #define SPI_CLK_T2 3 #define SPI_SS_DISABLED 1 ////////////////////////////////////////////////////////////////// UART // Constants used in setup_uart() are: // FALSE - Turn UART off // TRUE - Turn UART on ////////////////////////////////////////////////////////////////// ADC // ADC Functions: SETUP_ADC(), SETUP_ADC_PORTS() (aka SETUP_PORT_A), // SET_ADC_CHANNEL(), READ_ADC() // Constants used for SETUP_ADC() are: #define ADC_OFF 0x00 // ADC Off #define ADC_CLOCK_DIV_2 0x00 #define ADC_CLOCK_DIV_8 0x40 #define ADC_CLOCK_DIV_32 0x80 #define ADC_CLOCK_INTERNAL 0xc0 // Internal 2-6us 120

María Aranda Elcuaz

Universidad Pública de Navarra

// Constants used in SETUP_ADC_PORTS() are: #define NO_ANALOGS 7 // None #define ALL_ANALOG 0 // A0 A1 A2 A3 A5 E0 E1 E2 Ref=Vdd #define AN0_AN1_AN2_AN4_AN5_AN6_AN7_VSS_VREF 1 // A0 A1 A2 A5 E0 E1 E2 Ref=A3 #define AN0_AN1_AN2_AN3_AN4 2 // A0 A1 A2 A3 A5 Ref=Vdd #define AN0_AN1_AN2_AN4_VSS_VREF 3 // A0 A1 A2 A5 Ref=A3 #define AN0_AN1_AN3 4 // A0 A1 A3 Ref=Vdd #define AN0_AN1_VSS_VREF 5 // A0 A1 Ref=A3 #define ANALOG_RA3_REF 1 \\old only provided for compatibility #define A_ANALOG 2 \\old only provided for compatibility #define A_ANALOG_RA3_REF 3 \\old only provided for compatibility #define RA0_RA1_RA3_ANALOG 4 \\old only provided for compatibility #define RA0_RA1_ANALOG_RA3_REF 5 \\old only provided for compatibility // Constants used in READ_ADC() are: #define ADC_START_AND_READ 7 // This is the default if no param is present #define ADC_START_ONLY 1 #define ADC_READ_ONLY 6 // This device allows 4 params to set_adc_channel to set the channel // for each group A,B,C,D ////////////////////////////////////////////////////////////////// INT // Interrupt Functions: ENABLE_INTERRUPTS(), DISABLE_INTERRUPTS(), // EXT_INT_EDGE() // // Constants used in EXT_INT_EDGE() are: #define L_TO_H 0x40 #define H_TO_L 0 // Constants used in ENABLE/DISABLE_INTERRUPTS() are: #define GLOBAL 0x0BC0 #define INT_RTCC 0x0B20 #define INT_RB 0x0B08 #define INT_EXT 0x0B10 #define INT_AD 0x8C40 #define INT_TBE 0x8C10 #define INT_RDA 0x8C20 #define INT_TIMER1 0x8C01 #define INT_TIMER2 0x8C02 #define INT_CCP1 0x8C04 #define INT_CCP2 0x8D01 #define INT_SSP 0x8C08 #define INT_PSP 0x8C80 #define INT_TIMER0 0x0B20 #list

121

María Aranda Elcuaz

Universidad Pública de Navarra

Anexo 2: Modulación PWM A) Circuito de potencia básico: Célula elemental de conmutación Ii T1 Vi T2

I0 V0

Figura 1 En la figura a se representa un circuito de intercambio de potencia eléctrica entre dos fuentes que se rige por las siguientes reglas de funcionamiento: - La fuente de tensión Vi no se puede cortocircuitar. - La fuente de corriente no se puede poner en circuito abierto. Por lo tanto, con estas dos reglas de funcionamiento se obtienen las leyes de conmutación para T1 y T2: - Si el transistor T1 está encendido, el transistor T2 deberá estar apagado. - Si el transistor T1 está apagado, el transistor T2 deberá estar encendido. A1) Tensión de salida Con estas leyes de conmutación se obtiene la siguiente tabla para el valor de la tensión de salida V0: T1 1 0

T2 0 1

V0 Vi 0

Esta tabla representa la tensión de salida siempre que uno de los transistores esté siempre encendido o siempre apagado. ¿Pero que sucede si el estado de los transistores cambia cada cierto tiempo? A2) Tensiones de salida intermedias Tomando como referencia al transistor T1, se llama t on el periodo que éste transistor permanece encendido y toff al periodo en el que dicho transistor permanece apagado, siendo T el periodo total que se irá repitiendo a lo largo del tiempo. La tensión de salida V0 dibujará una gráfica tal como la que se dibuja en la página siguiente.

122

María Aranda Elcuaz

V0

Universidad Pública de Navarra

Vi

Vi

Vi

0 ton

0

toff T

Figura 2 La tensión o tensión V0 media se calcula como sigue: < Vo >=

Vi ·ton + 0·toff T

t = Vi · on = Vi ·D T

Donde Є [0,Vi] y D se conoce como Ciclo de trabajo. A3) Corriente de entrada Según el estado de los transistores se realiza la siguiente tabla de la misma manera que se realizó para la tensión de salida, pero esta vez para la corriente: T1 1 0

T2 0 1

Ii 0 I0

A4) Corrientes de entrada intermedias Tal y como se ha dibujado para la tensión de salida, se realiza también la gráfica para la corriente de entrada:

Ii

I0

I0

0 ton

I0

0

toff T

Figura 3

123

María Aranda Elcuaz

Universidad Pública de Navarra

Para el cálculo de la corriente intermedia :

< I i >=

t on ·I 0 + t off ·0 T

= I0

t on = I 0 ·D T

Donde Є [0,I0]

A5) Balance de potencias Para comprobar que todo lo que se ha dicho hasta ahora es correcto se realiza el balance de potencias en un ciclo de trabajo determinado en las dos fuentes y se comprueba que efectivamente son iguales: PVi= Vi·=Vi ·I0·D PVo= ·I0=Vi·D·I0

B) Circuitos de gobierno de la célula elemental de conmutación Los circuitos de gobierno de la célula elemental de conmutación son circuitos moduladores que siguen la técnica PWM (modulación por anchura de pulsos). Se dibuja a continuación el diagrama de bloques esencial de un ejemplo sencillo de circuito modulador:

T1 V0 Є [0,Vi]

Modulador T2

Figura 4

v0 Є [0,1]

T1 [0,1]

V0 Є [0,Vi]

T2 Vi

VTRI

1

Figura 5 124

María Aranda Elcuaz

Universidad Pública de Navarra

El circuito de la figura 5 primeramente divide las tensiones de salida y entrada para obtener una tensión entre 0 y 1 que se compara con una onda triangular que trabaja también en dicho intervalo. El diagrama de ondas del circuito queda representado de la siguiente manera: VTRI 1 v0

ton

T1

toff

On

Off

T2

On

Off

V0

Vi



La primera gráfica representa la comparación entre la onda triangular y el valor de v0 en el intervalo [0,1]. Las dos siguientes representan los estados de los dos transistores T 1 y T2 y por último, la gráfica inferior representa la tensión de salida del circuito. Para calcular la tensión media se pueden emplear dos métodos distintos: 1º método: De la misma manera que se ha calculado hasta ahora: < Vo >=

Vi ·ton + 0·toff T

t = Vi · on T 125

María Aranda Elcuaz

Universidad Pública de Navarra

2º método: Por semejanza triangular: De la gráfica de la onda triangular se obtiene que: pero como v0 =

t 1 v0 = Þ on = v0 T ton T

V0 Vi

se puede sustituir y queda:

ton V0 = , T Vi

t despejando de esta ecuación se obtiene que: V0 = Vi · on =< V0 > T

126

María Aranda Elcuaz

Universidad Pública de Navarra

Anexo 3: Presentación de las Comunicaciones CAN

127

María Aranda Elcuaz

Universidad Pública de Navarra

128

María Aranda Elcuaz

Universidad Pública de Navarra

129

María Aranda Elcuaz

Universidad Pública de Navarra

130

María Aranda Elcuaz

Universidad Pública de Navarra

131

María Aranda Elcuaz

Universidad Pública de Navarra

132

María Aranda Elcuaz

Universidad Pública de Navarra

133

María Aranda Elcuaz

Universidad Pública de Navarra

134

María Aranda Elcuaz

Universidad Pública de Navarra

135

María Aranda Elcuaz

Universidad Pública de Navarra

136

María Aranda Elcuaz

Universidad Pública de Navarra

137

María Aranda Elcuaz

Universidad Pública de Navarra

138

María Aranda Elcuaz

Universidad Pública de Navarra

139

María Aranda Elcuaz

Universidad Pública de Navarra

140

María Aranda Elcuaz

Universidad Pública de Navarra

BIBLIOGRAFÍA

141

María Aranda Elcuaz

Universidad Pública de Navarra

Libros: -

MICROCONTROLADORES PIC, LA CLAVE DEL DISEÑO. Martín Cuenca, Angulo Usategui y Angulo Martínez. Ed Thomson, 2003. MICROCONTROLADORES PIC, DISEÑO PRÁCTICO DE APLICACIONES. Angulo Usategui y Angulo Martínez. Ed Mc Graw Hill, 2003. MANUAL DE USUARIO DEL COMPILADOR PCW DE CCS. Andrés Cánovas López

Artículos técnicos: -

CONTROLLER AREA NETWORK (CAN) BASICS. Keith Fazui. Microchip Technology Inc, 1999.

Datasheet: -

PIC16F87X: 28/40-Pin 8-Bit CMOS FLASH Microcontrollers PICDEM™ 2 Plus User’s Guide

Páginas Web: -

http://www.can-cia.org: página dedicada al bus CAN http://miarroba.com/foros/ver.php?id=6510: Foro dedicado a microcontroladores

142

Related Documents

Guia Pics Completa
October 2019 11
Guia Salidas Completa
November 2019 14
Pics Pics Pics
December 2019 49
Guia Completa 2008 Trata
December 2019 20
Guia Quimica Completa
October 2019 13