Está en la página 1de 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 Universidad Pública de Navarra

Título __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 Universidad Pública de Navarra

Título __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 Universidad Pública de Navarra

Título __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 Bus de Instrucciones

MEMORIA DE MEMORIA DE
CPU
DATOS INSTRUCCIONES
8 12
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: Oscilador de cristal de cuarzo o resonador cerámico de baja potencia


- XT: Cristal o resonador cerámico
- HS: Oscilador de cristal o resonador de alta velocidad
- RC: 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 PD Estado tras el RESET


0 0 WDT en el modo “SLEEP”
0 1 WDT en el modo normal
1 0 MCLR en el modo SLEEP
1 1 Conexión de la alimentación (POR)
u u 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) Un flanco ascendente
b) Un flanco descendente
c) Cada 4 flancos ascendentes
d) 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ógico-
digitales, 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
Perro guardián (Watchdog)
W
Registro W, similar al acumulador
F
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.
D
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.
Dest
Destino (registro W o f)
TO
Bit “Time Out” del registro de estado
PD
Bit “Power Down” del registro de estado
b
Suele ser un campo de 3 bits (bbb) que determinan la posición de
un bit dentro de un registro de 8 bits
k
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
x
Valor indeterminado (puede ser un 0 o un 1). Para mantener la
compatibilidad con las herramientas software de Microchip
conviene hacer x = 0
label
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 Universidad Pública de Navarra

ADDLW Suma un literal ADDWF W + F ANDLW W AND literal

Sintaxis: [label] ADDLW k Sintaxis: [label] ADDWF f,d Sintaxis: [label] ANDLW k
Operandos: 0 £ k £ 255 Operandos: d Î [0,1], 0 £ f £ 127 Operandos: 0 £ k £ 255
Operación: (W) + (k)Þ (W) Operación: (W) + (f) Þ (dest) Operación: : (W) AND (k)Þ (W)
Flags afectados: C, DC, Z Flags afectados: C, DC, Z Flags afectados: Z
Código OP: 11 111x kkkk kkkk Código OP: 00 0111 dfff ffff Código OP: 11 1001 kkkk kkkk
Descripción: Suma el contenido del Descripción: Suma el contenido del Descripción: Realiza la operación
registro W y k, guardando el registro W y el registro f. Si d es 0, el lógica AND entre el contenido del
resultado en W. resultado se almacena en W, si d es 1 registro W y k, guardando el
se almacena en f. resultado en W.

Ejemplo: ADDLW 0xC2 Ejemplo: ADDWF REG,0 Ejemplo: ADDLW 0xC2

Antes: W = 0x17 Antes: W = 0x17., REG = 0xC2 Antes: W = 0x17


Después: W = 0xD9 Después: W = 0xD9, REG = 0xC2 Después: W = 0xD9

ANDWF W AND F BCF Borra un bit BSF Activa un bit

Sintaxis: [label] ANDWF f,d Sintaxis: [label] BCF f,b Sintaxis: [label] BSF f,b
Operandos: d Î [0,1], 0 £ f £ 127 Operandos: 0 £ f £ 127, 0 £ b £ 7 Operandos: 0 £ f £ 127, , 0 £ b £ 7
Operación: (W) AND (f) Þ (dest) Operación: 0 Þ (f<b>) Operación: 1 Þ (f<b>)
Flags afectados: Z Flags afectados: Ninguno Flags afectados: Ninguno
Código OP: 00 0101 dfff ffff Código OP: 01 00bb bfff ffff Código OP: 01 01bb bfff ffff

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

Ejemplo: : ANDWF REG,0 Ejemplo: BCF REG,7 Ejemplo: : BSF REG,7

Antes: W = 0x17., REG = 0xC2 Antes: REG = 0xC7 Antes: REG = 0x0A
Después: W = 0x17, REG = 0x02 Después: REG = 0x47 Después: REG = 0x8A

BTFSC Test de bit y salto BTFSS Test de bit y salto CALL Salto a subrutina

