Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Guia Pics Completa
Guia Pics Completa
Índice general
Título __Página
INTRODUCCIÓN…………………………………………………………………………..5
MEMORIA………………………………………………………………………………….8
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
1
María Aranda Elcuaz Universidad Pública de Navarra
Título __Página
2
María Aranda Elcuaz Universidad Pública de Navarra
Título __Página
Capítulo 4: Prácticas…………………………………………………………………………...70
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
ANEXOS…………………………………………………………………………………113
1.1. LCD………………………………………………………………….114
1.2. PIC 16F877…………………………………………………………..118
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
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.
Para realizar este dispositivo es necesario seguir una serie de pautas o fases que se
detallan a continuación.
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.
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.
7
María Aranda Elcuaz Universidad Pública de Navarra
MEMORIA
8
María Aranda Elcuaz Universidad Pública de Navarra
1.1 Definición
1.2.2 Procesador
9
María Aranda Elcuaz Universidad Pública de Navarra
1.2.3 Memoria
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.
2ª. OTP
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
4ª EEPROM
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.
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
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.
1. Temporizadores o “Timers”:
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:
6. Comparador analógico:
8. Puertas de comunicació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.
13
María Aranda Elcuaz Universidad Pública de Navarra
1.5 Fabricantes
Otras empresas como Hitachi, Texas, Toshiba y Zilog abarcan pequeñas partes del
mercado.
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.
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
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.
MEMORIA DE MEMORIA DE
CPU
DATOS INSTRUCCIONES
8 12
Figura 2.1.a
15
María Aranda Elcuaz Universidad Pública de Navarra
CLK
ciclo
Fin INSTR0
Fin INSTR1
Fin INSTR2
Figura 2.1.b
Esto significa que todos los objetos del sistema (puertas de E/S, temporizadores,
posiciones de memoria, etc.) están implementados físicamente como registros.
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
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.
Al igual que todos los miembros de la familia PIC16/17, los componentes de la gama
baja se caracterizan por poseer los siguientes recursos.
Todos los PIC tienen la facultad de generar un auto reset al conectarles la alimentación.
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
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.
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.
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.
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.
18
María Aranda Elcuaz Universidad Pública de Navarra
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.
19
María Aranda Elcuaz Universidad Pública de Navarra
Los registros son de 8 bits y están formados por cuatro bancos como se puede ver en la
figura 2.3.2:
20
María Aranda Elcuaz Universidad Pública de Navarra
21
María Aranda Elcuaz Universidad Pública de Navarra
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.
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.
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.
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:
23
María Aranda Elcuaz Universidad Pública de Navarra
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.
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:
24
María Aranda Elcuaz Universidad Pública de Navarra
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.
25
María Aranda Elcuaz Universidad Pública de Navarra
En la siguiente tabla se muestran las características más relevantes de los PIC 16F87X:
Todos estos elementos que se muestran en la tabla serán analizados y explicados en los
puntos sucesivos de este capítulo.
26
María Aranda Elcuaz Universidad Pública de Navarra
27
María Aranda Elcuaz Universidad Pública de Navarra
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.
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:
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.
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.
29
María Aranda Elcuaz Universidad Pública de Navarra
2.4.2.4 Reset
El reset de los microcontroladores puede ser originado por las siguientes causas:
30
María Aranda Elcuaz Universidad Pública de Navarra
Los bits TO y PD del Registro de Estado toman el valor correspondiente según la causa
que haya provocado el reset.
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 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.
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.
32
María Aranda Elcuaz Universidad Pública de Navarra
2.5 Periféricos
2.5.1 Puertos de entrada y salida
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.
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
El módulo de A/D tiene cuatro registros que son: ADRESH, ADRESL, ADCON0 y
ADCON1.
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).
Finalmente, se describen de forma resumida los pasos para realizar una conversión en el
CA/D:
36
María Aranda Elcuaz Universidad Pública de Navarra
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.
37
María Aranda Elcuaz Universidad Pública de Navarra
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.
38
María Aranda Elcuaz Universidad Pública de Navarra
La salida EQ se puede utilizar como señal de reloj para el modulo de interfaz serie SSP.
Los módulos CCP1 y CCP2 son idénticos, excepto en ciertas funciones especiales de
disparo. Ambos constan de dos registros CCPRxH y CCPRxL.
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
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.
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.
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.
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.
40
María Aranda Elcuaz Universidad Pública de Navarra
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:
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 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.
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.
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.
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.
La interfaz de comunicaciones SCI proporciona las mismas prestaciones que una UART
programable. Se puede configurar de dos modo diferentes:
Asíncrono (full-duplex)
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.
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
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.
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.
45
María Aranda Elcuaz Universidad Pública de Navarra
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.
46
María Aranda Elcuaz Universidad Pública de Navarra
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.
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
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.
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.
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.
49
María Aranda Elcuaz Universidad Pública de Navarra
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
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
50
María Aranda Elcuaz Universidad Pública de Navarra
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
Antes: W = 0x9A Antes: W = 0x91, REG = 0x13 Después: REG = 0x4F, W = 0x5A
Después: W = 0xBF Después: W = 0x93, REG = 0x13
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.
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”.
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
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.
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.
52
María Aranda Elcuaz Universidad Pública de Navarra
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
53
María Aranda Elcuaz Universidad Pública de Navarra
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
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.
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.
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.
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.
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:
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.
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:
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.
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.
#IF expresión_constante
#ELSE
#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>.
#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:
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
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.
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.
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.
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
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).
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.
62
María Aranda Elcuaz Universidad Pública de Navarra
SET_UART_SPEED(baud)
SETUP_ADC(mode)
ADC_OFF
ADC_CLOCK_DIV_2
ADC_CLOCK_DIV_8
ADC_CLOCK_DIV_32
ADC_CLOCK_INTERNAL
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)
DELAY_CYCLES(count)
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.
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()
3.3.3.5 Contadores/Temporizadores
GET_RTCC()
GET_TIMER0()
GET_TIMER1()
i=GET_TIMER2()
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)
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().
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().
- T2_DISABLED
- T2_DIV_BY_1
- T2_DIV_BY_4
- T2_DIV_BY_16
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)
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.
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.
READ_EEPROM(address)
WRITE_EEPROM(address, value)
Especificadores de tipo:
67
María Aranda Elcuaz Universidad Pública de Navarra
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_...
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.
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.
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
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.
4.1.1.1 Organigrama
Inicio
Puerto B: Salida
Inicialización de registros
Encender Led
Retardo 65 ms
Apagar Led
Retardo 65 ms
Para el correcto diseño de este programa habrá que seguir estos tres simples pasos:
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:
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:
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.
<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
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:
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.
#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.
72
María Aranda Elcuaz Universidad Pública de Navarra
4.1.2.1 Organigrama
Inicio
Chequeo pulsador
¿Han No
Apagar led
pulsado?
Sí
Retardo para evitar rebotes
Encender led
Para dar solución a este problema se deben seguir los siguientes pasos:
<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
4.1.2.3 Solución en c
<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
}
}
}
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:
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.
75
María Aranda Elcuaz Universidad Pública de Navarra
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.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?
Sí
Borrar pantalla
Situar cursor
Enviar menaje 3
Retardo 5000 ms
4.2.1.2 Solución
Para que este programa funcione correctamente primero habrá que inicializar la pantalla
con su correspondiente función en el programa principal. Los mensajes primero y tercero
son simples, bastará una función para enviarlos y el suficiente retardo para que la vista de
cualquier persona sea capaz de percibirlo. Sin embargo, el segundo mensaje será un poco
más complicado, primeramente habrá que definir un vector de caracteres que contenga el
abecedario y todos los números a enviar. Posteriormente, y ya en el programa principal,
habrá que generar un bucle para ir moviéndose a lo largo de toda la pantalla y asimismo
meter el retardo solicitado de 0,5s entre el envío del primer carácter y el segundo.
<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;
78
María Aranda Elcuaz Universidad Pública de Navarra
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.
4.2.2.1 Organigrama
Inicio
Leer EEPROM
No
Turno>99?
Sí
Turno = 1
Posicionar cursor
Escribir LCD
Chequeo Pulsador
¿Han pulsado?
Sí No
Retardo rebotes
Incrementar turno
No
Turno>99?
Sí
79
María Aranda Elcuaz Universidad Pública de Navarra
Turno = 1
Escribir EEPROM
Situar Cursor
Enviar turno al LCD
4.2.2.2 Solución
Para diseñar este programa será necesario conocer las funciones para el manejo de la
Eeprom que se pueden encontrar en el capítulo del lenguaje C. Por otra parte, se
recomienda generar una rutina que coloque el cursor en todo momento para sobrescribir el
número y que a su vez lo muestre a través de la pantalla LCD; A esta rutina se le podrá
llamar cuando sea necesario.
<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
81
María Aranda Elcuaz Universidad Pública de Navarra
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
82
María Aranda Elcuaz Universidad Pública de Navarra
Seleccionar canal
Hacer conversión AD
Escalar valores
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.
<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);
84
María Aranda Elcuaz Universidad Pública de Navarra
4.4 PWM
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
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.
85
María Aranda Elcuaz Universidad Pública de Navarra
4.4.1.1 Organigrama
Inicio
Configurar puertos
Configurar CCP1
Elegir frecuencia
Inicializar Duty
Comprobar pulsadores
No
RB0 ON?
Sí
Cambiar duty a 1,5 ms
No
RA4 ON?
Sí
Cambiar duty a 750 ms
4.4.1.2 Solución
Para los cálculos de PR2 y CCPRL1 hay que tener en cuenta que el oscilador de la placa
de pruebas PICDEM 2 PLUS trabaja a una frecuencia de oscilación de 4MHz y
TMR2preescaler se le da el valor de 16. Con esto y despejando de las fórmulas dadas se
obtiene que para una frecuencia de 500 Hz habrá que cargar PR2 con el valor 124.
Por otro lado se trabajará con 8 bits por lo tanto los bits CCPCON1<5:4> se cargan con
00 y así despejando de la segunda fórmula dada se tendrá que los valores de CCPR1L
serán de 62 para los 1 ms de salida, 94 cuando se pulsa RB0 y 16 al pulsar RA4.
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.
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.
Para los cálculos de PR2 y CCPR1L emplear las fórmulas dadas en el ejercicio anterior.
4.4.2.1 Organigrama
Inicio
87
María Aranda Elcuaz Universidad Pública de Navarra
Iniciar LCD
Configurar CCP1
Seleccionar frecuencia
Encender ADC
Seleccionar canal
Convertir AD
Establecer Duty
Escalar Duty
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
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.
89
María Aranda Elcuaz Universidad Pública de Navarra
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.
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.
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.1 Organigrama
Inicio
Iniciar LCD
Transmitir cadena a PC
Escribir LCD
Situar cursor
Escribirlo en la LCD
91
María Aranda Elcuaz Universidad Pública de Navarra
4.5.1.2 Solución
<1rs232.c>
#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;
}
}
}
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
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.
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.
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
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
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
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);
//Esta parte hasta el bucle infinito comprueba la eeprom para saber con
//que valores se trabajó anteriormente
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:
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:
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(" ");
}
}
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
Declarar variables
Seleccionar duty
Enviar datos al PC
Parte 1
Parte 2
97
María Aranda Elcuaz Universidad Pública de Navarra
Parte 1 Parte 2
No
No ¿PR2 ¿CCPR1L
válido? correcto?
Sí Sí
Seleccionar frecuencia Seleccionar duty
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:
99
María Aranda Elcuaz Universidad Pública de Navarra
100
María Aranda Elcuaz Universidad Pública de Navarra
5.1 Introducción
5.1.1 El CAN y su historia
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
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
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
Figura 5.2.b
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.
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.
Figura 5.3.1.a
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).
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
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…
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.
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.
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.
- 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
Figura 5.4.1.d
105
María Aranda Elcuaz Universidad Pública de Navarra
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)
CRC: Código de redundancia cíclica: Tras comprobar este código se podrá comprobar
si se han producido errores.
Fin de trama (EOF): Consiste en 7 bits recesivos sucesivos e indica el final de la trama.
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
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.
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 Indicador de error es distinto según el estado de error del nodo que detecta el error:
Figura 5.4.3.a
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
Figura 5.4.3.c
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.
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.
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.
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.
109
María Aranda Elcuaz Universidad Pública de Navarra
Figura 5.5.b
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.
Ejemplos de protocolo de más alto nivel pueden ser CANopen y MCNet protocol
110
María Aranda Elcuaz Universidad Pública de Navarra
Es la arquitectura más simple, para llevar a cabo una comunicación en una red CAN
será necesario:
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.
Figura 5.8.2
111
María Aranda Elcuaz Universidad Pública de Navarra
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
////////////////////////////////////////////////////////////////////////
-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;
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
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
-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
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
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
#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
118
María Aranda Elcuaz Universidad Pública de Navarra
//////////////////////////////////////////////////////////////// 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
////////////////////////////////////////////////////////////////// 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
////////////////////////////////////////////////////////////////// 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
T1
I0
Vi
V0
T2
Figura 1
Por lo tanto, con estas dos reglas de funcionamiento se obtienen las leyes de
conmutación para T1 y T2:
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?
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
Vi ·ton + 0·toff t
< Vo >= = Vi · on = Vi ·D
T T
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
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
t on ·I 0 + t off ·0 t on
< I i >= = I0 = I 0 ·D Donde <Ii> Є [0,I0]
T T
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:
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
VTRI
1
v0
ton toff
T1 On
Off
T2 On
Off
V0 Vi
<V0>
Para calcular la tensión media <V0> se pueden emplear dos métodos distintos:
Vi ·ton + 0·toff t
< Vo >= = Vi · on
T T
125
María Aranda Elcuaz Universidad Pública de Navarra
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
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:
Artículos técnicos:
Datasheet:
Páginas Web:
142