Sintaxis: [label] BTFSC f,d Sintaxis: [label] BTFSS f,d Sintaxis: [label] CALL k
Operandos: d Î [0,1], 0 £ f £ 127 Operandos: d Î [0,1], 0 £ f £ 127 Operandos: 0 £ k £ 2047
Operación: Salto si (f<b>) = 0 Operación: Salto si (f<b>) = 1 Operación: PC Þ Pila; k Þ PC
Flags afectados: Ninguno Flags afectados: Ninguno Flags afectados: Ninguno
Código OP: 01 10bb bfff ffff Código OP: 01 11bb bfff ffff Código OP: 10 0kkk kkkk kkkk

Descripción: Si el bit b del registro f Descripción: Si el bit b del registro f Descripción: Salto a una subrutina.
es 0, se salta una instrucción y se es 1, se salta una instrucción y se La parte baja de k se carga en PCL, y
continúa con la ejecución. En caso de continúa con la ejecución. En caso de la alta en PCLATCH. Ocupa 2 ciclos
salto, ocupará dos ciclos de reloj. salto, ocupará dos ciclos de reloj. de reloj.

Ejemplo: BTFSC REG,6 Ejemplo: BTFSS REG,6 Ejemplo:ORIGEN CALL DESTINO


GOTO NO_ES_0 GOTO NO_ES_0
SI_ES_0 Instrucción SI_ES_0 Instrucción Antes: PC = ORIGEN
NO_ES_0 Instrucción NO_ES_0 Instrucción Después: PC = DESTINO

49
María Aranda Elcuaz Universidad Pública de Navarra

CLRF Borra un registro CLRW Borra el registro W CLRWDT Borra el WDT

Sintaxis: [label] CLRF f Sintaxis: [label] CLRW Sintaxis: [label] CLRWDT


Operandos: 0 £ f £ 127 Operandos: Ninguno Operandos: Ninguno
Operación: : 0x00 Þ (f), 1 Þ Z Operación: : 0x00 Þ W, 1 Þ Z Operación: 0x00 Þ WDT, 1 Þ /TO
Flags afectados: Z Flags afectados: Z 1 Þ /PD
Código OP: 00 0001 1fff ffff Código OP: 00 0001 0xxx xxxx Flags afectados: /TO, /PD
Código OP: 00 0000 0110 0100
Descripción: El registro f se carga Descripción: El registro de trabajo Descripción: Esta instrucción borra
con 0x00. El flag Z se activa. W se carga con 0x00. El flag Z se tanto el WDT como su preescaler.
activa. Los bits /TO y /PD del registro de
estado se ponen a 1.

Ejemplo: : CLRF REG Ejemplo: : CLRW Ejemplo: : CLRWDT


Después: Contador WDT = 0,
Antes: REG = 0x5A Antes: W = 0x5A Preescales WDT = 0,
Después: REG = 0x00, Z = 1 Después: W = 0x00, Z = 1 /TO = 1, /PD = 1

COMF Complemento de f DECF Decremento de f DECFSZ Decremento y salto

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

Descripción: El registro f es Descripción: Decrementa en 1 el Descripción: Decrementa el


complementado. El flag Z se activa si contenido de f. Si d es 0, el resultado contenido del registro f. Si d es 0, el
el resultado es 0. Si d es 0, el se almacena en W, si d es 1 se resultado se almacena en W, si d es 1
resultado se almacena en W, si d es 1 almacena en f. se almacena en f. Si la resta es 0 salta
se almacena en f.. la siguiente instrucción, en cuyo caso
costaría 2 ciclos.
Ejemplo: : COMF REG,0 Ejemplo: : DECF CONT,1
Ejemplo: DECFSC REG,0
Antes: REG = 0x13 Antes: CONT = 0x01, Z = 0 GOTO NO_ES_0
Después: REG = 0x13, W = 0XEC Después: CONT = 0x00, Z = 1 SI_ES_0 Instrucción
NO_ES_0 Salta instrucción anterior

GOTO Salto incondicional INCF Incremento de f INCFSZ Incremento y salto

Sintaxis: [label] GOTO k Sintaxis: [label] INCF f,d Sintaxis: [label] INCFSZ f,d
Operandos: 0 £ k £ 2047 Operandos: d Î [0,1], 0 £ f £ 127 Operandos: d Î [0,1], 0 £ f £ 127
Operación: k Þ PC <8:0> Operación: : (f ) + 1 Þ (dest) Operación: (f) -1 Þ d; Salto si R=0
Flags afectados: Ninguno Flags afectados: Z Flags afectados: Ninguno
Código OP: 10 1kkk kkkk kkkk Código OP: 00 1010 dfff ffff Código OP: 00 1111 dfff ffff

Descripción: Se trata de un salto Descripción: Incrementa en 1 el Descripción: Incrementa el


incondicional. La parte baja de k se contenido de f. Si d es 0, el resultado contenido del registro f. Si d es 0, el
carga en PCL, y la alta en se almacena en W, si d es 1 se resultado se almacena en W, si d es 1
PCLATCH. Ocupa 2 ciclos de reloj. almacena en f. se almacena en f. Si la resta es 0 salta
la siguiente instrucción, en cuyo caso
Ejemplo: ORIGEN GOTO Ejemplo: INCF CONT,1 costaría 2 ciclos.
DESTINO
Antes: CONT = 0xFF, Z = 0 Ejemplo: INCFSC REG,0
Antes: PC = ORIGEN Después: CONT = 0x00, Z = 1 GOTO NO_ES_0
Después: PC = DESTINO SI_ES_0 Instrucción
NO_ES_0 Salta instrucción anterior

50
María Aranda Elcuaz Universidad Pública de Navarra

IORLW W OR literal IORWF W AND F MOVLW Cargar literal en W

Sintaxis: [label] IORLW k Sintaxis: [label] IORWF f,d Sintaxis: [label] MOVLW f
Operandos: 0 £ k £ 255 Operandos: d Î [0,1], 0 £ f £ 127 Operandos: 0 £ f £ 255
Operación: : (W) OR (k)Þ (W) Operación: (W) OR (f) Þ (dest) Operación: (k) Þ (W)
Flags afectados: Z Flags afectados: Z Flags afectados: Ninguno
Código OP: 11 1000 kkkk kkkk Código OP: 00 0100 dfff ffff Código OP: 11 00xx kkkk kkkk

Descripción: Se realiza la operación Descripción: Realiza la operación Descripción: El literal k pasa al


lógica OR entre el contenido del lógica OR entre los registros W y f. registro W.
registro W y k, guardando el Si d es 0, el resultado se almacena en
resultado en W. W, si d es 1 se almacena en f.

Ejemplo: IORLW 0x35 Ejemplo: IORWF REG,0 Ejemplo: MOVLW 0x5A

Antes: W = 0x9A Antes: W = 0x91, REG = 0x13 Después: REG = 0x4F, W = 0x5A
Después: W = 0xBF Después: W = 0x93, REG = 0x13

MOVF Mover a f MOVWF Mover a f NOP No operar

Sintaxis: [label] MOVF f,d Sintaxis: [label] MOVWF f Sintaxis: [label] NOP
Operandos: d Î [0,1], 0 £ f £ 127 Operandos: 0 £ f £ 127 Operandos: Ninguno
Operación: (f) Þ (dest) Operación: W Þ (f) Operación: No operar
Flags afectados: Z Flags afectados: Ninguno Flags afectados: Ninguno
Código OP: 00 1000 dfff ffff Código OP: 00 0000 1fff ffff Código OP: 00 0000 0xx0 0000
Descripción: El contenido del
registro f se mueve al destino d. Si d Descripción: El contenido del Descripción: No realiza operación
es 0, el resultado se almacena en W, registro W pasa el registro f. alguna. En realidad consume un ciclo
si d es 1 se almacena en f. Permite de instrucción sin hacer nada.
verificar el registro, puesto que afecta
a Z.

Ejemplo: MOVF REG,0 Ejemplo: MOVWF REG,0 Ejemplo: CLRWDT

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


Después: REG = 0x4F, W = 0x4F Preescales WDT = 0,
/TO = 1, /PD = 1

RETFIE Retorno de interrup. RETLW Retorno, carga W RETURN Retorno de rutina

Sintaxis: [label] RETFIE Sintaxis: [label] RETLW k Sintaxis: [label] RETURN


Operandos: Ninguno Operandos: 0 £ k £ 255 Operandos: Ninguno
Operación: : 1 Þ GIE; TOSÞPC Operación: : (k)Þ (W); TOSÞPC Operación: : TOS Þ PC
Flags afectados: Ninguno Flags afectados: Ninguno Flags afectados: Ninguno
Código OP: 00 0000 0000 1001 Código OP: 11 01xx kkkk kkkk Código OP: 00 0000 0000 1000

Descripción: El PC se carga con el Descripción: El registro W se carga Descripción: El PC se carga con el


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

Ejemplo: RETFIE Ejemplo: RETLW 0x37 Ejemplo: RETURN

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


GIE = 1 W = 0x37

51
María Aranda Elcuaz Universidad Pública de Navarra

RLF Rota f a la izquierda RRF Rota f a la derecha SLEEP Modo bajo consumo

Sintaxis: [label] RLF f,d Sintaxis: [label] RRF f,d Sintaxis: [label] SLEEP
Operandos: d Î [0,1], 0 £ f £ 127 Operandos: d Î [0,1], 0 £ f £ 127 Operandos: Ninguno
Operación: Rotación a la izquierda Operación: Rotación a la derecha Operación: 0x00ÞWDT, 1 Þ / TO
Flags afectados: C Flags afectados: C 0 Þ WDT Preescaler, 0 Þ / PD
Código OP: 00 1101 dfff ffff Código OP: 00 1100 dfff ffff Flags afectados: / PD, / TO
Código OP: 00 0000 0110 0011
Descripción: El contenido de f se Descripción: El contenido de f se
rota a la izquierda. El bit de menos rota a la derecha. El bit de menos Descripción: El bit de energía se
peso de f pasa al carry (C), y el carry peso de f pasa al carry (C), y el carry pone a 0, y a 1 el de descanso. El
se coloca en el de mayor peso. Si d es se coloca en el de mayor peso. Si d es WDT y su preescaler se borran. El
0, el resultado se almacena en W, si d 0, el resultado se almacena en W, si d micro para el oscilador, llendo al
es 1 se almacena en f. es 1 se almacena en f. modo “durmiente”.

Ejemplo: RRF REG,0 Ejemplo: RRF REG,0 Ejemplo: : SLEEP

Antes: REG = 1110 0110, C = 0 Antes: REG = 1110 0110, C = 1 Preescales WDT = 0,
Después: REG = 1110 0110, Después: REG = 1110 0110, /TO = 1, /PD = 1
W = 1100 1100, C = 1 W = 01110 0011, C = 0

SUBLW Resta Literal - W SUBWF Resta f – W SWAPF Intercambio de f

Sintaxis: [label] SUBLW k Sintaxis: [label] SUBWF f,d Sintaxis: [label] SWAPF f,d
Operandos: 0 £ k £ 255 Operandos: d Î [0,1], 0 £ f £ 127 Operandos: d Î [0,1], 0 £ f £ 127
Operación: ( k ) - (W) Þ (W) Operación: ( f ) – (W )Þ (dest) Operación: : (f <3: 0>)Û (f <7:4>)
Flags afectados: Z, C, DC Flags afectados: C, DC, Z Flags afectados: Ninguno
Código OP: 11 110x kkkk kkkk Código OP: 00 0010 dfff ffff Código OP: 00 1110 dfff ffff
Descripción: Mediante el método del Descripción: Mediante el método del
complemento a dos el contenido de complemento a dos el contenido de Descripción: Los 4 bits de más peso
W es restado al literal. El resultado se W es restado al de f. . Si d es 0, el y los 4 de menos son intercambiados.
almacena en W. resultado se almacena en W, si d es 1 Si d es 0, el resultado se almacena en
se almacena en f. W, si d es 1 se almacena en f.

Ejemplos: SUBLW 0x02 Ejemplos: SUBWF REG,1 Ejemplo: : SWAPF REG,0


Antes: REG = 0x03, W = 0x02, C = ?
Antes:W=1,C=?. Después: W=1, C=1 Después:REG=0x01, W = 0x4F, C=1 Antes: REG = 0xA5
Antes:W=2,C=?. Después: W=0, C=1 Antes: REG = 0x02, W = 0x02, C = ? Después: REG = 0xA5, W = 0x5A
Antes:W=3,C=?.Después:W=FF,C=0 Después:REG=0x00, W =0x02, C= 1
(El resultado es negativo) Antes: REG= 0x01, W= 0x02, C= ?
Después:REG=0xFF, W=0x02, C= 0
(Resultado negativo)

XORLW W OR literal XORWF W AND F

Sintaxis: [label] XORLW k Sintaxis: [label] XORWF f,d La gama media tiene un
Operandos: 0 £ k £ 255 Operandos: d Î [0,1], 0 £ f £ 127
Operación: : (W) XOR (k)Þ (W) Operación: (W) XOR (f) Þ (dest)
total de 35 instrucciones,
Flags afectados: Z Flags afectados: Z cada una de las cuales
Código OP: 11 1010 kkkk kkkk Código OP: 00 0110 dfff ffff ocupan 14 bits.
Descripción: Se realiza la operación Descripción: Realiza la operación
lógica XOR entre el contenido del lógica XOR entre los registros W y f.
registro W y k, guardando el Si d es 0, el resultado se almacena en
resultado en W. W, si d es 1 se almacena en f.

Ejemplo: : XORLW 0xAF Ejemplo: : XORWF REG,0

Antes: W = 0xB5 Antes: W = 0xB5, REG = 0xAF


Después: W = 0x1A 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 <Nombre_Fichero>
#INCLUDE "Nombre_Fichero"

Esta directiva hace que el compilador incluya en el fichero fuente el texto que contiene
el archivo especificado en <Nombre_Fichero>.

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 los parámetros) del conversor


analógico/digital. Los modos son los siguientes:

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 define un número de 8 bits sin signo


unsigned int define un número de 8 bits sin signo
int define un número de 8 bits sin signo
char define un número de 8 bits sin signo
long define un número de 16 bits sin signo
long int define un número de 16 bits sin signo

67
María Aranda Elcuaz Universidad Pública de Navarra

signed define un número de 8 bits con signo


signed int define un número de 8 bits con signo
signed long define un número de 16 bits con signo
float define un número de 32 bits en punto flotante
short define un bit
short int 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 BANK1 bsf STATUS,5 ;Macro para abreviar el BANCO 1
#define BANK0 bcf STATUS,5 ;Macro para abreviar el BANCO 0
org 0 ;Posición 0 de la memoria de programa
INIC BANK1 ;Selección del Banco 1
clrf TRISB ;Se configura todo el puerto B como salida
movlw b'11010111' ;Se configura el registro
movwf OPTION_REG ;OPTION:TMR0:Preescaler 256
BANK0 ;Selección del Banco 0
clrf PORTB ;Apaga todos los leds del puerto B
PARPA bsf PORTB,0 ;Enciende el led RB0
call RETAR ;Llama a la rutina de RETARDO
bcf PORTB,0 ;Apaga el led RB0
call RETAR ;Llama a la rutina de RETARDO
goto PARPA ;Comienza de nuevo el ciclo PARPA
RETAR clrf TMR0 ;TMR0=0 y empieza su incremento
LOOP btfss INTCON,2 ;Se ha desbordado?
goto LOOP ;No, repite el proceso
bcf INTCON,2 ;Si, se pone el flag a 0
return ;retorna al programa principal
end ;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 No
Apagar led
pulsado?


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 BANK1 bsf STATUS,5 ;Macro para abreviar el BANCO 1
#define BANK0 bcf STATUS,5 ;Macro para abreviar el BANCO 0

73
María Aranda Elcuaz Universidad Pública de Navarra

org 0 ;Posición 0 de la memoria de programa


INIC BANK1 ;Seleccion del Banco 1
clrf TRISB ;Configura el puerto B como Salida
movlw b'00001000' ;
movwf TRISA ;Configura el pulsador en RA4 como Entrada
movlw b'11010010' ;Se configura el registro
;OPTION:TMR0:Preescaler 8
movwf OPTION_REG ;
BANK0 ;selección del Banco 0
WAIT clrf PORTB ;Apaga los LEDS borrando el puerto B
btfsc PORTA,4 ;Lee el interruptor y espera a que sea "0". Han
;pulsado?
goto WAIT ;No han pulsado, va a la etiqueta WAIT
call RETAR ;Si han pulsado, llama a la rutina de RETARDO
PULSA bsf PORTB,1 ;Bit 1 del PUERTO B "1". Enciende el LED
btfss PORTA,4 ;Lee el interruptor y espera a que sea "1". Han
;soltado?
goto PULSA ;No, va a la etiqueta PULSAR
call WAIT ;Si, va a la etiqueta WAIT
RETAR clrf TMR0 ;TMR0=0 y empieza su incremento
LOOP btfss INTCON,2 ;Se ha desbordado?
goto LOOP ;No, repite el proceso
bcf INTCON,2 ;Si, se pone el flag a 0
return ;retorna al programa principal
end ;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 No
carácter?


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 <lcd-picdem.c> //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(); //Inicia la pantalla


lcd_putc(" Hola "); //Envía Hola
delay_ms(5000); //Pausa de 5 segundos
lcd_putc("\f"); //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"); //Vuelve a borrar pantalla
lcd_gotoxy(1,2); //Y coloca el cursor en la segunda
//línea
lcd_putc(" Adios! "); //Envia Adios
delay_ms(5000); //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?


Turno = 1

Posicionar cursor
Escribir LCD

Chequeo Pulsador

¿Han pulsado?

Sí No
Retardo rebotes

Incrementar turno

No
Turno>99?

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 <lcd-picdem.c>
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); //PIN RA4 como entrada
lcd_init(); // Comandos de inicialización del LCD.
lcd_putc("Turno: ");
turno = read_eeprom(0); //Lee la posición 0 de la EEPROM
if((turno<1)||(turno>99)) //Poner a 1 si está fuera del rango
{
turno=1;
}
Visualizar_Turno(); //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:

<adc.c>

#include <16F877.h>
#device adc=8
#use delay(clock=4000000)
#include <lcd-picdem.c>
#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

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

No
RB0 ON?


Cambiar duty a 1,5 ms

No
RA4 ON?


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); // Configura CCP1 como PWM
setup_timer_2(T2_DIV_BY_16,124,1); // f=500Hz (T=2ms)
set_pwm1_duty(62); // 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 <lcd-picdem.c>
#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); // Configura CCP1 como PWM
setup_timer_2(T2_DIV_BY_16,124,1); // f=500Hz (T=2ms)
setup_adc(adc_clock_div_32); // Selecciona Reloj
setup_adc_ports(AN0); // RA0 analogico
set_adc_channel(0);
while(1)
{
valor=read_adc(); // Lee valor RA0
set_pwm1_duty(valor); // Establece duty como valor
calcula_duty(valor,duty); // Escala el duty
lcd_gotoxy(8,2);
printf(lcd_putc,"%3.2f",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, PARITY=N, XMIT=PIN_C6, RCV=PIN_C7,
RESTART_WDT)
#include <lcd-picdem.c>
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 Parte 1 Parte 2

Incluir librería
LCD y RS232 Enviar cadenas para Enviar cadenas para
selección de frec al PC selección de duty al PC
Declarar variables
Recibir respuesta vía Recibir respuesta vía
RS232 RS232
Iniciar Pantalla y led
Convertir ASCII Convertir ASCII
Configurar CCP1 a entero a entero
como PWM
Escribir EEPROM Escribir EEPROM
Leer EEPROM

No ¿Frecuencia No ¿Duty
Seleccionar
frecuencia y duty correcta? correcto?

Enviar datos al PC Sí Sí
Seleccionar frecuencia Seleccionar duty
(PR2) (CCPR1L)
Parte 1
Mandar datos LCD Mandar datos LCD
Parte 2
Mandar datos PC Mandar datos PC

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:

<Pwmrs232.c>

#include <16f877.h>
#fuses HS,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP

#use delay(clock=4000000)
#use RS232(BAUD=9600, BITS=8, PARITY=N, XMIT=PIN_C6, RCV=PIN_C7,
RESTART_WDT)
#use fast_io(B)
#byte PORTB=6
#include <lcd-picdem.c>
#include <stdlib.h>
char c[1];
long int k1,k2;
main()
{
lcd_init();
lcd_gotoxy(1,1);

PORTB=0b00000010; // B1 será el led para la modulación


setup_ccp1(CCP_PWM); // 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, 2 o 3 segun a la frecuencia que ahora prefieras


trabajar: ");
puts("1. f=500Hz (T=2ms=2000us)");
puts("2. f=2kHz (T=0.5ms=500us)");
puts("3. f=20kHz (T=50us)");

gets(c);
k1 = atoi32(c); //Convierte los ascii recibidos a numero entero.
write_eeprom(0,k1); // 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); // Duty=1,5ms
puts("Has seleccionado el duty de 1.5ms");
lcd_putc(" Duty = 1.5ms ");
}
if (k2==2)
{
set_pwm1_duty(16); // Duty=750us
puts("Has seleccionado el duty de 750us");
lcd_putc(" 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 Enviar cadenas para


selección de frec al PC selección de duty al PC

Recibir respuesta vía Recibir respuesta vía


RS232 RS232

Convertir ASCII Convertir ASCII


a entero a entero

Calcular PR2 Calcular CCPR1L

No
No ¿PR2 ¿CCPR1L
válido? correcto?

Sí Sí
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.

<Pwmrs232version1.2>

#include <16f877.h>
#fuses HS,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
#use delay(clock=4000000)
#use RS232(BAUD=9600, BITS=8, PARITY=N, XMIT=PIN_C6, RCV=PIN_C7,
RESTART_WDT)
#use fast_io(B)
#byte PORTB=6
#include <lcd-picdem.c>
#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; // B1 led para la modulación
setup_ccp1(CCP_PWM); // 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); //Devuelve el dato recibido
puts(" ");
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 de Datos
RD0 D4
RD1 D5
RD2 D6
RD3 D7
////////////////////////////////////////////////////////////////////////
struct lcd_pines_control
{ // Estructura que se define para facilitar acceso
booleannada;
booleanenable; //y asociarlos a los 3 bits más bajos del PORTA
booleanrw; //se asigna luego a esta estructura el PORTA
booleanrs; //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 //Se pone la estructura entera en el PORTA
#byte trisa = 0x85 //Registro de dirección de datos
#byte lcd_datos = 8 //Lo mismo para los datos, en el PORTD
#byte trisd = 0x88 //Registro de dirección de datos

114
María Aranda Elcuaz Universidad Pública de Navarra

#define lcd_linea_dos 0x40 //Dirección de inicio para la 2ª línea en la


//DDRAM

////////////////////////////////////////////////////////////////////////
-Prototipos de las funciones
////////////////////////////////////////////////////////////////////////
void lcd_init();
byte lcd_read_byte();
void lcd_send_nibble(byte n);
void lcd_send_byte(byte address, byte n);
void lcd_gotoxy(byte x, byte y);
void lcd_putc(char c);
char lcd_getc(byte x, byte y);
void 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 envía Function set 0 0 1 DL N F -
lcd_send_byte(0,0b00001100);//Se envía Display on/off 0 0 0 0 1 D C B
lcd_send_byte(0,0b00000001);//Se envía Clear Display
lcd_send_byte(0,0b00000110);//Se envía 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 PIN_A0 40
#define PIN_A1 41
#define PIN_A2 42
#define PIN_A3 43
#define PIN_A4 44
#define PIN_A5 45
#define PIN_B0 48
#define PIN_B1 49
#define PIN_B2 50
#define PIN_B3 51
#define PIN_B4 52
#define PIN_B5 53
#define PIN_B6 54
#define PIN_B7 55
#define PIN_C0 56
#define PIN_C1 57
#define PIN_C2 58
#define PIN_C3 59
#define PIN_C4 60
#define PIN_C5 61
#define PIN_C6 62
#define PIN_C7 63
#define PIN_D0 64
#define PIN_D1 65
#define PIN_D2 66
#define PIN_D3 67
#define PIN_D4 68
#define PIN_D5 69
#define PIN_D6 70
#define PIN_D7 71
#define PIN_E0 72
#define PIN_E1 73
#define PIN_E2 74
///////////////////////////////////////////////////////// Useful defines
#define FALSE 0
#define TRUE 1

#define BYTE int


#define BOOLEAN short int

#define getc getch


#define fgetc getch
#define getchar getch
#define 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 RTCC_DIV_1 8
#define RTCC_DIV_2 0
#define RTCC_DIV_4 1
#define RTCC_DIV_8 2
#define RTCC_DIV_16 3
#define RTCC_DIV_32 4
#define RTCC_DIV_64 5
#define RTCC_DIV_128 6
#define RTCC_DIV_256 7

#define RTCC_8_BIT 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 T1_DIV_BY_1 0
#define T1_DIV_BY_2 0x10
#define T1_DIV_BY_4 0x20
#define T1_DIV_BY_8 0x30

//////////////////////////////////////////////////////////////// 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
I0
Vi
V0
T2

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 T2 V0
1 0 Vi
0 1 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 Universidad Pública de Navarra

V0 Vi Vi Vi

0 0

ton toff
T
Figura 2

La tensión <V0> o tensión V0 media se calcula como sigue:

Vi ·ton + 0·toff t
< Vo >= = Vi · on = Vi ·D
T T

Donde <V0> Є [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 T2 Ii
1 0 0
0 1 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 I0

0 0

ton toff
T
Figura 3

123
María Aranda Elcuaz Universidad Pública de Navarra

Para el cálculo de la corriente intermedia <Ii>:

t on ·I 0 + t off ·0 t on
< I i >= = I0 = I 0 ·D Donde <Ii> Є [0,I0]
T T

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·<Ii>=Vi ·I0·D


PVo= <V0>·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

Modulador
V0 Є [0,Vi]

T2

Figura 4

v0 Є [0,1] T1
[0,1]
V0 Є [0,Vi]
T2
Vi VTRI

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 toff

T1 On

Off

T2 On

Off

V0 Vi

<V0>

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 <V0> se pueden emplear dos métodos distintos:

1º método: De la misma manera que se ha calculado hasta ahora:

Vi ·ton + 0·toff t
< Vo >= = Vi · on
T T

125
María Aranda Elcuaz Universidad Pública de Navarra

2º método: Por semejanza triangular:

1 v0 t
De la gráfica de la onda triangular se obtiene que: = Þ on = v0
T ton T
V0
pero como v0 =
Vi
ton V0
se puede sustituir y queda: = ,
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

También podría gustarte