Libro MIKROC Milan Verle

402
Programación en C - Mikro C Página | 1 MICROCONTROLADORES PIC PROGRAMACIÓN EN C MikroC

Transcript of Libro MIKROC Milan Verle

Page 1: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 1

MICROCONTROLADORES PIC

PROGRAMACIÓN EN C

MikroC

Page 2: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 2

Book: PIC Microcontrollers - Programming in C

Capitulo 1: El mundo de los microcontroladores

La situación actual en el campo de los microcontroladores se ha producido

gracias al desarrollo de la tecnología de fabricación de los circuitos

integrados. Este desarrollo ha permitido construir las centenas de miles de

transistores en un chip. Esto fue una condición previa para la fabricación de

un microprocesador. Las primeras microcomputadoras se fabricaron al

añadirles periféricos externos, tales como memoria, líneas de

entrada/salida, temporizadores u otros. El incremento posterior de la

densidad de integración permitió crear un circuito integrado que contenía

tanto al procesador como periféricos. Así es cómo fue desarrollada la

primera microcomputadora en un solo chip, denominada más tarde

microcontrolador.

1.1 Introducción

1.2 NÚMEROS, NÚMEROS, NÚMEROS...

1.3 DETALLES IMPORTANTES

1.4 MICROCONTROLADORES PIC

1.1 INTRODUCCIÓN

Los principiantes en electrónica creen que un microcontrolador es igual a un

microprocesador. Esto no es cierto. Difieren uno del otro en muchos

sentidos. La primera y la más importante diferencia es su funcionalidad.

Para utilizar al microprocesador en una aplicación real, se debe de conectar

con componentes tales como memoria o componentes buses de

transmisión de datos. Aunque el microprocesador se considera una

máquina de computación poderosa, no está preparado para la

comunicación con los dispositivos periféricos que se le conectan. Para que

el microprocesador se comunique con algún periférico, se deben utilizar los

circuitos especiales. Así era en el principio y esta práctica sigue vigente en

la actualidad.

Page 3: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 3

Por otro lado, al microcontrolador se le diseña de tal manera que tenga

todas las componentes integradas en el mismo chip. No necesita de otros

componentes especializados para su aplicación, porque todos los circuitos

necesarios, que de otra manera correspondan a los periféricos, ya se

encuentran incorporados. Así se ahorra tiempo y espacio necesario para

construir un dispositivo.

¿QUE PUEDEN HACER LOS MICROCONTROLADORES?

Para entender con más facilidad las razones del éxito tan grande de los

microcontroladores, vamos a prestar atención al siguiente ejemplo. Hace

unos 10 años, diseñar un dispositivo electrónico de control de un ascensor

de un edificio de varios pisos era muy difícil, incluso para un equipo de

expertos. ¿Ha pensado alguna vez en qué requisitos debe cumplir un

simple ascensor? ¿Cómo lidiar con la situación cuando dos o más personas

llaman al ascensor al mismo tiempo? ¿Cuál llamada tiene la prioridad?

¿Cómo solucionar las cuestiones de seguridad, de pérdida de electricidad,

de fallos, de uso indebido? Lo que sucede después de resolver estos

problemas básicos es un proceso meticuloso de diseñar los dispositivos

adecuados utilizando un gran número de los chips especializados. Este

proceso puede tardar semanas o meses, dependiendo de la complejidad del

dispositivo. Cuando haya terminado el proceso, llega la hora de diseñar una

Page 4: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 4

placa de circuito impreso y de montar el dispositivo.¡Un dispositivo enorme!

Es otro trabajo difícil y tardado. Por último, cuando todo está terminado y

probado adecuadamente, pasamos al momento crucial y es cuando uno se

concentra, respira profundamente y enciende la fuente de alimentación.

Esto suele ser el punto en el que la fiesta se convierte en un verdadero

trabajo puesto que los dispositivos electrónicos casi nunca funcionan

apropiadamente desde el inicio. Prepárese para muchas noches sin dormir,

correcciones, mejoras... y no se olvide de que todavía estamos hablando de

cómo poner en marcha un simple ascensor.

Cuando el dispositivo finalmente empiece a funcionar perfectamente y todo

el mundo esté satisfecho, y le paguen por el trabajo que ha hecho, muchas

compañías de desarrollo estarán interesadas en su trabajo. Por supuesto, si

tiene suerte, cada día le traerá una oferta de trabajo de un nuevo

inversionista. Sin embargo, si lo requieren para trabajar en el control de los

elevadores de un nuevo edificio que tiene cuatro pisos más de los que ya

maneja su sistema de control. ¿Sabe cómo proceder? ¿Cree acaso que se

pueden controlar las demandas de sus clientes? Pensamos que usted va a

construir un dispositivo universal que se puede utilizar en los edificios de 4 a

40 pisos, una obra maestra de electrónica. Bueno, incluso si usted consigue

construir una joya electrónica, su inversionista le esperarará delante de la

puerta pidiendo una cámara en el ascensor o una música relajante en caso

de fallo de ascensor. O un ascensor con dos puertas.

De todos modos, la ley de Murphy es inexorable y sin duda usted no podrá

tomar ventaja a pesar de todos los esfuerzos que ha hecho. Por desgracia,

todo lo que se ha dicho hasta ahora sucede en la realidad. Esto es lo que

“dedicarse a la ingeniería electrónica” realmente significa. Es así como se

hacían las cosas hasta aparición de los microcontroladores diseñados -

pequeños, potentes y baratos. Desde ese momento su programación dejó

de ser una ciencia, y todo tomó otra dirección ...

El dispositivo electrónico capaz de controlar un pequeño submarino, una

grúa o un ascensor como el anteriormente mencionado, ahora está

incorporado en un sólo chip. Los microcontroladores ofrecen una amplia

gama de aplicaciones y sólo algunas se exploran normalmente. Le toca a

usted decidir qué quiere que haga el microcontrolador y cargar un programa

en él con las instrucciones apropiadas. Antes de encender el dispositivo es

recomendable verificar su funcionamiento con ayuda de un simulador. Si

todo funciona como es debido, incorpore el microcontrolador en el sistema.

Si alguna vez necesita cambiar, mejorar o actualizar el programa, hágalo.

Page 5: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 5

¿Hasta cuándo? Hasta quedar satisfecho. Eso puede realizarse sin ningún

problema.

Page 6: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 6

Sabía usted que todas las personas pueden ser clasificadas en uno de 10

grupos, en los que están familiarizados con el sistema de numeración

binario y en los que no están familiarizados con él. Si no entendió lo anterior

significa que todavía pertenece al segundo grupo. Si desea cambiar su

estado, lea el siguiente texto que describe brevemente algunos de los

conceptos básicos utilizados más tarde en este libro (sólo para estar seguro

de que estamos hablando en los mismos términos).

1.2 NÚMEROS, NÚMEROS, NÚMEROS...

¡La matemática es una gran ciencia! Todo es tan lógico y simple... El

universo de los números se puede describir con sólo diez dígitos. No

obstante, ¿realmente tiene que ser así? ¿Necesitamos exactamente esos

10 dígitos? Por supuesto que no, es sólo cuestión del hábito. Acuérdese de

las lecciones de la escuela. Por ejemplo, ¿qué significa el número 764?

Cuatro unidades, seis decenas y siete centenas. ¡Muy simple! ¿Se podría

expresar de una forma más desarrollada? Por supuesto que sí: 4 + 60 +

700. ¿Aún más desarrollado? Sí: 4*1 + 6*10 + 7*100. ¿Podría este número

parecer un poco más “científico”? La respuesta es sí otra vez: 4*100 +

6*101 + 7*102. ¿Qué significa esto realmente? ¿Por qué utilizamos

exactamente estos números 100, 101 y 102 ? ¿Por qué es siempre el

número 10? Es porque utilizamos 10 dígitos diferentes (0, 1, 2...8, 9). En

otras palabras, es porque utilizamos el sistema de numeración en base 10,

es decir el sistema de numeración decimal.

Page 7: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 7

SISTEMA DE NUMERACIÓN BINARIO

¿Qué pasaría si utilizáramos sólo dos números 0 y 1? Si sólo pudiéramos

afirmar (1) o negar (0) que algo existe. La respuesta es “nada especial”,

seguiríamos utilizando los mismos números de la misma manera que

utilizamos hoy en día, no obstante ellos parecerían un poco diferentes. Por

ejemplo: 11011010.¿Cuántas son realmente 11011010 páginas de un libro?

Para entenderlo, siga la misma lógica como en el ejemplo anterior, pero en

el orden invertido. Tenga en cuenta que se trata de aritmética con sólo dos

dígitos 0 y 1, es decir, del sistema de numeración en base 2 (sistema de

numeración binario).

Page 8: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 8

Evidentemente, se trata del mismo número representado en dos sistemas

de numeración diferentes. La única diferencia entre estas dos

representaciones yace en el número de dígitos necesarios para escribir un

número. Un dígito (2) se utiliza para escribir el número 2 en el sistema

decimal, mientras que dos dígitos (1 y 0) se utilizan para escribir aquel

número en el sistema binario. ¿Ahora está de acuerdo que hay 10 grupos

de gente? ¡Bienvenido al mundo de la aritmética binaria! ¿Tiene alguna idea

de dónde se utiliza?

Excepto en las condiciones de laboratorio estrictamente controladas, los

circuitos electrónicos más complicados no pueden especificar con exactitud

la diferencia entre dos magnitudes (dos valores de voltaje, por ejemplo), si

son demasiado pequeños (más pequeños que unos pocos voltios). La razón

son los ruidos eléctricos y fenómenos que se presentan dentro de lo que

llamamos “entorno de trabajo real” (algunos ejemplos de estos fenómenos

son los cambios imprevisibles de la tensión de alimentación, cambios de

temperatura, tolerancia a los valores de los componentes etc...). Imagínese

una computadora que opera sobre números decimales al tratarlos de la

siguiente manera: 0=0V, 1=5V, 2=10V, 3=15V, 4=20V... 9=45V!?

¿Alguien dijo baterías?

Una solución mucho más fácil es una lógica binaria donde 0 indica la

ausencia de voltaje, mientras que 1 indica la presencia de voltaje.

Simplemente, es fácil de escribir 0 o 1 en vez de “no hay voltaje” o “ hay

voltaje”. Mediante el cero lógico (0) y uno lógico (1) la electrónica se

enfrenta perfectamente y realiza con facilidad todas las operaciones

aritméticas. Evidentemente, se trata de electrónica que en realidad aplica

aritmética en la que todos los números son representados con sólo dos

Page 9: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 9

dígitos y donde sólo es importante saber si hay voltaje o no. Por supuesto,

estamos hablando de electrónica digital.

SISTEMA DE NUMERACIÓN HEXADECIMAL

En el principio del desarrollo de las computadoras era evidente que a la

gente le costaba mucho trabajar con números binarios. Por eso, se

estableció un nuevo sistema de numeración, que utilizaba 16 símbolos

diferentes. Es llamado el sistema de numeración hexadecimal. Este sistema

está compuesto de 10 dígitos a los que estamos acostumbrados (0, 1, 2,

3,... 9) y de seis letras del alfabeto A, B, C, D, E y F. ¿Cuál es el propósito

de esta combinación aparentemente extraña? Basta con mirar cómo todo

en la historia de los números binarios encaja perfectamente para lograr una

mejor comprensión del tema.

El mayor número que puede ser representado con 4 dígitos binarios es el

número 1111. Corresponde al número 15 en el sistema decimal. En el

sistema hexadecimal ese número se representa con sólo un dígito F. Es el

mayor número de un dígito en el sistema hexadecimal. ¿Se da cuenta de la

gran utilidad de estas equivalencias? El mayor número escrito con ocho

dígitos binarios es a la vez el mayor número de dos dígitos en el sistema

hexadecimal. Tenga en cuenta que una computadora utiliza números

binarios de 8 dígitos. ¿Acaso se trata de una casualidad?

CÓDIGO BCD

El código BCD (Binary-Coded Decimal - Código binario decimal) es un

código binario utilizado para representar a los números decimales. Se utiliza

para que los circuitos electrónicos puedan comunicarse con los periféricos

utilizando el sistema de numeración decimal o bien utilizando el sistema

binario dentro de “su propio mundo”. Consiste en números binarios de 4

dígitos que representan los primeros diez dígitos (0, 1, 2, 3...8, 9). Aunque

cuatro dígitos pueden hacer 16 combinaciones posibles en total, el código

BCD normalmente utiliza a las primeras diez.

Page 10: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 10

CONVERSIÓN DE SISTEMAS DE NÚMERACIÓN

El sistema de numeración binario es el que utilizan los microcontroladores,

el sistema decimal es el que nos resulta más comprensible, mientras que el

sistema hexadecimal presenta un balance entre los dos. Por eso, es muy

importante aprender cómo convertir los números de un sistema de

numeración a otro, por ejemplo, cómo convertir una serie de ceros y unos a

una forma de representación comprensible para nosotros.

CONVERSIÓN DE NÚMEROS BINARIOS A DECIMALES

Los dígitos en un número binario tienen ponderaciones diferentes lo que

depende de sus posiciones dentro del número que están representando.

Además, cada dígito puede ser 1 o 0, y su ponderación se puede

determinar con facilidad al contar su posición empezando por la derecha.

Para hacer una conversión de un número binario a decimal es necesario

multiplicar las ponderaciones con los dígitos correspondientes (0 o 1) y

sumar todos los resultados. La magia de la conversión de un número binario

a decimal funciona de maravilla... ¿Tiene duda? Veamos el siguiente

ejemplo:

Cabe destacar que es necesario utilizar sólo dos dígitos binarios para

representar a todos los números decimales de 0 a 3. Por consiguiente, para

representar los números de 0 a 7 es necesario utilizar tres dígitos binarios,

para representar los números de 0 a 15 - cuatro dígitos etc. Dicho de

manera sencilla, el mayor número binario que se puede representar

utilizando n dígitos se obtiene al elevar la base 2 a la potencia n. Luego, al

resultado se le resta 1. Por ejemplo, si n=4:

24 - 1 = 16 - 1 = 15

Por consiguiente, al utilizar 4 dígitos binarios, es posible representar los

números decimales de 0 a 15, que son 16 valores diferentes en total.

CONVERSIÓN DE NÚMEROS HEXADECIMALES A DECIMALES

Para realizar una conversión de un número hexadecimal a decimal, cada

dígito hexadecimal debe ser multiplicado con el número 16 elevado al valor

de su posición. Por ejemplo:

Page 11: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 11

CONVERSIÓN DE NÚMEROS HEXADECIMALES A BINARIOS

No es necesario realizar ningún cálculo para convertir un número

hexadecimal a binario. Los dígitos hexadecimales se reemplazan

simplemente por los cuatro dígitos binarios apropiados. Ya que el dígito

hexadecimal máximo es equivalente al número decimal 15, es necesario

utilizar cuatro dígitos binarios para representar un dígito hexadecimal. Por

ejemplo:

MARCAR LOS NÚMEROS

El sistema de numeración hexadecimal, junto con los sistemas binario y

decimal, se consideran los más importantes para nosotros. Es fácil realizar

una conversión de cualquier número hexadecimal a binario, además es fácil

de recordarlo. Sin obstante, estas conversiones pueden provocar una

confusión. Por ejemplo, ¿qué significa en realidad la sentencia: “Es

necesario contar 110 productos en una cadena de montaje”? Dependiendo

del sistema en cuestión (binario, decimal o hexadecimal), el resultado

podría ser 6, 110 o 272 productos, respectivamente. Por consiguiente, para

evitar equivocaciones, diferentes prefijos y sufijos se añaden directamente a

los números. El prefijo $ o 0x así como el sufijo h marca los números en el

sistema hexadecimal. Por ejemplo, el número hexadecimal 10AF se puede

escribir así: $10AF, 0x10AF o 10AFh. De manera similar, los números

binarios normalmente obtienen el sufijo % o 0B. Si un número no tiene ni

sufijo ni prefijo se considera decimal. Desafortunadamente, esta forma de

Page 12: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 12

marcar los números no es estandarizada, por consiguiente depende de la

aplicación concreta.

La siguiente es tabla comparativa que contiene los valores de números 0-

255 representados en tres sistemas de numeración diferentes. Esto es

probablemente la manera más fácil de entender lógica común aplicada a

todos los sistemas de numeración.

NÚMEROS NEGATIVOS

Como ya hemos visto, para escribir un número negativo en matemáticas,

basta con añadirle el prefijo “-” (signo menos). Sin embargo, en la

programación, al acabarse el proceso de la compilación, se quedan sólo los

números binarios, volviéndose las cosas más complicadas. Se utilizan sólo

dos dígitos - 0 y 1, mientras que todos los demás números, símbolos y

signos se forman por medio de las combinaciones de estos dos dígitos. En

el caso de los números negativos, la solución es la siguiente: En los

números negativos, el bit más significativo (el bit del extremo izquierdo)

representa el signo del número (donde 0 será positivo y 1 negativo). En el

caso de un número de 8 bits, para representar un valor numérico sólo

Page 13: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 13

quedan 7 bits. De acuerdo a este tipo de codificación el número +127 es el

mayor número positivo con signo que se puede representar con 8 bits.

Asimismo, hay cero (0) positivo y negativo (refiérase a la tabla de la

derecha). La siguiente pregunta sería: ¿Cómo es posible saber de qué

número se trata? Por ejemplo, si ponemos el número 10000001, ¿es -1 o

129? No se preocupe, de eso se encarga el compilador. Ésta es la razón

por la que se declaran variables al escribir el programa. Bueno, de eso

vamos a hablar a continuación.

BIT

La teoría dice que un bit es la unidad básica de información...Vamos a

olvidarlo por un momento y demostrar qué es eso en la práctica. La

respuesta es - nada especial- un bit es un sólo dígito binario. Similar a un

sistema de numeración decimal en el que los dígitos de un número no

tienen la misma ponderación (por ejemplo, los dígitos en el número 444 son

los mismos pero tienen los valores diferentes), el “significado” de un bit

depende de la posición que tiene en número binario. En este caso no tiene

sentido hablar de unidades, centenas etc. en los números binarios, sus

dígitos se denominan el bit cero (el primer bit a la derecha), el primer bit (el

segundo bit a la derecha) etc. Además, ya que el sistema binario utiliza

solamente dos dígitos (0 y 1), el valor de un bit puede ser 0 o 1.

No se confunda si se encuentra con un bit que tiene el valor 4, 16 o 64. Son

los valores representados en el sistema decimal. Simplemente, nos hemos

acostumbrado tanto a utilizar los números decimales que estas expresiones

llegaron a ser comunes. Sería correcto decir por ejemplo, “el valor del sexto

bit en cualquier número binario equivale al número decimal 64”. Pero todos

somos humanos y los viejos hábitos mueren difícilmente. Además, ¿cómo le

suena “número uno-uno-cero-uno-cero...”?

Page 14: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 14

BYTE

Un byte consiste en 8 bits colocados uno junto al otro. Si un bit es un dígito,

es lógico que los bytes representen los números. Todas las operaciones

matemáticas se pueden realizar por medio de ellos, como por medio de los

números decimales comunes. Similar a los dígitos de cualquier número, los

dígitos de un byte no tienen el mismo significado. El bit del extremo

izquierdo tiene la mayor ponderación, por eso es denominado el bit más

significativo (MSB). El bit del extremo derecho tiene la menor ponderación,

por eso es denominado el bit menos significativo (LSB). Puesto que los 8

dígitos de un byte se pueden combinar de 256 maneras diferentes, el mayor

número decimal que se puede representar con un byte es 255 (una

combinación representa un cero).

Un nibble o un cuarteto representa una mitad de byte. Dependiendo de la

mitad del número en cuestión (izquierda o derecha), se les denomina

nibbles “altos” o “bajos”, respectivamente.

Usted seguramente ha pensado alguna vez en cómo es la electrónica

dentro de un circuito integrado digital, un microcontrolador o un

microprocesador. ¿Cómo son los circuitos que realizan las operaciones

matemáticas complicadas y toman decisiones? ¿Sabía que sus esquemas,

aparentemente complicadas consisten en sólo unos pocos elementos

diferentes, denominados circuitos lógicos o compuertas lógicas?

1.3 DETALLES IMPORTANTES

El funcionamiento de estos elementos es basado en los principios

establecidos por el matemático británico George Boole en la mitad del siglo

19 - es decir, ¡antes de la invención de la primera bombilla! En breve, la

idea principal era de expresar las formas lógicas por medio de las funciones

algebraicas. Tal idea pronto se transformó en un producto práctico que se

convirtió más tarde en lo que hoy en día conocemos como circuitos lógicos

Y (AND), O (OR) o NO (NOT). El principio de su funcionamiento es

conocido como algebra de Boole.

Page 15: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 15

CIRCUITOS LÓGICOS

Algunas instrucciones de programa utilizadas por un microcontrolador

funcionan de la misma manera que las compuertas lógicas, pero en forma

de comandos. A continuación vamos a explicar el principio de su

funcionamiento.

COMPUERTA Y (AND)

Una compuerta lógica “Y” dispone de dos o más entradas y de una salida.

En este caso la compuerta utilizada dispone de sólo dos entradas. Un uno

lógico (1) aparecerá en su salida sólo en caso de que ambas entradas (A Y

B) sean llevadas a alto (1). La tabla a la derecha es la tabla de verdad que

muestra la relación entre las entradas y salidas de la compuerta. El principio

de funcionamiento es el mismo cuando la compuerta disponga de más de

dos entradas: la salida proporciona un uno lógico (1) sólo si todas las

entradas son llevadas a alto (1).

Cualquier otra combinación de voltajes de entrada proporcionará un cero

lógico (0) en su salida. Utilizada en el programa, la operación Y lógico es

realizada por una instrucción de programa, de la que vamos a hablar más

tarde. Por ahora basta con conocer que Y lógico en un programa se refiere

a la realización de este tipo de operación sobre los bits correspondientes de

dos registros diferentes.

Page 16: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 16

COMPUERTA O (OR)

De manera similar, la compuerta O también dispone de dos o más entradas

y de una salida. Si la compuerta dispone de sólo dos entradas, es aplicable

lo siguiente: la salida proporciona un uno lógico (1) si una u otra entrada (A

o B) es llevada a alto (1). En caso de que la compuerta O disponga de más

de dos entradas, es aplicable lo siguiente: La salida proporciona un uno

lógico (1) si por lo menos una entrada es llevada a alto (1). Si todas las

entradas están a cero lógico (0), la salida estará a cero lógico (0) también.

En un programa, la operación O lógico se realiza de la misma manera que

la operación Y.

COMPUERTA NO (NOT)

La compuerta lógica NO dispone de una sola entrada y una sola salida, por

lo que funciona muy simplemente. Cuando un cero lógico (0) aparezca en

su entrada, la salida proporciona un uno lógico (1) y viceversa. Esto

significa que esta compuerta invierte las señales por sí mismas y por eso es

denominada inversor.

Page 17: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 17

En el programa la operación lógica NO se realiza sobre un byte. El

resultado es un byte con los bits invertidos. Si los bits de un byte se

consideran número, el valor invertido es un complemento a ese número. El

complemento de un número es el valor que se añade al número hasta llegar

al mayor número binario de 8 dígitos. En otras palabras, la suma de un

dígito de 8 números y de su complemento es siempre 255.

COMPUERTA XOR (O EXCLUSIVA)

La compuerta XOR (O EXCLUSIVA) es un poco complicada en

comparación con las demás. Representa una combinación de todas las

compuertas anteriormente descritas. La salida proporciona un uno lógico (1)

sólo si sus entradas están en estados lógicos diferentes.

En el programa, esta operación se utiliza con frecuencia para comparar dos

bytes. La resta se puede utilizar con el mismo propósito (si el resultado es 0,

los bytes son iguales). A diferencia de la resta, la ventaja de esta operación

lógica es que no es posible obtener los resultados negativos.

Page 18: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 18

REGISTROS

Un registro o una celda de memoria es un circuito electrónico que puede

memorizar el estado de un byte.

REGISTROS SFR

A diferencia de los registros que no tienen ninguna función especial y

predeterminada, cada microcontrolador dispone de un número de registros

de funciones especiales (SFR), con la función predeterminada por el

fabricante. Sus bits están conectados a los circuitos internos del

microcontrolador tales como temporizadores, convertidores A/D, osciladores

entre otros, lo que significa que directamente manejan el funcionamiento de

estos circuitos, o sea del microcontrolador. Imagínese ocho interruptores

que manejan el funcionamiento de un circuito pequeño dentro del

microcontrolador. Los registros SFR hacen exactamente lo mismo.

Page 19: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 19

En otras palabras, el estado de los bits de registros se fija dentro de

programa, los registros SFR dirigen los pequeños circuitos dentro del

microcontrolador, estos circuitos se conectan por los pines del

microcontrolador a un dispositivo periférico utilizado para... Bueno, depende

de usted.

PUERTOS DE ENTRADA/SALIDA (E/S)

Para hacer útil un microcontrolador, hay que conectarlo a un dispositivo

externo, o sea, a un periférico. Cada microcontrolador tiene uno o más

registros (denominados puertos) conectados a los pines en el

microcontrolador. ¿Por qué se denominan como puertos de entrada/salida?

Porque usted puede cambiar la función de cada pin como quiera. Por

ejemplo, usted desea que su dispositivo encienda y apague los tres señales

LEDs y que simultáneamente monitoree el estado lógico de 5 sensores o

botones de presión. Uno de los puertos debe estar configurado de tal

manera que haya tres salidas (conectadas a los LEDs) y cinco entradas

(conectadas a los sensores). Eso se realiza simplemente por medio de

software, lo que significa que la función de algún pin puede ser cambiada

durante el funcionamiento.

Una de las características más importantes de los pines de entrada/salida

(E/S) es la corriente máxima que pueden entregar/recibir. En la mayoría de

los microcontroladores la corriente obtenida de un pin es suficiente para

activar un LED u otro dispositivo de baja corriente (10-20mA). Mientras más

Page 20: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 20

pines de E/S haya, más baja es la corriente máxima de un pin. En otras

palabras, todos los puertos de E/S comparten la corriente máxima

declarada en la hoja de especificación técnica del microprocesador.

Otra característica importante de los pines es que pueden disponer de los

resistores pull-up. Estos resistores conectan los pines al polo positivo del

voltaje de la fuente de alimentación y su efecto se puede ver al configurar el

pin como una entrada conectada a un interruptor mecánico o a un botón de

presión. Las últimas versiones de los microcontroladores tienen las

resistencias pull-up configurables por software.

Cada puerto de E/S normalmente está bajo el control de un registro SFR

especializado, lo que significa que cada bit de ese registro determina el

estado del pin correspondiente en el el microcontrolador. Por ejemplo, al

escribir un uno lógico (1) a un bit del registro de control (SFR), el pin

apropiado del puerto se configura automáticamente como salida. Eso

significa que el voltaje llevado a ese pin se puede leer como 0 o 1 lógico. En

caso contrario, al escribir 0 al registro SFR, el pin apropiado del puerto se

configura como salida. Su voltaje (0V o 5V) corresponde al estado del bit

apropiado del registro del puerto.

UNIDAD DE MEMORIA

La unidad de memoria es una parte del microcontrolador utilizada para

almacenar los datos. La manera más fácil de explicarlo es compararlo con

un armario grande con muchos cajones. Si marcamos los cajones

claramente, será fácil acceder a cualquiera de sus contenidos al leer la

etiqueta en la parte delantera del cajón.

Page 21: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 21

De manera similar, cada dirección de memoria corresponde a una localidad

de memoria. El contenido de cualquier localidad se puede leer y se le puede

acceder al direccionarla. La memoria se puede escribir en la localidad o

leer.

Hay varios tipos de memoria dentro del microcontrolador:

MEMORIA ROM (READ ONLY MEMORY) - MEMORIA DE SÓLO

LECTURA

La memoria ROM se utiliza para guardar permanentemente el programa

que se está ejecutando. El tamaño de programa que se puede escribir

depende del tamaño de esta memoria. Los microcontroladores actuales

normalmente utilizan el direccionamiento de 16 bits, que significa que son

capaces de direccionar hasta 64 Kb de memoria, o sea 65535 localidades.

Por ejemplo, si usted es principiante, su programa excederá pocas veces el

límite de varios cientos de instrucciones. Hay varios tipos de memoria ROM.

Rom de máscara (enmascarada) - MROM

La ROM enmascarada es un tipo de ROM cuyo contenido es programado

por el fabricante. El término “de máscara” viene del proceso de fabricación,

donde las partes del chip se plasman en las mascaras utilizadas durante el

proceso de fotolitografía. En caso de fabricación de grandes series, el

precio es muy bajo. Olvide la idea de modificarla...

Page 22: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 22

OTP ROM (One Time Programmable ROM) - ROM programable una

sola vez

La memoria programable una sola vez permite descargar un programa en el

chip, pero como dice su nombre, una sola vez. Si se detecta un error

después de descargarlo, lo único que se puede hacer es descargar el

programa correcto en otro chip.

UV EPROM (UV Erasable Programmable ROM) - ROM programable

borrable por rayos ultravioleta

El encapsulado de este microcontrolador tiene una “ventana” reconocible en

la parte alta. Eso permite exponer la superficie del chip de silicio a la luz de

ultravioleta y borrar el programa completamente en varios minutos. Luego

es posible descargar un nuevo programa en él.

La instalación de esta ventana es complicada, lo que por supuesto afecta al

precio. Desde nuestro punto de vista, desgraciadamente, de manera

negativa...

Memoria Flash

Este tipo de memoria se inventó en los años 80 en los laboratorios de la

compañía INTEL, como forma desarrollada de la memoria UV EPROM. Ya

que es posible escribir y borrar el contenido de esta memoria prácticamente

un número ilimitado de veces, los microcontroladores con memoria Flash

son perfectos para estudiar, experimentar y para la fabricación en pequeña

escala. Por la gran popularidad de esta memoria, la mayoría de los

Page 23: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 23

microconroladores se fabrican con tecnología flash hoy en día. Si usted va a

comprar un microcontrolador, ¡éste es en definitiva la opción perfecta!

MEMORIA RAM (RANDOM ACCESS MEMORY) - MEMORIA DE

ACCESO ALEATORIO

Al apagar la fuente de alimentación, se pierde el contenido de la memoria

RAM. Se utiliza para almacenar temporalmente los datos y los resultados

inmediatos creados y utilizados durante el funcionamiento del

microcontrolador. Por ejemplo, si el programa ejecuta la adición (de

cualquier cosa) es necesario tener un registro que representa lo que se

llama “suma” en vida cotidiana. Con tal propósito, uno de los registros de la

RAM es denominado “suma” y se utiliza para almacenar los resultados de la

adición.

MEMORIA EEPROM (ELECTRICALLY ERASABLE PROGRAMMABLE

ROM) - ROM PROGRAMABLE Y BORRABLE ELÉCTRICAMENTE

El contenido de la EEPROM se puede cambiar durante el funcionamiento

(similar a la RAM), pero se queda permanentemente guardado después de

la pérdida de la fuente de alimentación (similar a la ROM). Por lo tanto, la

EEPROM se utiliza con frecuencia para almacenar los valores creados

durante el funcionamiento, que tienen que estar permanentemente

guardados. Por ejemplo, si usted ha diseñado una llave electrónica o un

alarma, sería estupendo permitir al usuario crear e introducir una

contraseña por su cuenta. Por supuesto, la nueva contraseña tiene que

estar guardada al apagar la fuente de alimentación. En tal caso una

solución perfecta es el microcontrolador con una EEPROM embebida.

INTERRUPCIÓN

La mayoría de programas utilizan interrupciones durante ejecución de

programa regular. El propósito del microcontrolador generalmente consiste

en reaccionar a los cambios en su entorno. En otras palabras, cuando

ocurre algo, el microcontrolador reacciona de alguna manera... Por ejemplo,

al apretar el botón del mando a distancia, el microcontrolador lo registra y

responde al comando cambiando de canal, subiendo o bajando el volumen

etc. Si el microcontrolador pasará la mayoría del tiempo comprobando

varios botones sin parar - las horas, los días, esto no sería nada práctico.

Page 24: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 24

Por lo tanto, el microcontrolador “aprendió un truco” durante su evolución.

En vez de seguir comprobando algún pin o bit, el microconrolador deja su

“trabajo de esperar” a un “experto” que reaccionará sólo en caso de que

suceda algo digno de atención.

La señal que informa al procesador central acerca de tal acontecimiento se

denomina INTERRUPCIÓN.

UNIDAD CENTRAL DE PROCESAMIENTO (CENTRAL PROCESSOR

UNIT - CPU)

Como indica su nombre, esto es una unidad que controla todos los

procesos dentro del microcontrolador. Consiste en varias unidades más

pequeñas, de las que las más importantes son:

Decodificador de instrucciones es la parte que descodifica las

instrucciones del programa y acciona otros circuitos basándose en

esto. El “conjunto de instrucciones” que es diferente para cada familia

de microcontrolador expresa las capacidades de este circuito;

Unidad lógica aritmética (Arithmetical Logical Unit - ALU) realiza

todas las operaciones matemáticas y lógicas sobre datos; y

Acumulador o registro de trabajo. Es un registro SFR estrechamente

relacionado con el funcionamiento de la ALU. Es utilizado para

almacenar todos los datos sobre los que se debe realizar alguna

operación (sumar, mover). También almacena los resultados

preparados para el procesamiento futuro. Uno de los registros SFR,

denominado Registro Status (PSW), está estrechamente relacionado

con el acumulador. Muestra el “estado” de un número almacenado en

el acumulador (el número es mayor o menor que cero etc.) en

cualquier instante dado.

Page 25: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 25

BUS

El bus está formado por 8, 16 o más cables. Hay dos tipos de buses: el bus

de direcciones y el bus de datos. El bus de direcciones consiste en tantas

líneas como sean necesarias para direccionar la memoria. Se utiliza para

transmitir la dirección de la CPU a la memoria. El bus de datos es tan ancho

como los datos, en este caso es de 8 bits o líneas de ancho. Se utiliza para

conectar todos los circuitos dentro del microcontrolador.

COMUNICACIÓN EN SERIE

La conexión paralela entre el microcontrolador y los periféricos a través de

los puertos de entrada/salida es una solución perfecta para las distancias

cortas - hasta varios metros. No obstante, en otros casos cuando es

necesario establecer comunicación entre dos dispositivos a largas

distancias no es posible utilizar la conexión paralela. En vez de eso, se

utiliza la conexión en serie.

Hoy en día, la mayoría de los microcontroladores llevan incorporados varios

sistemas diferentes para la comunicación en serie, como un equipo

estándar. Cuál de estos sistemas se utilizará en un caso concreto, depende

de muchos factores, de los que más importantes son:

¿Con cuántos dispositivos el microcontrolador tiene que intercambiar

los datos?

¿Cuál es la velocidad del intercambio de datos obligatoria?

¿Cuál es la distancia entre los dispositivos?

¿Es necesario transmitir y recibir los datos simultáneamente?

Page 26: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 26

Una de las cosas más importantes en cuanto a la comunicación en serie es

el Protocolo que debe ser estrictamente observado. Es un conjunto de

reglas que se aplican obligatoriamente para que los dispositivos puedan

interpretar correctamente los datos que intercambian mutuamente.

Afortunadamente, los microcontroladores se encargan de eso

automáticamente, así que el trabajo de programador/usuario es reducido a

la escritura y lectura de datos.

VELOCIDAD DE TRANSMISIÓN SERIAL

La velocidad de transmisión serial (baud rate) es el término utilizado para

denotar el número de bits transmitidos por segundo [bps]. ¡Fíjese que este

término se refiere a bits, y no a bytes! El protocolo normalmente requiere

que cada byte se transmita junto con varios bits de control. Eso quiere decir

que un byte en un flujo de datos serial puede consistir en 11 bits. Por

ejemplo, si velocidad de transmisión serial es 300 bps un máximo de 37 y

un mínimo de 27 bytes se pueden transmitir por segundo.

Los sistemas de comunicación serial más utilizados son:

I2C (INTER INTEGRATED CIRCUIT) - CIRCUITO INTER-INTEGRADO

Circuito inter-integrado es un sistema para el intercambio de datos serial

entre los microcontroladores y los circuitos integrados especializados de

Page 27: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 27

generación. Se utiliza cuando la distancia entre ellos es corta (el receptor y

el transmisor están normalmente en la misma placa de circuito impreso). La

conexión se establece por medio de dos líneas - una se utiliza para

transmitir los datos, mientras que la otra se utiliza para la sincronización (la

señal de reloj). Como se muestra en la figura, un dispositivo es siempre el

principal (master - maestro), el que realiza el direccionamiento de un chip

subordinado (slave - esclavo) antes de que se inicie la comunicación. De

esta manera un microcontrolador puede comunicarse con 112 dispositivos

diferentes. La velocidad de transmisión serial es normalmente 100 Kb/seg

(el modo estándar) o 10 Kb/seg (modo de velocidad de transmisión baja).

Recientemente han aparecido los sistemas con la velocidad de transmisión

serial 3.4 Mb/sec. La distancia entre los dispositivos que se comunican por

el bus I2C está limitada a unos metros.

SPI (SERIAL PERIPHERAL INTERFACE BUS) - BUS SERIAL DE

INTERFAZ DE PERIFÉRICOS

Un bus serial de interfaz de periféricos es un sistema para la comunicación

serial que utiliza hasta cuatro líneas (normalmente solo son necesarias tres)

- para recibir los datos, para transmitir los datos, para sincronizar y

(opcional) para seleccionar el dispositivo con el que se comunica. Esto es la

conexión full duplex, lo que significa que los datos se envían y se reciben

simultáneamente.

La velocidad de transmisión máxima es mayor que en el sistema de

conexión I2C.

Page 28: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 28

UART (UNIVERSAL ASYNCHRONOUS RECEIVER/TRANSMITTER) -

TRANSMISOR-RECEPTOR ASÍNCRONO UNIVERSAL

Este tipo de conexión es asíncrona, lo que significa que no se utiliza una

línea especial para transmitir la señal de reloj. En algunas aplicaciones este

rasgo es crucial (por ejemplo, en mandar datos a distancia por RF o por luz

infrarroja). Puesto que se utiliza sólo una línea de comunicación, tanto el

receptor como el transmisor reciben y envían los datos a velocidad misma

que ha sido predefinida para mantener la sincronización necesaria. Esto es

una manera simple de transmitir datos puesto que básicamente representa

una conversión de datos de 8 bits de paralelo a serial. La velocidad de

transmisión no es alta, es hasta 1 Mbit/sec.

OSCILADOR

Los pulsos uniformes generados por el oscilador permiten el funcionamiento

armónico y síncrono de todos los circuitos del microcontrolador. El oscilador

se configura normalmente de tal manera que utilice un cristal de cuarzo o

resonador cerámico para estabilización de frecuencia. Además, puede

Page 29: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 29

funcionar como un circuito autónomo (como oscilador RC). Es importante

decir que las instrucciones del programa no se ejecutan a la velocidad

impuesta por el mismo oscilador sino varias veces más despacio. Eso

ocurre porque cada instrucción se ejecuta en varios ciclos del oscilador. En

algunos microcontroladores se necesita el mismo número de ciclos para

ejecutar todas las instrucciones, mientras que en otros el tiempo de

ejecución no es el mismo para todas las instrucciones. Por consiguiente, si

el sistema utiliza el cristal de cuarzo con una frecuencia de 20 MHZ, el

tiempo de ejecución de una instrucción de programa no es 50 nS, sino 200,

400 o 800 nS dependiendo del tipo del microcontrolador.

CIRCUITO DE ALIMENTACIÓN

Hay que mencionar dos cosas dignas de atención con relación al circuito de

la fuente de alimentación de microcontroladores:

Brown out es un estado potencialmente peligroso que ocurre al

apagar el microcontrolador o en caso de que el voltaje de la fuente de

alimentación salga de unos márgenes debido al ruido eléctrico. Como

el microcontrolador dispone de varios circuitos que funcionan a

niveles de voltaje diferentes, ese estado puede causar un

comportamiento descontrolado. Para evitarlo, el microcontrolador

normalmente tiene un circuito incorporado para el brown out reset. El

circuito reinicia inmediatamente el microcontrolador si el voltaje de

alimentación cae por debajo del límite.

El pin de reset (reinicio), marcado frecuentemente con MCLR (Master

Clear Reset), sirve para el reinicio externo del microcontrolador al

aplicar un cero (0) o un uno (1) lógico dependiendo del tipo del

microcontrolador. En caso de que el circuito brown out no esté

incorporado, un simple circuito externo para el brown out reset se

puede conectar al pin MCLR.

Page 30: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 30

TEMPORIZADORES/CONTADORES

El oscilador del microcontrolador utiliza cristal de cuarzo para su

funcionamiento. Aunque no se trata de la solución más simple, hay muchas

razones para utilizarlo. La frecuencia del oscilador es definida con precisión

y muy estable, así que siempre genera los pulsos del mismo ancho, lo que

los hace perfectos para medición de tiempo. Tales osciladores se utilizan en

los relojes de cuarzo. Si es necesario medir el tiempo transcurrido entre dos

eventos, basta con contar los pulsos generados por este oscilador. Esto es

exactamente lo que hace el temporizador.

La mayoría de los programas utiliza estos cronómetros electrónicos en

miniatura. Generalmente son registros SFR de 8 o 16 bits cuyo contenido se

aumenta automáticamente con cada pulso. ¡Una vez que se llena el

registro, se genera una interrupción!

Si el temporizador utiliza el oscilador de cuarzo interno para su

funcionamiento, es posible medir el tiempo entre dos eventos (el valor de

registro en el momento de iniciar la medición es T1, en el momento de

Page 31: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 31

finalizar la medición es T2, el tiempo transcurrido es igual al resultado de la

resta T2 - T1). Si los registros se aumentan con los pulsos que vienen de la

fuente externa, tal temporizador se convierte en un contador.

Esto es una explicación simple de su funcionamiento. Es un poco más

complicado en práctica.

¿CÓMO FUNCIONAN LOS TEMPORIZADORES?

En práctica, los pulsos generados por el oscilador de cuarzo son llevados al

circuito una vez por cada ciclo de máquina directamente o por el pre-

escalador, lo que aumenta el número en el registro del temporizador. Si una

instrucción (un ciclo de máquina) dura cuatro períodos del oscilador de

cuarzo, este número será cambiado un millón de veces por segundo (cada

microsegundo) al incorporar al cuarzo que oscila con una frecuencia de 4

MHz.

Es fácil de medir los intervalos de tiempo cortos de la manera descrita

anteriormente (hasta 256 microsegundos porque es el mayor número que

un registro puede contener). Esta obvia desventaja se puede superar de

varias maneras: al utilizar el oscilador más lento, por medio de registros con

más bits, del pre-escalador o de la interrupción. Las primeras dos

soluciones tienen algunas debilidades así que se recomienda utilizar el pre-

escalador y/o la interrupción.

UTILIZAR UN PREESCALADOR EN EL FUNCIONAMIENTO DEL

TEMPORIZADOR

Un pre-escalador es un dispositivo electrónico utilizado para dividir la

frecuencia por un factor predeterminado. Esto quiere decir que se necesita

llevar 1, 2, 4 o más pulsos a su entrada para generar un pulso a la salida.

La mayoría de los microcontroladores disponen de uno o más pre-

Page 32: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 32

escaladores incorporados y su tasa de división puede ser cambiada dentro

del programa. El pre-escalador se utiliza cuando es necesario medir los

períodos de tiempo más largos. Si el temporizador y el temporizador perro

guardián comparten un pre-escalador, éste no se puede utilizar por los dos

simultáneamente.

UTILIZAR UNA INTERRUPCIÓN EN EL FUNCIONAMIENTO DEL

TEMPORIZADOR

Si el registro del temporizador es de 8 bits, el mayor número que se puede

escribir en él es 255 (en los registros de 16 bits es el número 65.535). Si se

excede este número, el temporizador se reinicia automáticamente y el

conteo comienza de nuevo en cero. Esto es denominado desbordamiento o

sobreflujo (overflow). Permitido por el programa, el desbordamiento puede

provocar una interrupción, lo que abre completamente nuevas posibilidades.

Por ejemplo, el estado de registros utilizados para contar segundos, minutos

o días puede ser implementado en una rutina de interrupción. El proceso

entero (excepto la rutina de interrupción) se lleva a cabo internamente, lo

que permite que los circuitos principales del microcontrolador funcionen

regularmente.

Page 33: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 33

La figura anterior describe el uso de una interrupción en el funcionamiento

del temporizador. Al asignarle un pre-escalador al temporizador, se

producen retrasos de duración arbitraria con mínima interferencia en la

ejecución del programa principal.

CONTADORES

Si un temporizador se suministra por los pulsos ingresados por el pin de

entrada en el microcontrolador, se produce un contador. Evidentemente, es

el mismo circuito electrónico. La única diferencia es que los pulsos para

contar se ingresan por el pin de entrada y que su duración (anchura) no es

definida. Por eso, no se pueden utilizar para medición de tiempo, sino que

se utilizan para otros propósitos, por ejemplo: contar los productos en la

cadena de montaje, número de rotaciones del eje de un motor, pasajeros

etc. (dependiendo del sensor utilizado.

TEMPORIZADOR PERRO GUARDIÁN (WATCHDOG)

El perro guardián es un temporizador conectado a un oscilador RC

completamente independiente dentro del microcontrolador.

Si el perro guardián está habilitado, cada vez que cuenta hasta el máximo

valor en el que ocurre el desbordamiento del registro se genera una señal

de reinicio del microcontrolador y la ejecución de programa inicia en la

primera instrucción. El punto es evitar que eso ocurra al utilizar el comando

adecuado.

La idea se basa en el hecho de que cada programa se ejecuta en varios

bucles, más largos o cortos. Si las instrucciones que reinician el

temporizador perro guardián se colocan en lugares estratégicos del

Page 34: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 34

programa, aparte los comandos que se ejecutan regularmente, el

funcionamiento del perro guardián no afectará a la ejecución del programa.

Si por cualquier razón (ruidos eléctricos frecuentes en la industria) el

contador de programa “se queda atrapado” dentro de un bucle infinito, el

valor del registro continuará aumentado por el temporizador perro guardián

alcanzará el máximo valor, el registro se desbordará y, ¡aleluya! ¡Ocurre el

reinicio!

CONVERTIDOR A/D

Las señales del mundo real son muy diferentes de las que “entiende” el

microcontrolador (ceros y unos), así que deben ser convertidas para que el

microcontrolador pueda entenderlas. Un convertidor analógico-digital es un

Page 35: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 35

circuito electrónico encargado de convertir las señales continuas en

números digitales discretos. En otras palabras, este circuito convierte un

número real en un número binario y se lo envía a la CPU para ser

procesado. Este módulo se utiliza para medir el voltaje en el pin de entrada.

El resultado de esta medición es un número (el valor digital) utilizado y

procesado más tarde en el programa.

ARQUITECTURA INTERNA

Todos los microcontroladores actuales utilizan uno de dos modelos básicos

de arquitectura denominados Harvard y von-Neumann.

Son dos maneras diferentes del intercambio de datos entre la CPU y la

memoria.

Page 36: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 36

Arquitectura de von-Neumann

Los microcontroladores que utilizan la arquitectura von- Neumann disponen

de un solo bloque de memoria y de un bus de datos de 8 bits. Como todos

los datos se intercambian por medio de estas 8 líneas, este bus está

sobrecargado, y la comunicación por si misma es muy lenta e ineficaz. La

CPU puede leer una instrucción o leer/escribir datos de/en la memoria. Los

dos procesos no pueden ocurrir a la vez puesto que las instrucciones y los

datos utilizan el mismo bus. Por ejemplo, si alguna línea de programa dice

que el registro de la memoria RAM llamado “SUM” debe ser aumentado por

uno (instrucción: incf SUMA), el microcontrolador hará lo siguiente:

1. Leer la parte de la instrucción de programa que especifica QUÉ es lo

que debe realizar (en este caso es la instrucción para incrementar “incf”)

2. Seguir leyendo la misma instrucción que especifica sobre CUÁL dato lo

debe realizar (en este caso es el contenido del registro “SUMA”)

3. Después de haber sido incrementado, el contenido de este registro se

debe escribir en el registro del que fue leído (dirección del registro

“SUMA”)

El mismo bus de datos se utiliza para todas estas operaciones intermedias.

Page 37: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 37

ARQUITECTURA DE HARVARD

Los microcontroladores que utilizan esta arquitectura disponen de dos

buses de datos diferentes. Uno es de 8 bits de ancho y conecta la CPU con

la memoria RAM. El otro consiste en varias líneas (12, 14 o 16) y conecta a

la CPU y la memoria ROM. Por consiguiente, la CPU puede leer las

instrucciones y realizar el acceso a la memoria de datos a la vez. Puesto

que todos los registros de la memoria RAM son de 8 bits de ancho, todos

los datos dentro del microcontrolador que se intercambian son de la misma

anchura. Durante el proceso de la escritura de programa, sólo se manejan

los datos de 8 bits. En otras palabras, todo lo que usted podrá cambiar en el

programa y a lo que podrá afectar será de 8 bits de ancho. Todos los

programas escritos para estos microcontroladores serán almacenados en la

memoria ROM interna del microcontrolador después de haber sido

compilados a código máquina. No obstante, estas localidades de memoria

ROM no tienen 8, sino 12, 14 o 16 bits. 4, 6 o 8 bits adicionales representan

una instrucción que especifica a la CPU qué hacer con los datos de 8 bits.

Las ventajas de este diseño son las siguientes:

Todos los datos en el programa son de un byte (8 bits) de ancho.

Como un bus de datos utilizado para lectura de programa tiene unas

líneas más (12, 14 o 16), tanto la instrucción como el dato se pueden

leer simultáneamente al utilizar estos bits adicionales. Por eso, todas

las instrucciones se ejecutan en un ciclo salvo las instrucciones de

salto que son de dos ciclos.

Page 38: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 38

El hecho de que un programa (la ROM) y los datos temporales (la

RAM) estén separados, permite a la CPU poder ejecutar dos

instrucciones simultáneamente. Dicho de manera sencilla, mientras

que se realiza la lectura o escritura de la RAM (que marca el fin de

una instrucción), la siguiente instrucción se lee por medio de otro bus.

En los microcontroladores que utilizan la arquitectura de von-

Neumann, nunca se sabe cuánta memoria ocupará algún programa.

Generalmente, la mayoría de las instrucciones de programa ocupan

dos localidades de memoria (una contiene información sobre QUÉ se

debe realizar, mientras que la otra contiene informa ción sobre CUÁL

dato se debe realizar). Sin embargo, esto no es una fórmula rígida,

sino el caso más frecuente. En los microcontroladores que utilizan una

arquitectura Harvard, el bus de la palabra de programa es más ancho

que un byte, lo que permite que cada palabra de programa esté

compuesto por una instrucción y un dato. En otras palabras, una

localidad de memoria - una instrucción de programa.

JUEGO DE INSTRUCCIONES

El nombre colectivo de todas las instrucciones que puede entender el

microcontrolador es llamadoJuego de Instrucciones. Cuando se escribe un

Page 39: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 39

programa en ensamblador, en realidad se especifican instrucciones en el

orden en el que deben ser ejecutadas. La restricción principal es el número

de instrucciones disponibles. Los fabricantes aceptan cualquiera de los dos

enfoques descritos a continuación:

RISC (Reduced Instruction Set Computer) - Computadora con Juego

de Instrucciones Reducidas

En este caso la idea es que el microcontrolador reconoce y ejecuta sólo

operaciones básicas (sumar, restar, copiar etc...) Las operaciones más

complicadas se realizan al combinar éstas (por ejemplo, multiplicación se

lleva a cabo al realizar adición sucesiva). Es como intentar explicarle a

alguien con pocas palabras cómo llegar al aeropuerto en una nueva ciudad.

Sin embargo, no todo es tan oscuro. Además, el microcontrolador es muy

rápido así que no es posible ver todas las “acrobacias” aritméticas que

realiza. El usuario sólo puede ver el resultado final de todas las

operaciones. Por último, no es tan difícil explicar dónde está el aeropuerto si

se utilizan las palabras adecuadas tales como: a la derecha, a la izquierda,

el kilómetro etc.

CISC (Complex Instruction Set Computer) - Computadoras con un

juego de instrucciones complejo

¡CISC es opuesto a RISC! Los microcontroladores diseñados para

reconocer más de 200 instrucciones diferentes realmente pueden realizar

muchas cosas a alta velocidad. No obstante, uno debe saber cómo utilizar

todas las posibilidades que ofrece un lenguaje tan rico, lo que no es siempre

tan fácil...

¿CÓMO ELEGIR UN MICROCONTROLADOR?

Bueno, si usted es principiante, y ha tomado decisión de trabajar con los

microcontroladores. ¡Felicitaciones por la elección! No obstante, a primera

vista, no es fácil la elección del microcontrolador más adecuado como

parece a la primera vista. ¡El problema no es el pequeño rango de

dispositivos a elegir, sino todo lo contrario!

Antes de empezar a diseñar un dispositivo basado en un microcontrolador,

tome en cuenta lo siguiente: cuántas entradas/líneas son necesarias para

su funcionamiento, realizaría el dispositivo otras operaciones además

encender/apagar un relé, necesita algún modulo especializado tal como el

Page 40: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 40

de comunicación en serie, convertidor A/D etc. Cuando usted tiene una

clara imagen de lo que quiere, el rango de selección se reduce

considerablemente, y le queda pensar en el precio. ¿Va a tener varios

dispositivos? ¿Varios cientos? ¿Un millón? De todos modos ahora es más

claro.

Si está pensando en todas estas cosas por primera vez, todo le parecerá un

poco confuso. Por esa razón, vaya paso a paso. Antes que nada,

seleccione al fabricante, es decir, la familia de microcontroladores que

ofrece. Luego, aprenda a trabajar con un modelo particular. Sólo aprenda lo

que necesite aprender, no entre demasiado en detalles. Resuelva el

problema específico y le pasará una cosa increíble - será capaz de manejar

cualquier modelo del mismo fabricante...

Más o menos, todo se parece a montar en bicicleta: después de varias

caídas inevitables en el principio, será capaz de mantener el equilibrio y

montar en cualquier otra bicicleta. ¡Por supuesto, nunca se olvida tanto de

montar en bicicleta, como de la destreza de programación!

1.4 MICROCONTROLADORES PIC

Los microcontroladores PIC desarrollados por Microchip Technology son

probablemente la mejor opción si es principiante. Hay varias razones por lo

que esto es verdadero...

El nombre verdadero de este microcontrolador es PICmicro (Peripheral

Interface Controller), conocido bajo el nombre PIC. Su primer antecesor fue

creado en 1975 por la compañía General Instruments. Este chip

denominado PIC1650 fue diseñado para propósitos completamente

diferentes. Diez años más tarde, al añadir una memoria EEPROM, este

circuito se convirtió en un verdadero microcontrolador PIC. Hace unos

pocos años la compañía Microchip Technology fabricó la 5 billonésima

muestra. Si está interesado en aprender más sobre eso, siga leyendo.

If you are interested in learning more about it, just keep on reading.

La idea principal de este libro es proporcionar la información necesaria al

usuario para que sea capaz de utilizar los microcontroladores en la práctica

después de leerlo. Para evitar explicaciones pesadas y las historias infinitas

sobre las características útiles de los microcontroladores diferentes, este

libro describe el funcionamiento de un modelo particular que pertenece a la

“clase media alta”. Es PIC16F887 - bastante poderoso para ser digno de

Page 41: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 41

atención y bastante simple para poder ser utilizado por cualquiera. Así, los

siguientes capítulos describen este microcontrolador en detalle y también se

refieren a la familia PIC entera.

Page 42: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 42

Familia ROM

[Kbytes] RAM [bytes] Pines

Frecuencia de reloj. [MHz]

Entradas A/D

Resolución del

convertidor A/D

Comparador

es

Temporizadores de 8/16 bits

Comunicación serial

Salidas PWM

Otros

Arquitectura de la gama baja de 8 bits, palabra de instrucción de 12 bits

PIC10FXXX

0.375 - 0.75 16 - 24 6 - 8 4 - 8 0 - 2 8 0 - 1 1 x 8 - - -

PIC12FXXX

0.75 - 1.5 25 - 38 8 4 - 8 0 - 3 8 0 - 1 1 x 8 - - EEPRO

M

PIC16FXXX

0.75 - 3 25 - 134 14 - 44 20 0 - 3 8 0 - 2 1 x 8 - - EEPRO

M

PIC16HVXXX

1.5 25 18 - 20 20 - - - 1 x 8 - - Vdd = 15V

Arquitectura de la gama media de 8 bits, palabra de instrucción de 14 bits

PIC12FXXX

1.75 - 3.5 64 - 128 8 20 0 - 4 10 1 1 - 2 x 8 1 x 16 - 0 - 1 EEPRO

M

PIC12HVXXX

1.75 64 8 20 0 - 4 10 1 1 - 2 x 8 1 x 16 - 0 - 1 -

PIC16FXXX

1.75 - 14 64 - 368 14 - 64 20 0 - 13 8 or 10 0 - 2 1 - 2 x 8 1 x 16 USART I2C SPI

0 - 3 -

PIC16HVXXX

1.75 - 3.5 64 - 128 14 - 20 20 0 - 12 10 2 2 x 8 1 x 16 USART I2C SPI

- -

Arquitectura de la gama alta de 8 bits, palabra de instrucción de 16 bits

PIC18FXXX

4 - 128 256 - 3936 18 - 80 32 - 48 4 - 16 10 or 12 0 - 3 0 - 2 x 8 2 - 3 x 16

USB2.0 CAN2.0 USART I2C SPI

0 - 5 -

PIC18FXXJXX

8 - 128 1024 - 3936 28 - 100 40 - 48 10 - 16

10 2 0 - 2 x 8 2 - 3 x 16

USB2.0 USART Ethernet I2C SPI

2 - 5 -

Page 43: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 43

PIC18FXXKXX

8 - 64 768 - 3936 28 - 44 64 10 - 13

10 2 1 x 8 3 x 16 USART I2C SPI

2 -

Todos los microcontroladores PIC utilizan una arquitectura Harvard, lo que quiere decir que su memoria de

programa está conectada a la CPU por más de 8 líneas. Hay microcontroladores de 12, 14 y 16 bits, dependiendo

de la anchura del bus. La tabla anterior muestra las características principales de estas tres categorías.

Como se puede ver en la tabla de la página anterior, salvo “los monstruos de 16 bits” PIC 24FXXX y PIC 24HXXX -

todos los microcontroladores tienen la arquitectura Harvard de 8 bits y pertenecen a una de las tres grandes

grupos. Por eso, dependiendo del tamaño de palabra de programa existen la primera, la segunda y la tercera

categoría de microcontroladores, es decir microcontroladores de 12, 14 o 16 bits. Puesto que disponen del núcleo

similar de 8 bits, todos utilizan el mismo juego de instrucciones y el “esqueleto” básico de hardware conectado a

más o menos unidades periféricas.

Los microcontroladores PIC con palabras de programa de 14 bits parecen ser la mejor opción para los principiantes.

Aquí está el porqué...

JUEGO DE INSTRUCCIONES

El juego de instrucciones para los microcontroladores 16F8XX incluye 35 instrucciones en total. La razón para un

número tan reducido de instrucciones yace en la arquietectura RISC. Esto quiere decir que las instrucciones son

bien optimizadas desde el aspecto de la velocidad operativa, la sencillez de la arquitectura y la compacidad del

código. Lo malo de la arquitectura RISC es que se espera del programador que haga frente a estas instrucciones.

Por supuesto, esto es relevante sólo si se utiliza el lenguaje ensamblador para la programación. Este libro se refiere

a la programación en el lenguaje de alto nivel C, lo que significa que la mayor parte del trabajo ya fue hecho por

alguien más. Así, sólo se tienen que utilizar instrucciones relativamente simples.

Page 44: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 44

TIEMPO DE EJECUCIÓN DE INSTRUCCIONES

Todas las instrucciones se ejecutan en un ciclo. La únicas excepciones

pueden ser las instrucciones de ramificación condicional o las instrucciones

que cambian el contenido del contador de programa. En ambos casos, dos

ciclos de reloj son necesarios para la ejecución de la instrucción, mientras

que el segundo ciclo se ejecuta como un NOP (No operation). Las

instrucciones de un ciclo consisten en cuatro ciclos de reloj. Si se utiliza un

oscilador de 4 MHz, el tiempo nominal para la ejecución de la instrucción es

1μS. En cuanto a las instrucciones de ramificación, el tiempo de ejecución

de la instrucción es 2μS.

Juego de instrucciones de los microcontroladores PIC de 14 bits:

Page 45: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 45

I N S T R U C C I Ó N D E S C R I P C I Ó N O P E R A C I Ó N B A N D E R A C L K *

Instrucciones para la transmisión de datos

MOVLW k Mover literal a W k -> w 1

MOVWF f Mover el contenido de W a f W -> f 1

MOVF f,d Mover el contenido de f a d f -> d Z 1 1, 2

CLRW Borrar el contenido de W 0 -> W Z 1

CLRF f Borrar el contenido de f 0 -> f Z 1 2

SWAPF f,d Intercambiar de nibbles en f f(7:4),(3:0) -> f(3:0),(7:4) 1 1, 2

Instrucciones aritmético - lógicas

ADDLW k Sumar literal a W W+k -> W C, DC, Z 1

ADDWF f,d Sumar el contenido de W y f W+f -> d C, DC ,Z 1 1, 2

SUBLW k Restar W de literal k-W -> W C, DC, Z 1

SUBWF f,d Restar W de f f-W -> d C, DC, Z 1 1, 2

ANDLW k AND W con literal W AND k -> W Z 1

ANDWF f,d AND W con f W AND f -> d Z 1 1, 2

IORLW k OR inclusivo de W con literal W OR k -> W Z 1

IORWF f,d OR inclusivo de W con f W OR f -> d Z 1 1, 2

XORWF f,d OR exclusivo de W con literal W XOR k -> W Z 1 1, 2

XORLW k OR exclusivo de W con f W XOR f -> d Z 1

INCF f,d Sumar 1 a f f+1 -> f Z 1 1, 2

DECF f,d Restar 1 a f f-1 -> f Z 1 1, 2

Page 46: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 46

RLF f,d Rotar F a la izquierda a través del bit de Acarreo C 1 1, 2

RRF f,d Rotar F a la derecha a través del bit de Acarreo C 1 1, 2

COMF f,d Complementar f f -> d Z 1 1, 2

Instrucciones orientadas a bit

BCF f,b Poner a 0 el bit b del registro f 0 -> f(b) 1 1, 2

BSF f,b Poner a 1 el bit b del registro f 1 -> f(b) 1 1, 2

Instrucciones de control de programa

BTFSC f,b Saltar si bit b de registro f es 0 Skip if f(b) = 0 1 (2) 3

BTFSS f,b Saltar si bit b de reg. f es 1 Skip if f(b) = 1 1 (2) 3

DECFSZ f,d Disminuir f en 1. Saltar si el resultado es 0 f-1 -> d skip if Z = 1 1 (2) 1, 2, 3

INCFSZ f,d Incrementar f en 1. Saltar si el resultado es 1 f+1 -> d skip if Z = 0 1 (2) 1, 2, 3

GOTO k Saltar a una dirección k -> PC 2

CALL k Llamar a una subrutina PC -> TOS, k -> PC 2

RETURN Retornar de una subrutina TOS -> PC 2

RETLW k Retornar con literal en W k -> W, TOS -> PC 2

RETFIE Retornar de una interupción TOS -> PC, 1 -> GIE 2

Otras instrucciones

NOP No operación TOS -> PC, 1 -> GIE 1

CLRWDT Reiniciar el temporizador perro guardián 0 -> WDT, 1 -> TO, 1 -> PD TO, PD 1

SLEEP Poner en estado de reposo 0 -> WDT, 1 -> TO, 0 -> PD TO, PD 1

*

Page 47: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 47

1 Si un registro de E/S está modificado, el valor utilizado será el valor presentado en

los pines del microcontrolador.

*2 Si la instrucción se ejecuta en el registro TMR y si d=1, el pre-escalador será

borrado.

*3 Si la instrucción se ejecuta en el registro TMR y si d=1, el pre-escalador será

borrado

Arquitectura de los microcontroladores PIC de 8 bits. Cuáles de estos módulos

pertenecerán al microcontrolador, dependerá del tipo de microcontrolador.

Page 48: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 48

.Capitulo 2 - Programación de los microcontroladores

Usted seguramente sabe que no es suficiente sólo conectar el

microcontrolador a los otros componentes y encender una fuente de

alimentación para hacerlo funcionar, ¿verdad? Hay que hacer algo más. Se

necesita programar el microcontrolador. Si cree que esto es complicado,

está equivocado. Todo el procedimiento es muy simple. Basta con leer el

texto para entender de lo que estamos hablando. 2.1 LENGUAJES DE PROGRAMACIÓN 2.2 CARACTERÍSTICAS PRINCIPALES DEL MIKROC 2.3 TIPOS DE DATOS EN MIKROC 2.4 VARIABLES Y CONSTANTES 2.5 OPERADORES 2.6 ESTRUCTURAS DE CONTROL 2.7 TIPOS DE DATOS AVANZADOS 2.8 FUNCIONES 2.9 CARACTERÍSTICAS PRINCIPALES DEL PREPROCESADOR 2.10 MIKROC PRO FOR PIC 2.11 PROGRAMAR LOS PIC UTILIZANDO MIKROC PRO FOR PIC

2.1 LENGUAJES DE PROGRAMACIÓN

El microcontrolador ejecuta el programa cargado en la memoria Flash. Esto

se denomina el código ejecutable y está compuesto por una serie de ceros

y unos, aparentemente sin significado. Dependiendo de la arquitectura del

microcontrolador, el código binario está compuesto por palabras de 12, 14 o

16 bits de anchura. Cada palabra se interpreta por la CPU como una

instrucción a ser ejecutada durante el funcionamiento del microcontrolador.

Todas las instrucciones que el microcontrolador puede reconocer y ejecutar

se les denominan colectivamente Conjunto de instrucciones. Como es más

fácil trabajar con el sistema de numeración hexadecimal, el código

ejecutable se representa con frecuencia como una serie de los números

hexadecimales denominada código Hex. En los microcontroladores PIC con

Page 49: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 49

las palabras de programa de 14 bits de anchura, el conjunto de

instrucciones tiene 35 instrucciones diferentes.

LENGUAJE ENSAMBLADOR

Como el proceso de escribir un código ejecutable era considerablemente

arduo, en consecuencia fue creado el primer lenguaje de programación

denominado ensamblador (ASM). Siguiendo la sintaxis básica del

ensamblador, era más fácil escribir y comprender el código. Las

instrucciones en ensamblador consisten en las abreviaturas con significado

y a cada instrucción corresponde una localidad de memoria. Un programa

denominado ensamblador compila (traduce) las instrucciones del lenguaje

ensamblador a código máquina (código binario).

HEste programa compila instrucción a instrucción sin optimización. Como

permite controlar en detalle todos los procesos puestos en marcha dentro

del chip, este lenguaje de programación todavía sigue siendo popular.

Ventajas de lenguajes de programación de alto nivel

A pesar de todos los lados buenos, el lenguaje ensamblador tiene algunas

desventajas:

Incluso una sola operación en el programa escrito en ensamblador consiste en muchas instrucciones, haciéndolo muy largo y difícil de manejar.

Cada tipo de microcontrolador tiene su propio conjunto de instrucciones que un programador tiene que conocer para escribir un programa

Un programador tiene que conocer el hardware del microcontrolador para escribir un programa

Programa escrito en C (El mismo programa compilado al código

ensamblador):

Page 50: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 50

Los lenguajes de programación de alto nivel (Basic, Pascal, C etc.) fueron

creados con el propósito de superar las desventajas del ensamblador. En

lenguajes de programación de alto nivel varias instrucciones en

ensamblador se sustituyen por una sentencia. El programador ya no tiene

que conocer el conjunto de instrucciones o características del hardware del

microcontrolador utilizado. Ya no es posible conocer exactamente cómo se

ejecuta cada sentencia, de todas formas ya no importa. Aunque siempre se

puede insertar en el programa una secuencia escrita en ensamblador.

Si alguna vez ha escrito un programa para un microcontrolador PIC en

lenguaje ensamblador, probablemente sepa que la arquitectura RISC

carece de algunas instrucciones. Por ejemplo, no hay instrucción apropiada

para multiplicar dos números. Por supuesto, para cada problema hay una

solución y éste no es una excepción gracias a la aritmética que permite

realizar las operaciones complejas al descomponerlas en un gran número

operaciones más simples. En este caso, la multiplicación se puede sustituir

con facilidad por adición sucesiva (a x b = a + a + a + ... + a). Ya estamos

en el comienzo de una historia muy larga... No hay que preocuparse al

utilizar uno de estos lenguajes de programación de alto nivel como es C,

Page 51: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 51

porque el compilador encontrará automáticamente la solución a éste

problema y otros similares. Para multiplicar los números a y b, basta con

escribir a*b.

Lenguaje C

El lenguaje C dispone de todas las ventajas de un lenguaje de

programación de alto nivel (anteriormente descritas) y le permite realizar

algunas operaciones tanto sobre los bytes como sobre los bits (operaciones

lógicas, desplazamiento etc.). Las características de C pueden ser muy

útiles al programar los microcontroladores. Además, C está estandarizado

(el estándar ANSI), es muy portable, así que el mismo código se puede

utilizar muchas veces en diferentes proyectos. Lo que lo hace accesible

para cualquiera que conozca este lenguaje sin reparar en el propósito de

uso del microcontrolador. C es un lenguaje compilado, lo que significa que

los archivos fuentes que contienen el código C se traducen a lenguaje

máquina por el compilador. Todas estas características hicieron al C uno de

los lenguajes de programación más populares.

La figura anterior es un ejemplo general de lo que sucede durante la

compilación de programa de un lenguaje de programación de alto nivel a

bajo nivel.

2.2 CARACTERÍSTICAS PRINCIPALES DEL MIKROC

A continuación vamos a presentar a los elementos principales del lenguaje

mikroC desarrollado por Mikroelektronika. Este lenguaje es muy similar al C

estándar, no obstante en determinados aspectos difiere del ANSI estándar

en algunas características. Algunas de estas diferencias se refieren a las

mejoras, destinadas a facilitar la programación de los microcontroladores

PIC, mientras que las demás son la consecuencia de la limitación de la

Page 52: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 52

arquitectura del hardware de los PIC. Aquí vamos a presentar

características específicas del lenguaje mikroC en la programación de los

microcontroladores PIC. El término C se utilizará para referirse a las

características comunes de los lenguajes C y mikroC.

Este libro describe una aplicación muy concreta del lenguaje de

programación C utilizado en el compilador mikroC PRO for PIC. En este

caso, el compilador se utiliza para la programación de los

microcontroladores PIC.

FASES DE COMPILACIÓN

El proceso de compilación consiste en varios pasos y se ejecuta

automáticamente por el compilador. Por con, un conocimiento básico del

funcionamiento puede ser útil para entender el concepto del lenguaje

mikroC.

El archivo fuente contiene el código en mikroC que usted escribe para

programar el microcontrolador. El preprocesador se utiliza automáticamente

por el compilador al iniciarse el proceso de la compilación. El compilador

busca las directivas del preprocesador (que siempre empiezan por „#‟)

dentro del código y modifica el código fuente de acuerdo con las directivas.

En esta fase se llevan a cabo inclusión de archivos, definición de constantes

y macros etc, lo que facilita el proceso. Más tarde vamos a describir estas

directivas en detalle. Elanalizador sintáctico (parser) elimina toda la

información inútil del código (comentarios, espacios en blanco). Luego,

el compilador traduce el código a un archivo binario denominado archivo

.mcl. El enlazador (linker) recupera toda la información requerida para

ejecutar el programa de los archivos externos y la agrupa en un solo archivo

(.dbg). Además, un proyecto puede contener más de un archivo fuente y el

Page 53: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 53

programador puede utilizar funciones predefinidas y agrupadas dentro de

los archivos denominados librerías. Por último, el generador .hexproduce

un archivo .hex. Es el archivo que se va a cargar en el microcontrolador.

El proceso entero de la compilación que incluye todos los pasos

anteriormente descritos se le denomina “building”. ESTRUCTURA DE PROGRAMA

La idea principal de escribir un programa en C es de “romper” un problema

mayor en varios trozos más pequeños. Supongamos que es necesario

escribir un programa para el microcontrolador para medir la temperatura y

visualizar los resultados en un LCD. El proceso de medición se realiza por

un sensor que convierte temperatura en voltaje. El microcontrolador utiliza

el convertidor A/D para convertir este voltaje (valor analógico) en un número

(valor digital) que luego se envía al LCD por medio de varios conductores.

En consecuencia, el programa se divide en cuatro partes, de las que cada

una corresponde a una acción específica:

1. Activar y configurar el convertidor A/D incorporado;

2. Medir el valor analógico;

3. Calcular temperatura; y

4. Enviar los datos en el formato apropiado al LCD;

Los lenguajes de programación de alto nivel como es C le permiten

solucionar este problema con facilidad al escribir cuatro funciones que se

ejecutarán cíclicamente sin parar.

La idea general es de dividir el problema en varios trozos, de los que cada

uno se puede escribir como una sola función. Todos los programas escritos

en mikroC contienen por lo menos una función llamada main() que encierra

entre llaves {} las sentencias a ser ejecutadas. Esto es la primera función a

ser ejecutada al iniciarse la ejecución de programa. Las otras funciones se

pueden llamar dentro de la función main. En otras palabras, podemos decir

que la función main() es obligatoria, mientras que las demás son

Page 54: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 54

opcionales. Si todavía no ha escrito un programa en C, es probable que

todo le resulte confuso. No se preocupe, acéptelo tal como es por el

momento y más tarde entenderá la sintaxis.

¡Y ahora, su primer programa „real‟! La figura muestra la estructura de

programa, señalando las partes en las que consiste.

La manera de escribir el código en C es muy importante. Por ejemplo, C

difiere entre minúsculas y mayúsculas, así que la función main() no se

puede escribir MAIN() o Main(). Además, note que dos líneas del código

dentro de la función terminan con un punto y coma. En C todas las

Page 55: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 55

sentencias deben terminar con un punto y coma „;‟, así el compilador puede

aislarlas y traducirlas a código máquina.

COMENTARIOS

Los comentarios son las partes del programa utilizados para aclarar las

instrucciones de programa o para proporcionar más información al respecto.

El compilador no hace caso a los comentarios y no los compila al código

ejecutable. Dicho de manera sencilla, el compilador es capaz de reconocer

los caracteres especiales utilizados para designar dónde los comentarios

comienzan y terminan y no hace nada de caso al texto entre ellos durante la

compilación. Hay dos tipos de tales caracteres. Unos designan los

comentarios largos que ocupan varias líneas de programa marcados por la

secuencia especial /*...*/, mientras que otros designan los comentarios

Page 56: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 56

cortos que caben en una sola línea //. Aunque los comentarios no pueden

afectar a la ejecución de programa, son tan importantes como cualquier otra

parte de programa. Aquí está el porqué... Con frecuencia es necesario

mejorar, modificar, actualizar, simplificar un programa... No es posible

interpretar incluso los programas simples sin utilizar los comentarios.

2.3 TIPOS DE DATOS EN MIKROC

En el lenguaje C, los datos tienen un tipo, o sea, cada dato utilizado en el

programa debe tener su tipo especificado. Esto permite al compilador

conocer el tamaño de dato (número de bytes requerido en la memoria) y su

representación. Hay varios tipos de datos que se pueden utilizar en el

lenguaje de programación mikroC dependiendo del tamaño de dato y del

rango de valores. La tabla muestra el rango de valores que los datos

pueden tener cuando se utilizan en su forma básica.

TIPO DE

DATO DESCRIPCIÓN

TAMAÑO (NÚMERO DE

BITS) RANGO DE VALORES

char Texto (caracteres) 8 de 0 a 255

int Valores enteros 16 de -32768 a 32767

float Valores en punto

flotante 32

de ±1.17549435082·10-38 a ±6.80564774407·1038

double Valores en punto flotante de doble

precisión 32

de ±1.17549435082·10-38 a ±6.80564774407·1038

*Debido a las limitaciones impuestas por el hardware del microcontrolador,

es imposible alcanzar una mayor precisión de datos que la del tipo float. Por

eso, el tipo double en mikroC equivale al tipo float.

Al añadir un prefijo (calificador) a cualquier tipo de dato entero o carácter, el

rango de sus posibles valores cambia así como el número de los bytes de

memoria necesarios. Por defecto, los datos de tipo int son con signo,

mientras que los de tipo char son sin signo. El calificador signed (con signo)

indica que el dato puede ser positivo o negativo. El prefijo unsigned indica

que el dato puede ser sólo positivo. Note que el prefijo es opcional.

Page 57: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 57

TIPO DE

DATO

TIPO DE DATO CON PREFIJO

TAMAÑO (NÚMERO DE

BITS)

RANGO DE VALORES

char signed char 8 de -128 a 128

int

unsigned int 16 de 0 a 65535

short int 8 de 0 a 255

signed short int 8 de -128 a 127

long int 32 de 0 a 4294967295

signed long int 32 de -2147483648 a

2147483647

Tipo entero (int)

Un entero es un número sin parte fraccionaria que puede estar expresado

en los siguientes formatos:

Hexadecimal (base 16): el número empieza con 0x (o 0X). Los enteros hexadecimales consisten en los dígitos (de 0 a 9) y/o las letras (A, B, C,D, E, F). Por ejemplo: „0x1A‟.

Decimal (base 10): el número consiste en los dígitos (de 0 a 9). El primer dígito no puede ser 0. En este formato, se puede introducir el signo de número („+‟ o „-‟). Por ejemplo: 569, -25, +1500.

Octal (base 8): los números se representan a base 8 utilizando sólo 8 dígitos (de 0 a 7). Los enteros octales empiezan con 0. Por ejemplo: „056‟.

Binario: cuando un entero empieza con 0b (o 0B) se representan como una serie de bits („0‟ y „1‟). Por ejemplo: 0B10011111

0x11 // formato hexadecimal equivale a decimal 17 11 // formato decimal -152 // formato decimal 011 // formato octal equivale a decimal 9 0b11 // formato binario equivale a decimal 3

Tipo punto flotante (float)

El tipo punto flotante (float) se utiliza para los números reales con el punto

decimal. Los datos de tipo float se pueden representar de varias maneras.

Un dato float es siempre consigno (signed).

Page 58: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 58

0. // = 0.0 -1.23 // = -1.23 23.45e6 // = 23.45 * 10^6 2e-5 // = 2.0 * 10^-5 3E+10 // = 3.0 * 10^10 .09E34 // = 0.09 * 10^34

Tipo carácter (char)

El tipo char es considerado como un entero por el compilador. No obstante,

se utiliza normalmente para los datos de tipo carácter. Un dato de tipo

carácter está encerrado entre comillas y codificado en un carácter ASCII.

59 // entero 'p' // carácter ASCII 'p'

Una secuencia de caracteres es denominada cadena (string). Las cadenas

están encerradas entre comillas dobles, por ejemplo:

"Presione el botón RA0"

2.4 VARIABLES Y CONSTANTES

Definiciones

Una variable es un objeto nombrado capaz de contener un dato que puede

ser modificado durante la ejecución de programa. En C, las variables tienen

tipo, que significa que es necesario especificar el tipo de dato que se le

asigna a una variable (int, float etc.). Las variables se almacenan en la

memoria RAM y el espacio de memoria que ocupan (en bytes) depende de

su tipo.

/* dos líneas de programa consecutivas. En la primera línea del programa se define el tipo de variable */ int a = 1000; // Variable a es de tipo int y equivale a 1000 a = 15; // a equivale a 15

Una constante tiene las mismas características que una variable excepto el

hecho de que su valor asignado no puede ser cambiado durante la

ejecución de programa. A diferencia de las variables, las constantes se

almacenan en la memoria Flash del microcontrolador para guardar el mayor

espacio posible de memoria RAM. El compilador las reconoce por el

Page 59: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 59

nombre y el prefijo const. En mikroC, el compilador reconoce

automáticamente el tipo de dato de una constante, así que no es necesario

especificar el tipo adicionalmente.

/* dos líneas de programa consecutivas */ const A = 1000 // el valor de la constante A está definido A = 15; // ¡ERROR! no se puede modificar el valor de la constante

Cada variable o constante debe tener un identificador que lo distingue de

otras variables y constantes. Refiérase a los ejemplos anteriores, a y A son

identificadores.

Reglas para nombrar

En mikroC, los identificadores pueden ser tan largos como quiera. Sin

embargo, hay varias restricciones:

Los identificadores pueden incluir cualquiera de los caracteres alfabéticos A-Z (a-z), los dígitos 0-9 y el carácter subrayado '_'. El compilador es sensible a la diferencia entre minúsculas y mayúsculas. Los nombres de funciones y variables se escriben con frecuencia con minúsculas, mientras que los nombres de constantes se escriben con mayúsculas.

Los identificadores no pueden empezar con un dígito. Los identificadores no pueden coincidir con las palabras clave del

lenguaje mikroC, porque son las palabras reservadas del compilador.1

El compilador mikroC reconoce 33 palabras clave:

Page 60: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 60

MIKROC - PALABRAS CLAVE

absolute data if return typedef

asm default inline rx typeid

at delete int sfr typename

auto do io short union

bit double long signed unsigned

bool else mutable sizeof using

break enum namespace static virtual

case explicit operator struct void

catch extern org switch volatile

char false pascal template while

class float private this

code for protected throw

const friend public true

continue goto register try

Ejemplos de los identificadores válidos e inválidos:

temperatura_V1 // OK Presión // OK no_corresponder // OK dat2string // OK SuM3 // OK _vtexto // OK 7temp // NO -- no puede empezar con un número %más_alto // NO -- no pueden contener caracteres especiales if // NO -- no puede coincidir con una palabra reservada j23.07.04 // NO -- no puede contener caracteres especiales (punto) nombre de variable // NO -- no puede contener espacio en blanco

Declaración de variables

Cada variable debe ser declarada antes de ser utilizada en el programa.

Como las variables se almacenan en la memoria RAM, es necesario

reservar el espacio para ellas (uno, dos o más bytes). Al escribir un

programa, usted sabe qué tipo de datos quiere utilizar y qué tipo de datos

espera como resultado de una operación, mientras que el compilador no lo

sabe. No se olvide de que el programa maneja las variables con los

nombres asignados. El compilador las reconoce como números en la

Page 61: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 61

memoria RAM sin conocer su tamaño y formato. Para mejorar la legibilidad

de código, las variables se declaran con frecuencia al principio de las

funciones:

<tipo> variable;

Es posible declarar más de una variable de una vez si tienen el mismo tipo.

<tipo> variable1, variable2, variable3;

Aparte del nombre y del tipo, a las variables se les asignan con frecuencia

los valores iniciales justamente enseguida de su declaración. Esto no es un

paso obligatorio, sino „una cuestión de buenas costumbres‟. Se parece a lo

siguiente:

unsigned int peso; // Declarar una variable llamada peso peso = 20; // Asignar el valor 20 a la variable peso

Un método más rápido se le denomina declaración con inicialización

(asignación de los valores iniciales):

unsigned int peso = 20; // peso está declarado y su valor es 20

Si hay varias variables con el mismo valor inicial asignado, el proceso se

puede simplificar:

unsigned int peso1 = peso2 = peso3 = 20; int valor_inicial = un_mínimo_de_petróleo = 0;

Tenga cuidado de no declarar la misma variable otra vez dentro de la misma función.

Puede modificar el contenido de una variable al asignarle un nuevo valor tantas veces que quiera

Al declarar una variable, siempre piense en los valores que la variable tendrá que contener durante la ejecución de programa. En el ejemplo anterior, peso1 no se puede representar con un número con punto decimal o un número con valor negativo.

Page 62: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 62

Declaración de constantes

Similar a las variables, las constantes deben ser declaradas antes de ser

utilizadas en el programa. En mikroC, no es obligatorio especificar el tipo de

constante al declararla. Por otra parte, las constantes deben ser

inicializadas a la vez que se declaran. El compilador reconoce las

constantes por su prefijo const utilizado en la declaración. Dos siguientes

declaraciones son equivalentes:

const int MINIMUM = -100; // Declarar constante MINIMUM const MINIMUM = -100; // Declarar constante MINIMUM

Las constantes pueden ser de cualquier tipo, incluyendo cadenas:

const T_MAX = 3.260E1; // constante de punto flotante T_MAX const I_CLASS = 'A'; // constante carácter I_CLASS const Mensaje = "Presione el botón IZQUIERDA"; // constante de cadena Mensaje

Las constantes de enumeración son un tipo especial de constantes enteras

que hace un programa más comprensible al asignar los números ordinales

a las constantes. Por defecto, el valor 0 se asigna automáticamente a la

primera constante entre llaves, el valor 1 a la segunda, el valor 2 a la tercera

etc.

enum surtidores {AGUA,GASÓLEO,CLORO}; // AGUA = 0; GASÓLEO = 1; CLORO = 2

Es posible introducir directamente el valor de una constante dentro de la

lista de enumeraciones. El incremento se detiene al asignar un valor a un

elemento de matriz, después se reinicia a partir del valor asignado. Vea el

siguiente ejemplo:

enum surtidores {AGUA,GASÓLEO=0,CLORO}; // AGUA = 0; GÁSOLEO = 0; CLORO = 1

Las constantes de enumeración se utilizan de la siguiente manera:

int Velocidad_de_ascensor enum motor_de_ascensor {PARADA,INICIO,NORMAL,MÁXIMO}; Velocidad_de_ascensor = NORMAL; // Velocidad_de_ascensor = 2

Page 63: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 63

Definir los nuevos tipos de datos

La palabra clave typedef le permite crear con facilidad los nuevos tipos de

datos.

typedef unsigned int positivo; // positivo es un sinónimo para el tipo sin signo int positivo a,b; // Variables a y b son de tipo positivo a = 10; // Variable a equivale a 10 b = 5; // Variable b equivale a 5

Ámbito de variables y constantes

Una variable o una constante es reconocida por el compilador en base de

su identificador. Un identificador tiene significado si el compilador lo puede

reconocer. El ámbito de una variable o una constante es el rango de

programa en el que su identificador tiene significado. El ámbito es

determinado por el lugar en el que se declara una variable o una constante.

Intentar acceder a una variable o una constante fuera de su ámbito resulta

en un error. Una variable o una constante es invisible fuera de su ámbito.

Todas las variables y constantes que pensamos utilizar en un programa

deben ser declaradas anteriormente en el código. Las variables y

constantes pueden ser globales o locales. Una variable global se declara en

el código fuente, fuera de todas las funciones, mientras que una variable

local se declara dentro del cuerpo de la función o dentro de un bloque

anidado en una función.

Page 64: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 64

A las variables globales se les puede acceder de cualquiera parte en el

código, aún dentro de las funciones con tal de que sean declaradas. El

ámbito de una variable global está limitado por el fin del archivo fuente en el

que ha sido declarado.

El ámbito de variables locales está limitado por el bloque encerrado entre

llaves {} en el que han sido declaradas. Por ejemplo, si están declaradas en

el principio del cuerpo de función (igual que en la función main) su ámbito

está entre el punto de declaración y el fin de esa función. Refiérase al

ejemplo anterior. A las variables locales declaradas en main() no se les

puede acceder desde la Función_1 y al revés.

Un bloque compuesto es un grupo de declaraciones y sentencias (que

pueden ser bloques también) encerradas entre llaves. Un bloque puede ser

una función, una estructura de control etc. Una variable declarada dentro de

un bloque se considera local, o sea, „existe‟ sólo dentro del bloque. Sin

embargo, las variables declaradas fuera del ámbito todavía son visibles.

Aunque las constantes no pueden ser modificadas en el programa, siguen

las mismas reglas que las variables. Esto significa que son visibles dentro

de su bloque a excepción de las constantes globales (declaradas fuera de

cualquier función). Las constantes se declaran normalmente en el inicio del

código fuera de cualquier función (como variables globales).

Clases de almacenamiento

Las clases de almacenamiento se utilizan para definir el ámbito y la vida de

variables, constantes y funciones dentro de un programa. En mikroC se

pueden utilizar diferentes clases de almacenamiento:

auto es una clase de almacenamiento por defecto para las variables locales, así que se utiliza raramente. Se utiliza para definir que una variable local tiene duración local. La clase de almacenamiento auto no se puede utilizar con variables globales.

static es una clase de almacenamiento por defecto para las variables

globales. Especifica que una variable es visible dentro del archivo. A las variables locales declaradas con el prefijo static se les puede acceder dentro del archivo fuente (o sea se comportan como variables globales).

extern: la palabra clave extern se utiliza cuando el programa está compuesto por diferentes archivos fuente. Esto le permite utilizar una variable, una constante o una función declarada en otro archivo. Por

Page 65: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 65

supuesto, para compilar y enlazar este archivo correctamente, el mismo debe ser incluido en su proyecto. En los siguientes ejemplos, el programa consiste en dos archivos: File_1 y File_2. El File_1 utiliza una variable y una función declaradas en File_2.

File 1:

extern int cnt; // Variable cnt es visible en File_1 extern void hello(); // Función hello()se puede utilizar en File_1 void main(){ PORTA = cnt++; // Cualquier modificación de cnt en File_1 será visible en File_2 hello(); // Función hello()se puede llamar desde aquí }

File 2:

int cnt = 0; void hello(); void hello(){ // Modificaciones que afectan a la . // cnt en File_1 son visibles aquí . . }

2.5 OPERADORES

Un operador es un símbolo que denota una operación aritmética, lógica u

otra operación particular. Dicho de manera sencilla, varias operaciones

aritméticas y lógicas se realizan por medio de los operadores. Hay más de

40 operaciones disponibles en el lenguaje C, pero se utiliza un máximo de

10-15 de ellas en práctica. Cada operación se realiza sobre uno o más

operandos que pueden ser variables o constantes. Además, cada operación

se caracteriza por la prioridad de ejecución y por la asociatividad.

OPERADORES ARITMÉTICOS

Los operadores aritméticos se utilizan en las operaciones aritméticas y

siempre devuelven resultados numéricos. Hay dos tipos de operadores, los

unitarios y los binarios. A diferencia de las operaciones unitarias que se

realizan sobre un operando, las operaciones binarias se realizan sobre dos

operandos. En otras palabras, se requieren dos números para ejecutar una

operación binaria. Por ejemplo: a+b o a/b.

Page 66: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 66

OPERADOR OPERACIÓN

+ Adición

- Resta

* Multiplicación

/ División

% Resto de la división

int a,b,c; // Declarar 3 enteros a, b, c a = 5; // Inicializar a b = 4; // Inicializar b c = a + b; // c = 9 c = c%2; // c = 1. Esta operación se utiliza con frecuencia // para comprobar la paridad. En este caso, el // resultado es 1 lo que significa que la variable // es un número imparo

OPERADORES DE ASIGNACIÓN

Hay dos tipos de asignación en el lenguaje C:

Los operadores simples asignan los valores a las variables utilizando el carácter común '='. Por ejemplo: a =8

Las asignaciones compuestas son específicas para el lenguaje C. Consisten en dos caracteres como se muestra en la tabla a la derecha. Se utilizan para simplificar la sintaxis y habilitar la ejecución más rápida.

OPERADOR EJEMPLO

Expresión Equivalente

+= a += 8 a = a + 8

-= a -= 8 a = a - 8

*= a *= 8 a = a * 8

/= a /= 8 a = a / 8

%= a %= 8 a = a % 8

int a = 5; // Declarar e inicializar la variable a a += 10; // a = a + 10 = 15

OPERADORES DE INCREMENTO Y DECREMENTO

Page 67: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 67

Las operaciones de incremento y decremento por 1 se denotan con "++" y "-

-". Estos caracteres pueden preceder o seguir a una variable. En primer

caso (++x), la variable x será incrementada por 1 antes de ser utilizada en la

expresión. De lo contrario, la variable se utilizará en la expresión antes de

ser aumentada por 1. Lo mismo se aplica a la operación de decremento.

OPERADOR EJEMPLO DESCRIPCIÓN

++ ++a Variable "a" es incrementada por 1

a++

-- --b Variable "a" es decrementada por 1

b--

int a, b, c; a = b = 5; c = 1 + a++; // c = 6 b = ++c + a // b = 7 + 6 = 13

OPERADORES RELACIONALES

Los operadores relacionales se utilizan en comparaciones con el propósito

de comparar dos valores. En mikroC, si una expresión es evaluada como

falsa (false), el operador devuelve 0, mientras que si una oración es

evaluada como verdadera (true), devuelve 1. Esto se utiliza en expresiones

tales como „si la expresión es evaluada como verdadera, entonces...‟

OPERADOR DESCRIPCIÓN EJEMPLO CONDICIÓN DE

VERACIDAD

> mayor que b > a si b es mayor que a

>= mayor o igual que a >= 5 si a es mayor o igual que 5

< menor que a < b si a es menor que b

<= menor o igual que a <= b si a es menor o igual que b

== igual que a == 6 si a es igual que 6

!= desigual que a != b si a es desigual que b

int prop; int var = 5; prop = var < 10; // Expresión es evaluada como verdadera, prop = 1

OPERADORES LÓGICOS

Page 68: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 68

Hay tres tipos de operaciones lógicas en el lenguaje C: Y (AND) lógico, O

(OR) lógico y negación - NO (NOT) lógico. Los operadores lógicos

devuelven verdadero (1 lógico) si la expresión evaluada es distinta de cero.

En caso contrario, devuelve falso (0 lógico) si la expresión evaluada

equivale a cero. Esto es muy importante porque las operaciones lógicas se

realizan generalmente sobre las expresiones, y no sobre las variables

(números) particulares en el programa. Por lo tanto, las operaciones lógicas

se refieren a la veracidad de toda la expresión.

Por ejemplo: 1 && 0 es igual a (expresión verdadera) && (expresión

falsa)

El resultado 0, o sea - Falso en ambos casos.

OPERADOR FUNCIÓN

&& Y

|| O

! NO

OPERADORES DE MANEJO DE BITS

A diferencia de las operaciones lógicas que se realizan sobre los valores o

expresiones, las operaciones de manejo de bits se realizan sobre los bits de

un operando. Se enumeran en la siguiente tabla:

OPERADOR DESCRIPCIÓN EJEMPLO RESULTADO

~ Complemento a uno a = ~b b = 5 a = -5

<< Desplazamiento a la

izquierda a = b << 2 b = 11110011 a = 11001100

>> Desplazamiento a la

derecha a = b >> 2 b = 11110011 a = 00011110

& Y lógico para manejo

de bits c = a & b

a = 11100011 b = 11001100

c = 11000000

| O lógico para manejo

de bits c = a | b

a = 11100011 b = 11001100

c = 11101111

^ EXOR lógico para

manejo de bits c = a ^ b

a = 11100011 b = 11001100

c = 00101111

Note que el resultado de la operación de desplazamiento a la derecha

depende del signo de la variable. En caso de que el operando se aplique a

una variable sin signo o positiva, se introducirán los ceros en el espacio

vacío creado por desplazamiento. Si se aplica a un entero con signo

negativo, se introducirá un 1 para mantener el signo correcto de la variable.

Page 69: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 69

¿CÓMO UTILIZAR LOS OPERADORES?

Aparte de los operadores de asignación, dos operadores no deben estar escritos uno junto al otro.

x*%12; // esta expresión generará un error

Cada operador tiene su prioridad y asociatividad como se muestra en la tabla:

Similar a las expresiones aritméticas, los operadores se agrupan juntos por medio de paréntesis. Primero se calculan las expresiones encerradas entre paréntesis. Si es necesario, se pueden utilizar los paréntesis múltiples (anidados).

PRIORIDAD

OPERADORES ASOCI ATIVIDAD

Alta () [] -> . de izquierda a derecha

! ~ ++ -- +(unitario) -(unitario) *Puntero &Puntero de derecha a izquierda

* / % de izquierda a derecha

+ - de izquierda a derecha

< > de izquierda a derecha

< <= > >= de izquierda a derecha

== != de izquierda a derecha

& de izquierda a derecha

^ de izquierda a derecha

| de izquierda a derecha

&& de izquierda a derecha

|| de derecha a izquierda

?: de derecha a izquierda

Baja = += -= *= /= /= &= ^= |= <= >= de izquierda a derecha

int a, b, res; a = 10; b = 100; res = a*(a + b); // resultado = 1100 res = a*a + b; // resultado = 200

Page 70: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 70

CONVERSIÓN DE TIPOS DE DATOS

Algunas operaciones implican conversión de datos. Por ejemplo, si divide

dos valores enteros, hay una alta posibilidad de que el resultado no sea un

entero. El mikroC realiza una conversión automática cuando se requiera.

Si dos operandos de tipo diferente se utilizan en una operación aritmética, el

tipo de operando de la prioridad más baja se convierte automáticamente en

el tipo de operando de la prioridad más alta. Los tipos de datos principales

se colocan según el siguiente orden jerárquico:

La autoconversión se realiza asimismo en las operaciones de asignación. El

resultado de la expresión de la derecha del operador de la asignación

siempre se convierte en el tipo de la variable de la izquierda del operador. Si

el resultado es de tipo de la prioridad más alta, se descarta o se redondea

para coincidir con el tipo de la variable. Al convertir un dato real en un

entero, siempre se descartan los números que siguen al punto decimal.

int x; // A la variable x se le asigna el tipo integer (un entero) x = 3; // A la variable x se le asigna el valor 3 x+ = 3.14; // El valor 3.14 se agrega a la variable x al // realizar la operación de asignación /* El resultado de la adición es 6 en vez de 6.14, como era de esperar. Para obtener el resultado esperado sin descartar los números que siguen al punto decimal, se debe declarar x como un punto flotante. */

Para realizar una conversión explícita, antes de escribir una expresión o una

variable hay que especificar el tipo de resultado de operación entre

paréntesis.

double distancia, tiempo, velocidad; distancia = 0.89; tiempo = 0.1; velocidad = (int)(a/b); // c = (int)8.9 = 8.0 velocidad = ((int)a)/b; // c = 0/0.1 = 0.0

Page 71: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 71

2.6 ESTRUCTURAS DE CONTROL

ESTRUCTURAS CONDICIONALES

Las condiciones son ingredientes comunes de un programa. Las

condiciones permiten ejecutar una o varias sentencias dependiendo de

validez de una expresión. En otras palabras, „Si se cumple la condición (...),

se debe hacer (...). De lo contrario, si la condición no se cumple, se debe

hacer (...)‟. Los operandos condicionales if-else y switch se utilizan en las

operaciones condicionales. Una sentencia condicional puede ser seguida

por una sola sentencia o por un bloque de sentencias a ser ejecutadas.

OPERADOR CONDICIONAL if-else

El operador if se puede utilizar solo o asociado al operador else (if-else).

Ejemplo del operador if:

if(expresión) operación;

Si el resultado de la expresión encerrada entre paréntesis es verdadero

(distinto de 0) la operación se realiza y el programa continúa con la

ejecución. Si el resultado de la expresión es falso (0), la operación no se

realiza y el programa continúa inmediatamente con la ejecución.

Como hemos mencionado, la otra forma combina tanto el operador if como

el else:

if(expresión) operación1 else operación2;

Si el resultado de la expresión es verdadero (distinto de 0), se

realiza operación1, de lo contrario se realiza la operación2. Después de

realizar una de las operaciones, el programa continúa con la ejecución.

La sentencia if-else se parece a lo siguiente:

if(expresión) operación1 else operación2

Si operación1 u operación2 está compuesta, escriba una lista de sentencias

encerradas entre llaves. Por ejemplo:

if(expresión) { ... // ... // operación1 ...} //

Page 72: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 72

else operación2

El operador if-else se puede sustituir por el operador condicional '?:':

(expresión1)? expresión2 : expresión3

Si el valor de la expresión1 es distinto de 0 (verdadero), el resultado de la

expresión entera será equivalente al resultado obtenido de laexpresión2. De

lo contrario, si la expresión1 es 0 (falso), el resultado de la expresión entera

será equivalente al resultado obtenido de laexpresión3. Por ejemplo:

maximum = (a>b)? a : b // A la variable maximum se le asigna el // valor de la variable mayor(a o b)

Operador Switch

A diferencia de la sentencia if-else que selecciona entre dos opciones en el

programa, el operador switch permite elegir entre varias opciones. La

sintaxis de la sentencia switch es:

switch (selector) // Selector es de tipo char o int { case constante1: operación1 // El grupo de operadores que se ejecutan si ... // el selector y la constante1 son equivalentes break; case constante2: operación2 // El grupo de operadores se ejecuta si ... // el selector y la constante2 son equivalentes break; ... default: operación_esperada // El grupo de operadores que se ejecuta si ... // ninguna constante equivale al selector break; }

Page 73: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 73

La operación switch se ejecuta de la siguiente manera: primero se ejecuta el

selector y se compara con la constante1. Si coinciden, las sentencias que

pertenecen a ese bloque se ejecutan hasta llegar a la palabra clave break o

hasta el final de la operación switch. Si no coinciden, el selector se compara

con la constante2. Si coinciden, las sentencias que pertenecen a ese bloque

se ejecutan hasta llegar a la palabra clave break etc. Si el selector no

coincide con ninguna constante, se ejecutarán las operaciones que siguen

al operador default.

También es posible comparar una expresión con un grupo de constantes. Si

coincide con alguna de ellas, se ejecutarán las operaciones apropiadas:

switch (días) // La variable días representa un día de la semana. { // Es necesario determinar si es un día laborable o no lo es case1:case2:case3:case4:case5: LCD_message = 'Día laborable'; break; case6:case7: LCD_message = 'Fin de semana'; break; default:LCD_message_1 = 'Elija un día de la semana'; break; }

La palabra clave de C „break‟ se puede utilizar en cualquier tipo de bloques.

Al utilizar „break‟, es posible salir de un bloque aunque la condición para su

final no se haya cumplido. Se puede utilizar para terminar un bucle infinito, o

para forzar un bucle a terminar antes de lo normal. BUCLES

A menudo es necesario repetir una cierta operación un par de veces en el

programa. Un conjunto de comandos que se repiten es denominado un

bucle de programa. Cuántas veces se ejecutará, es decir cuánto tiempo el

programa se quedará en el bucle, depende de las condiciones de salir del

bucle.

Bucle While

El bucle while se parece a lo siguiente:

while(expresión){ comandos ... }

Los comandos se ejecutan repetidamente (el programa se queda en el

bucle) hasta que la expresión llegue a ser falsa. Si la expresión es falsa en

la entrada del bucle, entonces el bucle no se ejecutará y el programa

continuará desde el fin del bucle while.

Page 74: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 74

Un tipo especial del bucle de programa es un bucle infinito. Se forma si la

condición sigue sin cambios dentro del bucle. La ejecución es simple en

este caso ya que el resultado entre llaves es siempre verdadero

(1=verdadero), lo que significa que el programa se queda en el mismo

bucle:

while(1){ // En vez de "while(1)", se puede escribir "while(true)" ... // Expresiones encerradas entre llaves se ejecutarán ... // repetidamente (bucle infinito) }

Bucle For

El bucle for se parece a lo siguiente:

for(expresión_inicial; expresión_de_condición; cambiar_expresión) { operaciones ... }

La ejecución de esta secuencia de programa es similar al bucle while, salvo

que en este caso el proceso de especificar el valor inicial (inicialización) se

realice en la declaración. La expresión_ inicial especifica la variable inicial

del bucle, que más tarde se compara con la expresión_ de_condición antes

de entrar al bucle. Las operaciones dentro del bucle se ejecutan

repetidamente y después de cada iteración el valor de la expresión_inicial

se incrementa de acuerdo con la regla cambiar_expresión. La iteración

continúa hasta que la expresión_de_condición llegue a ser falsa.

for(k=0; k<5; k++) // La variable k se incrementa 5 veces (de 1 a 4) y operación // cada vez se repite la expresión operación ...

La operación se ejecutará cinco veces. Luego, al comprobar se valida que

la expresión k<5 sea falsa (después de 5 iteraciones k=5) y el programa

saldrá del bucle for.

Bucle Do-while

El bucle do-while se parece a lo siguiente:

do operación while (cambiar_condición);

Page 75: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 75

La expresión cambiar_condición se ejecuta al final del bucle, que significa

que operación se ejecuta como mínimo una vez sin reparar en que si la

condición es verdadera o falsa. Si el resultado es distinto de 0 (verdadero),

el procedimiento se repite.

Todos los siguientes ejemplos son equivalentes. Esta parte del código

visualiza "hello" en un LCD 10 veces con un retardo de un segundo. Note

que en este ejemplo se utilizan funciones predefinidas, que se encuentran

en las librerías del compilador mikroC PRO for PIC. No obstante le

aconsejamos que no trate de entenderlas en detalle. Su comportamiento

general dentro del bucle se explica por medio de los comentarios.

i = 0; // Inicialización del contador while (i<10) { // Condición Lcd_Out(1,3,"hello"); // Visualizar “hello” en el LCD Delay_ms(1000); // Retardo de 1000 ms Lcd_Cmd(_LCD_CLEAR); // Borrar el LCD Delay_ms(500); // Retardo de 500ms i++; // Contador se incrementa } for(i=0; i<10; i++) { // Inicialización, condición, incremento Lcd_Out(1,3,"hello"); // Visualizar “hello” en el LCD Delay_ms(1000); // Retardo de 1000 ms Lcd_Cmd(_LCD_CLEAR); // Borrar el LCD Delay_ms(500); // Retardo de 500ms } i = 0; // Inicialización del contador do { Lcd_Out(1,3,"hello"); // Visualizar “hello” en el LCD Delay_ms(1000); // Retardo de 1000 ms Lcd_Cmd(_LCD_CLEAR); // Borrar LCD Delay_ms(500); // Retardo de 500ms i++; // Contador se incrementa } while (i<10); // Condición

SENTENCIAS DE SALTO

SENTENCIA BREAK

A veces es necesario detener y salir de un bucle dentro de su cuerpo. La

sentencia break se puede utilizar dentro de cualquier bucle (while, for, do

while) y en las sentencias switch también. En éstas la sentencia break se

utiliza para salir de las sentencias switch si la condición case es verdadera.

Page 76: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 76

En este ejemplo, “Esperar” está parpadeando en la pantalla LCD hasta que

el programa detecte un uno lógico en el pin 0 del puerto PORTA.

while(1){ // Bucle infinito if(PORTA.F0 == 1) // Probar si el estado lógico del pin 0 del puerto break; // PORTA es 1; si equivale, salir del bucle Lcd_Out(1,3,"Esperar"); // Visualizar “Esperar” en el LCD Delay_ms(1000); // Retardo de 1000 ms Lcd_Cmd(_LCD_CLEAR); // Borrar LCD Delay_ms(500); // Retardo de 500ms }

SENTENCIA CONTINUE

La sentencia continue colocada dentro de un bucle se utiliza para saltar una

iteración. A diferencia de la sentencia break, el programa se queda dentro

del bucle y las iteraciones continúan.

// Si x=7, puede ocurrir una división por 0. // continue se utiliza aquí para evitar esta situación. x=1; while (x<=10) { if (x == 7) { // saltar x=7 para evitar división por 0 Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,3,"Division by 0"); Delay_ms(1000); x++; continue; // Después de esta línea, saltar a la sentencia while con x=8 } a = 1/(x-7); // Esta división generará un error si x=7 /* Muchas operaciones pueden ocurrir aquí */ Lcd_Out(1,3,"Division is OK"); // Poner este mensaje en el LCD Delay_ms(1000); x++; }

Page 77: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 77

SENTENCIA GOTO

La sentencia goto le permite hacer un salto absoluto al otro punto en el

programa. Esta característica se debe utilizar con precaución ya que su

ejecución puede causar un salto incondicional sin hacer caso a todos los

tipos de limitaciones de anidación. El punto destino es identificado por una

etiqueta, utilizada como un argumento para la sentencia goto. Una etiqueta

consiste en un identificador válido seguido por un colon (:).

...

if(CO2_sensor) goto aire acondicionado; // Si se consta que el valor ... // de la variable CO2_sensor =1 // hacer salto a la línea de programa // Aire acondicionado ... Aire acondicionado: // Desde aquí sigue la parte del código que se ejecutará // en caso de una concentración de CO2 demasiado alta ... // en el ambiente

2.7 TIPOS DE DATOS AVANZADOS

MATRICES

Una matriz es una lista de elementos del mismo tipo colocados en

localidades de memoria contiguas. Cada elemento es referenciado por un

índice. Para declarar una matriz, es necesario especificar el tipo de sus

elementos (denominado tipo de matriz), su nombre y el número de sus

elementos encerrados entre corchetes. Todos los elementos de una matriz

tienen el mismo tipo.

tipo_de_matriz nombre_de_matriz [nº_de_elementos];

Los elementos de una matriz se identifican por su posición. En C, el índice

va desde 0 (el primer elemento de una matriz) a N-1 (N es el número de

elementos contenidos en una matriz). El compilador tiene que “saber”

cuántas localidades de memoria debe alojar al declarar una matriz. El

tamaño de una matiz no puede ser una variable. Por eso, se pueden utilizar

dos métodos:

// método 1

Page 78: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 78

int display [3]; // Declaración de la matriz display capaz de contener 3 enteros // método 2 const DÍGITOS = 5; char Matriz_nueva[DÍGITOS]; // Declaración de la matriz Matriz_nueva // capaz de contener 5 enteros

Una matriz se puede inicializar a la vez que se declara, o más tarde en el

programa. En ambos casos, este paso se realiza al utilizar llaves:

int array_1[3] = {10,1,100};

Para leer o modificar un elemento de matriz del ejemplo anterior, basta con

introducir su índice encerrado entre corchetes:

/* Se supone que a ha sido declarado anteriormente como un entero */ a = array_1[0]; // A la variable a se le asigna el valor del miembro de matriz // con índice 0 (a = 10) array_1[2] = 20; // Miembro de matriz array_1[2] es modificado (nuevo valor es 20)

El siguiente programa cambia el orden de los elementos de una matriz.

Note que el índice se puede expresar mediante variables y operaciones

básicas.

void main() { const MUESTRAS_DE_AGUA = 4; // Valor de la constante MUESTRAS_DE_AGUA es 4 int i, temp; // Variables i y temp son de tipo int int profunidad_de_sonda [MUESTRAS_DE_AGUA] = {24,25,1,1987};// Todos // los miembros de la matriz profundidad // de sonda son de tipo int for(i=0;i<(MUESTRAS_DE_AGUA/2);i++){ // Bucle se ejecuta 2 veces

Page 79: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 79

temp = profundiad_de_sonda [i]; // temp se utiliza para guardar un valor // temporalmente profundiad_de_sonda [i] = profundiad_de_sonda [MUESTRAS_DE_AGUA-1-i]; profundiad_de_sonda [MUESTRAS_DE_AGUA-1-i] = temp; } // Aquí tenemos: profundidad_de_sonda [MUESTRAS_DE_AGUA] = {1987,1,25,24} }

MATRICES BIDIMENSIONALES

Aparte de las matrices unidimensionales que se pueden interpretar como

una lista de valores, el lenguaje C le permite declarar matrices

multidimensionales. En esta parte vamos a describir sólo las matrices

bidimensionales, también denominadas tablas o matrices. Una matriz

bidimensional se declara al especificar el tipo de dato de matriz, el nombre

de matriz y el tamaño de cada dimensión.

tipo_de_matriz nombre_de_matriz [número_de_filas] [número_de_columnas];

En la declaración de esta matriz número_de_filas y número_de_columnas

representan el número de filas y columnas en las que consiste una tabla,

respectivamente. Vea la siguiente matriz bidimensional:

int Tabla [3][4]; // Tabla se define de modo que tenga 3 filas y 4 columnas

Esta matriz se puede representar en la forma de una tabla.

tabla[0][0] tabla[0][1] tabla[0][2] tabla[0][3]

tabla[1][0] tabla[1][1] tabla[1][2] tabla[1][3]

tabla[2][0] tabla[2][1] tabla[2][2] tabla[2][3]

Similar a las matrices unidimesionales, es posible asignar los valores a los

elementos de una tabla en la línea de declaración. La asignación debe ser

realizada línea a línea como en el siguiente ejemplo. Como hemos visto

anteriormente, esta matriz tiene dos filas y tres columnas:

Page 80: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 80

int Tabla [2][3]= { {3,42,1},{7,7,19} };

La matriz anterior se puede representar también en la forma de una tabla de

valores:

3 42 1

7 7 19

PUNTEROS

Un puntero es una variable destinada a recibir una dirección. Un puntero

“apunta” a una localidad de memoria, referenciada por una dirección. En C,

la dirección de un objeto se puede obtener por medio un operador unitario

&. Para acceder al contenido de la memoria en una dirección específica

(también llamado objeto apuntado), se utiliza un operador de indirección (*).

'&n' es la dirección de la localidad de memoria 'n'.

'*(&n)' es el contenido de la dirección '(&n)', o sea de 'n'.

Para declarar un puntero, se debe que especificar el tipo de la variable

apuntada:

tipo_de_variable *puntero;

En esta etapa, el puntero mi_puntero apunta al valor almacenado en esta

localidad de memoria, o sea, a un valor desconocido. Así que, una

inicialización es muy recomendable:

puntero = &variable;

Ahora, puntero contiene la dirección de variable.

Para acceder al contenido de la variable apuntada, debe utilizar „*‟. El

siguiente ejemplo muestra el contenido de memoria dependiendo de la

acción realizada por medio del puntero.

Page 81: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 81

Los punteros son muy útiles para manejar las matrices. En este caso, un

puntero se utilizará para apuntar al primer elemento de una matriz. Debido

al hecho de que es posible realizar operaciones básicas sobre los punteros

(aritmética de punteros), es fácil manejar los elementos de una matriz.

Fíjese en la diferencia entre „*v+1‟ y „*(v+1)‟ en el siguiente ejemplo:

short int voltio[3] = {0,5,10}; short int *v; v = &(voltio[0]); // v contiene la dirección de voltio[0] *(v+1) = 2; // voltio[1] = 2 voltio[2] = *v+1; // tab[2] = 1 (tab[0] + 1) *(v+2) = *(v+1); // voltio[2] = 2 v++; // v contiene la dirección de voltio[1] *v = 1; // voltio[1] = 1

Los punteros también pueden ser declarados con el prefijo „const‟. En este caso, su valor no puede ser modificado después de la inicialización, similar a una constante.

A diferencia de C, el mikroC no admite alojamiento dinámico. ESTRUCTURAS

Ya hemos visto cómo agrupar los elementos dentro de matrices. No

obstante, al utilizar este método todos los elementos deben ser del mismo

tipo. Al utilizar estructuras, es posible agrupar diferentes tipos de variables

bajo el mismo nombre. Las variables dentro de una estructura se le

denominan los miembros de la estructura. Las estructuras de datos se

declaran al utilizar la siguiente sintaxis:

struct nombre_de_estructura { tipo1_de_miembro1 miembro1; tipo2_de_miembro2 miembro2; tipo3_de_miembro3 miembro3;

Page 82: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 82

.. };

No es posible inicializar variables dentro de la declaración de la estructura

de datos:

struct generador { int voltaje; char corriente; };

Entonces, podrá definir los objetos denominados „turbina‟ en el código. A

cada uno de estos tres objetos (turbinas) se le asignan las variables

„corriente‟ y „voltaje‟.

struct generadores turbina_1, turbina_2, turbina_3;

Para acceder a las variables, es preciso utilizar el operador '.'

turbina_3.voltaje = 150;

turbina_3.corriente = 12;

Por supuesto, igual que al utilizar los punteros, todavía se le permite realizar

operaciones por medio de operadores y sentencias definidos en las partes

anteriores.

Si está familiarizado con el lenguaje C, recuerde que mikroC no admite la

inicialización de los miembros de estructura por medio de las llaves. Por

ejemplo, „conjunto_1 ={15,„m‟};‟ devuelve un error en mikroC.

2.8 FUNCIONES

Una función es una subrutina que contiene una lista de sentencias a

realizar. La idea principal es dividir un programa en varias partes utilizando

estas funciones para resolver el problema inicial con más facilidad. Además,

las funciones nos permiten utilizar las destrezas y el conocimiento de otros

programadores. Una función se ejecuta cada vez que se llame dentro de

otra función. En C, un programa contiene como mínimo una función, la

función main(), aunque el número de funciones es normalmente mayor. Al

utilizar funciones el código se hace más corto ya que es posible llamar una

función tantas veces como se necesite. En C, el código normalmente

Page 83: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 83

consiste en muchas funciones. No obstante, en caso de que su programa

sea muy corto y simple, puede escribir todas las sentencias dentro de la

función principal.

FUNCIÓN PRINCIPAL

La función principal main() es una función particular puesto que es la que se

ejecuta al iniciar el programa. Además, el programa termina una vez

completada la ejecución de esta función. El compilador reconoce

automáticamente esta función y no es posible llamarla por otra función. La

sintaxis de esta función es la siguiente:

void main (void) { /* el primer 'void' significa que main no devuelve ningún valor. El segundo 'void' significa que no recibe ningún valor. Note que el compilador también admite la siguiente sintaxis: 'main()' o 'void main()' o 'main(void)' */ .. /* --- Introduzca su programa aquí --- */ . };

Esto significa que f es una función que recibe un número real x como

parámetro y devuelve 2*x-y.

La misma función en C se parece a lo siguiente:

float f (float x, float y) // variables flotantes x y y se pueden utilizar en f { float r; // declarar r para almacenar el resultado r = 2*x - y; // almacenar el resultado del cálculo en r return r; // devolver el valor de r }

Cada función debe ser declarada apropiadamente para poder interpretarla

correctamente durante el proceso de compilación. La declaración contiene

los siguientes elementos:

Tipo de resultado (valor devuelto): tipo de dato del valor devuelto Nombre de función: es un identificador que hace posible llamar a una

función.

Page 84: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 84

Declaración de parámetros se parece a la declaración de variable regular (por ejemplo: float x). Cada parámetro consiste en una variable, constante, puntero o matriz, precedidos por la etiqueta de tipo de dato. Se utilizan para pasar la información a la función al llamarla. Los parámetros diferentes están delimitados por comas.

Cuerpo de función: bloque de sentencias dentro de llaves

Una función se parece a lo siguiente:

tipo_de_resultado nombre_de_función (tipo argumento1, tipo argumento2,...) { Sentencia; Sentencia; ... return ... }

Note que una función no necesita parámetros (función main() por ejemplo),

pero debe estar entre paréntesis. En caso contrario, el compilador

malinterpretaría la función. Para hacerlo más claro, puede sustituir el

espacio en blanco encerrado entre paréntesis por la palabra clave void:

main (void).

VALOR DEVUELTO

Una función puede devolver un valor (esto no es obligatorio) por medio de la

palabra clave return. Al llegar a return, la función evalúa un valor (puede ser

una expresión) y lo devuelve a la línea de programa desde la que fue

llamada.

return r; // Devolver el valor contenido en r return (2*x - y); // Devolver el valor de la expresión 2*x-y

Una función no puede devolver más de un valor, pero puede devolver un

puntero o una estructura. Tenga cuidado al utilizar matrices y punteros. El

siguiente ejemplo es un error típico:

int *reverse(int *tab) // Esta función debe devolver una matriz r { // cuyo contenido está en orden inverso con // respecto a la matriz tab int r[DIM]; // Declaración de una nueva matriz denominada r int i; for(i=0;i<DIM;i++) // Bucle que copia el contenido de tab en r r[i] = tab[DIM-1-i]; // al invertir el orden

Page 85: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 85

return r; // Devolver el valor r }

En realidad, el compilador reserva memoria para el almacenamiento de

variables de la función reverse sólo durante su ejecución. Una vez

completada la ejecución de reverse, la localidad de memoria para la

variable i o para la matriz r ya no está reservada. Esto significa que la

dirección que contiene los valores de i o r[] está libre para introducir datos

nuevos. Concretamente, la función devuelve sólo el valor &r[0], así que sólo

el primer elemento de la matriz tab será almacenado en la memoria. Las

demás localidades de memoria, tales como &tab[1], &tab[2], etc. serán

consideradas por el compilador como espacios en blanco, o sea, estarán

listas para recibir los nuevos valores.

Para escribir esta función es necesario pasar la matriz r [] como parámetro

(vea la subsección Pasar los parámetros).

La función puede contener más de una sentencia return. En este caso, al

ejecutar la primera sentencia return, la función devuelve el valor

correspondiente y se detiene la ejecución de la función.

float abs (float x, float y) // Devolver el valor absoluto de 2*x-y { if ((2*x - y) >= 0) return (2*x - y); else return (-2*x + y); }

Si la función no devuelve ningún valor, la palabra void debe ser utilizada

como un tipo de resultado en la declaración. En este caso, la sentencia

return no debe ser seguida por ninguna expresión. Puede ser omitida como

en el siguiente ejemplo:

void wait_1 (unsigned int a) { cnt ++; // Incremento de una variable global cnt Delay_ms(a) ; // Ejecución de la función Delay_ms } // Note que Delay_ms no devuelve nada

DECLARAR PROTOTIPOS DE FUNCIONES

Page 86: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 86

Para utilizar una función, el compilador debe ser consciente de su presencia

en el programa. En la programación en C, los programadores normalmente

primero escriben la función main() y luego las funciones adicionales. Para

avisar al compilador de la presencia de las funciones adicionales, se

requiere declarar los prototipos de funciones en el principio de programa

antes de la función main(). Un prototipo de función está compuesto por: tipo de resultado nombre de función tipos de parámetros un punto y coma (;)

El prototipo de la función main no necesita ser declarado.

float f (float, float); /* no es obligatorio escribir los nombres de los parámetros. Este prototipo informa al compilador: en el programa se utilizará la función f, que utiliza dos parámetros de tipo float y devuelve el resultado del tipo float. */

LLAMAR UNA FUNCIÓN

Mientras una función es definida y su prototipo declarado, se puede utilizar

en culquier parte de programa. Sin embargo, como la función maines 'raiz'

del programa, no puede ser llamada de ninguna parte de programa. Para

ejecutar una función, es necesario escribir su nombre y los parámetros

asociados. Vea los siguientes ejemplos:

float resultado,a,b; // resultado,a,b,time deben coincidir con los tipos // definidos int time = 100; // en la declaración de las funciones f y wait_1 a = 10.54; b = 5.2; resultado = f(a,b); // Ejecutar la función f por medio de los parámetros a y b // El valor devuelto se le asigna a la variable resultado pausa_1(tiempo); // Ejecutar la función pausa_1 por medio de la variable tiempo funciónX(); // Ejecutar la función funciónX (sin parámetros)

Cuando se llama una función, el programa salta a la función llamada, la

ejecuta, después vuelve a la línea desde la que fue llamada.

PASAR LOS PARÁMETROS

Page 87: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 87

Al llamar una función, se le pasan los parámetros. En C existen dos formas

diferentes para pasar parámetros a una función.

El primer método, denominado „paso por valor‟, es el más fácil. En este

caso, los parámetros se pueden considerar como variables locales de la

función. Cuando se llama una función, el valor de cada parámetro se copia

a un nuevo espacio de memoria reservado durante la ejecución de la

función. Como los parámetros se consideran como variables locales por el

compilador, sus valores pueden ser modificados dentro de la función, pero

sus modificaciones no se quedan en la memoria una vez completada la

ejecución de la función.

Tenga en cuenta de que la función devuelve un valor, y no una variable.

Además, se crean copias de los valores de los parámetros, por lo que sus

nombres en la función f pueden ser diferentes de los parámetros utilizados

en la main(). La mayor desventaja del „paso por el valor‟ es que la única

interacción que una función tiene con el resto del programa es el valor

devuelto de un solo resultado (o la modificación de las variables globales).

El otro método, denominado 'paso por dirección' le permite sobrepasar este

problema. En vez de enviar el valor de una variable al llamar a función, se

debe enviar la dirección de memoria del valor. Entonces, la función llamada

será capaz de modificar el contenido de esta localidad de memoria.

// Función 'sort'ordena los miembros de la matriz por valor ascendente // y devuelve el miembro con máximo valor int sort(int *); // Prototipo de función const SIZE = 5; // Número de miembros a ordenar void main() { int maximum, input[SIZE] = {5,10,3,12,0}; // Declaración de variables en la matriz maximum = sort(input); // Llamar a función y asignarle el máximo // valor a la variable maximum } int sort(int *sequence) { int i, temp, permut; // Declaración de variables permut = 1; // Bandera de bit indica que se ha hecho una permutación while(permut!=0) { // Quedarse en el bucle hasta reinicar la bandera

Page 88: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 88

permut = 0; // Bandera reiniciada for(i=0;i<SIZE-1;i++) { // Comparar y oredenar los miembros de la // matriz (dos a dos) if(sequence [i] > sequence[i+1]){ temp = sequence [i]; sequence[i] = sequence[i+1]; sequence[i+1] = temp; permut = 1; // Se ha hecho una permutación, bandera de bit //se pone a uno } } } return sequence[SIZE-1]; // Devolver el valor del último miembro } // que es al mismo tiempo el miembro con el máximo valor

En este ejemplo, por medio de una función se realizan dos operaciones:

ordena los miembros de la matriz por valor asdendente y devuelve el

máximo valor.

Para utilizar una matriz en una función es necesario asignar la dirección a la

matriz (o a su primer miembro). Vea el siguiente ejemplo:

float método_1(int[]); // Declaración de prototipo de la función Método_1 float método_2(int*); // Declaración de prototipo de la función Método_2 const NÚMERO_DE_MEDICIONES = 7; // Número de los miembros de la matriz void main() { double promedio1, promedio2; // Declaración de las variables promedio1 // y promedio2 int voltaje [NÚMERO_DE_MEDICIONES] = {7,8,3,5,6,1,9}; // Declaración de la // matriz voltaje promedio1 = método_1(&voltaje[0]); // Parámetro de la función es la dirección // del primer miembro promedio2 = método_2(voltaje); // Parámetro de la función es la dirección de

Page 89: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 89

// la matriz } //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× float método_1(int voltaje[]) // Inicio de la función método_1 { int i, suma; // Declaración de las variables locales i y suma for(i=0;i<NÚMERO_DE_MEDICIONES;i++) // Cálculo del valor promedio de voltaje suma += voltaje[i]; // Es posible utilizar *(voltaje+i)en vez de voltaje[i] return(suma/NÚMERO_DE_MEDICIONES); } //×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× float método_2 (int *voltaje) //Inicio de la función método_2 { int i, suma; // Declaración de las variables locales i y suma for(i=0;i<NÚMERO_DE_MEDICIONES;i++) // Cálculo del valor promedio de voltaje suma += *(voltaje+i); // Es posible utilizar voltaje[i] en vez de *(voltaje+i) return(suma/NÚMERO_DE_MEDICIONES); }

Las funciones 'método_1' y 'método_2' son completamente equivalentes.

Las dos devuelven el valor promedio de la matriz 'voltaje[]'. Después de

declararla, la dirección del primer miembro se puede escribir como 'voltaje' o

'&voltaje[0]'.

2.9 CARACTERÍSTICAS PRINCIPALES DEL PREPROCESADOR

El preprocesador es un programa que procesa el código antes de que pase

por el compilador. Funciona bajo el control de las líneas de comando del

preprocesador denominadas directivas. Las directivas del preprocesador se

colocan en el código fuente, normalmente en el principio del archivo. Antes

de pasar por el compilador, el código fuente se examina por el

Page 90: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 90

preprocesador que detecta y ejecuta todas las directivas del preprocesador.

Las directivas del preprocesador siguen a una regla de la sintaxis especial,

empiezan por un símbolo „#‟ y no requieren ningún punto y coma al final (;).

DIRECTIVAS DEL PREPROCESADOR

La siguiente tabla contiene un conjunto de directivas del preprocesador

frecuentemente utilizadas:

Las directivas del preprocesador se pueden dividir en tres categorías:

DIRECTIVAS FUNCIONES

#define Define una sustitución de macro

#undef Quita una definición de nombre de macro

#define Especifica un archivo a ser incluido

#ifdef Prueba para definición de macro

#endif Especificar el final de #if

#ifndef Prueba si una macro no está definida

#if Prueba las condiciones de compilar

#else Especifica alternativas cuando la prueba de #if falla

#elif Especifica alternativas cuando más de dos condiciones

se necesitan

Definiciones de macro Inclusiones de archivos Control de compilación

Ahora, vamos a presentar sólo las directivas del preprocesador utilizadas

con más frecuencia. Sin embargo, no es necesario saber todas ellas para

programar microcontroladores. Sólo tenga en cuenta que el preprocesador

es una herramienta muy poderosa para los programadores avanzados en C,

especialmente para el control de compilación.

DIRECTIVAS DEL PREPROCESADOR PARA DEFINIR MACROS

Por medio de los macros es posible definir las constantes y ejecutar

funciones básicas. Una sustitución de macro es un proceso en el que un

identificador del programa se sustituye por una cadena predefinida. El

preprocesador sustituye cada ocurrencia del identificador en el código

Page 91: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 91

fuente por una cadena. Después de la sustitución, el código será compilado

normalmente.

Esto significa que el código sustituido debe respetar la sintaxis del mikroC.

La acción se realiza por medio de la directiva '#define'.

#define PI 3.14159 // Sustitución simple, PI será sustituido por // el valor 3.14159 en todas las partes del programa

También puede utilizar los parámetros para realizar substituciones más

complejas:

#define VOLUMEN (D,H) (((D/2)*(D/2)*PI))*H // Macro con parámetros

Entonces, en el código, la siguiente sentencia:

Tanque_1 = VOLUMEN (Diámetro,altura);

será sustituida por:

Tanque_1 = (((Diámetro/2)*(Diámetro/2)*PI)*altura;

Por medio de la directiva #undef es posible quitar una definición de nombre

de macro. Así se especifica que la substitución que se ha definido

anteriormente ya no va ocurrir en el siguiente código. Esto es útil cuando

usted quiere restringir la definición sólo a una parte particular del programa.

#undef TANQUE // Quitar la definición del macro VOLUMEN

INCLUSIÓN DE ARCHIVOS

La directiva de preprocesador #include copia un archivo específico en el

código fuente. El código incluido debe observar la sintaxis de C para ser

compilado correctamente.

Hay dos formas de escribir estas directivas. En el primer ejemplo, sólo el

nombre de archivo se especifica, así que el preprocesador lo buscará

dentro del archivo include. En el segundo ejemplo, se especifica la ruta

entera, así que el archivo estará directamente incluido (este método es más

rápido).

Page 92: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 92

#include <nombre_de_archivo> // Se especifica sólo el nombre del archivo #include "C:\Ruta\nombre_de_archivo.h" // Se especifica la localidad // exacta del archivo

2.10 MIKROC PRO FOR PIC

Como ya hemos visto, hay varias divergencias entre los lenguajes mikroC y

ANSI C. En este capítulo vamos a presentar las características específicas

del mikroC con el propósito de facilitar la programación de los

microcontroladores PIC.

ACCESO A LOS REGISTROS DE FUNCIONES ESPECIALES (SFR)

Como todos los microcontroladores, los de familia PIC tienen los registros

de funciones especiales (SFR). Para programar un PIC, es necesario

acceder a estos registros (para leerlos o escribir en ellos). Al utilizar el

compilador mikroC PRO for PIC es posible de acceder a cualquier SFR del

microcontrolador de cualquier parte del código (los SFR se consideran

como variables globales) sin necesidad de declararlo anteriormente. Los

registros de funciones especiales se definen en un archivo externo e

incluido dentro del compilador (archivo .def). Este archivo contiene todos los

SFR del microcontrolador PIC a programar.

TRISB = 0; // todos los pines del puerto PORTB se configuran como salidas PORTB = 0; // todos los pines del PORTB se ponen a 0

ACCESO A LOS BITS INDIVIDUALES

El compilador mikroC PRO for PIC le permite acceder a los bits individuales

de variables de 8 bits por su nombre o su posición en byte:

INTCON.B0 = 0; // Poner a 0 el bit 0 del registro INTCON ADCON0.F5 = 1; // Poner a 1 el bit 5 del registo ADCON0 INTCON.GIE = 0; // Poner a 0 el bit de interrupción global (GIE)

Para acceder a un bit individual, se puede utilizar '.FX' así como '.BX' (X es

un entero entre 0 y 7 que representa la posición de bit).

Page 93: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 93

TIPO SBIT

Si quiere declarar una variable que corresponde a un bit de un SFR, hay

que utilizar el tipo sbit. Una variable de tipo sbit se comporta como un

puntero y se debe declarar como una variable global:

sbit Botón_PARADA at PORTA.B7; // Botón_PARADA está definido ... void main() { // Cualquier modificación de Botón_PARADA afectará a PORTA.B7 ... // Cualquier modificación de PORTA.B7 afectará a Botón_PARADA }

En este ejemplo, El Botón_PARADA es una variable declarada por el

usuario, mientras que PORTA.B7 (bit 7 del puerto PORTA) será

automáticamente reconocido por el compilador.

TIPO BIT

El compilador mikroC PRO for PIC proporciona un tipo de datos bit que se

puede utilizar para declarar variables. No se puede utilizar en las listas de

argumentos, punteros y los valores devueltos de funciones. Además, no es

posible declarar e inicializar una variable de tipo bit en la misma línea. El

compilador determina el bit en uno de los registros disponibles para

almacenar las variables.

bit bf; // Variable de tipo bit válida bit *ptr; // Varibale de tipo bit inválida. // No hay punteros a una variable de tipo bit bit bg = 0; // ERROR ; declaración con inicialización no está permitida bit bg; bg = 0; // Declaración e inicialización válidas

INSERTAR CÓDIGO ASM EN C

A veces el proceso de escribir un programa en C requiere las partes del

código escritas en ensamblador. Esto permite ejecutar las partes

complicadas del programa de una forma definida con precisión en un

período de tiempo exacto. Por ejemplo, cuando se necesita que los pulsos

muy cortos (de unos microsegundos) aparezcan periódicamente en un pin

del microcontrolador. En tales casos la solución más simple sería utilizar el

código ensamblador en la parte del programa que controla la duración de

pulsos.

Page 94: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 94

Una o más instrucciones en ensamblador están insertadas en el programa

escrito en C, utilizando el comando asm:

asm { instrucciones en ensamblador ... }

Los códigos escritos en ensamblador pueden utilizar constantes y variables

anteriormente definidos en C. Por supuesto, como el programa entero está

escrito en C, sus reglas se aplican al declarar estas constantes y variables.

unsigned char maximum = 100; // Declarar variables: maximum = 100 asm { // Inicio del código ensamblador MOVF maximum,W // W = maximum = 100 ... } // Final del código ensamblador

FUNCIÓN DE INTERRUPCIÓN

Una interrupción detiene la ejecución normal de un programa para ejecutar

las operaciones específicas. Una lista de sentencias a ejecutar debe estar

escrita dentro de una función particular denominada interrupt(). La sintaxis

de una interrupción en mikroC se parece a lo siguiente:

Page 95: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 95

void interrupt() { cnt++ ; // Al producirse una interrupción // la cnt se incrementa en 1 PIR1.TMR1IF = 0; // Poner a 0 el bit TMR1IF }

A diferencia de las funciones estándar, no es necesario declarar el prototipo

de la función interrupt(). Además, como la ejecución de esta función no

forma parte de la ejecución de programa regular, no se debe llamar de

ninguna parte de programa (se ejecutará automáticamente dependiendo de

las condiciones que el usuario ha definido en el programa). En el siguiente

capítulo vamos a dar una clara explicación de la ejecución y definición de

subrutinas de interrupción.

LIBRERÍAS

Usted probablemente ha notado que en los ejemplos anteriores hemos

utilizado algunas funciones como son 'Delay_ms', 'LCD_out', 'LCD_cmd' etc.

Estas funciones están definidas en las librerías contenidas en el

compilador mikroC.

Una librería representa un código compilado, anteriormente escrito en

mikroC, que contiene un conjunto de variables y funciones. Cada librería

tiene un propósito específico. Por ejemplo, la librería LCD contiene

funciones de visualización de la pantalla LCD, mientras

que C_mathproporciona algunas funciones matemáticas.

Antes de utilizar alguna de ellas en el programa, es necesario

comunicárselo al compilador al marcarlas en la lista de las librerías del

compilador existentes. Si el compilador encuentra una función desconocida

durante la ejecución de programa, primero va a buscar su declaración en

las librerías marcadas.

Page 96: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 96

Aparte de las librerías existentes, es posible crear las librerías y luego

utilizarlas en el programa. El procedimiento de cómo crear librerías se

describe en detalles en Help (Ayuda) del compilador.

El compilador mikroC incluye tres tipos de librerías:

- librerías ANSI C estándar:

LIBRARÍA DESCRIPCIÓN

ANSI C Ctype Library

Utilizada principalmente para probar o para convertir los datos

ANSI C Math Library Utilizada para las operaciones matemáticas de punto flotante

ANSI C Stdlib Library

Contiene las funciones de librerías estándar

ANSI C String Library

Utilizada para realizar las operaciones de cadenas y de manipulación de memoria

- librerías misceláneas:

LIBRARÍA DESCRIPCIÓN

Button Library Utilizada para desarrollar los proyectos

Conversion Library Utilizada para la conversión de tipos de datos

Sprint Library Utilizada para formatear los datos con facilidad

PrintOut Library Utilizada para formatear los datos e imprimirlos

Time Library Utilizada para cálculos de tiempo (formato UNIX time)

Trigonometry Library

Utilizada para la implementación de funciones trigonométricas fundamentales

Setjmp Library Utilizada para los saltos de programa

- librerías para el hardware:

LIBRARÍA DESCRIPCIÓN

ADC Library Utilizada para el funcionamiento del convertidor A/D

CAN Library Utilizada para las operaciones con el módulo CAN

CANSPI Library Utilizada para las operaciones con el módulo CAN externo

(MCP2515 o MCP2510)

Compact Flash Library Utilizada para las operaciones con las tarjetas de

memoria Compact Flash

Page 97: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 97

EEPROM Library Utilizada para las operaciones con la memoria EEPROM

incorporada

EthernetPIC18FxxJ60 Library

Utilizada para las operaciones con el módulo Ethernet incorporado

Flash Memory Library Utilizada para las operaciones con la memoria Flash

incorporada

Graphic Lcd Library Utilizada para las operaciones con el módulo LCD gráfico

con resolución 128x64

I2C Library Utilizada para las operaciones con el módulo de

comunicación serial I2C incorporado

Keypad Library Utilizada para las operaciones con el teclado (botones de

presión 4x4)

Lcd Library Utilizada para las operaciones con el LCD (de 2x16

caracteres)

Manchester Code Library Utilizada para la comunicación utilizando el

código Manchester

Multi Media Card Library Utilizada para las operaciones con las tarjetas multimedia

MMC flash

One Wire Library Utilizada para las operaciones con los circuitos utilizando

la comunicación serial One Wire

Port Expander Library Utilizada para las operaciones con el extensor de puertos

MCP23S17

PS/2 Library Utilizada para las operaciones con el teclado estándar

PS/2

PWM Library Utilizada para las operaciones con el módulo PWM

incorporado

RS-485 Library Utilizada para las operaciones con los módulos utilizando

la comunicación serial RS485

Software I2C Library Utilizada para simular la comunicación I2C con software

Software SPI Library Utilizada para simular la comunicación SPI con software

Software UART Library Utilizada para simular la comunicación UART con software

Sound Library Utilizada para generar las señales de audio

SPI Library Utilizada para las operaciones con el módulo SPI

incorporado

SPI Ethernet Library Utilizada para la comunicación SPI con el módulo

ETHERNET (ENC28J60)

SPI Graphic Lcd Library Utilizada para la comunicación SPI de 4 bits con el LCD

gráfico

SPI LCD Library Utilizada para la comunicación SPI de 4 bits con el LCD

(de 2x16 caracteres)

Page 98: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 98

SPI Lcd8 Library Utilizada para la comunicación SPI de 8 bits con el LCD

SPI T6963C Graphic Lcd Library

Utilizada para la comunicación SPI con el LCD gráfico

UART Library Utilizada para las operaciones con el módulo UART

incorporado

USB Hid Library Utilizada para las operaciones con el módulo USB

incorporado

2.11 PROGRAMAR LOS PIC UTILIZANDO MIKROC PRO FOR PIC

En las secciones anteriores hemos presentado el lenguaje mikroC,

especialmente diseñado para programar los PIC. Ahora, lo que hemos

revisado es suficiente para empezar a programar, es hora de presentar el

software que utilizará para desarrollar y editar los proyectos. Este software

se le denomina Entorno de desarrollo integrado (Integrated Developement

Environment - IDE) e incluye todas las herramientas necesarias para

desarrollar los proyectos (editor, depurador etc.). Por extensión, IDE es a

veces llamado compilador. En esta sección le enseñaremos lo básico que

debe saber para empezar a desarrollar su primer proyecto en mikroC

utilizando el IDE del compilador mikroC PRO for PIC.

Aparte de todas las características comunes de cualquier IDE, mikroC PRO

for PIC contiene las informaciones de arquitectura de los microcontroladores

PIC (registros, módulos de memoria, funcionamiento de circuitos

particulares etc.) para compilar y generar un archivo legible por un

microcontrolador PIC. Además, incluye las herramientas específicas para

programar los microcontroladores PIC.

El proceso de crear y ejecutar un proyecto contiene los siguientes pasos:

1. Crear un proyecto (nombre de proyecto, configuración de proyecto, dependencias entre archivos)

2. Editar un programa

3. Compilar el programa y corrección de errores

4. Depurar (ejecutar el programa paso a paso para asegurarse de que se ejecutan las operaciones deseadas).

5. Programar un microcontrolador (cargar el archivo .hex generado por el compilador en el microcontrolador utilizando el programador PICflash).

Page 99: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 99

INSTALAR MIKROC PRO FOR PIC

Antes que nada, usted debe instalar el compilador (con su IDE) en la PC. La

instalación del mikroC PRO for PIC es similar a la instalación de cualquier

programa en Windows. Todo el procedimiento se lleva a cabo por medio de

los wizards (asistentes de instalación):

Basta con seguir las instrucciones y pulsar sobre Next, OK, Next, Next... En

general, es el mismo procedimiento menos la última opción: 'Do you want to

install PICFLASH v7.11 programmer?'. ¿Para qué sirve este software? De

eso vamos a hablar más tarde. Por ahora, basta con saber que es un

software autónomo utilizado para cargar el programa en el microcontrolador.

Una vez más: Next, OK, Next, Next...

Page 100: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 100

Una vez completada la instalación del PICflash, el sistema operativo le

preguntará a instalar otro programa similar, un software para programar un

grupo especial de los microcontroladores PIC que funcionan en modo de

bajo consumo (3.3 V). Salte este paso...

El último paso - ¡la instalación del controlador (driver)!

Pulse sobre Yes.

Un controlador es un programa que permite al sistema operativo comunicar

con un periférico. En este caso, este dispositivo es el programador

(hardware) del sistema de desarrollo.

Page 101: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 101

El controlador a instalar depende del sistema operativo utilizado. Seleccione

el controlador correspondiente al SO (sistema operativo) utilizado (por

medio de abrir la carpeta correspondiente) e inicie la instalación. Otra vez,

Next, OK, Next, Next... Bueno, ¡todo está instalado para iniciar a programar!

CARACTERÍSTICAS PRINCIPALES DEL MIKROC PRO FOR PIC

Al iniciar el IDE del compilador mikroC PRO for PIC por primera vez,

aparecerá una ventana como se muestra a continuación:

Page 102: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 102

Desgraciadamente, una descripción detallada de todas las opciones

disponibles de este IDE nos tomaría mucho tiempo. Por eso vamos a

describir sólo lo más importante del compilador mikroC PRO for PIC. De

todos modos, para obtener más informacion presione el botón de Ayuda

(Help) [F1].

MANEJAR LOS PROYECTOS

Antes de empezar a escribir el código, usted debe crear un proyecto. Un

programa escrito en el compilador mikroC PRO for PIC no es un archivo

fuente autónomo, sino que forma parte de un proyecto que incluye un

código hex, un código ensamblador, cabecera y otros archivos. Algunos de

ellos se requieren para compilar el programa, mientras que otros se crean

durante el proceso de compilación. Un archivo con extensión .mcppi le

permite abrir cualquiera de estos proyectos.

Para crear un proyecto, basta con seleccionar la opción Project/New

Project, y un wizard aparecerá automáticamente. ¿Qué hacer entonces?

Siga las instrucciones...

Page 103: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 103

PROJECT MANAGER (ADMINISTRADOR DEL PROYECTO)

Una vez creado el proyecto, es posible manejar todos los archivos que

contiene al utilizar la ventana Project Manager. Basta con pulsar con el

botón derecho del ratón sobre una carpeta y seleccionar la opción que

necesita para su proyecto.

PROJECT SETTINGS (CONFIGURACIÓN DE PROYECTOS)

Al compilar un proyecto, el compilador genera el archivo .hex que se

cargará en el microcontrolador. Estos archivos serán diferentes lo que

depende del tipo del microcontrolador así como del propósito de la

compilación. Por esta razón es necesario ajustar algunos parámetros de

proyectos utilizando la ventana Project Settings.

Device (dispositivo):

Al seleccionar el tipo de microcontrolador a utilizar permite al compilador

extraer el archivo de definición (archivo .def) asociado. El archivo de

definición de un microcontrolador contiene las informaciones específicas de

sus registros SFR, de sus direcciones de memoria y algunas variables de

Page 104: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 104

programación específicas a ese tipo del microcontrolador. Es obligatorio

crear un archivo .hex compatible.

Oscillator (oscilador):

Se debe especificar la velocidad de operación del microcontrolador. Por

supuesto, este valor depende del oscilador utilizado. El compilador la

necesita para compilar rutinas, lo que requiere información del tiempo (por

ejemplo, la función Delay_ms). Más tarde, el programador necesitará esta

información también. La velocidad de operación se configura de modo que

permita al oscilador interno del microcontrolador funcionar a una frecuencia

seleccionada.

Build/Debugger Type:

Todo el proceso de compilar (building) está compuesto por análisis

sintáctico (parsing), compilar, enlazar (linking) y generar los archivos .hex.

El tipo de compilación le permite ajustar el modo de compilación.

Dependiendo del modo seleccionado, difieren los archivos generados a

cargar en el microcontrolador.

Release: Al elegir esta opción , el compilador no puede afectar más a la

ejecución de programa después de la compilación. El programa a cargar en

el microcontrolador no será modificado de ninguna manera.

ICD debug: Al elegir esta opción, una vez completado el proceso de la

compilación y cargado el programa en la memoria del microcontrolador, el

compilador se queda conectado al microcontrolador por medio del cable

USB y el programador, y todavía puede afectar a su funcionamiento. El

archivo .hex generado contiene los datos adicionales que permiten el

funcionamiento del depurador. Una herramienta denominada mikroICD

(Depurador en circuito - In Circuit Debugger) permite ejecutar el programa

paso a paso y proporcionar un acceso al contenido actual de todos los

registros de un microcontrolador real.

El simulador no utiliza los dispositivos reales para simular el funcionamiento

del microcontrolador, así que algunas operaciones no pueden ser

reproducidas (por ejemplo, interrupción). De todos modos, resulta más

rápido depurar un programa por medio de un simulador. Además, no se

requiere ningún dispositivo destino.

Note que es posible modificar cualquier configuración en cualquier momento

mientras se edita el programa. No se olvide de recompilar y reprogramar su

dispositivo después de modificar una configuración.

Page 105: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 105

LIBRARY MANAGING (EDITOR DE LIBRERÍAS)

El compilador tiene que conocer todas las dependencias de su archivo

fuente en mikroC para compilarlo apropiadamente. Por ejemplo, si las

librerías forman parte de su proyecto, debe especificar cuáles de ellas se

utilizan.

Las librerías contienen un gran número de funciones listas para ser

utilizadas. Las librerías en mikroC proporcionan muchas facilidades para

escribir programas para los microcontroladores PIC. Abra la ventana Library

Manager, y marque las que quiere utilizar en el programa. Al marcar una

librería, se añade automáticamente al proyecto y se enlaza durante el

proceso de la compilación. Así, no necesita incluir las librerías manualmente

en sus archivos del código fuente por medio de la directiva del

preprocesador #include.

Por ejemplo, si su programa utiliza un LCD no hace falta escribir nuevas

funciones ya que al seleccionar la librería Lcd, usted podrá utilizar funciones

listas para ser utilizadas de la librería LCD (Lcd_Cmd, LCD_Init...) en su

programa. Si esta librería no está seleccionada en la ventana Library

Manager, cada vez que intente utilizar una función de la librería LCD, el

compilador le informará de un error. Una descripción de cada librería está

disponible al pulsar con el botón derecho del ratón sobre su nombre y

seleccionar la opción Help.

EDITAR Y COMPILAR PROGRAMAS

CODE EDITOR (EDITOR DE CÓDIGO)

El proceso de editar programas se debe realizar dentro de la ventana

principal del IDE denominada Code Editor. Al escribir el programa no se

Page 106: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 106

olvide de los comentarios. Los comentarios son muy importantes para

depurar y mejorar el programa. Además, aunque el compilador no tenga las

restricciones de formateo, siempre debe seguir a las mismas reglas de

editar (como en los ejemplos proporcionados en este libro). Como no hay

limitaciones de tamaño, no vacile en utilizar los espacios en blanco para

hacer su código más legible.

Al escribir un programa, no espere que termine la redacción del programa

para compilarlo. Compile su código de forma regular con el propósito de

corregir cuánto más errores de sintaxis. Asimismo usted puede compilar su

programa cada vez que se complete la redacción de una nueva función así

como probar su comportamiento al utilizar modo de depuración (ver la

próxima sección). De este modo, resulta más fácil solucionar los errores de

programa para no “tomar un camino erróneo” en redactar su programa. De

lo contrario, usted tendrá que editar el programa entero.

CODE EXPLORER (EXPLORADOR DEL CÓDIGO)

La ventana Code Explorer le permite localizar funciones y procedimientos

dentro de los programas largos. Por ejemplo, si usted busca una función

utilizada en el programa, basta con pulsar dos veces sobre su nombre en

esta ventana, y el cursor estará automáticamente posicionado en la línea

apropiada en el programa.

COMPILAR Y SOLUCIONAR LOS ERRORES

Para compilar su código, pulse sobre la opción Build en el menú Project. En

realidad, el proyecto entero se ha compilado, y si la compilación se ha

realizado con éxito, se generarán los archivos de salida (asm, .hex etc.).

Una compilación se ha realizado con éxito si no se ha encontrado ningún

error. Durante el proceso de compilación se generan muchos mensajes que

Page 107: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 107

se visualizan en la ventana Messages. Estos mensajes consisten en

información, advertencia y errores. Cada error encontrado se asocia con su

línea de programa y su descripción.

Como un error en su código puede generar mucho más errores,

simplemente debe intentar solucionar el primer error en la lista y después

recompile su programa. En otras palabras, es recomendable solucionar los

errores uno a uno.

En el ejemplo anterior hay dos errores y una advertencia: faltan un punto y

coma y una declaración de variable La advertencia le informa que falta el

tipo del valor devuelto de la función main.

La compilación le permite corregir su programa por medio de solucionar

todos los errores en mikroC. Cuando todos los errores se solucionen, su

programa está listo para ser cargado en el microcontrolador. De todas

formas, su tarea todavía no está terminada, porque aún no sabe si su

programa se comporta como se esperaba o no.

DEPURAR EL PROGRAMA

La depuración es un paso muy importante ya que permite probar el

programa después de una compilación realizada con éxito, o solucionar los

errores descubiertos mientras se ejecuta el programa. Como ya hemos

visto, hay dos modos de depurar: un depurador software que simula el

funcionamiento del microcontrolador (modo por defecto) y depurador

hardware (mikroICD) que lee directamente el contenido de la memoria del

microcontrolador. El procedimiento de depuración es el mismo sin reparar

en el modo elegido. En caso de elegir la opción ICD debug, hay que cargar

el programa en el microcontrolador antes de depurarlo.

Para iniciar la depuración, pulse sobre la opción Start debugger del

menú Run. El editor del código será ligeramente modificado

automáticamente y aparecerá una ventana denominada Watch Values. El

Page 108: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 108

principio de depuración se basa en ejecutar el programa paso a paso y

monitorear el contenido de los registros y los valores de las variables. De

este modo, es posible comprobar el resultado de un cálculo y ver si algo

inesperado ha ocurrido. Al ejecutar el programa paso a paso, podrá localizar

los problemas con facilidad.

Durante una depuración el programa será modificado, por lo que usted

siempre debe recompilar el programa después de cada corrección, y

reiniciar el depurador para comprobar qué ha sido modificado.

COMANDOS DEL DEPURADOR

Hay varios comandos disponibles para depurar el código:

Step Into - Ejecuta una sola instrucción. Cuando la instrucción es una llamada a una rutina, el depurador hará un salto a la rutina y se detendrá después de ejecutar la primera instrucción dentro de la rutina.

Step Over - Se ejecuta una sola instrucción. Cuando la instrucción es una llamada a una rutina, el depurador no hará un salto a la rutina, sino que se ejecutará toda la rutina. El depurador se detiene a la primera instrucción después de la llamada a la rutina.

Run To Cursor - El programa se ejecuta hasta la línea en la que se encuentre el cursor.

Step out - Se ejecutan las demás instrucciones dentro de la rutina. El depurador se detiene inmediatamente al salir de la rutina.

PUNTOS DE RUPTURA (BREAKPOINTS)

Los puntos de ruptura hacen el proceso de depurar los programas de una

manera más eficiente, puesto que permiten ejecutar el programa a toda

velocidad y detenerlo automáticamente en una línea específica (punto de

ruptura). Eso resulta muy útil, permitiéndole comprobar sólo las partes

críticas del programa y no perder el tiempo probando todo el programa línea

a línea. Para añadir o quitar un punto de ruptura basta con pulsar sobre la

línea apropiada en el lado izquierdo del editor del código, o presionar [F5].

Una pequeña ventana denominada Breakpoints muestra dónde están los

puntos de ruptura. Note que las líneas designadas como puntos de ruptura

están marcadas en rojo.

Page 109: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 109

La línea que se está ejecutando actualmente está marcada en azul. Es

posible leer el contenido de registros y variables seleccionados en la

ventana Watch Values en cualquier momento. Para ejecutar la parte de

programa desde la línea en la que está el cursor hasta el punto de ruptura,

utilice el comando Run/Pause Debugger.

VENTANA WATCH VALUES

El depurador software y hardware tienen la misma función de monitorear el

estado de los registros durante la ejecución del programa. La diferencia es

que el depurador software simula ejecución de programa en una PC,

mientras que el depurador ICD (depurador hardware) utiliza un

microcontrolador real. Cualquier cambio de estado lógico de los pines se

indica en el registro (puerto) apropiado. Como la ventana Watch Values

permite monitorear el estado de todos los registros, resulta fácil comprobar

si un pin está a cero o a uno. La última modificación está marcada en rojo

en la ventana Watch Values. Esto le permite localizar la modificación en la

lista de variables y registros durante el proceso de la depuración.

Page 110: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 110

Para visualizar esta ventana es necesario seleccionar la opción View/Debug

Windows/Watch Values. Entonces usted puede hacer una lista de

registros/variables que quiere monitorear y la manera de visualizarlos.

STOPWATCH (CRONÓMETRO)

Si quiere saber cuánto tiempo tarda un microcontrolador en ejecutar una

parte del programa, seleccione la opción Run/View Stopwatch. Aparecerá

una ventana como se muestra en la figura a la derecha. ¿Cómo funciona un

cronómetro? Eso es pan comido... El tiempo que tarda un comando (step

into, step over, run/pause etc.) en ejecutarse por el depurador se mide

automáticamente y se visualiza en la ventana Stopwatch. Por ejemplo, se

mide tiempo para ejecutar un programa, tiempo para ejecutar el último paso

etc.

PROGRAMAR EL MICROCONTROLADOR

Si ha solucionado todos los errores en su código y cree que su programa

está listo para ser utilizado, el siguiente paso es cargarlo en el

microcontrolador. El programador PICflash se utiliza para este propósito. Es

Page 111: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 111

una herramienta diseñada para programar todos los tipos de

microcontroladores PIC. Está compuesto por dos partes:

La parte hardware se utiliza para introducir un código hexadecimal (el programa a ser cargado en el microcontrolador) y para programar el microcontrolador por medio de niveles de voltaje específicos. Durante el proceso de la programación, un nuevo programa se escribe en la memoria flash del microcontrolador, mientras que el programa anterior se borra automáticamente.

La parte de software se encarga de enviar el programa (archivo .hex ) a la parte hardware del programador por medio de un cable USB. A la interfaz de usuario de este software se le puede acceder desde IDE al pulsar sobre la opción mE_Programmer del menú Tools o al pulsar [F11]. Por consiguiente, es posible modificar algunas configuraciones del programador y controlar el funcionamiento de la parte hardware (Cargar, Escribir, Verificar...).

Se puede reprogramar el microcontrolador tantas veces como se necesite.

OTRAS HERRAMIENTAS DEL COMPILADOR

El compilador mikroC PRO for PIC proporciona herramientas que en gran

medida simplifican el proceso de escribir el programa. Todas estas

herramientas se encuentran en el menú Tools. En la siguiente sección

vamos a darle una breve descripción de todas ellas.

Page 112: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 112

TERMINAL USART

El terminal USART representa una sustitución para la estándar Windows

Hyper Terminal. Se puede utilizar para controlar el funcionamiento del

microcontrolador que utiliza la comunicación USART. Tales

microcontroladores están incorporados en un dispositivo destino y

conectados al conector RS232 de la PC por medio de un cable serial.

La ventana USART terminal dispone de opciones para configurar la

comunicación serial y visualizar los datos enviados/ recibidos.

EDITOR EEPROM

Al seleccionar la opción EEPROM Editor del menú Tools, aparecerá una

ventana como se muestra en la siguiente figura. Así es cómo funciona la

memoria EEPROM del microcontrolador. Si quiere cambiar de su contenido

después de cargar el programa en el microcontrolador, ésta es la forma

correcta de hacerlo. El nuevo contenido es un dato de un tipo específico

(char, int o double), primero debe seleccionarlo, introducir el valor en el

campo Edit Value y pulsar sobre Edit. Luego, pulse sobre el botón Save

para guardarlo como un documento con extensión .hex. Si la opción Use

EEPROM in Project está activa, los datos se cargarán automáticamente en

el microcontrolador durante el proceso de la programación.

Page 113: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 113

VENTANA ASCII CHART

Si necesita representar numéricamente un carácter ASCII, seleccione la

opción ASCII chart del menú Tools. Aparecerá una tabla, como se muestra

en la figura que está a continuación. Usted probablemente sabe que cada

tecla de teclado está asociada con un código (código ASCII). Como se

puede ver, los caracteres que representan los números tienen valores

diferentes. Por esta razón, la instrucción de programa para visualizar el

número 7 en un LCD no visualizará este número, sino el equivalente a la

instrucción BEL. Si envía el mismo número en forma de un carácter a un

LCD, obtendrá el resultado esperado - número 7. Por consiguiente, si quiere

visualizar un número sin convertirlo en un carácter apropiado, es necesario

añadir el número 48 a cada dígito en el que consiste el número a visualizar.

Page 114: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 114

EDITOR DE SIETE SEGMENTOS

Un editor de siete segmentos le permite determinar con facilidad el número

a poner en un puerto de salida con el propósito de visualizar un símbolo

deseado. Por supuesto, se da por entendido que los pines del puerto deben

estar conectados a los segmentos del visualizador de manera apropiada.

Basta con colocar el cursor en cualquier segmento del visualizador y pulsar

sobre él. Se visualizará inmediatamente el número a introducir en el

programa.

Page 115: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 115

LCD CUSTOM CHARACTER (CARACTERES LCD DEFINIDOS POR EL USUARIO)

Además de los caracteres estándar, el microcontrolador también puede

visualizar los caracteres creados por el programador. Al seleccionar la

herramienta LCD custom character, se evitará un pesado trabajo de crear

funciones para enviar un código apropiado a un visualizador. Para crear un

símbolo, pulse sobre los cuadros pequeños en la ventana LCD custom

character, luego seleccione la posición y la fila y pulse sobre el botón

GENERATE. El código apropiado aparece en otra ventana. No es necesita

pulsar más. Copy to Clipboard (copiar al portapapeles) - Paste (pegar)...

GENERADOR DE MAPA DE BITS PARA UN LCD GRÁFICO

El generador de mapa de bits para un LCD gráfico es una herramienta

insustituible en caso de que el programa que escribe utilice el visualizador

LCD (GLCD). Esta herramienta le permite visualizar un mapa de bits con

facilidad. Seleccione la opción Tools/Glcd Bitmap Editor aparecerá la

ventana apropiada. Para utilizarlo, seleccione el tipo de visualizador a

utilizar y cargue un mapa de bits. El mapa de bits debe ser monocromático y

tener la resolución apropiada del visualizador (128 x 64 píxeles en este

ejemplo). El procedimiento a seguir es igual que en el ejemplo anterior:

Copy to Clipboard...

Page 116: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 116

Un código generado que utiliza herramientas para controlar los

visualizadores LCD y GLCD contiene funciones de la librería Lcd. Si las

utiliza en el programa, no se olvide de marcar la caja de chequeo junto a

esta librería en la ventana Library Manager. Así el compilador será capaz de

reconocer estas funciones correctamente.

Page 117: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 117

Capitulo 3: Microcontrolador PIC16F887

El PIC16F887 es un producto conocido de la compañía Microchip. Dispone

de todos los componentes disponibles en la mayoría de los

microcontroladores modernos. Por su bajo precio, un rango amplio de

aplicaciones, alta calidad y disponibilidad, es una solución perfecta aplicarlo

para controlar diferentes procesos en la industria, en dispositivos de control

de máquinas, para medir variables de procesos etc. Algunas de sus

características principales se enumeran a continuación.

3.1 CARACTERÍSTICAS BÁSICAS DEL PIC16F887

3.2 PRINCIPALES REGISTROS SFR

3.3 PUERTOS DE ENTRADA/SALIDA

3.4 TEMPORIZADOR TIMER0

3.5 TEMPORIZADOR TIMER1

3.6 TEMPORIZADOR TIMER2

3.7 MÓDULOS CCP

3.8 MÓDULOS DE COMUNICACIÓN SERIE

3.9 MÓDULOS ANALÓGICOS

3.10 OSCILADOR DE RELOJ

3.11 MEMORIA EEPROM

3.12 ¡REINICIO! ¿BLACK-OUT, BROWN-OUT O RUIDOS?

3.1 CARACTERÍSTICAS BÁSICAS DEL PIC16F887

arquitectura RISC

o El microcontrolador cuenta con solo 35 instrucciones diferentes

o Todas las instrucciones son uni-ciclo excepto por las de

ramificación

Frecuencia de operación 0-20 MHz

Oscilador interno de alta precisión

o Calibrado de fábrica

Page 118: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 118

o Rango de frecuencia de 8MHz a 31KHz seleccionado por

software

Voltaje de la fuente de alimentación de 2.0V a 5.5V

o Consumo: 220uA (2.0V, 4MHz), 11uA (2.0 V, 32 KHz) 50nA (en

modo de espera)

Ahorro de energía en el Modo de suspensión

Brown-out Reset (BOR) con opción para controlar por software

35 pines de entrada/salida

o alta corriente de fuente y de drenador para manejo de LED

o resistencias pull-up programables individualmente por software

o interrupción al cambiar el estado del pin

memoria ROM de 8K con tecnología FLASH

o El chip se puede re-programar hasta 100.000 veces

Opción de programación serial en el circuito

o El chip se puede programar incluso incorporado en el dispositivo

destino.

256 bytes de memoria EEPROM

o Los datos se pueden grabar más de 1.000.000 veces

368 bytes de memoria RAM

Convertidor A/D:

o 14 canales

o resolución de 10 bits

3 temporizadores/contadores independientes

Temporizador perro guardián

Módulo comparador analógico con

o Dos comparadores analógicos

o Referencia de voltaje fija (0.6V)

o Referencia de voltaje programable en el chip

Page 119: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 119

Módulo PWM incorporado

Módulo USART mejorado

o Soporta las comunicaciones seriales RS-485, RS-232 y LIN2.0

o Auto detección de baudios

Puerto Serie Síncrono Maestro (MSSP)

o Soporta los modos SPI e I2C

Page 120: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 120

DESCRIPCIÓN DE PINES

La mayoría de los pines del microcontrolador PIC16F887 son multipropósito

como se muestra en la figura anterior. Por ejemplo, la asignación

RA3/AN3/Vref+/C1IN+ para el quinto pin del microcontrolador indica que

éste dispone de las siguientes funciones:

RA3 Tercera entrada/salida digital del puerto A

AN3 Tercera entrada analógica

Vref+ Referencia positiva de voltaje

C1IN+ Entrada positiva del comparador C1

La funcionalidad de los pines presentados anteriormente es muy útil puesto

que permite un mejor aprovechamiento de los recursos del microcontrolador

sin afectar a su funcionamiento. Estas funciones de los pines no se pueden

utilizar simultáneamente, sin embargo se pueden cambiar en cualquier

instante durante el funcionamiento.

Las siguientes tablas se refieren al microcontrolador DIP de 40 pines.

Page 121: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 121

Page 122: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 122

Page 123: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 123

UNIDAD CENTRAL DE PROCESAMIENTO (CPU)

Con el propósito de explicar en forma clara y concisa, sin describir

profundamente el funcionamiento de la CPU, vamos a hacer constar que la

CPU está fabricada con la tecnología RISC ya que esto es un factor

importante al decidir qué microcontrolador utilizar.

RISC es un acrónimo derivado del inglés Reduced Instruction Set

Computer, lo que proporciona al PIC16F887 dos grandes ventajas:

Page 124: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 124

La CPU cuenta con sólo 35 instrucciones simples. Cabe decir que

para poder programar otros microcontroladores en lenguaje

ensamblador es necesario saber más de 200 instrucciones

El tiempo de ejecución es igual para casi todas las instrucciones y

tarda 4 ciclos de reloj. La frecuencia del oscilador se estabiliza por un

cristal de cuarzo. Las instrucciones de salto y de ramificación tardan

ocho ciclos de reloj en ejecutarse. Esto significa que si la velocidad de

operación del microcontrolador es 20 MHz, el tiempo de ejecución de

cada instrucción será 200nS, o sea, ¡el programa ejecutará 5millones

de instrucciones por segundo!

MEMORIA

El PIC16F887 tiene tres tipos de memoria: ROM, RAM y EEPROM. Como

cada una tiene las funciones, características y organización específicas,

vamos a presentarlas por separado.

Page 125: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 125

MEMORIA ROM

La memoria ROM se utiliza para guardar permanente el programa que se

está ejecutando. Es la razón por la que es frecuentemente llamada

“memoria de programa”. El PIC16F887 tiene 8Kb de memoria ROM (en total

8192 localidades). Como la memoria ROM está fabricada con tecnología

FLASH, su contenido se puede cambiar al proporcionarle un voltaje de

programación especial (13V).

No obstante, no es necesario explicarlo en detalles puesto que se realiza

automáticamente por un programa especial en la PC y un simple dispositivo

electrónico denominado programador.

MEMORIA EEPROM

Similar a la memoria de programa, el contenido de memoria EEPROM está

permanentemente guardado al apagar la fuente de alimentación. Sin

embargo, a diferencia de la ROM, el contenido de la EEPROM se puede

cambiar durante el funcionamiento del microcontrolador. Es la razón por la

que esta memoria (256 localidades) es perfecta para guardar

permanentemente algunos resultados creados y utilizados durante la

ejecución del programa.

MEMORIA RAM

Es la tercera y la más compleja parte de la memoria del microcontrolador.

En este caso consiste en dos partes: en registros de propósito general y en

los registros de funciones especiales (SFR). Todos estos registros se

Page 126: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 126

dividen en cuatro bancos de memoria de los que vamos a hablar más tarde

en este capítulo.

A unque los dos grupos de registros se ponen a cero al apagar la fuente de

alimentación, además están fabricados de la misma forma y se comportan

de la manera similar, sus funciones no tienen muchas cosas en común.

REGISTROS DE PROPÓSITO GENERAL

Los registros de propósito general se utilizan para almacenar los datos

temporales y los resultados creados durante el funcionamiento. Por

ejemplo, si el programa realiza el conteo (de los productos en una cadena

de montaje), es necesario tener un registro que representa lo que en la vida

cotidiana llamamos “suma”. Como el microcontrolador no es nada creativo,

es necesario especificar la dirección de un registro de propósito general y

asignarle esa función. Se debe crear un programa simple para incrementar

Page 127: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 127

el valor de este registro por 1, después de que cada producto haya pasado

por el sensor.

Ahora el microcontrolador puede ejecutar el programa ya que sabe qué es y

dónde está la suma que se va a incrementar. De manera similar, a cada

variable de programa se le debe pre-asignar alguno de los registros de

propósito general.

/* En esta secuencia, la variable en el registro sum se aumenta cada vez

que se

lleve un uno (1) lógico en el pin de entrada RB0. */

...

if (PORTB.0 = 1) // Comprobar si el pin RB0 está a uno

sum++ ; // Si está, el valor de la variable se aumenta por 1

... // Si no está, el programa sale de la sentencia if

...

REGISTROS DE FUNCIONES ESPECIALES (SFR)

Los registros de funciones especiales son también parte de la memoria

RAM. A diferencia de los registros de propósito general, su propósito es

predeterminado durante el proceso de fabricación y no se pueden cambiar.

Como los bits están conectados a los circuitos particulares en el chip

(convertidor A/D, módulo de comunicación serial, etc), cualquier cambio de

su contenido afecta directamente al funcionamiento del microcontrolador o

de alguno de los circuitos.

Por ejemplo, el registro ADCON0 controla el funcionamiento del convertidor

A/D. Al cambiar los bits se determina qué pin del puerto se configurará

como la entrada del convertidor, el momento del inicio de la conversión así

como la velocidad de la conversión.

Otra característica de estas localidades de memoria es que tienen nombres

(tanto los registros como sus bits), lo que simplifica considerablemente el

proceso de escribir un programa. Como el lenguaje de programación de alto

Page 128: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 128

nivel puede utilizar la lista de todos los registros con sus direcciones

exactas, basta con especificar el nombre de registro para leer o cambiar su

contenido.

// En esta secuencia, el contenido de los registros TRISC y PORTC será

modificado

...

TRISC = 0x00 // un cero lógico (0) se escribe en el registro TRISC

(todos

// los pines del puerto PORTC se configuran como salidas)

PORTC = 0b01100011 // cambio de estado lógico de todos los pines del

puerto PORTC

...

BANCOS DE LA MEMORIA RAM

La memoria RAM está dividida en cuatro bancos. Antes de acceder a un

registro al escribir un programa (para leer o cambiar su contenido), es

necesario seleccionar el banco que contiene ese registro. Más tarde vamos

a tratar dos bits del registro STATUS utilizados para selección del banco.

Para simplificar el funcionamiento, los SFR utilizados con más frecuencia

tienen la misma dirección en todos los bancos, lo que permite accederlos

con facilidad.

Page 129: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 129

Trabajar con bancos puede ser difícil sólo si se escribe un programa en

lenguaje ensamblador. Al utilizar el lenguaje de programación de alto nivel

como es C y el compilador como es mikroC PRO for PIC, basta con escribir

el nombre del registro. A partir de esa información, el compilador selecciona

el banco necesario. Las instrucciones apropiadas para la selección del

banco serán incorporadas en el código durante el proceso de la

compilación. Hasta ahora usted ha utilizado sólo el lenguaje ensamblador y

esta es la primera vez que utiliza el compilador C, verdad? Es una noticia

maravillosa, no lo cree?

Page 130: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 130

Page 131: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 131

Page 132: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 132

PILA

Una parte de la RAM utilizada como pila consiste de ocho registros de 13

bits. Antes de que el microcontrolador se ponga a ejecutar una subrutina

(instrucción CALL) o al ocurrir una interrupción, la dirección de la primera

siguiente instrucción en ser ejecutada se coloca en la pila (se apila), o sea,

en uno de los registros. Gracias a eso, después de ejecutarse una subrutina

o una interrupción, el microcontrolador “sabe” dónde continuar con la

ejecución de programa. Esta dirección se borra (se desapila) después de

volver al programa, ya que no es necesario guardarla, disponiendo

automáticamente esas localidades de la pila para un uso futuro.

Page 133: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 133

Cabe tener en mente que el dato se apila circularmente. Esto significa que

después de que se apile ocho veces, la novena vez se sobrescribe el valor

que se almacenó al apilar el dato por primera vez. La décima vez que se

apile, se sobrescribe el valor que se almacenó al apilar el dato por segunda

vez etc. Datos sobrescritos de esta manera no se pueden recuperar.

Además, el programador no puede acceder a estos registros para hacer

escritura/lectura. No hay ningún bit de estado para indicar el estado de

desbordamiento o subdesbordamiento de pila. Por esta razón hay que tener

un especial cuidado al escribir un programa.

Vamos a hacerlo en mikroC...

/* Al entrar o al salir de la instrucción en ensamblador del programa, el

compilador

no va a guardar los datos en el banco de la RAM actualmente activo. Esto

significa

que en esta sección de programa la selección de banco depende de los

registros SFR

utilizados. Al volver a la sección de programa escrito en C, los bits de

control

RP0 y RP1 deben devolver el estado que tenían antes de la ejecución del

código en

lenguaje ensamblador. En este ejemplo, el problema se soluciona al

utilizar la

variable auxiliar saveBank que guarda el estado de estos dos bits*/

saveBank = STATUS & 0b01100000; // Guardar el estado de los bits RP0

y RP1

// (bits 5 y 6 del registro STATUS)

asm { // Inicio de la secuencia en ensamblador

...

... // Código ensamblador

Page 134: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 134

...

} // Final de la secuencia en ensamblador

STATUS &= 0b10011111; // Bits RP0 y RP1 devuelven su estado original

STATUS |= saveBank;

...

...

SISTEMA DE INTERRUPCIONES

Al aparecer una petición de interrupción lo primero que hace el

microcontrolador es ejecutar la instrucción actual después de que se

detiene el proceso de ejecución de programa. Como resultado, la dirección

de memoria de programa actual se apila automáticamente y la dirección por

defecto (predefinida por el fabricante) se escribe en el contador de

programa. La localidad en la que el programa continúa con la ejecución se

le denomina vector de interrupción. En el caso del microcontrolador

PIC16F887 esta dirección es 0x0004h. Como se muestra en la siguiente

figura la localidad que contiene el vector de interrupción se omite durante la

ejecución de programa regular.

Una parte de programa que se ejecutará al hacer una petición de

interrupción se le denomina rutina de interrupción. Su primera instrucción se

encuentra en el vector de interrupción. Cuánto tiempo tardará en ejecutar

esta subrutina y cómo será depende de la destreza del programador así

como de la fuente de interrupción. Algunos microcontroladores tienen más

de un vector de interrupción (cada petición de interrupción tiene su vector),

pero en este caso sólo hay uno. En consecuencia, la primera parte da la

rutina de interrupción consiste en detectar la fuente de interrupción.

Por fin, al reconocer la fuente de interrupción y al terminar de ejecutar la

rutina de interrupción el microcontrolador alcanza la instrucciónRETFIE,

toma la dirección de la pila y continúa con la ejecución de programa desde

donde se interrumpió.

Page 135: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 135

mikroC reconoce una rutina de interrupción que se ejecutará como la

función void interrupt(). El cuerpo de la función, o sea, rutina de

interrupción, debe ser escrito por el usuario.

void interrupt() { // Interrupt routine

cnt++ ; // Interrupt causes variable cnt to be incremented by 1

}

Cómo utilizar los registros SFR

Supongamos que usted ha comprado ya un microcontrolador y que tiene

una buena idea de cómo utilizarlo... La lista de los registros SFR así como

de sus bits es muy larga. Cada uno controla algún proceso. En general,

parece como una gran tabla de control con un gran número de instrumentos

e interruptores. ¿Ahora está preocupado de cómo conseguir aprender

acerca de todos ellos? Es poco probable, pero no se preocupe, ¡Usted no

tiene que hacerlo! Los microcontroladores son tan potentes que se parecen

a los supermercados: ofrecen tantas cosas a bajos precios y a usted solo le

toca elegir las que necesita. Por eso, seleccione el campo en que está

interesado y examine sólo lo que necesita. Cuando entienda completamente

el funcionamiento de hardware, examine los registros SFR encargados de

controlarlo (normalmente son unos pocos).

Como todos los dispositivos tienen un tipo de sistema de control el

microcontrolador tiene sus "palancas" con las que usted debe estar

familiarizado para ser capaz de utilizarlos correctamente. Por supuesto,

Page 136: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 136

estamos hablando de los registros SFR desde los que el proceso de

programación se inicia y en los que el mismo termina.

3.2 PRINCIPALES REGISTROS SFR

El siguiente texto describe los principales registros SFR del

microcontrolador PIC16F887. Los bits de cada registro controlan los

circuitos diferentes dentro del chip, así que no es posible clasificarlos en

grupos especiales. Por esta razón, se describen junto con los procesos que

controlan.

Registro STATUS

El registro STATUS contiene: el estado aritmético de datos en el registro W,

el estado RESET, los bits para seleccionar el banco para los datos de la

memoria.

IRP - Registro de selección de Banco (usado para direccionamiento

indirecto)

o 1 - Bancos 0 y 1 son activos (localidades de memoria 00h-FFh)

o 0 - Bancos 2 y 3 son activos (localidades de memoria 100h-

1FFh)

RP1,RP0 - Registro de selección de banco (usado para

direccionamiento directo).

Page 137: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 137

R P 1 R P 0 B A N C O A C T I V O

0 0 Banco 0

0 1 Banco 1

1 0 Banco 2

1 1 Banco 3

TO - Time-out bit (bit de salida del temporizador perro guardián)

o 1 - Después de encender el microcontrolador, después de

ejecutarse la instrucción CLRWDT que reinicia al WDT

(temporizador perro guardián) o después de ejecutarse la

instrucción SLEEP que pone al microcontrolador en el modo de bajo

consumo.

o 0 - Después de acabarse el tiempo del WDT.

PD - Power-down bit (bit de apagado)

o 1 - Después de encender el microcontrolador, después de

ejecutar la instrucción CLRWDT que reinicia al WDT.

o 0 - Después de ejecutarse la instrucción SLEEP que pone al

microcontrolador en el modo de bajo consumo.

Z - Zero bit (bit cero)

o 1 - El resultado de una operación lógica o aritmética es 0.

o 0 - El resultado de una operación lógica o aritmética es distinto

de 0.

DC - Digit carry/borrow bit (bit de acarreo/préstamo de dígito)

cambia al sumar o al restar si ocurre un "desbordamiento" o un

"préstamo" en el resultado.

o 1 - Hubo acarreo del cuarto bit de orden bajo (nibble bajo) en el

resultado.

Page 138: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 138

o 0 - No hubo acarreo del cuarto bit de orden bajo (nibble bajo) en

el resultado.

C - Carry/Borrow bit (bit de acarreo/préstamo) cambia al sumar o al

restar si ocurre un "desbordamiento" o un "préstamo" en el resultado,

o sea si el resultado es mayor de 255 o menor de 0.

o 1 - Ocurrió acarreo en el bit más significativo (MSB) del

resultado.

o 0 - No ocurrió acarreo en el bit más significativo (MSB) del

resultado.

Registro OPTION_REG

El registro OPTION_REG contiene varios bits de control para configurar el

pre - escalador del Temporizador 0/WDT, el temporizador Timer0, la

interrupción externa y las resistencias pull-up en el puerto PORTB.

RBPU - Port B Pull up Enable bit (resistencia Pull Up Puerto B)

o 1 - Desactivadas.

o 0 - Activadas.

Page 139: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 139

INTEDG - Interrupt Edge Select bit (bit selector de flanco activo

de la interrupción externa)

o 1 - Interrupción por flanco ascendente en el RB0/INT.

o 0 - Interrupción por flanco descendente en el RB0/INT.

T0CS - TMR0 Clock Source Select bit (bit selector de tipo de reloj

para el Timer0)

o 1 - Pulsos introducidos a través del TOCKI (contador).

o 0 - Pulsos de reloj internos Fosc/4 (temporizador).

T0SE - TMR0 Source Edge Select bit (bit selector de tipo de flanco

en TOCKI) selecciona el flanco (ascendente o descendente) contado

por el temporizador Timer0 por el pin RA4/T0CKI.

o 1 - Incrementa en flanco descendente en el pin TOCKI.

Page 140: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 140

o 0 - Incrementa en flanco ascendente en el pinTOCKI.

PSA - Prescaler Assignment bit asigna el pre-escalador (hay sólo

uno) al temporizador o al WDT.

o 1 - Pre - escalador se le asigna al WDT.

o 0 - Pre - escalador se le asigna al temporizador Timer0.

PS2, PS1, PS0 Prescaler Rate Select bits (bit selector del valor del

divisor de frecuencia)

El valor del divisor de frecuencia se selecciona al combinar estos tres bits.

Como se muestra en la siguiente tabla, el valor del divisor de frecuencia se

le asigna al temporizador (Timer0) o al temporizador perro guardián (WDT).

P S 2 P S 1 P S 0 T M R 0 W D T

0 0 0 1:2 1:1

0 0 1 1:4 1:2

0 1 0 1:8 1:4

0 1 1 1:16 1:8

1 0 1 1:64 1:32

1 1 0 1:128 1:64

1 1 1 1:256 1:128

Para conseguir el valor del divisor de frecuencia 1:1 cuando el temporizador

Timer0 cuenta pulsos, el preescalador debe ser asignado al WDT. En

consecuencia, el temporizador Timer0 no utiliza el pre-escalador, sino que

cuenta directamente los pulsos generados por el oscilador, lo que era el

objetivo.

Page 141: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 141

Vamos a hacerlo en mikroC...

/* Si el comando CLRWDT no se ejecuta,

el WDT va a reiniciar al microcontrolador cada 32.768 uS (f=4 MHz) */

void main() {

OPTION_REG = 0b00001111; // Pre-escalador está asignado al WDT

(1:128)

asm CLRWDT; // Comando en ensamblador para reiniciar al WDT

...

...// El tiempo entre estos dos comandos CLRWDT no debe exceder

32.768 microsegundos (128x256)

...

asm CLRWDT; // Comando en ensamblador para reiniciar al WDT

...

...// El tiempo entre estos dos comandos CLRWDT no debe exceder

32.768 microsegundos (128x256)

...

asm CLRWDT; // Comando en ensamblador para reiniciar al WDT

}

REGISTROS DEL SISTEMA DE INTERRUPCIÓN

Al llegar la petición de interrupción, no significa que una interrupción ocurrirá

automáticamente, puesto que debe ser habilitada por el usuario (por el

programa) también. Por esta razón, hay bits especiales utilizados para

habilitar o deshabilitar interrupciones. Es fácil de reconocerlos por las letras

IE contenidas en sus nombres (Interrupt Enable - Interrupción habilitada).

Además, cada interrupción se asocia con otro bit denominado bandera que

indica que una petición de interrupción ha llegado sin verificar si está

habilitada. Asimismo, se reconocen con facilidad por las dos últimas letras

contenidas en sus nombres - IF (Interrupt Flag - Bandera de interrupción).

Page 142: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 142

Como hemos visto, toda la idea es muy simple y eficiente. Al llegar la

petición de interrupción, primero el bit de bandera se pone a uno.

Si el bit IE apropiado está a cero (0), esta condición será ignorada

completamente. De lo contrario, ocurre una interrupción. Si varias fuentes

de interrupción están habilitadas, es necesario detectar la activa antes de

que la rutina de interrupción se ponga a ejecutar. La detección de la fuente

se realiza al comprobar los bits de las banderas.

Cabe destacar que los bits de cada bandera no se ponen a cero

automáticamente, sino por el software, mientras que la ejecución de la

rutina de interrupción continúa ejecutándose. Si no hacemos caso a este

detalle, ocurrirá otra interrupción inmediatamente después de volver al

programa principal, aunque no hay más peticiones de ejecución.

Simplemente, la bandera, así como el bit IE, se quedan en uno.

Todas las fuentes de interrupción típicas para el microcontrolador

PIC16F887 se muestran en la siguiente página. Fíjese en lo siguiente:

El bit GIE habilita/deshabilita simultáneamente las interrupciones no

enmascaradas.

El PEIE bit habilita/deshabilita las interrupciones no enmascaradas de

periféricos. Esto no se refiere al temporizador Timer0 y a las fuentes de

interrupción del puerto PORTB.

Para habilitar una interrupción causada por el cambio del estado lógico en el

puerto PORTB, es necesario habilitarla para cada bit por separado. En este

caso, los bits del registro IOCB se comportan como los bits IE de control.

Page 143: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 143

Registro INTCON

El registro INTCON contiene varios bits de habilitación y de bandera para el

desbordamiento en el registro TMR0, e interrupciones por el cambio del

estado en el puerto PORTB y las interrupciones externas en el pin INT.

GIE - Global Interrupt Enable bit - (bit de habilitación de

interrupciones globales) controla simultáneamente todas las fuentes

de interrupciones posibles.

Page 144: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 144

o 1 - Habilita las interrupciones no enmascaradas.

o 0 - Deshabilita las interrupciones no enmascaradas.

PEIE - Peripheral Interrupt Enable bit (bit de habilitación de

interrupciones periféricas) es similar al bit GIE, sin embargo controla

interrupciones habilitadas por los periféricos. Eso significa que no

influye en interrupciones causadas por el temporizador Timer0 o por el

cambio del estado en el puerto PORTB o por el cambio en el pin

RB0/INT.

o 1 - Habilita las interrupciones periféricas no enmascaradas.

o 0 - Deshabilita las interrupciones periféricas no enmascaradas.

T0IE - TMR0 Overflow Interrupt Enable bit (bit de habilitación de

interrupciones por el desbordamiento del temporizador Timer0)

controla interrupciones causadas por el desbordamiento del Timer0.

o 1 - Habilita interrupciones por Timer0.

o 0 - Deshabilita interrupciones por Timer0.

INTE - RB0/INT External Interrupt Enable bit (bit de habilitación de

la interrupción externa en RB0) controla interrupciones causadas por

el cambio del estado lógico en el pin de entrada RB0/INT (interrupción

externa).

o 1 - Habilita interrupciones externas INT.

o 0 - Deshabilita interrupciones externas INT.

RBIE - RB Port Change Interrupt Enable bit (bit de habilitación de

interrupciones por cambios en el puerto PORTB). Cuando se

configuran como entradas, los pines en el puerto PORTB pueden

causar una interrupción al cambiar el estado lógico (no importa si se

produce bajada o subida de tensión, lo que importa es que se produce

un cambio). Este bit determina si una interrupción va a ocurrir.

o 1 - Habilita interrupciones por cambio en el puerto PORTB.

Page 145: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 145

o 0 - Deshabilita interrupciones por cambio en el puerto PORTB.

T0IF - TMR0 Overflow Interrupt Flag bit (bit de bandera de

interrupción por el desbor damiento del Timer0) detecta el

desbordamiento en el registro del temporizador Timer0, o sea el

contador se pone a cero.

o 1 - En el registro del Timer0 ha ocurrido desbordamiento (esta

bandera debe volverse a 0 por software).

o 0 - En el registro del Timer0 no ha ocurrido desbordamiento.

INTF - RB0/INT External Interrupt Flag bit (bit de bandera de

interrupción externa en INT) detecta el cambio en el estado lógico en

el pin INT.

o 1 - Ha ocurrido una interrupción externa por INT (esta bandera

debe volverse a 0 por software)

o 0 - No ha ocurrido una interrupción externa por INT.

RBIF - RB Port Change Interrupt Flag bit (bit de bandera de

interrupción por cambio en el puerto RB) detecta cualquier cambio del

estado lógico de alguno de los pines de entrada en el puerto PORTB.

o 1 - Al menos uno de los pines de E/S de propósito general en el

puerto PORTB ha cambido de valor. Después de leer el puerto

PORTB, el bit RBIF debe volverse a 0 por software).

o 0 - Ninguno de los pines de E/S de propósito general en el

puerto PORTB ha cambiado de valor.

Vamos a hacerlo en mikroC...

// El pin PORTB.4 se configura como una entrada sensible al cambio del

estado lógico.

void initMain() {

Page 146: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 146

ANSEL = ANSELH = 0; // Todos los pines de E/S se configuran como

digitales

PORTB = 0; // Todos los pines del puerto PORTB se ponen a cero

TRISB = 0b00010000; // Todos los pines del puerto PORTB menos

PORTB.4 se

// configuran como salidas

RBIE = 1; // Se habilitan las interrupciones por el cambio en el

puerto PORTB

IOCB4 = 1; // Se habilita la interrupción por el cambio en el pin 4 en

el

// puerto PORTB

GIE = 1; // Se habilita la interrupción global

... // Desde este punto, se produce una interrupción con

cualquier cambio

... // del estado lógico en el pin PORTB.4

...

Registro PIE1

El registro PIE1 contiene los bits de habilitación de interrupciones

periféricas.

ADIE - A/D Converter Interrupt Enable bit (bit de habilitación de

interrupciones del convertidor A/D).

Page 147: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 147

o 1 - Habilita la interrupción ADC.

o 0 - Deshabilita la interrupción ADC.

RCIE - EUSART Receive Interrupt Enable bit (bit de habilitación

de interrupciones de recepción del EUSART).

o 1 - Habilita la interrupción de recepción del EUSART.

o 0 - Deshabilita la interrupción de recepción del EUSART.

TXIE - EUSART Transmit Interrupt Enable bit (bit de habilitación

de interrupciones de transmisión del EUSART).

o 1 - Habilita la interrupción de transmisión del EUSART.

o 0 - Deshabilita la interrupción de transmisión del EUSART.

SSPIE - Master Synchronous Serial Port (MSSP) Interrupt Enable

bit - (bit de habilitación de la interrupción del puerto serie síncrono

maestro (MSSP) habilita generar una petición de interrupción después

de cada transmisión de datos por el módulo de comunicación serie

síncrona (modo SPI o I2C).

o 1 - Habilita la interrupción del MSSP.

o 0 - Deshabilita la interrupción del MSSP.

CCP1IE - CCP1 Interrupt Enable bit (bit de habilitación de la

interrupción del módulo 1 de Comparación/Captura/PWM - CCP1)

permite generar una petición de interrupción en el módulo CCP1

utilizado para procesamiento de la señal PWM.

o 1 - Habilita la interrupción CCP1.

o 0 - Deshabilita la interrupción CCP1.

TMR2IE - TMR2 to PR2 Match Interrupt Enable bit (bit de

habilitación de la interrupción de igualdad entre TMR2 y PR2)

o 1 - Habilita la interrupción de igualdad entre TMR2 y PR2.

o 0 - Deshabilita la interrupción de igualdad entre TMR2 y PR2.

Page 148: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 148

TMR1IE - TMR1 Overflow Interrupt Enable bit (bit de habilitación de

la interrupción de desbordamiento del temporizador Timer1) habilita

generar una petición de interrupción después de cada

desbordamiento en el registro del temporizador Timer1, o sea el

contador se pone a cero.

o 1 - Habilita la interrupción de desbordamiento del temporizador

Timer1.

o 0 - Deshabilita la interrupción de desbordamiento del

temporizador Timer1.

Vamos a hecerlo en mikroC...

/* Se produce una interrupción con cada desbordamiento en el registro del

temporizador1

que consiste en TMR1H y TMR1L. En cada rutina de interrucpiones, la

variable

cnt será incrementada por 1 */

unsigned short cnt; // Definir la variable cnt

void interrupt() // Inicio de la rutina de interrupción

cnt++ ; // Al producirse una interrupción, la cnt se

// incrementa por 1

PIR1.TMR1IF = 0; // El bit TMR1IF se reinicia

TMR1H = 0x80; // A los registros del temporizador TMR1H y

TMR1L se les

TMR1L = 0x00; // devuelven sus valores iniciales

} // Final de la rutina de interrupción

void main() {

Page 149: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 149

ANSEL = ANSELH = 0; // Todos los pines de E/S se configuran como

digitales

T1CON = 1; // Encender el temporizador Timer

PIR1.TMR1IF = 0; // El bit TMR1IF se pone a cero

TMR1H = 0x80; // Establecer los valores iniciales para el

temporizador Timer1

TMR1L = 0x00;

PIE1.TMR1IE = 1; // Habilitar la interrupción al producirse un

// desbordamiento en el Timer1

cnt = 0; // Reiniciar la variable cnt

INTCON = 0xC0; // Habilitar la interrupción (los bits GIE y PEIE)

...

Registro PIE2

El registro PIE2 también contiene varios bits de habilitación de

interrupciones.

OSFIE - Oscillator Fail Interrupt Enable bit (bit de habilitación de

la interrupción de fallo en el oscilador)

o 1 - Habilita la interrupción de fallo en el oscilador.

o 0 - Deshabilita la interrupción de fallo en el oscilador.

C2IE - Comparator C2 Interrupt Enable bit (bit de habilitación de

la interrupción del comparador C2)

o 1 - Habilita la interrupción del comparador C2.

Page 150: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 150

o 0 - Deshabilita la interrupción del comparador C2.

C1IE - Comparator C1 Interrupt Enable bit (bit de habilitación de

la interupción del comparador C1)

o 1 - Habilita la interrupción del comparador C1

o 0 - Deshabilita la interrupción del comparador C1.

EEIE - EEPROM Write Operation Interrupt Enable bit (bit de

habilitación de la interrupción de escritura en la memoria

EEPROM)

o 1 - Habilita la interrupción de escritura en la memoria EEPROM.

o 0 - Deshabilita la interrupción de escritura en la memoria

EEPROM.

BCLIE - Bus Collision Interrupt Enable bit (bit de habilitación de

la interrupción de colisión de bus)

o 1 - Habilita la interrupción de colisión de bus.

o 0 - Deshabilita la interrupción de colisión de bus.

ULPWUIE - Ultra Low-Power Wake-up Interrupt Enable bit (bit de

habilitación de la interrupción para salir del modo de ultra bajo

consumo - la reactivación)

o 1 - Habilita la interrupción para salir del modo de ultra bajo

consumo.

o 0 - Deshabilita la interrupción para salir del modo de ultra bajo

consumo.

CCP2IE - CCP2 Interrupt Enable bit (bit de habilitación de la

interrupción del módulo 2 de Comparación/Captura/PWM (CCP2)

o 1 - Habilita la interrupción del CCP2.

o 0 - Deshabilita la interrupción del CCP2.

Vamos a hacerlo en mikroC...

Page 151: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 151

/* El comparador C2 se configura para utilizar los pines RA0 y RA2 como

entradas. Al producirse

un cambio en la salida del comparador, el pin de salida PORTB.1 cambia

el estado lógico en la

rutina de interrupción.*/

void interrupt() { // Inicio de la rutina de interrupción

PORTB.F1 = ~PORTB.F1 ; // La interrupción invertirá el estado lógico

del

// pin PORTB.1

PIR2.C2IF = 0; // Bit de bandera de interrupción C2IF se pone a

cero

} // Final de la rutina de interrupción

void main() {

TRISB = 0; // Todos los pines del puerto PORTB se

configuran

// como salidas

PORTB.F1 = 1; // El pin PORTB.1 se pone a uno

ANSEL = 0b00000101;; // Los pines RA0/C12IN0- y RA2/C2IN+

son las

// entradas analógicas

ANSELH = 0; // Todos los pines de E/S se configuran

como digitales

CM2CON0.C2CH0 = CM2CON0.C2CH1 = 0; // El pin RA0 se selecciona

para ser una

// entrada invertida del C2

Page 152: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 152

PIE2.C2IE = 1; // Habilita la interrupción del comparador

C2INT

CON.GIE = 1; // Interrupción global está habilitada

CM2CON0.C2ON = 1; // Comparador C2 está habilitado

...

...

Registro PIR1

El registro PIR1 contiene los bits de banderas de interrupción.

ADIF - A/D Converter Interrupt Flag bit (bit de bandera de la

interrupción del convertidor A/D)

o 1 - Se ha completado una conversión A/D (el bit debe volverse a

0 por software)

o 0 - No se ha completado una conversión A/D o no ha empezado

RCIF - EUSART Receive Interrupt Flag bit (bit de bandera de la

interrupción de recepción del EUSART)

o 1 - El búfer de recepción del EUSART está lleno. El bit se pone

a cero al leer el registro RCREG.

o 0 - El búfer de recepción del EUSART no está lleno.

TXIF - EUSART Transmit Interrupt Flag bit (bit de la interrupción

de transmisión del EUSART)

Page 153: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 153

o 1 - El búfer de transmisión del EUSART está vacío. El bit se

pone a cero al esribir un dato en el registro TXREG.

o 0 - El búfer de transmisión del EUSART está lleno.

SSPIF - Master Synchronous Serial Port (MSSP) Interrupt Flag bit

(bit de bandera de la interrupción de puerto serie síncrono

maestro)

o 1 - Se ha cumplido la condición de ocurrir una interrupción del

MSSP al transmitir/ recibir los datos. Difieren dependiendo del modo

de operación del MSSP (SPI o I2C). El bit debe ponerse a cero por

software antes de volver de la rutina de servicio de interrupciones)

o 0 - No se ha cumplido ninguna condición de ocurrir una

interrupción del MSSP.

CCP1IF - CCP1 Interrupt Flag bit (bit de bandera de la

interrupción del módulo 1 de Comparación/Captura/PWM (CCP1).

o 1 - Se ha cumplido la condición de la interrupción del CCP1

(CCP1 es una unidad para captar, comparar y generar una señal

PWM). Dependiendo del modo de operación (modo captura o modo

comparación), se produce una captura o la igualdad en la

comparación. En ambos casos, el bit debe volverse a cero por

software. El bit no se utiliza en el modo PWM.

o 0 - No se ha cumplido la condición de la interrupción del CCP1.

TMR2IF - Timer2 to PR2 Interrupt Flag bit (bit de bandera de la

interrupción de igual dad entre el temporizador Timer2 y el

registro PR2)

o 1 - Se ha producido igualdad con el valor del TMR2 (registro de

8 bits del temporizador) y el valor del PR2. El bit debe ponerse a

cero por software antes de volver de la rutina de servicio de

interrupciones).

Page 154: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 154

o 0 - No se ha producido igualdad con el valor del TMR2 y el valor

del PR2.

TMR1IF - Timer1 Overflow Interrupt Flag bit (bit de bandera de la

interrupción de desbordamiento del temporizador Timer1)

o 1 - Se ha producido desbordamiento del Timer1. El bit debe

ponerse a cero por software.

o 0 - No se ha producido desbordamiento del Timer1.

Registro PIR2

El registro PIR2 contiene los bits de banderas da la interrupción.

OSFIF - Oscillator Fail Interrupt Flag bit (bit de bandera de la

interrupción de fallo en el oscilador)

o 1 - Se ha producido un fallo en el oscilador del sistema. La

entrada de reloj ha sido conmutada al oscilador interno INTOSC. El

bit debe ponerse a cero por software.

o 0 - El oscilador del sistema funciona correctamente.

C2IF - Comparator C2 Interrupt Flag bit (bit de bandera de la

interrupción del comparador C2)

o 1 - La salida del comparador analógico C2 ha sido cambiada (el

bit C2OUT). El bit debe ponerse a cero por software.

o 0 - La salida del comparador analógico C2 no ha sido cambiada.

C1IF - Comparator C1 Interrupt Flag bit (bit de bandera de la

interrupción del comparador C1)

Page 155: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 155

o 1 - La salida del comparador analógico C1 ha sido cambiada (el

bit C1OUT). El bit debe ponerse a cero por software.

o 0 - La salida del comparador analógico C1 no ha sido cambiada.

EEIF - EE Write Operation Interrupt Flag bit (bit de bandera de la

interrupción de la operación de escritura en la memoria EEPROM)

o 1 - La operación de escritura en la memoria EEPROM se ha

completado. El bit debe ponerse a cero por software.

o 0 - La operación de escritura en la memoria EEPROM no se ha

completado o todavía no se ha iniciado.

BCLIF - Bus Collision Interrupt Flag bit (bit de bandera de la

interrupción de colisión de bus en el MSSP)

o 1 - Se ha producido una colisión de bus en el MSSP al ser

configurado para el modo maestro I2C. El bit debe ponerse a cero

por software.

o 0 - No se ha producido colisión de bus en el MSSP.

ULPWUIF - Ultra Low-power Wake-up Interrupt Flag bit (bit de

bandera de la interrupción para salir del modo de ultra bajo

consumo - la reactivación)

o 1 - Se ha cumplido la condición de salir del modo de ultra bajo

consumo. El bit debe ponerse a cero por software.

o 0 - No se ha cumplido la condición de salir del modo de ultra

bajo consumo.

CCP2IF - CCP2 Interrupt Flag bit (bit de la interrupción del

módulo 2 de Comparación/Captura/PWM - CCP2)

o 1 - Se ha cumplido la condición de la interrupción del CCP2

(CCP2 es una unidad para captar, comparar y generar una señal

PWM). Dependiendo del modo de operación (modo captura o modo

comparación), se produce una captura o la igualdad en la

Page 156: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 156

comparación. En ambos casos, el bit debe volverse a cero por

software. El bit no se utiliza en el modo PWM.

o 0 - No se ha cumplido la condición de la interrupción del CCP2.

Vamos a hacerlo en mikroC...

// Secuencia de activación del módulo ULPWU

void main() {

PORTA.F0 = 1; // Pin PORTA.0 se pone a uno

ANSEL = ANSELH = 0; // Todos los pines de E/S se configuran

como digitales

TRISA = 0; // Los pines del puerto PORTA se configuran

como salidas

Delay_ms(1); // Cargar el capacitor

PIR2.ULPWUIF = 0; // Bandera ULPWUIF se pone a cero

PCON.ULPWUE = 1; // Habilitar el funcionamiento del módulo

ULPWU

TRISA.F0 = 1; // PORTA.0 se configura como entrada

PIE2.ULPWUIE = 1; // Habilitar la interrupción por el módulo

ULPWU

INTCON.GIE = INTCON.PEIE = 1; // Habilitar todas las interrupciones

asm SLEEP; // Pasar al modo de bajo consumo

...

...

Page 157: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 157

Registro PCON

El registro PCON contiene solamente dos bits de banderas utilizados para

diferenciar entre un Power-on reset (POR), un Brown-out reset (BOR), un

reinicio por el temporizador perro guardián (WDT) y un reinicio externo por

el pin MCLR.

ULPWUE - Ultra Low-Power Wake-up Enable bit (bit de

habilitación para salir del modo de ultra bajo consumo - la

reactivación)

o 1 - Se habilita salir del modo de ultra bajo consumo.

o 0 - No se habilita salir del modo de ultra bajo consumo.

SBOREN - Software BOR Enable bit (bit de habilitación del BOR

por software)

o 1 - Se habilita Brown-out reset.

o 0 - Se deshabilita Brown-out reset.

POR - Power-on Reset Status bit (bit de estado Power - on reset)

o 1 - No se ha producido Power - on reset.

o 0 - Se ha producido Power - on reset. El bit debe ponerse a uno

por software después de que se haya producido un Power - on

reset.

BOR - Brown-out Reset Status bit (bit de estado Brown - out

reset)

o 1 - No se ha producido Brown - out reset.

Page 158: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 158

o 0 - Se ha producido Brown - out reset. El bit debe ponerse a uno

por software después de que se haya producido Brown - out reset.

REGISTROS PCL Y PCLATH

La memoria de programa del PIC16F887 es de 8K y tiene 8192 localidades

para el almacenamiento de programa. Por esta razón, el contador de

programa debe de ser de 13 bits de anchura (213 = 8192). Para habilitar el

acceso a una localidad de memoria de programa durante el funcionamiento

del microcontrolador , es necesario acceder a su dirección por medio de los

registros SFR. Como todos los registros SFR son de 8 bits de anchura, este

registro de direccionamiento es creado “artificialmente” al dividir los 13 bits

en dos registros independientes, PCLATH y PCL. Si la ejecución de

programa no afecta al contador de programa, el valor de este registro va

incrementándose automática y constantemente: +1, +1, +1, +1... De esta

manera, el programa se ejecuta como está escrito - instrucción a

instrucción, seguido por un incremento de dirección constante.

Si el contador de programa ha sido cambiado por software, debe tomar en

cuenta lo siguiente para evitar problemas:

Los ocho bits inferiores (el byte inferior) del registro PCL son de

lectura/escritura, mientras que los cinco bits superiores del registro

PCLATH son de sólo escritura.

El registro PCLATH se borra con cada reinicio.

En el lenguaje ensamblador, el valor del contador de programa está

marcado con PCL y se refiere sólo a los ocho bits. Usted debe tener

cuidado al utilizar la instrucción "ADDWF PCL". Esto es una

instrucción de salto que especifica la localidad destino al añadir un

número a la dirección actual. Se utiliza con frecuencia para saltar a la

tabla de búsqueda o a la tabla de ramificación de programa y leerlas.

Un problema surge si la dirección actual es de tal tamaño que al

Page 159: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 159

sumar se produce un cambio en un bit que pertenece al byte superior

del registro PCLATH.

La ejecución de una instrucción sobre el registro PCL causa

simultáneamente la sustitución de los bits del contador de programa

por los contenidos en el registro PCLATH. De todos modos, el registro

PCL puede acceder sólo a 8 bits inferiores del resultado de la

instrucción, pues el siguiente salto será completamente incorrecto. La

solución a este problema es poner estas instrucciones en las

direcciones que terminan en xx00h. De esta manera se habilitan los

saltos de programa hasta 255 localidades. Si se ejecutan los saltos

más largos por medio de esta instrucción, el registro PCLATH debe

ser incrementado por 1 cada vez que se produce desbordamiento en

el registro PCL.

Al llamar una subrutina o al ejecutarse un salto

(instrucciones CALL y GOTO), el microcontrolador es capaz de

proporcionar solamente direccionamiento de 11 bits. Similar a la RAM

que está dividida en “bancos”, la ROM está dividida en las cuatro

“páginas” de 2K cada una. Las instrucciones dentro de estas páginas

se ejecutan regularmente. Dicho de manera sencilla, como el

procesador está proporcionado con una dirección de 11 bits del

programa, es capaz de direccionar cualquier localidad dentro de 2KB.

La siguiente figura muestra el salto a la dirección del subprograma

PP1.

Page 160: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 160

Sin embargo, si una subrutina o una dirección de salto no está en la misma

página que la localidad de salto, se deben proporcionar dos bits superiores

que faltan al escribir en el registro PCLATH. La siguiente figura muestra el

salto a la dirección de la subrutina PP2.

En ambos casos, cuando la subrutina llega a las

instrucciones RETURN, RETLW o RETFIE (vuelta al programa principal), el

microcontrolador continuará con la ejecución de programa desde donde se

interrumpió, ya que la dirección de retorno se empuja y se guarda en la pila

que consiste en registros de 13 bits, como hemos mencionado.

REGISTROS DE DIRECCIONAMIENTO INDIRECTO

Además del direccionamiento directo, que es lógico y claro (basta con

especificar la dirección de un registro para leer su contenido), este

microcontrolador es capaz de realizar el direccionamiento indirecto por los

registros INDF y FSR. A veces esto facilita el proceso de escribir un

programa. El procedimiento entero está habilitado ya que el registro INDF

no es real (no existe físicamente), sino que solamente especifica el registro

cuya dirección está situada en el registro FSR. Por esta razón, escribir o

Page 161: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 161

leer los datos del registro INDF realmente significa escribir o leer del registro

cuya dirección está situada en el registro FSR. En otras palabras,

direcciones de registros se especifican en el registro FSR, y su contenido se

almacena en el registro INDF. La diferencia entre el direccionamiento

directo e indirecto se muestra en la siguiente figura:

Como hemos visto, el problema con "los bits de direccionamiento que

faltan" se soluciona con un "préstamo" del otro registro. Esta vez, es el

séptimo bit, denominado bit IRP del registro STATUS.

Una de las características más importantes del microcontrolador es el

número de los pines de entrada/ salida, que permite conectarlo con los

periféricos. El PIC16F887 tiene en total 35 pines de E/S de propósito

general, lo que es suficiente para la mayoría de las aplicaciones.

3.3 PUERTOS DE ENTRADA/SALIDA

Con el propósito de sincronizar el funcionamiento de los puertos de E/S con

la organización interna del microcontrolador de 8 bits, ellos se agrupan, de

manera similar a los registros, en cinco puertos denotados con A, B, C, D y

E. Todos ellos tienen las siguientes características en común:

Page 162: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 162

Por las razones prácticas, muchos pines de E/S son multifuncionales.

Si un pin re aliza una de estas funciones, puede ser utilizado como pin

de E/S de propósito general.

Cada puerto tiene su propio registro de control de flujo, o sea el

registro TRIS correspondiente: TRISA, TRISB, TRISC etc. lo que

determina el comportamiento de bits del puerto, pero no determina su

contenido.

Al poner a cero un bit del registro TRIS (pin=0), el pin correspondiente del

puerto se configurará como una salida. De manera similar, al poner a uno

un bit del registro TRIS (bit=1), el pin correspondiente del puerto se

configurará como una entrada. Esta regla es fácil de recordar: 0 = Entrada 1

= Salida.

Puerto PORTA y registro TRISA

El puerto PORTA es un puerto bidireccional, de 8 bits de anchura. Los bits

de los registros TRISA y ANSEL controlan los pines del PORTA. Todos los

pines del PORTA se comportan como entradas/salidas digitales. Cinco de

ellos pueden ser entradas analógicas (denotadas por AN):

Page 163: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 163

RA0 = AN0 (determinado por el bit ANS0 del registro ANSEL)

RA1 = AN1 (determinado por el bit ANS1 del registro ANSEL)

RA2 = AN2 (determinado por el bit ANS2 del registro ANSEL)

RA3 = AN3 (determinado por el bit ANS3 del registro ANSEL)

RA5 = AN4 (determinado por el bit ANS4 del registro ANSEL)

Similar a que los bits del registro TRISA determinan cuáles pines serán

configurados como entradas y cuáles serán configurados como salidas, los

bits apropiados del registro ANSEL determinan si los pines serán

configurados como entradas analógicas o entradas/salidas digitales.

Cada bit de este puerto tiene una función adicional relacionada a algunas

unidades periféricas integradas, que vamos a describir en los siguientes

capítulos. Este capítulo cubre sólo la función adicional del pin RA0, puesto

que está relacionado al puerto PORTA y a la unidad ULPWU.

Vamos a hacerlo en mikroC...

// El pin PORTA.2 se configura como una entrada digital. Todos los

demás pines del puerto

// PORTA son salidas digitales

...

Page 164: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 164

ANSEL = ANSELH = 0; // Todos los pines de E/S se configuran como

digitales

PORTA = 0; // Todos los pines del puerto PORTA se ponen a cero

TRISA = 0b00000100; // Todos los pines del puerto PORTA excepto el

// PORTA.2 se configuran como salidas

...

UNIDAD ULPWU

El microcontrolador se utiliza generalmente en los dispositivos que

funcionan periódicamente y completamente independiente utilizando una

fuente de alimentación de batería. En tal caso, el consumo de corriente

mínimo es una de las prioridades. Los ejemplos típicos de tales aplicaciones

son: termómetros, sensores de detección del fuego y similar. Es conocido

que al reducir frecuencia de reloj se reduce el consumo de corriente, pues

una de las soluciones más convenientes a este problema es bajar la

frecuencia de reloj, o sea utilizar el cristal de cuarzo de 32KHz en vez de el

de 20MHz.

Al poner el microcontrolador en el modo de reposo es otro paso en la misma

dirección. Aún ha quedado el problema de salir de este modo y poner el

microcontrolador en modo normal de funcionamiento. Es obviamente

necesario tener una señal externa en alguno de los pines. Esta señal debe

ser generada por componentes electrónicos adicionales, lo que resulta en

un consumo de energía más alto del dispositivo completo...

La solución perfecta sería que el microcontrolador saliera del modo de

reposo periódicamente por si mismo, lo que no es imposible. El circuito que

lo habilita se muestra en la figura a la izquierda.

Page 165: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 165

El principio de funcionamiento es simple:

Un pin se configura como salida y se le lleva un uno lógico (1). Esto causa

una carga del capacitor. Inmediatamente después, el mismo pin se

configura como entrada. El cambio de estado lógico habilita una interrupción

y el microcontrolador entra en modo de reposo. Sólo ha quedado esperar

que se descargue el capacitor por la corriente de fuga fluyendo por el pin de

entrada. Después de la descarga, se produce una interrupción y el

microcontrolador continúa con la ejecución de programa en modo normal.

Todo el procedimiento se repite.

En teoría, esto es una solución perfecta. El problema es que todos los pines

capaces de causar una interrupción son digitales y tienen una corriente de

fuga relativamente alta cuando el voltaje sobre ellos no está cerca de los

valores límites de Vdd (1) o VSS (0). En este caso, el condensador se

descarga en poco tiempo ya que la corriente es de varias centenas de

microamperios. Por esta razón se diseñó el circuito ULPWU, capaz de

indicar una lenta caída de voltaje con un consumo de corriente mínimo.

La salida genera una interrupción, mientras que la entrada está conectada a

uno de los pines del microcontrolador. Es el pin RA0. Refiriéndose a la

Figura (R=200 ohms, C=1nF), el tiempo de descarga es aproximadamente

30mS, mientras que un consumo total de corriente del microcontrolador es

1000 veces más bajo (de varias centenas de nanoamperios).

Puerto PORTB y registro TRISB

El puerto PORTB es un puerto bidireccional, de 8 bits de anchura. Los bits

del registro TRISB determinan la función de sus pines.

Page 166: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 166

Similar al puerto PORTA, un uno lógico (1) en el registro TRISB configura el

pin apropiado en el puerto PORTB y al revés. Los seis pines de este puerto

se pueden comportar como las entradas analógicas (AN). Los bits del

registro ANSELH determinan si estos pines serán configurados como

entradas analógicas o entradas/salidas digitales:

RB0 = AN12 (determinado por el bit ANS12 del registro ANSELH)

RB1 = AN10 (determinado por el bit ANS10 del registro ANSELH)

RB2 = AN8 (determinado por el bit ANS8 del registro ANSELH)

RB3 = AN9 (determinado por el bit ANS9 del registro ANSELH)

RB4 = AN11 (determinado por el bit ANS11del registro ANSELH)

RB4 = AN11 (determinado por el bit ANS11del registro ANSELH)

Cada bit de este puerto tiene una función adicional relacionada a algunas

unidades periféricas integradas, que vamos a describir en los siguientes

capítulos.

Este puerto dispone de varias características por las que se distingue de

otros puertos y por las que sus pines se utilizan con frecuencia:

Todos los pines del puerto PORTB tienen las resistencias pull-

up integradas, que los hacen perfectos para que se conecten con los

botones de presión (con el teclado), interruptores y optoacopladores.

Con el propósito de conectar las resisitencias a los puertos del

Page 167: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 167

microcontrolador, el bit apropiado del registro WPUB debe estar a

uno.*

Al tener un alto nivel de resistencia (varias decenas de kiloohmios), estas

resistencias "virtuales" no afectan a los pines configurados como salidas,

sino que sirven de un complemento útil a las entradas. Estas resistencias

están conectados a las entradas de los circuitos lógicos CMOS. De lo

contrario, se comportarían como si fueran flotantes gracias a su alta

resistencia de entrada.

Además de los bits del registro WPUB, hay otro bit que afecta a la

instalación de las resistencias pull-up. Es el bit RBPU del registro

OPTION_REG.

Al estar habilitado, cada bit del puerto PORTB configurado como una

entrada puede causar una interrupción al cambiar su estado lógico.

Con el propósito de habilitar que los termi nales causen una

interrupción, el bit apropiado del registro IOCB debe estar a uno.

Page 168: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 168

Gracias a estas características, los pines del puerto PORTB se utilizan con

frecuencia para comprobar los botones de presión en el teclado ya que

detectan cada apretón de botón infaliblemente. Por eso, no es necesario

examinar todas las entradas una y otra vez.

Cuando los pines X,Y y Z se configuran como entradas de puesta a uno (1),

sólo se necesita esperar una petición de interrupción que aparece al apretar

un botón. Más tarde, se comprueba cuál botón fue activado al combinar

ceros y unos en las entradas.

Page 169: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 169

Vamos a hacerlo en mikroC...

/* El pin PORTB.1 se configura como entrada digital. Se produce una

interrupción con cualquier

cambio de su estado lógico. También tiene una resistencia pull-up. Todos

los demás pines del

puerto PORTB son entradas digitales. */

...

ANSEL = ANSELH = 0; // Todos los pines de E/S se configuran como

digitales

PORTB = 0; // Todos los pines del puerto PORTB se ponen a cero

TRISB = 0b00000010; // Todos los pines del puerto PORTB excepto

PORTB.1

// se configuran como salidas

RBPU = 0; // Se habilitan las resistencias pull-up

WPUB1 = 1; // La resistencia pull-up se conecta al pin PORTB.1

IOCB1 = 1; // El pin PORTB.1 puede causar una interrupción por el

// cambio del estado lógico

RBIE = GIE = 1; // Se habilita una interrupción

...

PIN RB0/INT

El pin RB0/INT es la única fuente “verdadera” de la interrupción externa. Se

puede configurar de manera que reaccione al borde ascendente de señal

(transición de cero a uno) o al borde descendente de señal (transición de

uno a cero). El bit INTEDG del registro OPTION_REG selecciona la señal

apropriada.

Page 170: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 170

PINES RB6 Y RB7

El PIC16F887 no dispone de ningún pin especial para la programación (el

proceso de escribir un programa en la ROM). Los pines que generalmente

están disponibles como los pines de E/S de propósito general, se utilizan

para este propósito. Para decir con más precisión, son los pines del puerto

PORTB utilizados para la transmisión de señal de reloj (RB6) y de datos

(RB7) al cargar el programa. Además, es necesario suministrar el voltaje de

alimentación Vdd (5V) así como el voltaje apropiado Vpp (12-14V) para la

programación de memoria FLASH. Durante la programación, el voltaje Vpp

se aplica al pin MCLR. No se preocupe de los detalles relacionados a este

proceso, tampoco se preocupe de cuál voltaje se aplica primero puesto que

los componentes del programador se encargan de eso. Lo que es muy

importante es que el programa se puede cargar al microcontrolador aún

después de haber sido soldado en el dispositivo destino. Por supuesto, el

programa cargado se puede cambiar de la misma manera. Esta función se

le denomina ICSP (In-Circuit Serial Programming - Programación serial en

circuito)

Para utilizarlo correctamente es necesario planificar con antelación. ¡Es pan

comido! Sólo es necesario instalar un conector miniatura de 5 pines en el

dispositivo destino para suministrar al microcontrolador un voltaje de

programación necesario. Para evitar la interferencia entre los voltajes y los

componentes del dispositivo conectados a los pines del microcontrolador,

todos los periféricos adicionales deben estar desconectados durante la

programación (utilizando las resistencias o los puentes).

Como hemos visto, los voltajes aplicados a los pines del zócalo del

programador son los mismos que los utilizados durante la programación

ICSP.

Page 171: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 171

Puerto PORTC y registro TRISC

El puerto PORTC es un puerto bidireccional, de 8 bits de anchura. Los bits

del registro TRISC determinan la función de sus pines. Similar a otros

puertos, un uno lógico (1) en el registro TRISC configura el pin apropiado

del puerto PORTC como entrada.

Todas las funciones adicionales del puerto PORTC se describen en los

siguientes capítulos.

Puerto PORTD y registro TRISD

El puerto PORTD es un puerto bidireccional de 8 bits de anchura. Los bits

del registro TRISD determinan la función de sus pines. Similar a otros

puertos, un uno lógico (1) en el registro TRISD configura el pin apropiado

del puerto PORTD como entrada.

Page 172: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 172

Puerto PORTE y registro TRISE

El puerto PORTE es un puerto bidireccional, de 4 bits de anchura. Los bits

del registro TRISE determinan la función de sus pines. Similar a otros

puertos, un uno lógico (1) en el registro TRISE configura el pin apropiado

del puerto PORTE como entrada.

La excepción es el pin RE3, que siempre está configurado como entrada.

Similar a los puertos PORTA y PORTB, en este caso los tres pines se

pueden configurar como entradas analógicas. Los bits del registro ANSEL

determinan si estos pines serán configurados como entradas analógicas

(AN) o entradas/salidas digitales:

RE0 = AN5 (determinado por el bit ANS5 del registro ANSEL);

RE1 = AN6 (determinado por el bit ANS6 del registro ANSEL); y

RE2 = AN7 (determinado por el bit ANS7 del registro ANSEL).

Vamos a hacerlo en mikroC...

/* El pin PORTE.0 se configura como una entrada analógica mientras que

los demás tres

pines del mismo puerto se configuran como digitales */

...

ANSEL = 0b00100000; // El pin PORTE.0 se configura como analógico

Page 173: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 173

ANSELH = 0; // Todos los pines de E/S se configuran como digitales

TRISE = 0b00000001; // Todos los pines del puerto PORTE excepto el

// PORTE.0 se configuran como salidas

PORTE = 0; // Todos los bits del puerto PORTE se ponen a cero

...

Registros ANSEL y ANSELH

Los registros ANSEL y ANSELH se utilizan para configurar el modo de

entrada de un pin de E/S como analógico o como digital.

La regla es la siguiente:

Para configurar un pin como una entrada analógica, el bit apropiado de los

registros ANSEL o ANSELH se debe poner a uno (1). Para configurar un pin

como una entrada/salida digital, el bit apropiado se debe poner a cero (0).

El estado lógico de los bits del registro ANSEL no tiene influencia en las

funciones de salidas digitales. Al intentar a leer un pin de puerto configurado

como una entrada analógica, el resultado es siempre 0.

Page 174: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 174

Es probable que usted nunca vaya a escribir un programa que no utilice

puertos, así que el esfuerzo para aprender todo sobre ellos en definitiva

vale la pena. De todos modos, los puertos son probablemente los módulos

más simples dentro del microcontrolador. Se utilizan de la siguiente manera:

Al diseñar un dispositivo, seleccione un puerto por el que el

microcontrolador comunicará al entorno periférico. Si usted utiliza sólo

entradas/salidas digitales, seleccione cualquier puerto. Si utiliza

alguna de las entradas analógicas, seleccione los puertos apropiados

que soportan tal configuración de los pines (AN0-AN13).

Cada pin del puerto se puede configurar como salida o como entrada.

Los bits de los registros TRISA,TRISB, TRISC, TRISD y TRISE

determinan cómo se com portarán los pines apropiados de los puertos

PORTA, PORTB, PORTC, PORTD y PORTE. Simplemente...

Si utiliza alguna de las entradas analógicas, primero es necesario

poner a uno los bits apropiados de los registros ANSEL y ANSELH en

el principio de programa.

Si utiliza resistencias o botones de presión como una fuente de señal

de en trada, conéctelos a los pines del puerto PORTB, ya que tienen

Page 175: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 175

las resistencias pull-up. El uso de estos registros está habilitado por el

bit RBPU del registro OPTION_REG, mientras que la instalación de

las resistencias individuales está habilitada por los bits del registro

WPUB.

Con frecuencia se necesita responder tan pronto como los pines de

entrada cambien su estado lógico. Sin embargo, no es necesario

escribir un programa para comprobar el estado lógico de los pines. Es

mucho más simple conectar estas entradas a los pines del puerto

PORTB y habilitar que ocurra una interrupción con cada cambio de

voltaje. Los bits de los registros IOCB e INTCON se encargan de eso.

El microcontrolador PIC16F887 dispone de tres temporizadores/contadores

independientes, denominados Timer0, Timer1 y Timer2. En este capítulo se

presenta una descripción detallada de los mismos.

3.4 TEMPORIZADOR TIMER0

El temporizador Timer0 tiene una amplia gama de aplicaciones en la

práctica. Sólo unos pocos programas no lo utilizan de alguna forma. Es muy

conveniente y fácil de utilizar en programas o subrutinas para generar

pulsos de duración arbitraria, en medir tiempo o en contar los pulsos

externos (eventos) casi sin limitaciones.

El módulo del temporizador Timer0 es un temporizador/contador de 8 bits

con las siguientes características:

Temporizador/contador de 8 bits;

Pre-escalador de 8 bits (lo comparte con el temporizador perro

guardián);

Fuente de reloj interna o externa programable;

Generación de interrupción por desbordamiento; y

Selección del flanco de reloj externo programable.

Page 176: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 176

La siguiente figura muestra el esquema del temporizador Timer0 con todos

los bits que determinan su funcionamiento. Estos bits se almacenan en el

registro OPTION_REG.

Page 177: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 177

Registro OPTION_REG

RBPU - PORTB Pull-up enable bit (resistencia Pull Up del puerto

PORTB)

o 0 - Resistencias pull-up del puerto PORTB están deshabilitadas.

o 1 - Pines del puerto PORTB pueden estar conectados a las

resistencias pull-up.

INTEDG - Interrupt Edge Select bit (bit selector de flanco activo

de la interrupción externa)

o 0 - Interrupción por flanco ascendente en el pin INT (0-1).

o 1 - Interrupción por flanco descendente en el pin INT (1-0).

T0CS - TMR0 Clock Select bit (bit selector de tipo de reloj para el

Timer0)

o 0 - Los pulsos se llevan a la entrada del temporizador/contador

Timer0 por el pin RA4.

o 1 - El temporizador utiliza los pulsos de reloj internos (Fosc/4).

T0SE - TMR0 Source Edge Select bit (bit selector de tipo de

flanco)

o 0 - Incrementa en flanco descendente en el pin TMR0.

o 1 - Incrementa en flanco ascendente en el pin TMR0.

PSA - Prescaler Assignment bit (bit de asignación del pre-

escalador)

o 0 - Pre-escalador se le asigna al WDT.

o 1 - Pre-escalador se le asigna al temporizador/contador Timer0.

Page 178: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 178

PS2, PS1, PS0 - Prescaler Rate Select bit (bit selector del valor

del divisor de frecuencias)

o El valor del divisor de frecuencias se ajusta al combinar estos

bits. Como se muestra en la tabla a la derecha, la misma

combinación de bits proporciona los diferentes valores del divisor de

frecuencias para el temporizador/contador y el temporizador perro

guardián, respectivamente.

P S 2 P S 1 P S 0 T M R 0 W D T

0 0 0 1:2 1:1

0 0 1 1:4 1:2

0 1 0 1:8 1:4

0 1 1 1:16 1:8

1 0 0 1:32 1:16

1 0 1 1:64 1:32

1 1 0 1:128 1:64

1 1 1 1:256 1:128

Cuando el bit PSA está a 0, el pre-escalador se le asigna al

temporizador/contador Timer0, como se muestra en la siguiente figura.

Page 179: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 179

Vamos a hacerlo en mikroC...

// En este ejemplo, Timer0 se configura como un temporizador y se le

asigna un pre-escalador.

unsigned cnt; // Declarar la variable cnt

void interrupt() { // Rutina de interrupción

cnt++; // Interrupción causa el incremento de cnt por 1

TMR0 = 155; // Temporizador (o contador) Timer0 devuelve su valor

inicial

INTCON = 0x20; // Bit T0IE está a 1, bit T0IF está a 0

}

void main() {

OPTION_REG = 0x04; // Pre-escalador (1:32) se le asigna al

temporizador Timer0

TMR0 = 155; // Temporizador T0 cuenta de 155 a 255

INTCON = 0xA0; // Habilitada la generación de interrupción para el

// temporizador Timer0

...

...

// En el siguiente ejemplo, Timer0 se configura como un

temporizador

// y se le asigna un pre-escalador.

OPTION_REG = 0x20; // Pre-escalador (1:2) se le asigna al contador

Timer0

TMR0 = 155; // Contador T0 cuenta de 155 a 255

INTCON = 0xA0; // Habilitada la generación de interrupción por el

Page 180: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 180

// temporizador Timer0

...

...

Cuando el bit PSA está a 1, el pre-escalador se le asigna al temporizador

perro guardián como se muestra en la siguiente figura.

Vamos a hacerlo en mikroC...

// En este ejemplo, el pre-escalador (1:64) se le asigna al temporizador

perro guardián.

void main() {

OPTION_REG = 0x0E; // Pre-escalador se le asigna al WDT (1:64)

asm CLRWDT; // Comando en ensamblador para reiniciar el WDT

...

...

asm CLRWDT; // Comando en ensamblador para reiniciar el WDT

...

Page 181: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 181

Aparte de lo dicho anteriormente, cabe destacar lo siguiente:

Al asignarle el pre-escalador al temporizador/contador, el pre-

escalador se pondrá a 0 con cualquier escritura en el registro TMR0.

Al asignar el pre-escalador al temporizador perro guardián, tanto el

WDT como el preescalador se pondrán a 0 con la instrucción

CLRWDT.

Al escribir en el registro TMR0, utilizado como un temporizador, no se

inicia el conteo de los pulsos inmediatamente, sino con retraso de dos

ciclos de instrucciones. Por consiguiente, es necesario ajustar el valor

escrito en el registro TMR0.

Al poner el microcontrolador en el modo de reposo se apaga el

oscilador de reloj. No puede ocurrir el desbordamiento ya que no hay

pulsos a contar. Es la razón por la que la interrupción por el

desbordamiento del TMR0 no puede“despertar” al procesador del

modo de reposo.

Si se utiliza como un contador de reloj externo sin pre-escalador, la

longitud de pulso mínima o tiempo muerto entre dos pulsos deberá ser

2 Tosc + 20 nS (Tosc es el período de señal de reloj del oscilador).

Si se utiliza como un contador de reloj externo con pre-escalador, la

longitud de pulso mínima o tiempo muerto entre dos pulsos es sólo

10nS.

El registro del pre-escalador de 8 bits no está disponible al usuario, lo

que significa que no es posible leerlo o escribir en él directamente.

Al cambiar de asignación del pre-escalador del Timer0 al

temporizador perro guardián, es necesario ejecutar la siguiente

secuencia de instrucciones escritas en ensamblador para impedir

reiniciar el microcontrolador:

Page 182: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 182

BANKSEL TMR0

CLRWDT ;PONER A CERO WDT

CLRF TMR0 ;PONER A CERO TMR0 Y PRE-ESCALADOR

BANKSEL OPTION_REG

BSF OPTION_REG,PSA ;ASIGNARLE EL PRE-ESCALADOR AL

WDT

CLRWDT ;PONER A CERO WDT

MOVLW b'11111000' ;SELECCIONAR LOS BITS PS2,PS1,PS0 Y

PONERLOS

ANDWF OPTION_REG,W ;A CERO POR LA INSTRUCCIÓN 'Y

LÓGICO'

IORLW b'00000101' ;BITS PS2, PS1, Y PS0 PONEN EL VALOR

MOVWF OPTION_REG ;DEL DIVISOR DE FRECUENCIAS A 1:32

De manera similar, al cambiar de asignación del pre-escalador del

WDT al Timer0, es necesario ejecutar la siguiente secuencia de

instrucciones, también escritas en ensamblador:

BANKSEL TMR0

CLRWDT ;PONER A CERO WDT Y PRE-ESCALADOR

BANKSEL OPTION_REG

MOVLW b'11110000' ;SELECCIONAR SÓLO LOS BITS

PSA,PS2,PS1,PS0

ANDWF OPTION_REG,W ;Y PONERLOS A CERO POR LA

INSTRUCCIÓN 'Y LÓGICO'

Page 183: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 183

IORLW b'00000011' ;VALOR DEL DIVISOR DE FRECUENCIAS

ES 1:16

MOVWF OPTION_REG

Para utilizar el Timer0 apropiadamente, es necesario:

Paso 1: Seleccionar el modo:

El modo de temporizador se selecciona por el bit TOSC del registro

OPTION_REG (TOSC: 0=temporizador, 1=contador).

Cuando se asigna el pre-escalador al temporizador/contador se debe

poner a cero el bit PSA del registro OPTION_REG. El valor del divisor

de frecuencias se configura al utilizar los bits PS2-PS0 del mismo

registro.

Al utilizar una interrupción, los bits GIE y TMR0IE del registro INTCON

deben estar a uno.

Paso 2: Medir y contar

Para medir tiempo:

Reiniciar el registro TMR0 o escribir un valor conocido en él.

El tiempo transcurrido(en microsegundos al utilizar el oscilador de

4MHz) se mide al leer el registro TMR0.

El bit de bandera TMR0IF del registro INTCON se pone a uno

automáticamente siempre que ocurra el desbordamiento del registro

TMR0. Si está habilitada, ocurre una interrupción.

Para contar pulsos:

La polaridad de pulsos a contar en el pin RA4 se selecciona por el bit

TOSE del registro OPTION_REG (T0SE: 0=pulsos positivos, 1=pulsos

negativos).

Page 184: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 184

Varios pulsos se pueden leer del registro TMR0. El pre-escalador y la

interrupción se utilizan de la misma forma que en el modo de

temporizador.

3.5 TEMPORIZADOR TIMER1

El módulo del temporizador Timer1 es un temporizador/contador de 16 bits,

lo que significa que consiste en dos registros (TMR1L y TMR1H). Puede

contar hasta 65535 pulsos en un solo ciclo, o sea, antes de que el conteo se

inicie desde cero.

Similar al temporizador Timer0, estos registros se pueden leer o se puede

escribir en ellos en cualquier momento. En caso de que ocurra un

desbordamiento, se genera una interrupción si está habilitada.

El módulo del temporizador Timer1 puede funcionar en uno o dos modos

básicos, eso es como un temporizador o como un contador. A diferencia del

temporizador Timer0, cada uno de estos dos modos tiene funciones

adicionales.

El temporizador Timer1 tiene las siguientes características:

Temporizador/contador de 16 bits compuesto por un par de registros;

Fuente de reloj interna o externa programable;

Pre-escalador de 3 bits;

Oscilador LP opcional;

Funcionamiento síncrono o asíncrono;

Compuerta para controlar el temporizador Timer1 (conteo habilitado)

por medio del comparador o por el pin T1G;

Interrupción por desbordamiento;

Page 185: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 185

"Despierta" al microcontrolador (salida del modo de reposo) por

desbordamiento (reloj externo); y

Fuente de reloj para la función de Captura/Comparación.

SELECCIÓN DE LA FUENTE DE RELOJ DEL TEMPORIZADOR TIMER1

El bit TMR1CS del registro T1CON se utiliza para seleccionar la fuente de

reloj para este temporizador:

F U E N T E D E R E L O J

T M R 1 C S

Fosc/4 0

T1CKI pin 1

Al seleccionar la fuente de reloj interna, el par de registros TMR1H-TMR1L

será incrementado con varios pulsos Fosc como es determinado por el pre-

escalador.

Al seleccionar la fuente de reloj externa, este temporizador puede funcionar

como un temporizador o un contador. Los pulsos en el modo temporizador

pueden estar sincronizados con el reloj interno del microcontrolador o

funcionar asíncronamente. En caso de que se necesite un oscilador del reloj

Page 186: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 186

externo y el microcontrolador PIC16F887 utilice el oscilador interno INTOSC

con el pin RA6/OSC2/CLIKOUT, el temporizador Timer1 puede utilizar el

oscilador LP como una fuente de reloj.

PRE-ESCALADOR DEL TEMPORIZADOR TIMER1

El temporizador Timer1 tiene un escalador completamente separado que

permite dividir la frecuencia de entrada de reloj por 1,2,4 o 8. No es posible

leer el pre-escalador o escribir en él directamente. De todas formas, el

contador del pre-escalador se pone a 0 automáticamente después de

escribir en los registros TMR1H o TMR1L.

OSCILADOR DEL TEMPORIZADOR TIMER1

Los pines RC0/T1OSO y RC1/T1OSI se utilizan para registrar los pulsos

que vienen de los dispositivos periféricos, pero también tienen una función

adicional. Como se puede ver en la siguiente figura, se configuran

simultáneamente como entrada (pin RC1) y salida (pin RC0) del oscilador

de cuarzo LP (Low Power - de bajo consumo) adicional. Este circuito está

principalmente diseñado para funcionar a bajas frecuencias (hasta 200

KHz), exactamente para el uso de cristal de cuarzo de 32.768 KHz. Este

cristal se utiliza en los relojes de cristal puesto que es fácil de obtener un

pulso de duración de un segundo al dividir esta frecuencia.

Como el oscilador no depende del reloj interno, puede funcionar incluso en

el modo de reposo. Se habilita al poner a uno el bit de control T1OSCEN del

registro T1CON. El usuario debe proporcionar tiempo muerto por medio de

software (unos pocos milisegundos) para habilitar que el oscilador se inicie

apropiadamente.

La siguiente tabla muestra los valores recomendados de los capacitores

convenientes con el oscilador de cuarzo. No es necesario que estos valores

sean exactos. De todas formas, la regla general es: cuánto más alta sea la

Page 187: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 187

capacidad, tanto más alta será la estabilidad, lo que a la vez prolonga el

tiempo necesario para la estabilización del oscilador.

O S C I L A D O R F R E C U E N C I A C 1 C 2

LP

32 kHz 33 pF 33 pF

100 kHz 15 pF 15 pF

200 kHz 15 pF 15 pF

El consumo de corriente del microcontrolador se reduce a nivel más bajo en

el modo de reposo ya que el consumidor de corriente principal - el oscilador

- no funciona. Es fácil de poner al microcontrolador en este modo - al

ejecutar la instrucción SLEEP. El problema es cómo despertar al

microcontrolador porque sólo una interrupción puede producirlo. Como el

microcontrolador “duerme”, se debe usar una interrupción causada por

dispositivos periféricos para “despertarlo”. Se pone muy complicado si es

necesario despertar al microcontrolador a intervalos de tiempo regulares...

Para resolver el problema, un oscilador de cuarzo LP (de bajo consumo de

corriente) completamente independiente, capaz de funcionar en el modo de

reposo, está integrado en el microcontrolador PIC16F887. Simplemente, un

circuito anteriormente separado ahora está integrado en el microcontrolador

y asignado al temporizador Timer1. El oscilador está habilitado al poner a 1

el bit T1OSCEN del registro T1CON. El bit TMR1CS del mismo registro se

utiliza para habilitar que el temporizador Timer1 utilice secuencias de pulsos

de ese oscilador.

Page 188: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 188

Una señal generada por este oscilador de cuarzo está sincronizada

con el reloj del microcontrolador al poner a 0 el bit T1SYNC. En este

caso, el temporizador no puede funcionar en modo de reposo porque

el circuito para sincronización utiliza el reloj del microcontrolador.

La interrupción por desbordamiento en el registro del temporizador

Timer1 puede estar habilitada. Si el bit T1SYNC se pone a 1, tales

interrupciones se producirán en el modo de reposo también.

COMPUERTA DEL TEMPORIZADOR TIMER1

El pin TG1 o la salida del comparador C2 pueden ser una fuente de los

pulsos que pasan por la compuerta del temporizador Timer1. Se configuran

por software. Esta compuerta permite que el temporizador mida

directamente la duración de los eventos externos al utilizar el estado lógico

del pin T1G o los eventos analógicos al utilizar la salida del comparador C2.

Refiérase a la Figura en la página anterior. Para medir duración de señal,

basta con habilitar esta compuerta y contar los pulsos que pasan por ella.

TIMER1 EN EL MODO TEMPORIZADOR

Para seleccionar este modo, es necesario poner a 0 el bit TMR1CS.

Después de eso, el registro de 16 bits será incrementado con cada pulso

generado por el oscilador interno. Si se utiliza el cristal de cuarzo de 4 MHZ,

el registro será incrementado cada microsegundo.

Page 189: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 189

En este modo, el bit T1SYNC no afecta al temporizador porque cuenta los

pulsos de reloj interno. Como todos los dispositivos utilizan estos pulsos, no

hace falta sincronizarlos.

El oscilador de reloj del microcontrolador no funciona durante el modo de

reposo así que el desbordamiento en el registro del temporizador no puede

causar interrupción.

Vamos a hacerlo en mikroC...

// En este ejemplo, el TMR1 está configurado como un temporizador con

el valor

// del preescalador 1:8. Cada vez que ocurra un desbordamiento de los

registros TMR1H y

// TMR1L, se solicitará una interrupción.

void main() {

PIR1.TMR1IF = 0; // Poner a 0 la bandera de bit del TMR1IF

TMR1H = 0x22; // Poner el valor inicial para el temporizador Timer1

TMR1L = 0x00;

TMR1CS = 0; // Temporizador1 cuenta los pulsos del oscilador

interno

Page 190: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 190

T1CKPS1 = T1CKPS0 = 1; // El valor del pre-escalador asignada es 1:8

PIE1.TMR1IE = 1; // Interrupción habilitada por desbordamiento

INTCON = 0xC0; // Interrupción habilitada (bits GIE y PEIE)

TMR1ON = 1; // Encender el temporizador Timer1

...

TIMER1 EN EL MODO CONTADOR

El temporizador Timer1 se pone a funcionar como un contador al poner a 1

el bit TMR1CS. Este bit cuenta los pulsos llevados al pin PC0/T1CKI y se

incrementa en el flanco ascendente de la entrada del reloj externo T1CKI. Si

el bit de control T1SYNC del registro T1CON se pone a 0, las entradas del

reloj externo se sincronizarán en su camino al temporizador Timer1. En

otras palabras, el temporizador Timer1 se sincroniza con el reloj interno del

microcontrolador y se le denomina contador síncrono.

Al poner en modo de reposo el microcontrolador que funciona de esta

manera, los registros del temporizador Timer1H y TMR1L no serán

incrementados aunque los pulsos de reloj aparezcan en los pines de

entrada. Como el reloj interno del microcontrolador no funciona en este

modo, no hay entradas de reloj que se utilicen para la sincronización. De

todas formas, el pre-escalador sigue funcionando siempre que haya pulsos

de reloj en los pines, porque es un simple divisor de frecuencias.

Este contador detecta un uno lógico (1) en los pines de entrada. Cabe

destacar que al menos un flanco ascendente debe ser detectado antes de

empezar a contar los pulsos. Refiérase a la Figura a la izquierda. Las

flechas en la figura indican los incrementos del contador.

Page 191: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 191

Registro T1CON

T1GINV - Timer1 Gate Invert bit (Bit inversor de la compuerta del

temporizador1) se comporta como un inversor del estado lógico en la

compuerta formada por el pin T1G o la salida (C2OUT) del comparador C2.

Este bit habilita al temporizador para con tar los pulsos cuando la compuerta

esté a alto o a bajo.

1 - Temporizador 1 cuenta los pulsos cuando el pin T1G o el bit

C2OUT estén a alto (1).

0 - Temporizador 1 cuenta los pulsos cuando el pin T1G o el bit

C2OUT estén a bajo (0).

TMR1GE - Timer1 Gate Enable bit (Bit de habilitación de la compuerta del

temporizador1) determina si la compuerta formada por el pin T1G o salida

del comparador C2 (C2OUT) estará activa o no. Este bit es funcional sólo

en caso de que el temporizador Timer1 esté encendido (el bit TMR1ON =

1). De lo contrario, este bit se ignora.

1 - Temporizador Timer1 está encendido sólo si la compuerta no está

activa.

0 - Compuerta no afecta al temporizador Timer1.

Page 192: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 192

T1CKPS1, T1CKPS0 - Timer1 Input Clock Prescale Select bits (Bits de

selección del preescalador de señal de reloj del Temporizador1) determina

el valor del divisor de frecuen cias asignada al temporizador Timer1.

T 1 C K P S 1 T 1 C K P S 0 V A L O R D E L P R E -

E S C A L A D O R

0 0 1:1

0 1 1:2

1 0 1:4

1 1 1:8

T1OSCEN - LP Oscillator Enable Control bit (bit de habilitación del oscilador

LP del Timer1)

1 - Oscilador LP está habilitado para el reloj del Timer1 (oscilador de

bajo consumo y de frecuencia de 32.768 kHz)

0 - Oscilador LP está apagado.

T1SYNC - Timer1 External Clock Input Synchronization Control bit (Bit de

control de sincronización de la señal de entrada) habilita la sincronización

de la entrada del oscilador LP o de la entrada del pin T1CKI con el reloj

interno del microcontrolador. Este bit se ignora al contar los pulsos desde el

oscilador principal (el bit TMR1CS = 0).

1 - Entrada de reloj externa no está sincronizada.

0 - Entrada de reloj externa está sincronizada.

TMR1CS - Timer TMR1 Clock Source Select bit (bit de selección de la

fuente de reloj del temporizador Timer1)

1 - Cuenta los pulsos por el pin T1CKI (por el flanco ascendente 0-1)

0 - Cuenta los pulsos del reloj interno del microcontrolador

TMR1ON - Timer1 On bit (TMR activo, hace entrar o no en funcionamiento

el Timer1).

1 - Habilita el temporizador Timer1.

0 - Deshabilita el temporizador Timer1.

Para utilizar el Timer1 apropiadamente, es necesario hacer lo siguiente:

Page 193: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 193

Como no es posible apagar el pre-escalador, su valor debe estar

ajustado a los bits T1CKPS1 y T1CKPS0 del registro T1CON

(Refiérase a la tabla).

Seleccionar el modo por el bit TMR1CS del registro T1CON.

(TMR1CS: 0=la fuente de reloj es oscilador de cuarzo interno, 1= la

fuente de reloj es oscilador de cuarzo externo).

Al configurar el bit T1OSCEN del mismo registro, el oscilador está

habilitado y los registros TMR1H y TMR1L se incrementan con cada

pulso de reloj. Al poner este bit a 0, se detiene el conteo.

Al reiniciar los registros del contador o al escribir en ellos, se reinicia

el pre-escalador.

Al llenar ambos registros del temporizador, se configura la bandera

TMR1IF y el conteo empieza desde cero.

3.6 TEMPORIZADOR TIMER2

El módulo del temporizador Timer2 es un temporizador de 8 bits.

Los pulsos que vienen del oscilador de cuarzo primero pasan por el pre-

escalador cuyo valor puede ser modificado al combinar los bits T2CKPS1 y

T2CKPS0. La salida del preescalador se utiliza para incrementar el registro

TMR2 empezando por 00h. Los valores del TMR2 y del PR2 se comparan

constantemente y el registro TMR2 va incrementándose hasta alcanzar el

valor del registro PR2. Cuando se igualan los valores de los registros, lo que

Page 194: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 194

será registrado por el comparador, el TMR2 se reinicia a 00h

automáticamente. El postescalador del temporizador Timer2 se incrementa

y su salida se utiliza para generar una interrupción si está habilitada.

Los ambos registros TMR y PR2 son de lectura y escritura. El conteo se

puede detener al poner a 0 el bit TMR2ON, lo que resulta en un ahorro de

energía.

El momento de reinicio del TMR2 se puede utilizar para determinar la

velocidad de transmisión en baudios de la comunicación serie síncrona.

Varios bits del registro T2CON están en control del temporizador Timer2.

Registro T2CON

TOUTPS3 - TOUTPS0 - Timer2 Output Postcaler Select bits (bits de

selección del rango del divisor del post-escalador para el Timer2) se utilizan

para determinar el valor del post-escalador según la siguiente tabla:

Page 195: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 195

T O U T PS 3

T O U T PS 2

T O U T PS 1

T O U T PS 0

V A L O R D E L P O S T -E S C A L A DO R

0 0 0 0 1:1

0 0 0 1 1:2

0 0 1 0 1:3

0 0 1 1 1:4

0 1 0 0 1:5

0 1 0 1 1:6

0 1 1 0 1:7

0 1 1 1 1:8

1 0 0 0 1:9

1 0 0 1 1:10

1 0 1 0 1:11

1 0 1 1 1:12

1 1 0 0 1:13

1 1 0 1 1:14

1 1 1 0 1:15

1 1 1 1 1:16

TMR2ON Timer2 On bit - (bit de activación del TIMR2) hace entrar en

funcionamiento el temporizador Timer2.

1 - Habilita el funcionamiento del Timer2.

0 - Deshabilita el funcionamiento del Timer2.

T2CKPS1, T2CKPS0 - Timer2 Clock Prescaler bits (selección del rango del

divisor del preescalador del Timer2) determina el valor del divisor de

frecuencias:

Page 196: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 196

T 2 C K P S 1 T 2 C K P S 0 V A L O R D E L P R E -

E S C A L A D O R

0 0 1:1

0 1 1:4

1 x 1:16

Al utilizar el temporizador Timer2 hay que saber varios detalles relacionados

con sus registros:

En el momento de encender una fuente de alimentación, el registro

PR2 contiene el valor FFh.

Tanto el pre-escalador como el post-escalador se borran al escribir en

el registro TMR2.

Tanto el pre-escalador como el post-escalador se borran al escribir en

el registro T2CON.

Al producirse cualquier reinicio, como puede anticiparse, tanto el pre-

escalador como el post-escalador se borran.

Los módulos CCP pueden funcionar en muchos modos diferentes, por lo

que se consideran los más complicados. Si usted intenta analizar su

funcionamiento a base de tablas que describen las funciones de bits,

comprenderá mejor de lo qué le estamos hablando. Si utiliza alguno de los

módulos CCP, primero seleccione el modo que necesita, analice la figura

apropiada y entonces póngase a modificar los bits de registros. Si no...

3.7 MÓDULOS CCP

El módulo CCP (Captura/Comparación/PWM) es un periférico que le

permite medir y controlar diferentes eventos.

El modo de captura proporciona el acceso al estado actual de un registro

que cambia su valor constantemente. En este caso, es el registro del

temporizador Timer1.

El modo de comparación compara constantemente valores de dos

registros. Uno de ellos es el registro del temporizador Timer1. Este circuito

también le permite al usuario activar un evento externo después de que

haya expirado una cantidad de tiempo predeterminada.

Page 197: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 197

PWM (Pulse Width Modulation - modulación por ancho de pulsos) puede

generar señales de frecuencia y de ciclo de trabajo variados por uno o más

pines de salida.

El microcontrolador PIC16F887 dispone de dos módulos CCP - CCP1 y

CCP2.

Ambos son idénticos en modo normal de funcionamiento, mientras que las

características del PWM mejorado están disponibles sólo en el modo CCP1.

Ésta es la razón por la que en este capítulo se describe detalladamente el

funcionamiento del módulo CCP1. Con respecto al CCP2, se presentarán

sólo las características que lo distinguen del CCP1.

MÓDULO CCP1

Una parte central de este circuito es un registro CCPR1 de 16 bits que

consiste en registros CCPR1L y CCOR1H. Se utiliza para capturar y

comparar sus valores con los números almacenados en el registro del

temporizador Timer1 (TMR1H y TMR1L).

Si está habilitado por software, puede ocurrir el reinicio del temporizador

Timer1 al igualarse los valores en modo de Comparación. Además, el

módulo CCP1 puede generar señales PWM de frecuencia y de ciclo de

trabajo variados.

Los bits del registro CCP1CON están en control del módulo CCP1.

CCP1 EN MODO DE CAPTURA

En este modo, el registro del temporizador Timer1 (que consiste en los

TMR1H y TMR1L) se copia al registro CCP1 (que consiste en los CCPR1H

y CCPR1L) en las siguientes situaciones:

Cada flanco ascendente (1 -> 0) en el pin RC2/CCP;

Cada flanco descendente (0 -> 1) en el pin RC2/CCP1;

Cada cuarto flanco ascendente (0 -> 1) en el pin RC2/CCP1; y

Page 198: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 198

Cada decimosexto flanco descendente (0 -> 1) en el pin RC2/CCP1.

Una combinación de cuatro bits (CCP1M3 - CCP1M0) del registro de control

determina cuál de estos eventos causará transmisión de dato de 16 bits.

Además, se deben cumplir los siguientes requisitos::

El pin RC2/CCP1 debe estar configurado como entrada; y

El Timer1 debe funcionar como temporizador o contador síncrono.

El bit de bandera CCP1IF se pone a uno después de acabar la captura. Si

se pone a 1 el bit CCP1IE del registro PIE1, se producirá una interrupción.

En caso de que el módulo CCP1 esté en modo de captura, puede

producirse una interrupción no deseada. Para evitarlo, antes de que ocurra

un cambio en el registro de control se deben poner a 0 tanto el bit que

habilita la interrupción CCP1IE, como el bit de bandera CCP1IF.

Las interrupciones no deseadas pueden producirse al cambiar el valor del

pre-escalador. Para evitarlo, el módulo CCP1 debe estar apagado

temporalmente antes de cambiar el valor del pre-escalador.

Se recomienda la siguiente secuencia de programa, escrita en

ensamblador:

Page 199: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 199

BANKESEL CCP1CON

CLRF CCP1CON ;REGISTRO DE CONTROL BORRADO

;MÓDULO CCP1 ESTÁ APAGADO

MOVLW XX ;NUEVO MODO DEL PRE-ESCALADOR ESTÁ

SELECCIONADO

MOVWF CCP1CON ;EN EL REGISTRO DE CONTROL SE

INTRODUCE UN NUEVO VALOR

;MÓDULO CCP1 SE ENCIENDE SIMULTÁNEAMENTE

Vamos a hacerlo en mikroC...

...

ASM {

BANKESEL CCP1CON

CLRF CCP1CON // REGISTRO DE CONTROL BORRADO

// MÓDULO CCP1 ESTÁ APAGADO

MOVLW XX // NUEVO MODO DEL PRE-ESCALADOR ESTÁ

SELECCIONADO

MOVWF CCP1CON // EN EL REGISTRO DE CONTROL SE

INTRODUCE NUEVO VALOR

} // MÓDULO CCP1 SE ENCIENDE SIMULTÁNEAMENTE

...

Page 200: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 200

CCP1 EN MODO DE COMPARACIÓN

En este modo, el valor almacenado en el registro CCP1 se compara

constantemente al valor almacenado en el registro del temporizador Timer1.

Al igualarse los valores, el estado lógico en el pin de salida puede ser

cambiado, lo que depende del estado de bits en el registro de control

(CCP1M3 - CCP1M0). El bit de bandera CCP1IF se pone a uno

simultáneamente.

Para poner el módulo CCP1 en este modo de funcionamiento, se deben

cumplir dos condiciones:

El pin RC2/CCP1 debe estar configurado como salida; y

El temporizador Timer1 debe estar sincronizado con el reloj interno.

CCP1 EN MODO PWM

Las señales de frecuencia y de ciclo de trabajo variados tienen una amplia

gama de aplicaciones en automatización. Un ejemplo típico es un circuito de

control de potencia. Refiérase a la siguiente figura. Si un cero lógico (0)

indica un interruptor abierto y un uno lógico (1) indica un interruptor cerrado,

la potencia eléctrica que se transmite a los consumidores será directamente

proporcional a la duración del pulso. Esta relación se le denomina Ciclo de

Trabajo.

Page 201: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 201

El otro ejemplo, común en la práctica, es el uso de señales PWM en un

circuito para generar señales de forma de onda arbitraria como una onda

sinusoidal. Vea la siguiente figura:

Los dispositivos que funcionan según este principio se utilizan con

frecuencia en la práctica como variadores de frecuencia ajustable que

controlan motores eléctricos (velocidad, aceleración, desaceleración etc.)

Page 202: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 202

La Figura anterior muestra el diagrama de bloques del módulo CCP1 puesto

en el modo PWM. Para generar un pulso de forma arbitraria en el pin de

salida, es necesario ajustar el período de pulsos (frecuencia) y la duración

de pulsos.

PERÍODO DE PWM

El período de pulso de salida (T) se determina por el registro PR2 del

temporizador Timer2. El período de PWM se puede calcular por la siguiente

ecuación:

Período PWM = (PR2 +1) * 4Tosc * Valor de pre-escala del Timer2

Page 203: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 203

Si el período de PWM (T) es conocido, es fácil determinar la frecuencia de

señal F, porque estos dos valores están relacionados por la ecuación

F=1/T.

CICLO DE TRABAJO DE PWM

El ciclo de trabajo de PWM se especifica al utilizar en total 10 bits: los ocho

bits más significativos del registro CCPR1L y los dos bits menos

significativos adicionales del registro CCP1CON (DC1B1 y DC1B0). El

resultado es un número de 10 bits dado por la siguiente fórmula:

Ancho de pulsos = (CCPR1L,DC1B1,DC1B0) * Tosc * Valor de pre-escala

del Timer2

La siguiente tabla muestra cómo generar las señales PWM de diferentes

frecuencias cuando el microcontrolador utiliza un cristal de cuarzo de 20

MHz (Tosc=50nS).

F R E C U E N C I A [ K H Z ]

1 . 2 2 4 . 8 8 1 9 . 5 3 7 8 . 1 2 1 5 6 . 3 2 0 8 . 3

Pre-escalador del TMR2

16 4 1 1 1 1

Registro PR2 FFh FFh FFh 3Fh 1Fh 17h

Notas adicionales:

El pin de salida se va a poner a 1 constantemente, si por error el

ancho de pulso generado es más largo que el período de PWM.

En esta aplicación, no se puede utilizar el post-escalador del

temporizador Timer2 para generar períodos de PWM largos.

RESOLUCIÓN DE PWM

Una señal PWM no es nada más que una secuencia de pulsos que varían

su ciclo de trabajo. Para una frecuencia específica (número de pulsos por

segundo), hay un número limitado de combinaciones de ciclos de trabajo.

Este número representa una resolución medida en bits. Por ejemplo, si una

resolución es de 10 bits estarán disponibles 1024 ciclos de trabajo

discretos; si una resolución es de 8 bits estarán disponibles 256 ciclos de

Page 204: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 204

trabajo disretos etc. En este microcontrolador la resolución es determinada por el registro PR2. El máximo valor

se obtiene al usar el número FFh.

Frecuencias y resoluciones de PWM (Fosc = 20MHz):

F R E C U EN C I A D E

P W M

1 . 2 2K H Z

4 . 8 8K H Z

1 9 . 5 3K H Z

7 8 . 1 2 KH Z

1 5 6 . 3K H Z

2 0 8 . 3K H Z

Pre-escala del temporizador

16 4 1 1 1 1

Valor del PR2 FFh FFh FFh 3Fh 1Fh 17h

Resolución máxima

10 10 10 8 7 6

Page 205: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 205

Frecuencias y resoluciones de PWM (Fosc = 8MHz):

Vamos a hacerlo en mikroC...

/* En este ejemplo, el módulo PWM está inicializado y ajustado para

producir una secuencia

de pulsos de ciclo de trabajo del 50%. Para este propósito, se utilizan las

funciones

PWM1_Init(), PWM1_Start() y PWM1_Set_Duty(). Todas las funciones las

contiene la librería

PWM del mikroC PRO for PIC. Sólo es necesario copiarlas al programa */

unsigned short duty_c; // Definir la variable duty_c

void initMain() {

ANSEL = ANSELH = 0; // Todos los pines de E/S se configuran como

digitales

F R E C UE N C I A

D E L P W M

1 . 2 2K H Z

4 . 9 0K H Z

1 9 . 6 1K H Z

7 6 . 9 2K H Z

1 5 3 . 85 K H Z

2 0 0 . 0K H Z

Pre-escala del

temporizador

16 4 1 1 1 1

Valor del PR2

65h 65h 65h 19h 0Ch 09h

Resolución máxima

8 8 8 6 5 5

Page 206: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 206

PORTC = TRISC = 0; // Estado inicial de los pines de salida del puerto

PORTC

PWM1_Init(5000); // Inicialización del módulo PWM (5KHz)

}

void main() {

initMain();

duty_c = 127; // Valor inicial del ciclo de trabajo

PWM1_Start(); // Iniciar el módulo PWM1

PWM1_Set_Duty(duty_c); // Ajustar el ciclo de trabajo de PWM al 50%

...

...

Registro CCP1CON

P1M1, P1M0 - PWM Output Configuration bits (bits de configuración del

modo PWM) - El pin P1A es la entrada del módulo de Captura/Comparación

en todos los modos, menos en modo PWM. Los pines P1B, P1C y P1D

actúan como los pines de E/S del puerto D.

En modo PWM estos bits afectan al funcionamiento del módulo CCP1 como

se muestra en la siguiente tabla

Page 207: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 207

P 1 M1

P 1 M0

M O D O

0 0

PWM con una sóla salida

Por el pin P1A sale una señal modulada. Pines P1B, P1C y P1D son entradas/salidas del

puerto D.

0 1

Configuración Full Bridge - Forward (puente completo con salida directa)

Por el pin P1D sale una señal modulada. Por el pin P1D sale una señal modulada.

Pines P1B y P1C están inactivos.

1 0

Configuración Half Bridge (medio-puente)

Por los pines P1A y P1B sale una señal modulada. Pines P1C y P1D son entradas/salidas del puerto

D.

1 1

Configuración Full Bridge - Reverse (puente completo con salida inversa)

Por el pin P1B sale una señal modulada. Pin P1C está activo.

Pines P1A y P1D están inactivos.

DC1B1, DC1B0 - PWM Duty Cycle Least Significant bits (bits menos

significativos del ciclo de trabajo de PWM) - Se utilizan sólo en el modo

PWM y representan dos bits menos significativos de un número de 10 bits.

Este número determina el ciclo de trabajo de la señal PWM. Los demás 8

bits se almacenan en el registro CCPR1L.

Page 208: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 208

CCP1M3 - CCP1M0 - (bits de selección de modo del módulo CCP1) determina el modo del módulo CCP1.

C C P 1 M 3 C C P 1 M 2 C C P 1 M 1 C C P 1 M 0 M O D O

0 0 0 0 Módulo está deshabilitado (reinicio).

0 0 0 1 No utilizado.

0 0 1 0

Modo de comparación

El bit CCP1IF bit se pone a 1 al ocurrir una coincidencia.

0 0 1 1 No utilizado.

0 1 0 0

Modo de captura

Cada flanco descendente en el pin CCP1.

0 1 0 1

Modo de captura

Cada flanco ascendente en el pin CCP1.

0 1 1 0

Modo de captura

Cada cuarto flanco ascendente en el pin CCP1.

0 1 1 1

Modo de captura

Cada decimosexto flanco ascendente en el pin CCP1.

Page 209: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 209

1 0 0 0

Modo de comparación

La salida y el bit CCP1IF se ponen a 1 al ocurrir una coincidencia

1 0 0 1

Modo de comparación

La salida se pone a 0 y el bit CCP1IF se pone a 1 al ocurrir una coincidencia.

1 0 1 0

Modo de comparación

Llega la solicitud de interrupción y el bit CCP1IF se pone a 1 al ocurrir una coincidencia

1 0 1 1

Modo de comparación

El bit CCP1IF se pone a 1, y los registros de temporizadores 1 o 2 se borran al ocurrir una

coincidencia

1 1 0 0

Modo PWM

Pines P1A y P1C están activos a nivel alto. Pines P1B y P1D están activos a nivel alto.

1 1 0 1

Modo PWM

Pines P1A y P1C están activos a nivel alto. Pines P1B y P1D están activos a nivel bajo.

1 1 1 0 Modo PWM

Page 210: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 210

Pines P1A y P1C están activos a nivel bajo. Pines P1B y P1D están activos a nivel alto.

1 1 1 1

Modo PWM

Pines P1A y P1C están activos a nivel bajo. Pines P1B y P1D están activos a nivel bajo.

Page 211: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 211

MÓDULO CCP2

Con exclusión de los nombres diferentes de los registros y de los bits, este

módulo es una muy buena copia del módulo CCP1 puesto en modo normal.

La única diferencia significativa entre ellos es el funcionamiento en modo de

comparación del módulo CCP2. La diferencia se refiere a la señal de

reinicio del temporizador T1. Concretamente, si el convertidor A/D está

habilitado, al igualarse los valores de los registros TMR1 y CCPR2, la señal

de reinicio del temporizador T1 iniciará automáticamente la conversión A/D.

Similar al módulo anterior, este circuito también está bajo el control de los

bits del registro de control. Esta vez es el registro CCP2CON.

Registro CCP2CON

DC2B1, DC2B0 - PWM Duty Cycle Least Significant bits (bits menos

significativos del ciclo de trabajo de PWM) - Se utilizan sólo en modo PWM

y representan dos bits menos significativos de un número de 10 bits. Este

número determina el ciclo de trabajo de la señal PWM. Los demás 8 bits se

almacenan en el registro CCPR2L.

CCP2M3 - CCP2M0 - CCP2 Mode Select bits (bits de selección de modo

del módulo CCP2) determina el modo del módulo CCP2.

Page 212: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 212

C C P 2 M 3 C C P 2 M 2 C C P 2 M 1 C C P 2 M 0 M O D O

0 0 0 0 Módulo está deshabilitado (reinicio).

0 0 0 1 No utilizado.

0 0 1 0 No utilizado.

0 0 1 1 No utilizado.

0 1 0 0

Modo de Captura

Cada flanco descendente en el pin CCP2.

0 1 0 1

Modo de Captura

Cada flanco ascendente en el pin CCP2.

0 1 1 0

Modo de Captura

Cada cuarto flanco ascendente en el pin CCP2.

0 1 1 1

Modo de Captura

Cada decimosexto flanco ascendente en el pin CCP2.

1 0 0 0

Modo de comparación

La salida y el bit CCP2IF se ponen a 1 al ocurrir una coincidencia.

1 0 0 1 Modo de comparación

Page 213: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 213

La salida se pone a 0 y el bit CCP2IF se pone a 1 al ocurrir una coincidencia

1 0 1 0

Modo de comparación

Se produce una interrupción, el bit CCP2IF se pone a 1 y no hay cambio el pin CCP2 pin al ocurrir una

coincidencia.

1 0 1 1

Modo de comparación

Al ocurrir una coincidencia, el bit CCP2IF se pone a 1, los registros del temporizador 1 se borran y la conversión

A/D se inicia si el convertidor A/D está habilitado.

1 1 x x Modo PWM

Page 214: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 214

¿Cómo configurar e iniciar el módulo CCP1 para funcionar en modo

PWM?

Para configurar e iniciar el módulo CCP1 para funcionar en modo PWM,

siga los siguientes pasos:

Deshabilitar el pin de salida del CCP1. Deberá estar configurado

como entrada.

Seleccionar el período de señal PWM al introducir el valor en el

registro PR2.

Configurar el módulo CCP1 para funcionar en modo PWM al combinar

los bits del registro CCP1CON.

Ajustar el ciclo de trabajo de señal PWM al introducir el valor en el

registro CCPR1L y al utilizar los bits DC1B1 y DC1B0 del registro

CCP1CON.

Configurar e iniciar el temporizador Timer2:

o Poner a cero el bit de bandera de interrupción TMR2IF en el

registro PIR1

o Ajustar el valor de división de frecuencia del temporizador

Timer2 por los bits

o T2CKPS1 y T2CKPS0 del registro T2CON.

o Iniciar el temporizador Timer2 al poner a uno el bit TMR2ON del

registro T2CON.

Habilitar los pines de salida de PWM después de que haya sido

acabado un ciclo de PWM:

o Esperar el desbordamiento del temporizador Timer2 (el bit

TMR2IF del registro PIR1 se pone a uno)

o Configurar el pin apropiado como salida al poner a cero el bit en

el registro TRIS.

Page 215: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 215

MÓDULO CCP1 EN MODO MEJORADO

El módulo CCP1 es el único que se puede poner en modo mejorado. Este

modo básicamente no difiere del modo normal del CCP1 y la mejora se

refiere a la transmisión de la señal PWM a los pines de salida. ¿Por qué es

eso tan importante? Por el uso cada vez más frecuente de los

microcontroladores en los sistemas de control de motores eléctricos. Aquí

no vamos a describir estos dispositivos, sin embrago si tiene la oportunidad

de trabajar en el desarrollo de los dispositivos similares, reconocerá los

elementos que se utilizaban hasta hace poco como los periféricos. Decimos

&se utilizaban& porque todos estos elementos ahora están integrados en el

microcontrolador y pueden funcionar en varios modos diferentes.

MODO PWM CON UNA SALIDA

El modo PWM con una salida está habilitado sólo en el caso de que se

pongan a cero los bits P1M1 y P1M0 en el registro CCP1CON. En tal caso,

una señal PWM puede estar disponible simultáneamente en como máximo

cuatro diferentes pines de salida. Además, la secuencia de señales PWM

puede aparecer en forma de onda básica o invertida. La distribución de

señales depende de los bits del registro PSTRCON, mientras que su

polaridad depende de los bits CCP1M1 y CCP1M0 del registro CCP1CON.

Si se utiliza una salida invertida, los pines activos a nivel bajo y los pulsos

que tienen la misma forma de onda se generan siempre en parejas: en los

pines P1A y P1C así como en los pines P1B y P1D, respectivamente.

Page 216: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 216

MODO DE MEDIO-PUENTE

En cuanto al modo de medio-puente, la señal PWM es una salida en el pin

P1A, mientras que a la vez la señal complementaria PWM es una salida en

el pin P1B. Estos pulsos activan a los controladores MOSFET en modo de

Medio-Puente que habilitan/deshabilitan el flujo de corriente por el

dispositivo.

En este modo es muy peligroso encender los controladores MOSFET

simultáneamente (el cortocircuito producido en aquel momento sería fatal).

Para evitarlo, es necesario proporcionar un tiempo muerto entre encender y

apagar los controladores. Este tiempo muerto está marcado con 'td' (time

delay) en la siguiente figura. El problema se resuelve al utilizar los bits

PDC0-PDC6 del registro PWM1CON.

Page 217: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 217

Como se muestra en la siguiente figura, el modo de medio-puente se puede

utilizar para activar los controladores MOSFET en la configuración Puente

completo:

MODO PUENTE-COMPLETO

Todos los cuatro pines se utilizan como salidas en el modo Puente

completo. En la práctica, este modo es utiliza con frecuencia para activar los

motores, lo que proporciona un control simple y completo de velocidad y

dirección de rotación. Hay dos configuraciones de este modo: Full Bridge-

Forward (puente completo con salida directa) y Full Bridge-Reverse (puente

completo con salida inversa).

Page 218: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 218

CONFIGURACIÓN PUENTE COMPLETO - DIRECTO

En modo Directo ocurre lo siguiente:

Un uno lógico (1) aparece en el pin P1A (pin está activo a nivel alto);

Secuencia de pulsos aparece en el pin P1D; y

Un cero lógico (0) en los pines P1B y P1C (pines están activos a nivel

bajo).

La siguiente figura muestra el estado de los pines P1A-P1D durante un ciclo

PWM completo:

Page 219: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 219

CONFIGURACIÓN PUENTE COMPLETO - INVERSO

Lo similar ocurre en modo Inverso, a menos que estos pines dispongan de

funciones diferentes:

Un uno lógico (1) aparece en el pin P1C (pin está activo a nivel alto);

Secuencia de pulsos aparece en el pin P1B; y

Un cero lógico (0) aparece en los pines P1A y P1D (pines están

activos a nivel bajo).

Registro PWM1CON

STRC PWM Restart Enable bit (Bit de habilitación del reinicio

automático del PWM)

Page 220: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 220

1 - Después de un apagado automático, el módulo PWM se reinicia

automáticamente, y el bit ECCPASE del registro ECCPAS se pone a

cero.

0 - Para iciar el módulo PWM después de un apagado automático, el

bit ECCPASE debe ponerse a cero por software.

PDC6 - PDC0 PWM Delay Count bits (Bits de configuración del tiempo

muerto en el modo PWM) - El número binario de 7 dígitos determina el

número de ciclos de in strucciones (4žTosc) añadidos como tiempo muerto

al activar los pines de entrada PWM.

Page 221: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 221

Registro PSTRCON

STRSYNC - Steering Sync bit (bit de sincronización de dirección)

determina el momento de la dirección de los pulsos de PWM:

1 - La dirección ocurre después de que el registro PSTRCION haya

sido cambiado, sólo si se ha completado la forma de onda del PWM.

0 - La dirección ocurre después de que el registro PSTRCION haya

sido cambiado. La señal PWM en la salida del pin será cambiada

inmediatamente sin reparar en si el ciclo anterior ha sido completado.

Este procedimiento es útil cuando es necesario detener la transmisión

de una señal PWM del pin.

STRD - Steering Enable bit D (bit D de habilitación de dirección) determina

la función del pin P1D.

1 - El pin P1D tiene la forma de onda del PWM con polaridad

determinada por los bits CCP1M0 y CCP1M1.

0 - Pin está configurado como entrada/salida general del puerto

PORTD.

STRC Steering Enable bit C (bit C de habilitación de dirección) determina

la función del pin P1C.

1 - El pin P1C tiene la forma de onda del PWM con polaridad

determinada por los bits CCP1M0 y CCP1M1.

0 - Pin está configurado como entrada/salida general del puerto

PORTD.

STRB - Steering Enable bit B (bit B de habilitación de dirección) determina

la función del pin P1B.

Page 222: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 222

1 - El pin P1B tiene la forma de onda del PWM con polaridad

determinada por los bits CCP1M0 y CCP1M1.

0 - Pin está configurado como entrada/salida general del puerto

PORTD.

STRA - Steering Enable bit A (bit A de habilitación de dirección) determina

la función del pin P1A.

1 - El pin P1A tiene la forma de onda del PWM con polaridad

determinada por los bits CCP1M0 y CCP1M1.

0 - Pin está configurado como entrada/salida general del puerto

PORTC.

Registro ECCPAS

ECCPASE - ECCP Auto-Shutdown Event Status bit (bit de estado del

apagado automático) indica si ha ocurrido el apagado automático del

módulo CCP (estado de Apagado):

1 - Módulo CCP está en estado de Apagado.

0 - Módulo CCP funciona normalmente.

ECCPAS2 - ECCPAS0 - ECCP Auto-Shutdown Source Select bits (Bits

de selección de la fuente de apagado automático) selecciona la fuente de

apagado automático.

Page 223: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 223

E C C P A S 2 E C C P A S 1 E C C P A S 0 F U E N T E D E L E S T A D O D E

A P A G A D O

0 0 0 Estado del apagado

deshabilitado

0 0 1 Cambio de salida del

comparador C1

0 1 0 Cambio de salida del

comparador C2

0 1 1 Cambio de salidas de los comparadores C1 y C2

1 0 0 Cero lógico (0) en el pin

INT

1 0 1 Cero lógico (0) en el pin

INT o cambio de salida del comparador C1

1 1 0 Cero lógico (0) en el pin

INT o cambio de salida del comparador C2

1 1 1

Cero lógico (0) en el pin INT o cambio de salidas

de los comparadores C1 y C2

PSSAC1, PSSAC0 - Pins P1A, P1C Shutdown State Control bits (Bits de

configuración de los pines P1A y P1C en modo de apagado) define el

estado lógico de los pines P1A y P1C cuando el módulo CCP está en el

estado de apagado.

P S S A C 1 P S S A C 0 E S T A D O L Ó G I C O D E L O S P I N E S

0 0 0

0 1 1

1 X Alta impedancia (Tri-estado)

PSSBD1, PSSBD0 - Pins P1B, P1D Shutdown State Control bits (Bits de

configuración de los pines P1B y P1D en modo de apagado) define el

estado lógico de los pines P1B y P1D cuando el módulo CCP está en el

estado de apagado.

Page 224: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 224

P S S B D 1 P S S B D 0 E S T A D O L Ó G I C O D E L O S

P I N E S

0 0 0

0 1 1

1 X Alta impedancia (Tri-estado)

El microcontrolador PIC 16F887 dispone de varios módulos de

comunicación serie independientes, además cada uno se puede configurar

a funcionar en modos diferentes. Eso es lo que los hace insustituibles en

muchos casos. Acuérdese de lo que hemos dicho sobre los módulos CCP

ya que lo mismo se aplica aquí. No se preocupe de los detalles del

funcionamiento de todos los módulos, solo seleccione uno y utilice lo que

realmente necesita.

3.8 MÓDULOS DE COMUNICACIÓN SERIE

El USART es uno de los primeros sistemas de comunicación serie. Las

versiones nuevas de este sistema están actualizadas y se les denomina un

poco diferente - EUSART.

EUSART

El módulo Transmisor/Receptor Universal Síncrono/Asíncrono mejorado

(Enhanced Universal Synchronous Asynchronous Receiver Transmitter -

EUSART) es un periférico de comunicación serie de entrada/salida.

Asimismo es conocido como Interfaz de comunicación serie (Serial

Communications Interface - SCI). Contiene todos los generadores de

señales de reloj, registros de desplazamiento y búfers de datos necesarios

Page 225: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 225

para realizar transmisión de datos serie de entrada/salida,

independientemente de la ejecución de programa del dispositivo. Como

indica su nombre, aparte de utilizar el reloj para la sincronización, este

módulo puede establecer la conexión asíncrona, lo que lo hace único para

algunas aplicaciones. Por ejemplo, en caso de que sea difícil o imposible

proporcionar canales especiales para transmisión y recepción de datos y

señales de reloj (por ejemplo, mando a distancia de radio o infrarrojas), el

módulo EUSART es definitivamente la mejor opción posible.

El EUSART integrado en el PIC16F887 posee las siguientes características:

Transmisión y recepción asíncrona en modo Full-duplex;

Caracteres de anchura de 8 – 9 bits programables;

Detección de dirección en modo de 9 bits;

Detección de errores por saturación del búfer de entrada; y

Comunicación Half Duplex en modo síncrono.

EUSART EN MODO ASÍNCRONO

El EUSART transmite y recibe los datos utilizando la codificación de no

retorno a cero - NRZ (non-return-to-zero). Como se muestra en la siguiente

figura, no se utiliza una señal de reloj y los datos se transmiten de forma

muy simple:

Cada dato se transmite de la siguiente forma:

En estado inactivo la línea de datos permanece en estado alto (1);

Cada transmisión de datos comienza con un bit de arranque (START),

el cual, siempre es cero (0);

Page 226: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 226

Cada dato tiene un ancho de 8 o 9 bits (primero se transmite el bit

menos significativo - LSB); y

Cada transmisión de datos termina con un bit de parada (STOP), el

cual, siempre es uno (1) La siguiente figura muestra cómo conectar de

manera habitual un microcontrolador PIC que utiliza el módulo

EUSART. El circuito RS-232 se utiliza como un convertidor de nivel de

voltaje.

Figure below shows a common way of connecting PIC microcontroller that

uses EUSART module. The RS-232 circuit is used as a voltage level

converter.

Page 227: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 227

EUSART EN MODO DE TRANSMISOR ASÍNCRONO

Para habilitar la transmisión de datos por medio del módulo EUSART, es

necesario configurarlo para que funcione como un transmisor. En otras

palabras, es necesario definir el estado de los siguientes bits:

TXEN = 1 - El transmisor EUSART se habilita al poner a uno el bit

TXEN del registro TXSTA.

SYNC = 0 - El EUSART se configura a funcionar en modo asíncrono

al poner a cero el bit SYNC del registro TXSTA.

SPEN = 1 - Al poner a uno el bit SPEN del registro RCSTA, el

EUSART está habilitado y el pin TX/CK se configura automáticamente

como salida. Si el bit se utiliza simultáneamente para alguna función

analógica, se debe deshabilitar al poner a cero el bit correspondiente

del registro ANSEL.

La parte central del transmisor EUSART ocupa el registro de

desplazamiento TSR que no está directamente disponible al usuario. Para

iniciar la transmisión de datos, el módulo debe estar habilitado al poner a

uno el bit TXEN del registro TXSTA. Los datos a enviar se deben escribir en

el registro TXREG, lo que resultará en la siguiente secuencia de eventos:

Page 228: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 228

Byte será transmitido inmediatamente al registro de desplazamiento

TSR;

El registro TXREG permanece vacío, lo que indica la bandera de bit

TXIF del registro PIR1. Si se pone a uno el bit TXIE del registro PIE1,

se generará una interrupción. De todos modos, la bandera se pone a

uno sin reparar en si una interrupción está habilitada o no y no se

puede poner a cero por software, sino al escribir un dato nuevo en el

registro TXREG.

Dispositivos electrónicos de control "empujan" el dato hacia el pin TX

en sincronización con señal de reloj interna: bit de arranque (START)

(1).....datos....bit de parada (STOP) (1).

Cuando el último bit abandona el registro TSR, el bit TRMT en el

registro TXSTA se pone a cero automáticamente.

Si mientras tanto se escribe un dato nuevo en el registro TXREG, todo

el procedimiento se repite inmediatamente después de la transmisión

del bit de parada del dato anterior.

Para transmitir un dato de 9 bits es necesario poner a uno el bit TX9 del

registro TXSTA. El bit TX9D del registro TXSRTA es el noveno bit y el más

significativo. Al transmitir un dato de 9 bits, el bit de datos TX9D deberá

estar escrito antes de que de se escriban los 8 bits menos significativos en

el registro TXREG. Todos los nueve bits de datos se transmiten al registro

de desplazamiento TFR inmediatamente después de que se acabe la

escritura en el registro TXREG.

Page 229: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 229

EUSART EN MODO DE RECEPTOR ASÍNCRONO

Similar al poner en marcha el transmisor del EUSART, para habilitar el

receptor es necesario configurar los siguientes bits:

CREN = 1 - El receptor EUSART se habilita al poner a uno el bit

CREN del registro RCSTA;

SYNC = 0 - El EUSART se configura a funcionar en modo asíncrono

al poner a cero el bit SYNC del registro TXSTA; y

SPEN = 1 - Al poner a uno el bit SPEN del registro RCSTA, el

EUSART está habilitado y el pin RX/DT se configura automáticamente

como salida. Si el bit se utiliza simultáneamente para alguna función

analógica, se debe desha bilitar al poner a cero el bit correspondiente

del registro ANSEL.

Después de que se haya terminado el primer paso necesario y se haya

detectado el bit de arranque (START), el dato se transmite al registro de

desplazamiento RSR por el pin RX. Al haber recibido el bit de parada

(STOP), ocurre lo siguiente:

El dato se transmite automáticamente al registro RCREG (si está

vacío);

Page 230: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 230

El bit de bandera RCIF se pone a uno y ocurre una interrupción si está

habilita da por el bit RCIE en el registro PIE1. Similar al transmisor, el

bit de bandera se pone a cero sólo por software, o sea, al leer el

registro RCREG. Tenga en cuenta que esto es un doble registro de

tipo FIFO (primero en entrar, primero en salir - first-in, first-out), lo que

permite almacenamiento de dos caracteres simultáneamente);

Si el registro RCREG está ocupado (contiene dos bytes) y el registro

de desplazamiento detecta el nuevo bit de parada (STOP), el bit de

sobrescritura OERR se pondrá a uno. En tal caso se pierde un dato

nuevo que viene, y el bit OERR debe ponerse a cero por software al

poner a cero y luego al poner a uno el bit CREN;

Nota: No es posible recibir un dato nuevo sino hasta que el bit

OERR esté a uno.

Si el bit de parada (STOP) está a cero (0), el bit FERR del registro

RCSTA estará a uno, lo que indica un error en recepción; y

Para habilitar la recepción de un dato de 9 bits, es necesario poner a

uno el bit RX9 del registro RCSTA.

DETECCIÓN DE ERRORES EN RECEPCIÓN

El microcontrolador puede detectar automáticamente dos tipos de errores.

El primero es denominado error de encuadre (Framing error). Ocurre

cuando el receptor no detecta el bit de parada en un intervalo

predeterminado de tiempo. Este error se indica mediante el bit FERR del

registro RCSTA. Si el bit está a uno, el último dato recibido puede ser

incorrecto. Cabe destacar lo siguiente:

El error de encuadre no genera por si mismo una interrupción;

Si el bit está a uno, el último dato recibido contiene un error;

El error de encuadre (bit está a uno) no impide la recepción de un

dato nuevo;

El bit FERR se pone a cero al leer el dato recibido, lo que significa que

se debe hacer una verificación antes de leer el dato; y

Page 231: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 231

El bit FERR no se puede poner a cero por software. Si es necesario,

se puede borrar al poner a cero al bit SPEN del registro RCSTA, lo

cual, simultáneamente causa una reinicialización del sistema

EUSART.

Otro tipo de error es denominado error de sobrescritura (Overrun Error).

Como hemos mencionado anteriormente, el registro de tipo FIFO puede

almacenar sólo dos caracteres. Un error de sobrescritura ocurre cuando el

registro recibe el tercer carácter. Simplemente no hay espacio para

almacenar un byte más, por lo que un error es inevitable. Cuando ocurre

este error, el bit OERR del registro RCSTA se pone a uno. Las

consecuencias son las siguientes:

Los datos almacenados en los registros FIFO (2 bytes) se pueden leer

normalmente;

No se recibirán más datos hasta que el bit OERR esté puesto a cero;

y

A este bit no se le puede acceder directamente. Para borrarlo, es

necesario poner a cero el bit CREN del registro RCSTA o reiniciar el

sistema EUSART al poner a cero al bit SPEN del registro RCSTA.

RECEPCIÓN DE DATOS DE 9 BITS

Aparte de recibir los datos de forma estándar de 8 bits, el sistema EUSART

soporta la recepción de datos de 9 bits. En el lado del transmisor, el noveno

bit “se adjunta” al byte original directamente antes del bit de parada. En el

lado del receptor, al poner a uno el bit RX9 del registro RCSTA, el noveno

bit de datos será automáticamente escrito en el bit RX9D del mismo

registro. Después de almacenar este byte, es necesario tener cuidado en

como leer estos bits - primero se debe leer el bit RX9D y luego los ocho (8)

bits menos significativos del registro RCREG. De otra forma, el noveno bit

será puesto a cero antes de ser leído.

Page 232: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 232

DETECCIÓN DE DIRECCIÓN

Cuando el bit ADDEN del registro RCSTA está a uno, el modulo EUSART

es capaz de recibir sólo los datos de 9 bits, mientras que se ignoran todos

los datos de 8 bits. Aunque parece una restricción, este modo habilita la

comunicación serial entre varios microcontroladores. El principio de

funcionamiento es muy simple. El dispositivo maestro envía un dato de 9

bits que representa la dirección de un microcontrolador esclavo. No

obstante, todos deben tener el bit ADDEN puesto a uno, ya que de esta

manera se habilita la detección de dirección. Todos los microcontroladores

esclavos que comparten la misma línea de transmisión, reciben este dato

(dirección) y verifican automáticamente si coincide con su propia dirección.

El software, en el que ocurre la coincidencia de dirección, debe deshabilitar

la detección de dirección, poniendo a cero el bit ADDEN.

Page 233: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 233

El dispositivo maestro sigue enviando los datos de 8 bits al

microcontrolador. Todos los datos que pasan por la línea de transmisión

serán recibidos sólo por el módulo EUSART direccionado. Una vez recibido

el último byte, el microcontrolador esclavo debe poner a uno el bit ADDEN

para habilitar de nuevo la detección de dirección.

Registro TXSTA

Page 234: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 234

CSRC - Clock Source Select bit - (bit de selección de la fuente de reloj)

determina la fuente del reloj. Se utiliza sólo en modo sincrónico.

1 - Modo Maestro. Reloj generado internamente por el generador de

tasa de baudios.

0 - Modo Esclavo. Reloj proveniente de una fuente externa.

TX9 - 9-bit Transmit Enable bit (bit de habilitación del modo de 9 bits

en transmisión)

1 - Se habilita el modo de 9 bits en transmisión por el sistema

EUSART.

0 - Se habilita el modo de 8 bits en transmisión por el sistema

EUSART.

TXEN - Transmit Enable bit (Bit de habilitación de transmisión)

1 - Transmisión habilitada.

0 - Transmisión deshabilitada.

SYNC - EUSART Mode Select bit (Bit de selección del modo EUSART)

1 - El EUSART funciona en modo síncrono.

0 - El EUSART funciona en modo asíncrono.

SENDB - Send Break Character bit (Bit de envío de carácter Break en

modo asíncrono) se utiliza sólo en modo asíncrono y cuando se requiere

obedecer el estándar de bus LIN.

1 - Se enviará un carácter Break en la próxima transmisión (se pone a

0 por hardware cuando finaliza el envío).

0 - Envío del carácter de transmisión Break completado.

BRGH - High Baud Rate Select bit (bit de selección de modo de alta

velocidad en modo asíncrono). Determina la velocidad de transmisión en

modo síncrono. No afecta al EUSART en modo síncrono.

1 - EUSART funciona a alta velocidad.

0 - EUSART funciona a baja velocidad.

TRMT - Transmit Shift Register Status bit (bit de estado de registro de

desplazamiento de transmisión)

1 - Registro TSR está vacío.

0 - Registro TSR está lleno.

Page 235: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 235

TX9D - Ninth bit of Transmit Data (Valor del noveno bit en transmisión)

Puede ser utilizado como dirección o bit de paridad o para distinguir entre

dirección o dato en los buses maestro-esclavo).

Registro RCSTA

SPEN - Serial Port Enable bit (bit de habilitación del puerto serie)

1 - Puerto serie habilitado. Los pines RX/DT y TX/CK se configuran

automáticamente como entrada y salida, respectivamente.

0 - Puerto serie deshabilitado.

RX9 - (bit de habilitación del modo de 9 bits en recepción):

1 - Se habilita la recepción de datos de 9 bits por medio del sistema

EUSART.

0 - Se habilita la recepción de datos de 8 bits por medio del sistema

EUSART.

SREN - Single ReceiveEnable bit (bit de habilitación de la recepción

simple). Es utilizado sólo en modo sincrónico y en funcionamiento como

Maestro.

1 - Recepción simple habilitada.

Page 236: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 236

0 - Recepción simple deshabilitada.

CREN - Continuous Receive Enable bit (bit de habilitación de la recepción

continua) actúa dependiendo del modo EUSART.

Modo asíncrono:

1 - Recepción habilitada.

0 - Recepción deshabilitada.

Modo síncrono:

1 - Se habilita la recepción continua hasta que el bit CREN esté a

cero.

0 - No se habilita la recepción en forma continua.

ADDEN - Address Detect Enable bit (bit de habilitación de la detección de

dirección) se utiliza sólo en modo de detectar la dirección.

1 - Habilita la detección de dirección (sólo se procesa un byte recibido

en el registro de desplazamiento de recepción si el noveno bit está a

uno)

0 - Detección de dirección deshabilitada (todos los bytes recibidos en

el registro de desplazamiento de recepción son procesados

independientemente del valor del noveno bit recibido). El noveno bit

se utiliza como bit de paridad.

FERR - Framing Error bit (bit de error de encuadre)

1 - Se ha producido un error de encuadre en recepción.

0 - No se ha producido un error de encuadre.

OERR - Overrun Error bit (bit de error de sobrescritura).

1 - Se ha producido un error de sobrescritura en recepción.

0 - No se ha producido un error de sobrescritura.

RX9D - Ninth bit of Received Data No se ha producido un error de

sobrescritura.

Page 237: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 237

GENERADOR DE BAUDIOS DEL EUSART (BRG)

Si mira atentamente al diagrama del receptor o transmisor EUSART

asíncrono, verá que los ambos utilizan señal de reloj del temporizador local

BRG para la sincronización. La misma fuente de reloj se utiliza también en

modo síncrono.

El temporizador BRG consiste en dos registros de 8 bits haciendo un

registro de 16 bits.

El valor de un número escrito en estos dos registros determinará la

velocidad de transmisión en baudios. Adicionalmente, el bit BRGH del

registro TXSTA y el bit BRGH16 del registro BAUDCTL, afectan la

frecuencia de reloj utilizada para el cálculo de los baudios.

El valor de un número escrito en estos dos registros determinará la

velocidad de transmisión en baudios. Adicionalmente, el bit BRGH del

registro TXSTA y el bit BRGH16 del registro BAUDCTL, afectan la

frecuencia de reloj utilizada para el cálculo de los baudios.

Page 238: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 238

B I T S M O D O B R G /

E U S A R T

F Ó R M U L A D E V E L O C I D A D D E T R A N S M I S I Ó N E N B A U D I O S

SYNC BRG1G BRGH

0 0 0 de 8 bits

/asíncrono Fosc / [64 (n + 1)]

0 0 1 de 8 bits / asíncrono

Fosc / [16 (n + 1)]

0 1 0 de 16 bits / asíncrono

Fosc / [16 (n + 1)]

0 1 1 de 16 bits / asíncrono

Fosc / [4 (n + 1)]

1 0 X de 8 bits / síncrono

Fosc / [4 (n + 1)]

1 1 X de 16 bits / síncrono

Fosc / [4 (n + 1)]

Las tablas en las siguientes páginas contienen los valores que deben estar

escritos en el registro de 16 bits SPBRG y asignados a los bits SYNC,

BRGH y BRGH16 para obtener algunos valores de la velocidad de

transmisión en baudios estándar. La fórmula para hacer el cálculo de la

velocidad de transmisión en baudios:

Page 239: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 239

Page 240: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 240

Registro BAUDCTL

ABDOVF - Auto-Baud Detect Overflow bit (bit de desbordamiento de

auto-detección de la velocidad de transmisión) se utiliza sólo en modo

asíncrono durante la detección de la velocidad de transmisión.

Page 241: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 241

1 - Se ha producido desbordamiento durante la auto-detección.

0 - No se ha producido desbordamiento durante la auto-detección.

RCIDL - Receive Idle Flag bit No se ha producido desbordamiento durante

la auto-detección.

1 - Receptor en estado inactivo. No hay operación de recepción en

marcha.

0 - Se ha recibido el bit de arranque (START) y hay una operación de

recepción en marcha.

SCKP - Synchronous Clock Polarity Select bit. (bit de selección de

polaridad de la señal de reloj en modo síncrono). El estado lógico de este bit

difiere dependiendo de cuál modo de EUSART está activo

Modo asíncrono:

1 - El dato invertido se transmite al pin RC6/TX/CK.

0 - El dato no invertido se transmite al pin RC6/TX/CK.

Modo síncrono:

1 - Sincronización en el flanco ascendente de la señal de reloj.

0 - Sincronización en el flanco descendente de la señal de reloj.

BRG16 16-bit Baud Rate Generator bit - (bit de habilitación del generador

de velocidad de transmisión de 16 bits) determina si el registro SPBRGH se

utilizará, o sea si el temporizador BGRG tendrá 8 o 16 bits.

1 - Se utiliza el generador de velocidad de transmisión de 16 bits

0 - Se utiliza el generador de velocidad de transmisión de 8 bits

WUE Wake-up Enable bit (bit de habilitación del modo de auto-activación

en modo asíncrono):

1 - Modo de auto-activación habilitado. El receptor espera a que el

flanco descendente aparezca en el pin RC7/RX/DT para que el

microcontrolador se despierte del modo de reposo.

0 - Modo de auto-activación habilitado. El receptor funciona

normalmente.

Page 242: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 242

ABDEN - Auto-Baud Detect Enable bit (bit de habilitación de auto-

detección de velocidad de transmisión) se utiliza sólo en modo asíncrono.

1 - Modo de auto-detección habilitado. Al detectar la velocidad de

transmisión, el bit se pone a uno automáticamente.

0 - Modo de auto-detección deshabilitado.

Vamos a hacerlo en mikroC...

/* En este ejemplo, el módulo EUSART interno se inicializa y se ajusta

para enviar el

mensaje inmediatamente después de recibirlo. La velocidad de

transmisión en baudios se

ajusta a 9600 bps. El programa utiliza las siguientes rutinas de librería

UART:

UART1_init(), UART1_Write_Text(), UART1_Data_Ready(),

UART1_Write() y UART1_Read().*/

char uart_rd;

void main() {

ANSEL = ANSELH = 0; // Todos los pines se configuran como

digitales

C1ON_bit = C2ON_bit = 0; // Deshabilitar los comparadores

UART1_Init(9600); // Inicializar el módulo UART a 9600 bps

Delay_ms(100); // Esperar a que señal de reloj del módulo

UART se

// ponga estable

UART1_Write_Text("Start");

while (1) { // Bucle infinito

if (UART1_Data_Ready()) { // Si el dato se ha recibido,

uart_rd = UART1_Read(); // lea el dato recibido

Page 243: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 243

UART1_Write(uart_rd); // y envíelo atrás por el UART

}

}

}

Transmisión serial asíncrona a través de los registros del módulo

EUSART

1. La velocidad de transmisión deseada deberá estar ajustada a través de

los bits BRGH (del registro TXSTA) y BRG16 (del registro BAUDCTL) y

de los registros SPBRGH y SPBRG.

2. La velocidad de transmisión deseada deberá estar ajustada a través de

los bits BRGH (del registro TXSTA) y BRG16 (del registro BAUDCTL) y

de los registros SPBRGH y SPBRG.

3. La velocidad de transmisión deseada deberá estar ajustada a través de

los bits BRGH (del registro TXSTA) y BRG16 (del registro BAUDCTL) y

de los registros SPBRGH y SPBRG.

4. La transmisión de datos es habilitada poniendo a uno el bit TXEN del

registro TXSTA. El bit TXIF del registro PIR1 está automáticamente

puesto a uno.

5. Para que el bit TXEN cause una interrupción, tanto el bit TXIE del

registro PIE1 como los bits GIE, PEIE del registro INTCON deberán

estar puestos a uno.

6. En una transmisión de datos de 9 bits, el valor del noveno bit deberá

estar escrito en el bit TX9D del registro TXSTA.

7. La transmisión comienza cuando se escribe el dato de 8 bits sobre el

registro de recepción TXREG.

Page 244: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 244

Recepción serial asíncrona a través de los registros del módulo

EUSART:

1. La velocidad de transmisión deseada deberá estar ajustada a través de

los bits BRGH (del registro TXSTA) y BRG16 (del registro BAUDCTL) y

de los registros SPBRGH y SPBRG.

2. El bit SYNC (del registro TXSTA) deberá estar puesto a cero y el bit

SPEN (del registro RCSTA) deberá estar puesto a uno a fin de habilitar

el puerto serie.

3. Tanto el bit RCIE del registro PIE1 como los bits GIE y PEIE del registro

INTCON deberán estar puestos a uno si se necesita habilitar que la

recepción de dato cause una interrupción.

4. Para una recepción de datos de 9 bits, el bit RX9 (del registro RCSTA)

deberá estar puesto a uno

5. La recepción de datos es habilitada poniendo a uno el bit CREN del

registro RCSTA.

6. El registro RCSTA deberá leerse para obtener información acerca de la

ocurrencia de errores durante la recepción. El valor del noveno bit será

almacena do en este registro en la recepción de datos de 9 bits.

7. El dato de 8 bits recibido será almacenado en el registro RCREG y

deberá leerse para obtener dicho dato.

Ajustar el modo de detección de dirección:

1. La velocidad de transmisión deseada deberá estar ajustada a través de

los bits BRGH (del registro TXSTA) y BRG16 (del registro BAUDCTL) y

de los registros SPBRGH y SPBRG.

Page 245: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 245

2. El bit SYNC (del registro TXSTA) deberá estar puesto a cero y el bit

SPEN (del registro RCSTA) deberá estar puesto a uno (1) a fin de

habilitar el puerto serie.

3. Tanto el bit RCIE del registro PIE1 como los bits GIE y PEIE del registro

INTCON deberán estar puestos a uno si se necesita habilitar que la

recepción de dato cause una interrupción.

4. El bit RX9 del registro RCSTA debe estar a uno.

5. El bit ADDEN del registro RCSTA debe estar a uno, lo que habilita que

un dato sea reconocido como dirección.

6. La recepción de datos es habilitada poniendo a uno el bit CREN del

registro RCSTA.

7. Tan pronto como se reciba un dato de 9 bits, el bit RCIF del registro

PIR1 estará automáticamente puesto a uno. Si está habilitada se

produce una interrupción.

8. El registro RCSTA deberá leerse para obtener información acerca de la

ocurrencia de errores durante la transmisión. El noveno bit RX9D

siempre estará a uno.

9. El dato de 8 bits recibido será almacenado en el registro RCREG y

deberá leerse. Se deberá comprobar si la combinación de estos bits

coincide con la dirección predefinida. Si coincide, es necesario poner a

cero el bit ADDEN del registro RCSTA, lo que habilita la recepción de

datos de 8 bits.

MÓDULO PUERTO SERIE SÍNCRONO MAESTRO (MSSP)

El MSSP (Puerto serie síncrono maestro - Master Synchronous Serial Port)

es un módulo muy útil, y a la vez uno de los circuitos más complejos dentro

del microcontrolador. Este módulo permite la comunicación de alta

velocidad entre un microcontrolador y otros periféricos u otros

microcontroladores al utilizar varias líneas de E/S (como máximo dos o tres

líneas). Por eso, se utiliza con frecuencia para conectar el microcontrolador

Page 246: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 246

a los visualizadores LCD, los convertidores A/D, las memorias EEPROM

seriales, los registros de desplazamiento etc. La característica principal de

este tipo de comunicación es que es síncrona y adecuada para ser utilizada

en sistemas con un sólo maestro y uno o más esclavos. Un dispositivo

maestro contiene un circuito para generación de baudios y además,

suministra señales de reloj a todos los dispositivos del sistema. Los

dispositivos esclavos no disponen de un circuito interno para generación de

señales de reloj. El módulo MSSP puede funcionar en uno de dos modos:

modo SPI (Interfaz periférica serial - Serial Peripheral Interface); y

modo I2C (Circuito inter-integrado - Inter-Integrated Circuit).

Como se muestra en la siguiente figura, un módulo MSSP representa sólo

una mitad de un hardware necesario para establecer una comunicación

serial, mientras que la otra mitad se almacena en el dispositivo con el que

intercambia los datos. Aunque los módulos en ambas puntas de línea son

los mismos, sus modos de funcionamiento difieren esencialmente

dependiendo de si el módulo funciona como Maestro o como Esclavo:

Si el microcontrolador a ser programado controla otro dispositivo o circuito

(periféricos), deberá funcionar como un dispositivo maestro. Este módulo

generará señal de reloj cuando sea necesario, o sea sólo cuando se

requiera recibir y transmitir los datos por software. Por consiguiente, el

establecimiento de conexión depende únicamente del dispositivo maestro.

De lo contrario, si el microcontrolador a ser programado está integrado en

un dispositivo más complejo (por ejemplo en una PC), deberá funcionar

Page 247: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 247

como un dispositivo esclavo. Como tal, un esclavo siempre tiene que

esperar a que un dispositivo maestro envíe la solicitud de transmisión de

datos.

MODO SPI

El modo SPI permite la transmisión y recepción simultánea de datos de 8

bits al utilizar tres líneas de entrada/salida

SDO - Serial Data Out (salida de datos serie )- línea de transmisión;

SDI - Serial Data In (entrada de datos serie) - línea de recepción; y

SCK - Serial Clock (reloj de comunicación) - línea de sincronización.

Adicionalmente, hay una cuarta línea (SS) que se puede utilizar si el

microcontrolador intercambia los datos con varios dispositivos periféricos.

Refiérase a la siguiente figura.

SS - Slave Select (Selección de esclavo) - Es una línea adicional utilizada

para la selección de un dispositivo específico. Esta línea está activa sólo si

el microcontrolador funciona como esclavo, o sea cuando el dispositivo

externo - maestro requiere intercambiar los datos. Al funcionar en modo

SPI, el módulo MSSP utiliza 4 registros en total:

SSPSTAT - registro de estado

SSPCON - registro de control

SSPBUF - búfer serie de transmisión/recepción

SSPSR - registro de desplazamiento (no es accesible directamente)

Los primeros tres registros son de lectura/escritura y se pueden modificar

en cualquier momento, mientras que el cuarto, como no es accesible, se

utiliza para convertir datos en formato serial.

Page 248: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 248

Como se muestra en la siguiente figura, la parte central del módulo SPI

consiste de dos registros conectados a los pines para recepción,

transmisión y sincronización.

El registro de desplazamiento (SSPRS) está directamente conectado a los

pines del microcontrolador y es utilizado para transmisión de datos en

formato serie. El registro SSPRS dispone de la entrada y salida para

desplazar los datos hacia dentro y hacia fuera del dispositivo. En otras

palabras, cada bit que aparece en la entrada (línea de recepción) desplaza

simultáneamente otro bit hacia la salida (línea de transmisión).

El registro SSPBUF (Búfer) es una parte de memoria utilizada para

almacenar temporalmente los datos antes de que se envíen, o sea

inmediatamente después de que se reciban. Después de que todos los 8

bits hayan sido recibidos, el byte se mueve del registro SSPRS al registro

SSPBUF. Este proceso de crear un doble búfer para recibir los datos

permite iniciar la recepción del próximo byte antes de leer los datos que se

acaban de recibir. Durante la transmisión/recepción de datos se ignora un

intento de escribir un dato en el registro SSBUF. Desde el punto de vista de

un programador, este registro se considera el más importante por haber

sido accedido con más frecuencia. Concretamente, si dejamos aparte el

ajuste del modo de funcionamiento, la transmisión de datos por el módulo

SPI no es nada más que escritura y lectura de datos de este registro,

Page 249: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 249

mientras que las demás “acrobacias” como mover los registros, se llevan a

cabo automáticamente por el hardware.

Vamos a hacerlo en mikroC...

/* En este ejemplo, el microcontrolador PIC (maestro) envía un byte de

datos a un chip

periférico (esclavo) por el módulo SPI. El programa utiliza las funciones

de librería

SPI SPI1_init() y SPI1_Write. */

sbit Chip_Select at RC0_bit; // Pin RC0 es un pin de seleccionar

el chip

// periférico Selección_de_chip

sbit Chip_Select_Direction at TRISC0_bit; // Bit TRISC0 define el pin RC0

como entrada o salida

unsigned int value; // Dato a ser enviado es de tipo

unsigned int

void main() {

ANSEL = ANSELH = 0; // Todos los pines de E/S son digitales

TRISB0_bit = TRISB1_bit = 1; // Configurar los pines RB0, RB1 como

entradas

Chip_Select = 0; // Seleccionar el chip periférico

Chip_Select_Direction = 0; // Configurar el pin CS# como salida

SPI1_Init(); // Inicializar el módulo SPI

SPI1_Write(value); // Envíar el valor al chip periférico

...

Page 250: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 250

Comunicación serial síncrona SPI

Antes de inicializar el módulo SPI, es necesario especificar varias opciones:

Modo maestro TRISC.3=0 (pin SCK es salida de señal de reloj);

Modo de esclavo TRISC.3=1 (pin SCK es entrada de señal de reloj);

Fase de datos de entrada - la mitad o el final del tiempo de salida (bit

SMP del registro SSPSTAT );

Flanco de reloj (bit CKE del registro SSPSTAT);

Velocidad de transmisión en baudios, los bits SSPM3-SSPM0 del

registro SSPCON (sólo en modo Maestro);

Selección de modo esclavo, bits SSPM3-SSPM0 del registro

SSPCON (sólo en modo Esclavo)

El módulo se pone en marcha al poner a uno el bit SSPEN:

Paso 1.

Los datos a ser transmitidos deberán ser escritos en el registro del búfer

SSPBUF. Si el módulo SPI funciona en modo maestro, el microcontrolador

ejecutará automáticamente la secuencia de los siguientes pasos 2,3 y 4. Si

el módulo SPI funciona en modo esclavo, el microcontrolador no ejecutará

la secuencia de los siguientes pasos hasta que el pin SCK detecte señal de

reloj.

Paso 2.

El dato se mueve al registro SSPSR y el contenido del registro SSPBUF no

se borra.

Page 251: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 251

Paso 3.

El dato se desplaza hacia el pin de salida (primero se desplaza el bit más

significativo - MSB), mientras que a la vez el registro se carga con los bits

por el pin de entrada. En modo maestro el microcontrolador en si mismo

genera señal de reloj, mientras que el modo esclavo utiliza señal de reloj

externa (pin SCK).

Paso 4.

El registro SSPSR está lleno después de que hayan sido recibidos 8 bits de

datos, lo que se indica al poner a uno el bit BF del registro SSPSTAT y el bit

SSPIF del registro PIR1. Los datos recibidos (un byte) son automáticamente

movidos del registro SSPSR al registro SSPBUF. Como la transmisión de

datos serial se realiza automáticamente, el resto de programa se ejecuta

normalmente mientras que la transmisión de datos está en progreso. En

este caso, la función del bit SSPIF es de generar una interrupción al acabar

la transmisión de un byte.

Paso 5.

Por último, el dato almacenado en el registro SSPBUF está listo para su uso

y debe moverse al registro deseado.

Modo I2C

El modo I2C (Bus de circuito inter-integrado) es adecuado para ser utilizado

cuando el microcontrolador debe intercambiar los datos con un circuito

integrado dentro de un mismo dispositivo. Éstos son con frecuencia otros

microcontroladores, o los circuitos integrados especializados y baratos que

Page 252: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 252

pertenecen a la nueva generación de así llamados "periféricos inteligentes"

(memorias, sensores de temperatura, relojes de tiempo real etc.)

Similar a la comunicación serie en modo SPI, la transmisión de datos en

modo I2C es síncrona y bidireccional. Esta vez sólo dos pines se utilizan

para transmisión de datos. Éstos son los pines de SDA (Datos seriales) y

SCL (Reloj serial). El usuario debe configurar estos pines como entradas o

salidas por los bits TRISC.

Al observar las reglas particulares (protocolos), este modo habilita conectar

simultáneamente de una manera simple hasta 112 diferentes componentes

al utilizar sólo dos valiosos pines de E/S. Vamos a ver cómo funciona el

sistema:

El reloj, necesario para sincronizar el funcionamiento de ambos dispositivos,

siempre es generado por un dispositivo maestro (un microcontrolador) y su

frecuencia directamente afecta a la velocidad de transmisión de datos.

Aunque hay un protocolo que permite como máximo una frecuencia de reloj

de 3,4 MHz (así llamado bus I2C de alta velocidad), este libro cubre sólo el

protocolo utilizado con más frecuencia, con una frecuencia de reloj limitada

a 100 KHz. La frecuencia mínima no está limitada.

Cuando los componentes maestro y esclavo están sincronizados por el

reloj, el maestro siempre inicia cada intercambio de datos. Una vez que el

módulo MSSP se ha habilitado, espera que ocurra una condición de

arranque (Start condition). El dispositivo maestro primero envía el bit de

arranque (está a cero) por el pin SDA, luego la dirección de 7 bits del

dispositivo esclavo seleccionado, y por último, el bit que requiere al

dispositivo escribir (0) o leer (1) el dato enviado. En otras palabras, los ocho

bits se desplazan al registro SSPSR después de ocurrir una condición de

arranque. Todos los dispositivos esclavos que comparten la misma línea de

transmisión recibirán simultáneamente el primer byte, pero sólo el que

contiene la dirección coincidente recibirá el dato entero.

Page 253: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 253

Una vez que el primer byte se ha enviado (sólo se transmiten datos de 8

bits), el maestro se pone en modo de recepción y espera el reconocimiento

del dispositivo receptor acerca de la dirección coincidente.

Si el dispositivo esclavo envía un bit de reconocimiento (1) la transmisión de

datos continuará hasta que el dispositivo maestro (microcontrolador) envíe

el bit de parada (Stop).

Esto es una explicación simple de cómo se comunican dos componentes.

Este microcontrolador es capaz de controlar las situaciones más

complicadas cuando están conectados 1024 diferentes componentes

(dirección de 10 bits), compartidos por varios dispositivos maestros

diferentes. Por supuesto, estos dispositivos se utilizan pocas veces en la

práctica por lo que no es necesario hablar de ellos detalladamente.

Page 254: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 254

La siguiente figura muestra el diagrama de bloques del módulo MDSSP en

modo I2C.

En una operación I2C con el módulo MSSP intervienen seis registros.

Algunos de ellos se muestran en la Figura anterior.

SSPCON

SSPCON2

SSPSTAT

SSPBUF

SSPSR

SSPADD

Page 255: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 255

Registro SSPSTAT

SMP Sample bit (Bit de muestra)

Modo maestro SPI - Este bit determina fase de datos de entrada.

1 - Estado lógico se lee al final del tiempo de salida.

0 - Estado lógico se lee en la mitad del tiempo de salida.

Modo esclavo SPI - Este bit debe ser borrado cuando SPI se emplea en

modo esclavo.

Modo I²C (maestro o esclavo)

1 - Deshabilita control de variaciones para velocidad estándar

(100kHz).

0 - Habilita control de variaciones para velocidad alta (400k Hz).

CKE - Clock Edge Select bit (bit de selección del flanco de reloj)

selecciona el modo de sincronización.

CKP = 0:

1 - Dato transmitido en flanco ascendente de pulso de reloj (0 - 1).

0 - Dato transmitido en flanco descendente de pulso de reloj (1 - 0).

CKP = 1:

1 - Dato transmitido en flanco descendente de pulso de reloj (1 - 0).

0 - Dato transmitido en flanco ascendente de pulso de reloj (0 - 1).

D/A - Data/Address bit (bit de direcciones/datos) se utiliza sólo en modo

I2C.

1 - Indica que el último byte recibido o transmitido es un dato.

0 - Indica que el último byte recibido o transmitido es una dirección.

P - Stop bit (bit de parada) se utiliza sólo en modo I²C.

1 - Bit de parada (STOP) se ha detectado.

Page 256: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 256

0 - Bit de parada (STOP) no se ha detectado.

S - Start bit (bit de arranque) se utiliza sólo en modo I2C.

1 - Bit de arranque (START) se ha detectado.

0 - Bit de arranque (START) no se ha detectado.

R/W - Read Write bit (bit de información Lectura/Escritura) se utiliza sólo en

modo I2C. Este bit contiene la información del bit de L/E después de la

última dirección coin cidente. Este bit es válido sólo desde la dirección

coincidente hasta el siguiente bit de arranque, bit de parada o bit no ACK.

Modo I²C en modo esclavo

1 - Lectura de dato.

0 - Escritura de dato.

Modo I²C en modo esclavo

1 - Transmisión en progreso.

0 - Transmisión no está en progreso.

UA - Update Address bit (bit de activación de dirección) se utiliza sólo en

modo I2C de 10 bits.

1 - Indica que es necesario actualizar la dirección en el registro

SSPADD.

0 - Indica que la dirección es correcta y que no se necesita

actualizarla.

BF Buffer Full Status bit (bit de estado de búfer lleno)

Durante la recepción de dato (en modos SPI e I²C)

1 - Recepción completa. El registro SSPBUF está lleno.

0 - Recepción no completa. El registro SSPBUF está vacío.

Durante la transmisión de dato (sólo en modo I²C)

1 - Transmisión de dato en progreso (no incluye el bit ACK y bits de

parada).

0 - Transmisión de dato completa (no incluye el bit ACK y bits de

parada).

Registro SSPSTAT

Page 257: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 257

WCOL Write Collision Detect bit (bit detector de colisión)

1 - Colisión detectada. En el registro SSPBUF se ha escrito cuando no

se han cumplido las condiciones para iniciar una transmisión.

0 - No hay colisión.

SSPOV Receive Overflow Indicator bit (bit detector de desbordamiento en

recepción)

1 - Se recibe un nuevo byte cuando el registro SSPBUF aún mantiene

los datos ante riores. Como no hay espacio para recibir datos nuevos,

uno de estos dos bytes debe ser borrado. En este caso, los datos

almacenados en el registro SSPSR se pierden irremediablemente.

0 - Dato serial es recibido correctamente.

SSPEN - Synchronous Serial Port Enable bit (bit de habilitación del

módulo SSP - puerto serie síncrono) determina la función de los pines del

microcontrolador e inicializa el módulo MSSP:

En modo SPI

1 - Habilita el módulo MSSP y configura los pines SCK, SDO, SDI y

SS como una fuente de pines del puerto serie.

0 - Deshabilita el módulo MSSP y configura estos pines como pines

del puerto de E/S.

En modo I²C

1 - Habilita el módulo MSSP y configura los pines SDA y SCL como

una fuente de pines del puerto serie.

0 - Deshabilita el módulo MSSP y configura estos pines como pines

del puerto de E/S.

Page 258: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 258

CKP - Clock Polarity Select bit (bit de selección de polaridad de reloj) no

se utiliza en modo I²C maestro.

En modo SPI

1 - Para una señal de reloj, el estado inactivo es un nivel alto.

0 - Para una señal de reloj, el estado inactivo es un nivel bajo.

En modo I²C esclavo

Page 259: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 259

1 - Señal de reloj habilitada.

0 - Mantiene la salida de señal de reloj en estado bajo. Se utiliza para proporcionar más tiempo para

estabilización de datos.

SSPM3-SSPM0 - Synchronous Serial Port Mode Select bits. (bit de selección del modo del SSP (puerto serie

síncrono). El modo SSP se determina al combinar los siguientes bits:

S S P M 3 S S P M 2 S S P M 1 S S P M 0 M O D O

0 0 0 0 Modo maestro del SPI, reloj = Fosc/4.

0 0 0 1 Modo maestro del SPI, reloj = Fosc/16.

0 0 1 0 Modo maestro del SPI, reloj = Fosc/64.

0 0 1 1 Modo maestro del SPI, reloj = (TMR output)/2.

0 1 0 0 Modo esclavo del SPI, habilitado el pin de control SS.

0 1 0 1 Modo esclavo del SPI, deshabilitado el pin de control SS, SS se puede

utilizar como pin de E/S.

0 1 1 0 Modo esclavo I2C, dirección de 7 bits utilizada.

0 1 1 1 Modo esclavo I2C, dirección de 10 bits utilizada.

1 0 0 0 Modo maestro I2C, reloj = Fosc / [4(SSPAD+1)].

1 0 0 1 Máscara utilizada en modo esclavo I2C.

Page 260: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 260

1 0 1 0 No utilizado.

1 0 1 1 Modo maestro I2C controlado.

1 1 0 0 No utilizado.

1 1 0 1 No utilizado.

1 1 1 0 Modo esclavo I2C, dirección de 7 bits utilizada, los bits de arranque

(START) y de parada (STOP) habilitan interrupción.

1 1 1 1 Modo esclavo I2C, dirección de 10 bits utilizada, los bits de arranque

(START) y de parada (STOP) habilitan interrupción.

Page 261: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 261

Registro SSPCON2

GCEN - General Call Enable bit (bit de habilitación general)

Sólo en modo esclavo I²C

1 - Habilita interrupción cuando una dirección de llamada general es

recibida en el SSPST (0000h).

0 - Deshabilita dirección de llamada general.

ACKSTAT - Acknowledge Status bit (bit de estado de reconocimiento)

Sólo en modo de transmisión maestro I²C

1 - Reconocimiento del esclavo no recibido.

0 - Reconocimiento del esclavo recibido.

ACKDT - Acknowledge data bit (bit de recepción)

Sólo en modo de recepción maestro I²C

1 - No reconocimiento.

0 - Reconocimiento.

ACKEN - Acknowledge Sequence Enable bit (bit de habilitación de

secuencia de reconocimiento)

En modo de recepción maestro I²C

1 - Indica una secuencia de reconocimiento en los pines SDA y SCL y

transmite el bit ACKDT. Automáticamente borrado por hardware.

0 - Secuencia de reconocimiento en reposo.

RCEN - Receive Enable bit (bit de habilitación de recepción)

Sólo en modo maestro I²C

1 - Habilita recepción en modo I2C.

Page 262: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 262

0 - Recepción deshabilitada.

PEN - STOP condition Enable bit (bit de habilitación de condición de

Parada)

Sólo en modo maestro I²C

1 - Indica una condición de Parada en los pines SDA y SCL. Luego,

este bit es automáticamente borrado por hardware.

0 - Condición de Parada en reposo.

RSEN - Repeated START Condition Enabled bit (bit de habilitación de

repetir condición de Arranque)

Sólo en modo maestro I²C

1 - Indica repetición de condición de Arranque en los pines SDA y

SCL. Luego, este bit es automáticamente borrado por hardware.

0 - Condición de repetición de Arranque en reposo.

SEN - START Condition Enabled/Stretch Enabled bit (bit de habilitación

de condición de Arranque)

Sólo en modo maestro I²C

1 - Indica condición de Arranque en los pines SDA y SCL. Luego, este

bit es automáticamente borrado por hardware.

0 - Condición de Arranque en reposo.

I²C en Modo Maestro

El caso más común es que un microcontrolador funciona como maestro y

un periférico como esclavo. Es la razón por la que este libro sólo trata este

modo. Se da por entendido que la dirección consiste en 7 bits y el

dispositivo contiene un solo microcontrolador (dispositivo con maestro

único).

Para habilitar el módulo MSSP en este modo, siga las siguientes

instrucciones:

Page 263: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 263

Ajuste la velocidad de transmisión (registro SSPADD), desactive el control

de velocidad de rotación (al poner a uno el bit SMP del registro SSPSTAT) y

seleccione el modo maestro (registro SSPCON). Después de finalizar todos

los ajustes y habilitar el módulo (registro SSPCON: bit SSPEN), es

necesario esperar a que los circuitos de control internos indiquen con una

señal que todo esté preparado para transmisión de datos: o sea, que el bit

SSPIF del registro PIR1 se haya puesto a uno.

Después de poner este bit a cero por software, el microcontrolador está listo

para intercambiar los datos con los periféricos.

Transmisión de datos en Modo Maestro I²C

La transmisión de datos en el pin SDA se inicia con un cero lógico (0) que

aparece al poner a uno el bit SPEN del registro SSPCON2. Sin embargo,

aunque está habilitado, el microcontrolador tiene que esperar cierto tiempo

antes de iniciar la comunicación. Se le denomina 'Condición de Inicio'

durante la que se realizan las preparaciones y verificaciones internas. Si se

cumplen con todas la condiciones, el bit SSPIF del registro PIR1 se pone a

uno y la transmisión de datos se inicia en cuanto se cargue el registro

SSPBUF.

Page 264: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 264

Como máximo 112 circuitos integrados (dispositivos esclavos) pueden

compartir simultáneamente la misma línea de transmisión. El primer byte de

datos enviado por el dispositivo maestro contiene la dirección que coincide

con una sola dirección del dispositivo esclavo. Todas las direcciones se

enumeran en las hojas de datos respectivas. El octavo bit del primer byte de

datos especifica la dirección de transmisión de datos, o sea si el

microcontrolador va a enviar o recibir los datos. En este caso, como se trata

de transmisión de datos, el octavo bit se pone a cero (0).

Cuando ocurre la coincidencia de direcciones, el microcontrolador tiene que

esperar a que el dispositivo esclavo envíe el bit de reconocimiento, o sea

que se ponga a cero el bit ASKSTAT del registro SSPCON2. Una vez que la

coincidencia de direcciones ha ocurrido apropiadamente, todos los bytes de

datos se transmiten de la misma manera.

La transmisión de datos termina al poner a uno el bit SEN del registro

SSPCON2. Ocurre la condición de parada (STOP), lo que habilita que el pin

SDA reciba una secuencia de pulsos:

Page 265: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 265

Inicio - Dirección - Reconocimiento - Dato - Reconocimiento .... Dato -

Reconocimiento - Parada!

Recepción de datos en Modo Maestro I²C

Las preparaciones para recibir los datos son similares a las de transmitir los

datos, con excepción de que el último bit del primer byte enviado (el que

contiene la dirección) se ponga a uno lógico (1). Eso especifica que el

dispositivo maestro espera recibir los datos del dispositivo esclavo

direccionado. Con respecto al microcontrolador, ocurre lo siguiente:

Después de hacer las pruebas internas y poner a uno el bit de arranque

(START), el dispositivo esclavo envía byte por byte. Estos bytes se

almacenan en el registro serial SSPSR. Después de recibir el último -

octavo bit, cada dato se carga en el registro SSPBUF del que se puede leer.

Al leer este registro, se envía automáticamente el bit de reconocimiento, lo

que significa que el dispositivo maestro está listo para recibir los nuevos

datos.

Al igual que en el caso de la transmisión, la recepción de datos termina al

poner a uno el bit de parada (STOP):

Page 266: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 266

Inicio - Dirección - Reconocimiento - Dato - Reconocimiento .... Dato -

Reconocimiento - ¡Parada!

En esta secuencia de pulsos, el bit de reconocimiento se envía al

dispositivo esclavo.

Generador de baudios

Para sincronizar la transmisión de datos, todos los eventos que ocurren en

el pin SDA deben estar sincronizados con la señal de reloj generada en el

dispositivo maestro. Esta señal de reloj se genera por un simple oscilador

cuya frecuencia depende de la frecuencia del oscilador principal del

microcontrolador, del valor que se introduce al registro SSPADD y así como

del modo SPI actual. La frecuencia de señal de reloj del modo descrito en

este libro depende del cristal de cuarzo seleccionado y del registro SPADD.

La fórmula utilizada para hacer el cálculo de frecuencia de reloj es:

Vamos a hacerlo en mikroC...

/* En este ejemplo, el microcontrolador PIC está conectado a la memoria

EEPROM 24C02

por los pines SCL y SDA. El programa envía un byte de dato a la

dirección 2 de la EEPROM.

Entonces, el programa lee este dato por el modo I2C de la EEPROM y lo

envía al

Page 267: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 267

puerto PORTB para comprobar si el dato se ha escrito con éxito. El byte

para direccionar

la EEPROM está compuesto por 7 bits de la dirección (1010001) y el bit

que determina

lectura o escritura del dato (LSB - bit menos significativo).*/

void main(){

ANSEL = ANSELH = PORTB = TRISB = 0; // Todos los pines son

digitales. Los pines del

// puerto PORTB son salidas.

I2C1_Init(100000); // Inicializar I2C con reloj deseado

// Incio del bloque de sentencias para escribir un byte en la memoria

EEPROM.

I2C1_Start(); // Señal de inicio de I2C

I2C1_Wr(0xA2); // Enviar byte por I2C (dirección de

dispositivo + W)

I2C1_Wr(2); // Enviar byte (dirección de la localidad

EEPROM)

I2C1_Wr(0xF0); // Enviar los datos a escribir

I2C1_Stop(); // Señal de parada de I2C

Delay_100ms();

// En el siguiente bloque de sentencias se determina la dirección 2 de la

que se leerá el dato

I2C1_Start(); // Señal de inicio de I2C

Page 268: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 268

I2C1_Wr(0xA2); // Enviar byte por I2C (dirección de

dispositivo + W)

I2C1_Wr(2); // Enviar byte (dirección de dato)

// La dirección está determinada y el dato está listo para ser leído

I2C1_Repeated_Start(); // Se vuelve a generar el inicio de señal

I2C

I2C1_Wr(0xA3); // Enviar byte (dirección de dispositivo + R)

PORTB = I2C1_Rd(0u); // Leer el dato (reconocimiento NO)

I2C1_Stop(); // Señal de parada de I2C

}

NOTAS ÚTILES ...

Cuando el microcontrolador se comunica con un periférico, puede ocurrir un

fallo en la transmisión de datos por alguna razón. En este caso, es

recomendable comprobar el estado de algunos bits que pueden aclarar el

problema. En la práctica, el estado de estos bits se comprueba al ejecutar

una pequeña subrutina después de transmisión y recepción de cada byte

(por si acaso).

WCOL (SPCON,7) - Si intenta escribir un dato nuevo al registro SSPBUF

mientras que otra transmisión/recepción de datos está en progreso, el bit

WCOL se pone a uno y el contenido del registro SSBUF se queda sin

cambios. No hay escritura. Luego, el bit WCOL debe ser borrado por el

software.

BF (SSPSTAT,0) - Al transmitir los datos, este bit se pone a uno durante la

escritura en el registro SSPBUF y se queda puesto a uno hasta que el byte

en formato serial se desplace del registro SSPRS. En modo de recepción,

este bit se pone a uno al cargar un dato o una dirección al registro SSPBUF.

Se pone a cero después de leer el registro SSPBUF.

Page 269: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 269

SSPOV (SSPCON,6) - En modo de recepción, este bit se pone a uno al

recibir un nuevo byte en el registro SSPSR por medio de la comunicación

serial, todavía sin haber leído el dato anteriormente recibido del registro

SSPBUF.

Pines SDA y SCL - Cuando el módulo SSP está habilitado, estos pines se

vuelven a las salidas de Drenaje Abierto. Esto significa que deben estar

conectados a resistencias conectados a la otra punta al polo positivo de la

fuente de alimentación.

Para establecer la comunicación serial en modo I2C, se debe realizar lo

siguiente:

Ajustar el módulo y enviar la dirección:

Introducir en el registro SSPADD el valor para definir la velocidad de

transmisión en baudios.

Poner a uno el bit SMP del registro SSPSTAT para desactivar el

control de la velocidad de rotación.

Introducir el valor binario 1000 a los bits SSPM3-SSPM0 del registro

SSPCON1 para seleccionar el modo Maestro.

Poner a uno el bit SEN del registro SSPCON2 (secuencia de Inicio -

START).

El bit SSPIF se pone a uno automáticamente en final de la secuencia

de Inicio cuando el módulo está listo para funcionar. Se deberá poner

a cero.

Introducir la dirección de esclavo al registro SSPBUF.

Page 270: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 270

Cuando se envía un byte, el bit SSPIF (interrupción) se pone a uno

automáticamente después de haber recibido el bit de reconocimiento

del dispositivo esclavo.

Transmitir los datos:

Introducir en el registro SSPBUF los datos a enviar.

Cuando se envía un byte, el bit SSPIF (interrupción) se pone a uno

automáticamente después de haber recibido el bit de reconocimiento

del dispositivo esclavo.

La condición de Parada (STOP) se debe iniciar al poner a uno el bit

PEN del registro SSPCON para informar al dispositivo Esclavo que la

transmisión de datos se acabó.

Recibir los datos:

Poner a uno el bit RSEN del registro SSPCON2 para habilitar la

recepción.

El bit SSPIF indica con su estado lógico la recepción de datos.

Después de leer los datos del registro SSPBUF, el bit ACKEN del

registro SSPCON2 debe ponerse a uno para habilitar el envío del bit

de reconocimiento.

La condición de Parada (STOP) se debe iniciar al poner a uno el bit

PEN del registro SSPCON para informar al dispositivo Esclavo que la

transmisión se acabó.

Aparte de disponer de un gran número de líneas digitales de E/S utilizadas

para la comunicación con los periféricos, el PIC16F887 contiene 14

entradas analógicas. Debido a éstas, el microcontrolador no sólo puede

reconocer si un pin es llevado a bajo o alto (0 o +5V), sino que puede medir

con precisión el voltaje y convertirlo en un valor numérico, o sea, en formato

digital.

Page 271: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 271

3.9 MÓDULOS ANALÓGICOS

El módulo del convertidor A/D dispone de las siguientes características:

El convertidor genera un resultado binario de 10 bits utilizando el

método de aproximaciones sucesivas y almacena los resultados de

conversión en los registros ADC (ADRESL y ADRESH);

Dispone de 14 entradas analógicas separadas;

El convertidor A/D convierte una señal de entrada analógica en un

número binario de 10 bits;

La resolución mínima o calidad de conversión se puede ajustar a

diferentes necesidades al seleccionar voltajes de referencia Vref- y

Vref+.

CONVERTIDOR A/D

Aunque a primera vista parece muy complicado utilizar un convertidor A/D,

en realidad es muy simple. De hecho resulta más simple utilizar un

convertidor A/D que los temporizadores o módulos de comunicación serie.

Page 272: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 272

El funcionamiento del convertidor A/D está bajo el control de los bits de

cuatro registros:

ADRESH Registro alto del resultado de la conversión A/D;

ADRESL Registro bajo del resultado de la conversión A/D;

ADCON0 Registro de control 0; y

ADCON1 Registro de control 1.

Registros ADRESH y ADRESL

El resultado obtenido después de convertir un valor analógico en digital es

un número de 10 bits que se almacenará en los registros ADRESH y

ADRESL. Hay dos maneras de manejarlo: justificación a la izquierda y a la

derecha que simplifica en gran medida su uso. El formato del resultado de

la conversión depende del bit ADFM del registro ADCON1. En caso de que

no se utilice el convertidor A/D, estos registros se pueden utilizar como

registros de propósito general.

Page 273: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 273

REQUERIMIENTOS DE ADQUISICIÓN A/D

Para que el convertidor A/D alcance su exactitud especificada, es necesario

proporcionar un cierto tiempo muerto entre seleccionar una entrada

analógica específica y la medición misma. Este tiempo se le denomina

“tiempo de adquisición” y generalmente depende de la impedancia de la

fuente. Se utiliza una ecuación para hacer cálculo de tiempo de adquisición

con precisión, cuyo valor mínimo es de 20uS aproximadamente. Por

consiguiente, para realizar una conversión con precisión, no se olvide este

detalle.

RELOJ PARA LA CONVERSIÓN A/D

El tiempo necesario para realizar una conversión A/D cuyo resultado es 1 bit

se define en unidades de TAD. Se requiere que sea como mínimo 1,6 uS.

Para realizar una conversión completa de 10 bits se requiere un poco más

tiempo de lo esperado, son 11 TAD. Como la frecuencia de reloj así como la

fuente de conversión A/D son determinadas por software, es necesario

seleccionar una de las combinaciones de los bits disponibles ADCS1 y

ADCS0 antes de empezar a medir voltaje en una de las entradas

analógicas. Estos bits se almacenan en el registro ADCON0.

Page 274: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 274

F U E N TE D E

R E L O J D E

A D C

A D C S1

A D C S0

F R E C U E N C I A D E D I S P O S I T I V O ( F O S C )

20 Mhz

8 Mhz 4 Mhz 1 Mhz

Fosc/2 0 0 100 nS 250 nS 500 nS 2 uS

Fosc/8 0 1 400 nS 1 uS 2 uS 8 uS

Fosc/32 1 0 1.6 uS 4 uS 8 uS 32 uS

Frc 1 1 2 - 6 uS

2 - 6 uS

2 - 6 uS

2 - 6 uS

Cualquier cambio de la frecuencia de reloj del microcontrolador afectará a la

frecuencia de reloj de la conversión A/D, lo que puede perjudicar al

resultado de la conversión A/D. En la siguiente tabla se muestran las

características de la frecuencia del dispositivo. Los valores en las celdas

sombreadas están fuera del rango recomendado.

¿CÓMO UTILIZAR EL CONVERTIDOR A/D?

Para llevar a cabo una conversión A/D sin problemas así como para evitar

los resultados inesperados, es necesario considerar lo siguiente:

El convertidor A/D no hace diferencia entre señales digitales y

analógicas. Para evitar errores en medición o dañar el chip, los pines

se deben configurar como en tradas analógicas antes de que empiece

el proceso de conversión. Los bits utiliza dos para este propósito se

almacenan en los registros TRIS y ANSEL (ANSELH);

Page 275: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 275

Al leer el estado de puerto con las entradas analógicas, el estado de

los bits correspondientes se leerá como cero lógico (0), sin reparar en

el valor del voltaje real en el pin; y

Hablando en términos generales, la medición de voltaje en el

convertidor está basado en comparar voltaje de entrada con una

escala interna que tiene 1023 grados (210 - 1 =1023). El grado más

bajo de esta escala representa el voltaje Vref-, mientras que el grado

más alto se refiere al voltaje Vref+. La siguiente figura muestra los

voltajes de referencia seleccionables así como sus valores máximos y

mínimos.

Registro ADCON0

ADCS1, ADCS0 - A/D Conversion Clock Select bits (bits de selección de

reloj de conversión A/D) selecciona la frecuencia de reloj utilizada para

sincronización interna del convertidor A/D. Asimismo afecta a la duración de

la conversión.

Page 276: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 276

A D C S 1 A D C S 2 R E L O J

0 0 Fosc/2

0 1 Fosc/8

1 0 Fosc/32

1 1 RC *

* Señal de reloj se genera por el oscilador interno RC que está integrado en

el convertidor.

CHS3-CHS0 - Analog Channel Select bits (bits de selección de canal

analógico) selecciona un pin o un canal analógico para la conversión A/D, o

sea para medir el voltaje:

C H S 3 C H S 2 C H S 1 C H S 0 C A N A L P I N

0 0 0 0 0 RA0/AN0

0 0 0 1 1 RA1/AN1

0 0 1 0 2 RA2/AN2

0 0 1 1 3 RA3/AN3

0 1 0 0 4 RA5/AN4

0 1 0 1 5 RE0/AN5

0 1 1 0 6 RE1/AN6

0 1 1 1 7 RE2/AN7

1 0 0 0 8 RB2/AN8

1 0 0 1 9 RB3/AN9

1 0 1 0 10 RB1/AN10

1 0 1 1 11 RB4/AN11

1 1 0 0 12 RB0/AN12

1 1 0 1 13 RB5/AN13

1 1 1 0 CVref

1 1 1 1 Vref = 0.6V

Page 277: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 277

GO/DONE - A/D Conversion Status bit (bit de estado de la conversión

A/D) determina el estado actual de de la conversión:

1 - La conversión A/D está en progreso.

0 - La conversión A/D ha finalizado. El bit se pone a cero

automáticamente por hardware cuando la conversión A/D finaliza.

ADON - A/D On bit (bit de encendido A/D) habilita el convertidor A/D.

1 - Convertidor A/D está habilitado.

0 - Convertidor A/D está deshabilitado.

Vamos a hacerlo en mikroC...

/* Este código es un ejemplo de leer el valor analógico del canal 2 y de

visualizarlo

en los puertos PORTB y PORTC como número binario de 10 bits. */

#include <built_in.h>

unsigned int adc_rd;

void main() {

ANSEL = 0x04; // Configurar AN2 como pin analógico

TRISA = 0xFF; // PORTA se configura como entrada

ANSELH = 0; // Configurar los demás pines AN como E/S

digitales

TRISC = 0x3F; // Pines RC7 y RC6 se configuran como salidas

TRISB = 0; // PORTB se configura como salida

do {

temp_res = ADC_Read(2); // Obtener el resultado de 10 bits de la

conversión AD

PORTB = temp_res; // Enviar los 8 bits más bajos al PORTB

Page 278: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 278

PORTC = temp_res >> 2; // Enviar los 2 bits más significativos a los

RC7, RC6

} while(1); // Quedarse en el bucle

}

Registro ADCON1

ADFM - A/D Result Format Select bit (bit de selección del formato del

resultado de la conversión A/D)

1 - Resultado de conversión está justificado a la derecha. No se

utilizan los seis bits más significativos del registro ADRESH.

0 - Resultado de conversión está justificado a la izquierda. No se

utilizan los seis bits menos significativos del registro ADRESL.

VCFG1 - Voltage Reference bit (bit de configuración de voltaje de

referencia) selecciona la fuente de voltaje de referencia bajo que se

necesita para el funcionamiento del convertidor A/D.

1 - Voltaje de referencia bajo se aplica al pin Vref-

0 - Voltaje de alimentación Vss se utiliza como una fuente de voltaje

de referencia bajo.

VCFG0 - Voltage Reference bit (bit de configuración de voltaje de

referencia) selecciona la fuente de voltaje de referencia alto que se necesita

para el fucionamiento del convertidor A/D.

1 - Voltaje de referencia alto se aplica al pin Vref+.

0 - Voltaje de alimentación Vdd se utiliza como una fuente de voltaje

de referencia alto.

Para medir el voltaje en un pin de entrada por medio del convertidor A/D, se

debe realizar lo siguiente:

Page 279: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 279

Paso 1 - Configuración del puerto:

Escribir un uno lógico (1) a un bit del registro TRIS, lo que resulta en

configurar el pin apropiado como una entrada.

Escribir un uno lógico (1) a un bit del registro ANSEL, lo que resulta

en configurar el pin apropiado como una entrada analógica.

Paso 2 - Configuración del módulo de la conversión A/D:

Configurar voltaje de referencia en el registro ADCON1.

Seleccionar una señal de reloj de la conversión A/D en el registro

ADCON0.

Seleccionar uno de los canales de entrada CH0-CH13 del registro

ADCON0.

Seleccionar el formato de dato por medio de ADFM del registro

ADCON1.

Habilitar el convertidor A/D al poner a uno el bit ADON del registro

ADCON0.

Paso 3 - Configuración de la interrupción (opcionalmente):

Poner a cero el bit ADIF.

Poner a uno los bits ADIE, PEIE y GIE.

Paso 4 - Tiempo de espera para que transcurra el tiempo de adquisición

(aproximadamente 20uS).

Paso 5 - Inicio de la conversión poniendo a uno el bit GO/DONE del reg

istro ADCON0.

Paso 6 - Esperar a que la conversión A/D finalice.

Es necesario comprobar en el bucle de programa si el bit GO/DONE

está a cero o esperar que se produzca una interrupción (deberá estar

anteriormente habilitada).

Paso 7 - Lectura del resultado de la conversión A/D:

Leer los registros ADRESH y ADRESL.

COMPARADOR ANALÓGICO

Aparte del convertidor A/D, hay otro módulo, que hasta hace poco ha sido

incorpodo sólo en los circuitos integrados que pertenecen a los llamados

Page 280: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 280

“componentes analógicos”. Debido al hecho de que casi no hay ningún

dispositivo automático complejo que en cierto modo no utilice estos

circuitos, dos comparadores de alta calidad, junto con los componentes

adicionales están integrados en el microcontrolador y conectados a sus

pines.

¿Cómo funciona un comparador? Básicamente, el comparador analógico es

un amplificador que compara la magnitud de voltajes en dos entradas.

Dispone de dos entradas y una salida. Dependiendo de cuál voltaje de

entrada es más alto (valor analógico), un cero lógico (0) o un uno lógico (1)

(valores digitales) será la salida.

Cuando el voltaje analógico en Vin - es más alto que el voltaje

análogo en Vin+, la salida del comparador estará a un nivel digital

bajo.

Cuando el voltaje analógico en Vin+ es más alto que el voltaje

análogo en Vin-, la salida del comparador estará a un nivel digital alto.

El microcontrolador PIC16F887 dispone de dos de estos comparadores de

voltaje cuyas entradas están conectadas a los pines de E/S RA0-RA3,

mientras que las salidas están conectadas a los pines RA4 y RA5. Además,

hay una fuente de voltaje de referencia interna en el chip mismo, la que

vamos a discutir más tarde.

Estos dos circuitos están bajo el control de los bits almacenados en los

siguientes registros:

CM1CON0 está en control del comparador C1;

CM2CON0 está en control del comparador C2;

CM2CON1 está en control del comparador C2;

Page 281: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 281

FUENTE INTERNA DE VOLTAJE DE REFERENCIA

Uno de dos voltajes analógicos proporcionados en las entradas del

comparador es por lo general estable e inalterable. Es denominado „voltaje

de referencia‟(Vref). Para generarlo, se pueden utilizar tanto una fuente de

voltaje externa como una fuente de voltaje interna especial. El voltaje de

referencia Vref se deriva después de seleccionar una fuente, por medio de

una red en escalera que consiste en 16 resistencias, formando un divisor de

voltaje. La fuente de voltaje es seleccionable por el bit VRSS del registro

VRCON.

Además, la fracción de voltaje proporcionada por la red de resistencias es

seleccionable por los bits VR0-VR3 y utilizada como voltaje de referencia.

Vea la siguiente figura:

El voltaje de referencia del comparador dispone de dos gamas con 16

diferentes niveles de voltaje cada una. La selección de gama es controlada

por el bit VRR del registro VRCON. El voltaje de referencia seleccionado

CVref puede ser la salida al pin RA2/AN2 si el bit VROE se pone a uno.

Aunque la idea principal era obtener el voltaje de referencia variable para el

funcionamiento de módulos analógicos, de ese modo se obtiene un simple

convertidor A/D. Este convertidor es muy útil en algunas situaciones. Su

funcionamiento está bajo el control del registro VRCON.

Page 282: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 282

COMPARADORES E INTERRUPCIÓN

Siempre que haya un cambio del estado lógico en la salida de un

comparador, el bit de bandera CMIF del registro PIR se pone a uno. Ese

cambio también causará una interrupción si los siguientes bits se ponen a

uno:

El bit CMIE del registro PIE = 1;

El bit PEIE del registro INTCON = 1; y

El bit GIE del registro INTCON = 1.

Si una interrupción está habilitada, un cambio en la salida de un

comparador cuando el microcontrolador está en modo de reposo, puede

causar que el microcontrolador salga de reposo y vuelva a funcionar en

modo normal.

FUNCIONAMIENTO EN MODO DE REPOSO (SLEEP MODE)

Si está habilitado antes de entrar en modo de reposo, el comparador se

queda activo durante el modo de reposo. Si el comparador no se utiliza para

"despertar" el dispositivo, el consumo de corriente se puede reducir en

modo de reposo al apagar el comparador. Esto se lleva a cabo al poner a

cero el bit CxON del registro CMxCON0.

Para que el comparador "despierte" al microcontrolador del modo de

reposo, el bit CxIE del registro IE2 y el bit PEIE del registro INTCON

deberán ponerse a uno. La instrucción que sigue a la instrucción Sleep

siempre se ejecuta al salir del modo de reposo. Si el bit GIE del registro

INTCON se pone a uno, el dispositivo ejecutará la rutina de servicio de

interrupción.

Registro CM1CON0

Page 283: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 283

Los bits de este registro están en control del comparador C1. Eso afecta

principalmente a la configuración de las entradas. Para explicarlo con más

claridad, vea la siguiente figura en la que se muestran sólo los componentes

directamente afectados por los bits de este registro.

C1ON - Comparator C1 Enable bit (bit de habilitación del comparador C1)

habilita al comparador C1.

1 - Comparador C1 está habilitado.

0 - Comparador C1 está deshabilitado.

C1OUT - Comparator C1 Output bit (bit de salida del comparador C1) es

la salida del comparador C1.

Si C1POL = 1 (salida del comparador está invertida)

1 - Voltaje de entrada C1Vin+ es más bajo que el voltaje de entrada

C1Vin-.

0 - Voltaje de entrada C1Vin+ es más alto que el voltaje de entrada

C1Vin-.

If C1POL = 0 (salida del comparador no está invertida)

1 - Voltaje de entrada C1Vin+ es más alto que el voltaje de entrada

C1Vin-.

0 - Voltaje de entrada C1Vin+ es más bajo que el voltaje de entrada

C1Vin-.

Page 284: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 284

C1OE Comparator C1 Output Enable bit (bit de habilitación de salida del

comparador C1)

1 - Salida del comparador C1OUT está conectada al pin C1OUT *.

0 - Salida del comparador se utiliza internamente.

* Para habilitar que el bit C1OUT aparezca en el pin, se deben cumplir dos

condiciones: C1ON = 1 (el comparador debe estar activado) y el bit

correspondiente TRIS = 0 (pin se debe configurar como salida).

C1POL - Comparator C1 Output Polarity Select bit (bit de selección de

polaridad de salida del comparador C1) habilita la inversión del estado de la

salida del comparador C1.

1 - Salida del comparador C1 está invertida.

0 - Salida del comparador C1 no está invertida.

C1R - Comparator C1 Reference Select bit (bit de selección de la fuente

de voltaje de referencia del comparador C1)

1 - Entrada no invertida C1Vin+ está conectada a la fuente de voltaje

de referencia C1Vref.

0 - Entrada no invertida C1Vin+ está conectada al pin C1IN+.

C1CH1, C1CH0 - Comparator C1 Channel Select bit (bit de selección de

canal del comparador C1)

C 1 C H 1 C 1 C H 0 E N T R A D A C 1 V I N - D E L

C O M P A R A D O R

0 0 Entrada C1Vin- está conectada al pin C12IN0-

0 1 Entrada C1Vin- está conectada al pin C12IN1-

1 0 Entrada C1Vin- está conectada al pin C12IN2-

1 1 Entrada C1Vin- está conectada al pin C12IN3-

Page 285: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 285

Registro CM2CON0

Los bits de este registro están en control del comparador C2. Similar al caso

anterior, la siguiente figura muestra un esquema simplificado del circuito

afectado por los bits de este registro.

C2ON - Comparator C2 Enable bit (bit de habilitación del comparador C2)

habilita el comparador C2.

1 - Comparador C2 está habilitado.

0 - Comparador C2 está deshabilitado.

C2OUT - Comparator C2 Output bit (bit de salida del comparador C2) es

la salida del comparador C2.

If C2POL = 1 (salida del comparador está invertida)

1 - Voltaje de entrada C2Vin+ es más bajo que el voltaje de entrada

C2Vin-.

Page 286: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 286

0 - Voltaje de entrada C2Vin+ es más alto que el voltaje de entrada

C2Vin-.

If C2POL = 0 (salida del comparador no está invertida)

1 - Voltaje de entrada C2Vin+ es más alto que el voltaje de entrada

C2Vin-.

0 - Voltaje de entrada C2Vin+ es más bajo que el voltaje de entrada

C2Vin-.

C2OE - Comparator C2Output Enable bit (bit de habilitación de salida del

comparador C2)

1 - Salida del comparador C2OUT está conectada al pin C2OUT*.

0 - Salida del comparador se utiliza internamente.

* Para habilitar que el bit C2OUT aparezca en el pin, se deben cumplir dos

condiciones: C2ON = 1 (el comparador debe estar activado) y el bit

correspondiente TRIS = 0 (pin se debe configurar como salida).

C2POL - Comparator C2 Output Polarity Select bit (bit de selección de

polaridad de salida del comparador C2) habilita la inversión del estado de la

salida del comparador C2.

1 - Salida del comparador C2 está invertida.

0 - Salida del comparador C2 no está invertida.

C2R - Comparator C2 Reference Select bit (bit de selección de la fuente

de voltaje de referencia del comparador C2)

1 - Entrada no invertida C2Vin+ está conectada a la fuente de voltaje

de referencia C2Vref.

0 - Entrada no invertida C2Vin+ está conectada al pin C2IN+.

C2CH1, C2CH0 Comparator C2 Channel Select bit (bit de selección de

canal del comparador C2)

C 2 C H 1 C 2 C H 0 E N T R A D A C 2 V I N - D E L C O M P A R A D O R

0 0 Entrada C2Vin- está conectada al pin C12IN0-

0 1 Entrada C2Vin- está conectada al pin C12IN1-

1 0 Entrada C2Vin- está conectada al pin C12IN2-

1 1 Entrada C2Vin- está conectada al pin C12IN3-

Page 287: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 287

Registro CM2CON1

MC1OUT Mirror Copy of C1OUT bit es una copia del bit C1OUT

MC2OUT Mirror Copy of C2OUT bit es una copia del bit C2OUT

C1RSEL Comparator C1 Reference Select bit (bit de selección de la

fuente de voltaje de referencia del comparador C1)

1 - Voltaje seleccionable CVref se utiliza en la fuente de voltaje de

referencia C1Vref.

0 - Voltaje de referencia fijo de 0,6V se utiliza en la fuente de voltaje

de referencia C1Vref.

C2RSEL - Comparator C2 Reference Select bit (bit de selección de la

fuente de voltaje de referencia del comparador C2)

1 - Voltaje seleccionable CVref se utiliza en la fuente de voltaje de

referencia C2Vref.

0 - Voltaje de referencia fijo de 0,6V se utiliza en la fuente de voltaje

de referencia C2Vref.

T1GSS - Timer1 Gate Source Select bit (bit de selección de la fuente de la

compuerta del temporizador Timer1)

1 - Compuerta del temporizador Timer1 utiliza señal del pin T1G.

0 - Compuerta del temporizador Timer1 utiliza señal SYNCC2OUT.

C2SYNC - Comparator C2 Output Synchronization bit (bit de

sincronización de salida del comparador C2)

1 - Salida del comparador C2 está sincronizada con un flanco

ascendente de señal de reloj del temporizador Timer1

0 - Salida del comparador es una señal asíncrona.

Page 288: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 288

Registro VRCON

VREN Comparator C1 Voltage Reference Enable bit (bit de habilitación

de la fuente de voltaje de referencia del comparador C1)

1 - Fuente de voltaje de referencia CVref está encendido.

0 - Fuente de voltaje de referencia CVref está apagado.

VROE Comparator C2 Voltage Reference Enable bit (bit de habilitación

de la fuente de voltaje de referencia del comparador C2)

1 - Fuente de voltaje de referencia CVref está conectada al pin.

0 - Fuente de voltaje de referencia CVref no está conectada al pin.

VRR - CVref Range Selection bit (bit de selección de gama de voltaje de

referencia Vref)

1 - Fuente de voltaje de referencia se ajusta a producir baja gama de

voltaje.

0 - Fuente de voltaje de referencia se ajusta a producir alta gama de

voltaje.

VRSS - Comparator Vref Range selection bit (bit de selección de gama

de voltaje de referencia Vref del comparador)

1 - Voltaje de referencia está en la gama de Vref+ a Vref-.

0 - Voltaje de referencia está en la gama de Vdd a Vss. (voltaje de

alimentación).

VR3 - VR0 CVref Value Selection (selección de valor de voltaje de

referencia)

If VRR = 1 (gama baja)

El voltaje de referencia se calcula por medio de la fórmula: CVref =

([VR3:VR0]/24)Vdd.

If VRR = 0 (gama alta)

Page 289: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 289

El voltaje de referencia se calcula por medio de la fórmula CVref = Vdd/4 +

([VR3:VR0]/32)Vdd.

Pasos a seguir para utilizar apropiadamente los comparadores integrados:

Paso 1 - Configuración del módulo:

Para seleccionar el modo apropiado, se deben configurar los estados

de los bits de los registros CM1CON0 y CM2CON0. La interrupción

debe estar deshabilitada durante el cambio de modo.

Paso 2 - Configurar la fuente de voltaje de referencia Vref interna (sólo si se

utiliza). En el registro VRCON es necesario realizar lo siguiente:

Seleccionar una de dos gamas de voltaje por medio del bit VRR.

Configurar el voltaje de referencia Vref necesario por medio de los bits

VR3 - VR0.

Poner a uno el bit VROE si es necesario.

Habilitar la fuente de voltaje de referencia Vref al poner a uno el bit

VREN.

Fórmula utilizada para calcular el voltaje de referencia

VRR = 1 (gama baja)

CVref = ([VR3:VR0]/24)VLADDER

VRR = 0 (gama alta)

CVref = (VLADDER/4) + ([VR3:VR0]VLADDER/32)

Vladder = Vdd or ([Vref+] - [Vref-]) or Vref+

Paso 3 - Inicio del funcionamiento:

Habilitar una interrupción al poner a uno los bits CMIE (registro PIE),

PEIE y GIE (registro INTCON ).

Leer los bits C1OUT y C2OUT del registro CMCON.

Leer la bandera de bit CMIF del registro PIR. Después de haber sido

puesto a uno, este bit se pone a cero por software.

Para sincronizar todos los procesos que se llevan a cabo dentro del

microcontrolador, se debe utilizar una señal de reloj, mientras que para

generar una señal de reloj, se debe utilizar un oscilador. Así de simple. El

microcontrolador dispone de varios osciladores capaces de funcionar en

modos diferentes. Y aquí es donde viene lo interesante...

Page 290: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 290

3.10 OSCILADOR DE RELOJ

Como se muestra en la siguiente figura, la señal de reloj se genera por uno

de los dos osciladores integrados.

Un oscilador externo está instalado fuera del microcontrolador y conectado

a los pines OSC1 y OSC2. Es denominado 'externo' porque utiliza

componentes externos para generar una señal de reloj y estabilizar la

frecuencia. Estos son: cristal de cuarzo, resonador cerámico o circuito

resistor - capacitor. El modo de funcionamiento del oscilador se selecciona

por los bits, que se envían durante la programación, denominados Palabra

de Configuración.

El oscilador interno consiste en dos osciladores internos separados:

El HFINTOSC es un oscilador interno de alta frecuencia calibrado a 8MHz.

El microcontrolador puede utilizar una señal de reloj generada a esta

frecuencia o después de haber sido dividida en el pre-escalador.

El LFINTOSC es un oscilador interno de baja frecuencia calibrado a 31 kHz.

Sus pulsos de reloj se utilizan para funcionamiento de los temporizadores

de encendido y perro guardián, asimismo puede utilizarse como fuente de

señal de reloj para el funcionamiento de todo el microcontrolador.

Page 291: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 291

El bit System Clock Select (bit de selección del reloj del sistema - SCS) del

registro OSCCON determina si una fuente de señal de reloj del

microcontrolador será interna o externa.

Registro OSCCON

El registro OSCCON gobierna el microcontrolador y las opciones de

selección de frecuencia. Contiene los siguientes bits: bits de selección de

frecuencia (IRCF2, IRCF1, IRCF0), bits de estado de frecuencia (HTS,

LTS), bits de control de reloj del sistema (OSTA, SCS).

IRCF2-0 - Internal Oscillator Frequency Select bits. (bits de selección de

frecuencia del oscilador interno). El valor del divisor de frecuencias depende

de la combinación de estos tres bits. La frecuencia de reloj del oscilador

interno se determina de la misma manera.

I R C F 2 I R C F 1 I R C F 0 F R E C U E N C I A O S C .

1 1 1 8 MHz HFINTOSC

1 1 0 4 MHz HFINTOSC

1 0 1 2 MHz HFINTOSC

1 0 0 1 MHz HFINTOSC

0 1 1 500 kHz HFINTOSC

0 1 0 250 kHz HFINTOSC

0 0 1 125 kHz HFINTOSC

0 0 0 31 kHz LFINTOSC

Page 292: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 292

OSTS - Oscillator Start-up Time-out Status bit (bit de estado del

temporizador de encendido) indica cuál fuente de reloj está actualmente en

uso. Es un bit de sólo lectura.

1 - Se utiliza el oscilador de reloj externo.

0 - Se utiliza uno de los osciladores de reloj interno (HFINTOSC o

LFINTOSC).

HTS - HFINTOSC Status bit (8 MHz - 125 kHz) (bit de estado del

HFINTOSC) indica si el oscilador interno de alta frecuencia funciona en

modo estable.

1 - HFINTOSC está estable.

0 - HFINTOSC no está estable.

LTS - LFINTOSC Stable bit (31 kHz) (bit de estado del LFINTOSC) indica

si el oscilador de baja frecuencia funciona en modo estable.

1 - LFINTOSC está estable.

0 - LFINTOSC no está estable.

SCS - System Clock Select bit (bit de selección del reloj del sistema)

determina cuál oscilador se utilizará como una fuente de reloj.

1 - Oscilador interno se utiliza como reloj del sistema.

0 - Oscilador externo se utiliza como reloj del sistema.

El modo del oscilador se configura por medio de los bits,

denominados Palabra de Configuración, que se escribe en la memoria

del microcontrolador durante el proceso de la programación.

MODOS DE RELOJ EXTERNO

El oscilador externo se puede configurar para funcionar en uno de varios

modos, lo que habilita que funcione a diferentes velocidades y utilice

diferentes componentes para estabilizar la frecuencia. El modo de

funcionamiento se selecciona durante el proceso de escribir un programa en

el microcontrolador. Antes que nada, es necesario activar el programa en

una PC que se utilizará para programar el microcontrolador. En este caso,

es el programa PICflash. Pulse sobre la casilla del oscilador y seleccione

uno de la lista desplegable. Los bits apropiados se pondrán a uno

automáticamente, formando parte de varios bytes, denominados Palabra de

Configuración.

Page 293: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 293

Durante el proceso de la programación del microcontrolador, los bytes de la

Palabra de Configuración se escriben en la memoria ROM del

microcontrolador y se almacenan en los registros especiales no disponibles

al usuario. A base de estos bits, el microcontrolador “sabe” qué hacer,

aunque eso no se indica explícitamente en el programa.

Modo de funcionamiento se selecciona después de escribir y compilar un

programa

OSCILADOR EXTERNO EN MODO EC

El modo de reloj externo (EC - external clock) utiliza un oscilador externo

como una fuente de señal de reloj. La máxima frecuencia de señal de reloj

está limitada a 20 MHz.

Page 294: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 294

Las ventajas del funcionamiento del oscilador externo en modo EC son las

siguientes:

La fuente de reloj externa independiente está conectada al pin de

entrada OSC1. El pin OSC2 está disponible como pin de E/S de

propósito general;

Es posible sincronizar el funcionamiento del microcontrolador con los

demás componentes incorporados en el dispositivo;

En este modo el microcontrolador se pone a funcionar

inmediatamente después de encenderlo. No se requiere esperar para

estabilizar la frecuencia.

Al deshabilitar temporalmente la fuente de reloj externa, se detiene el

funcionamiento del dispositivo, dejando todos los datos intactos.

Después de reiniciar el reloj externo, el dispositivo sigue funcionando

como si no hubiera pasado nada.

Page 295: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 295

OSCILADOR EXTERNO EN MODO LP, XT O HS

Los modos LP, XT y HS utilizan un oscilador externo como una fuente de

reloj cuya frecuencia está determinada por un cristal de cuarzo o por

resonadores cerámicos conectados a los pines OSC1 y OSC2.

Dependiendo de las características de los componentes utilizados,

seleccione uno de los siguientes modos:

Modo LP - (Baja potencia) se utiliza sólo para cristal de cuarzo de

baja frecuencia. Este modo está destinado para trabajar con cristales

de 32.768 KHz normalmente embebidos en los relojes de cristal. Es

fácil de reconocerlos por sus dimensiones pequeñas y una forma

cilíndrica. Al utilizar este modo el consumo de corriente será menor

que en los demás modos.

Modo XT se utiliza para cristales de cuarzo de frecuencias

intermedias hasta 8 MHz. El consumo de corriente es media en

comparación con los demás modos.

Modo HS - (Alta velocidad) se utiliza para cristales de reloj de

frecuencia más alta de 8 MHz. Al utilizar este modo el consumo de

corriente será mayor que en los demás modos.

Page 296: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 296

RESONADORES CERÁMICOS EN MODO XT O HS

Los resonadores cerámicos son similares a los cristales de cuarzo según

sus características, por lo que se conectan de la misma manera. A

diferencia de los cristales de cuarzo, son más baratos y los osciladores que

hacen uso de ellos son de calidad más baja. Se utilizan para las frecuencias

de reloj entre 100 kHz y 20 MHz.

OSCILADOR EXTERNO EN MODOS RC Y RCIO

El uso de los elementos para estabilizar la frecuencia sin duda alguna tiene

muchas ventajas, pero a veces realmente no es necesario. En la mayoría

de casos el oscilador puede funcionar a frecuencias que no son

precisamente definidas, así que sería una pérdida de dinero embeber tales

elementos. La solución más simple y más barata es estas situaciones es

utilizar una resistencia y un capacitor para el funcionamiento del oscilador.

Hay dos modos:

Page 297: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 297

Modo RC. Cuando el oscilador externo se configura a funcionar en modo

RC, el pin OSC1 debe estar conectado al circuito RC como se muestra en la

figura a la derecha. La señal de frecuencia del oscilador RC dividida por 4

está disponible en el pin OSC2. Esta señal se puede utilizar para la

calibración, sincronización o para otros propósitos.

Modo RCIO. De manera similar, el circuito RC está conectado al pin OSC1.

Esta vez, el pin OSC2 está disponible para ser utilizado como pin de E/S de

propósito general.

En ambos casos se le recomienda utilizar los componentes como se

muestra en la figura.

La frecuencia de este oscilador se calcula por medio de la fórmula f = 1/T

según la que:

f = frecuencia [Hz];

T = R * C = constante de tiempo [s];

R = resistencia eléctrica [Ω]; y

C = capacitancia del condensador [F].

MODOS DE RELOJ INTERNO

El circuito del oscilador interno consiste en dos osciladores separados que

se pueden seleccionar como la fuente del reloj del microcontrolador:

El oscilador HFINTOSC está calibrado de fábrica y funciona a 8Mhz. La

frecuencia de este oscilador se puede configurar por el usuario por medio

de software utilizando los bits del registro OSCTUNE.

El oscilador LFINTOSC no está calibrado de fábrica y funciona a 31kHz.

Page 298: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 298

Similar al oscilador externo, el interno también puede funcionar en varios

modos. El modo de funcionamiento se selecciona de la misma manera que

en el oscilador externo - por medio de los bits que forman Palabra de

configuración. En otras palabras, todo se lleva a cabo dentro del software

de PC antes de escribir un programa en el microcontrolador.

OSCILADOR INTERNO EN MODO INTOSC

En este modo, el pin OSC1 está disponible para ser utilizado como pin de

E/S de propósito general. La señal de frecuencia del oscilador interno

dividida por 4 está disponible en el pin OSC2.

OSCILADOR INTERNO EN MODO INTOSCIO

En este modo, los dos pines están disponibles como pines de E/S de

propósito general.

CONFIGURACIÓN DEL OSCILADOR INTERNO

El oscilador interno consiste en dos circuitos separados:

1. El oscilador interno de alta frecuencia HFINTOSC está conectado al post-

escalador (divisor de frecuencias). Está calibrado de fábrica y funciona a 8

Mhz. Al utilizar el post-escalador, este oscilador puede producir una señal

de reloj a una de siete frecuencias. La selección de frecuencia se realiza

dentro del software utilizando los pines IRCF2, IRCF1 y IRCF0 del registro

OSCCON.

Page 299: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 299

El HFINTOSC está habilitado al seleccionar una de siete frecuencias (entre

8 Mhz y 125 kHz) y poner a uno el bit de la fuente de reloj del sistema

(SCS) del registro OSCCON. Como se muestra en la siguiente figura , todo

el procedimiento se realiza por medio de los bits del registro OSCCON.

2. El oscilador de baja frecuencia LFINTOSC no está calibrado de fábrica y

funciona a 31 kHz. Está habilitado al seleccionar la frecuencia (bits del

registro OSCCON) y poner a uno el bit SCS del mismo registro.

MODO DE CAMBIO AUTOMÁTICO DE VELOCIDAD DE RELOJ (TWO-

SPEED CLOCK START-UP MODE)

El modo de cambio automático de velocidad de reloj se utiliza para reducir

el consumo de corriente cuando el microcontrolador funciona en modo de

reposo. ¿De qué se trata todo esto?

Cuando se configura en modo LP, XT o HS, el oscilador externo se

desactiva al pasar a modo de reposo para reducir el consumo de corriente

total del dispositivo. Cuando se cumplen las condiciones de

"despertamiento", el microcontrolador no se pone a funcionar

inmediatamente puesto que tiene que esperar a que se estabilice la

frecuencia de señal de reloj. Este tiempo muerto dura exactamente 1024

pulsos, después de que el microcontrolador continúa con la ejecución del

programa. El caso es que se ejecutan sólo unas pocas instrucciones antes

de que el microcontrolador vuelva al modo de reposo.

Eso significa que la mayoría de tiempo así como la mayoría de corriente de

baterías se ha perdido en vano. El caso se soluciona utilizando el oscilador

interno para ejecutar el programa durante la duración de 1024 pulsos. Tan

pronto como se estabilice la frecuencia del oscilador externo, él retoma

Page 300: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 300

automáticamente "el papel principal". Todo el procedimiento se habilita al

poner a uno el bit de palabra de configuración. Para programar el

microcontrolador, es necesario seleccionar la opción Int-Ext Switchover

(conmutación interna/externa) por software.

MONITOR PARA DETECTAR UN FALLO DE LA FUENTE DE RELOJ

(FAIL-SAFE CLOCK MONITOR)

Como indica su nombre, el monitor para detectar un fallo de la fuente de

reloj (Fail-Safe Clock Monitor - FSCM) monitorea el funcionamiento externo

y permite al microcontrolador continuar con la ejecución de programa en

caso de que el oscilador falle por alguna razón. En tal caso, el oscilador

interno toma su función.

Page 301: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 301

El monitor detecta un fallo al comparar las fuentes de reloj interno y externo.

Si los pulsos del oscilador externo tardan más de 2mS en llegar, la fuente

de reloj será automáticamente cambiada por la interna. Así, el oscilador

interno sigue funcionando controlado por los bits del registro OSCCON. Si el

bit OSFIE del registro PIE2 está a uno, se producirá una interrupción.

El reloj interno sigue siendo la fuente del reloj del sistema hasta que el

dispositivo reinicie con éxito el oscilador externo que vuelve a ser la fuente

de reloj del sistema. De manera similar a casos anteriores, este módulo está

habilitado al cambiar la palabra de configuración justamente antes de que

se inicie el proceso de programar el chip. Esta vez, esto se realiza al

seleccionar la opción Fail-Safe Clock Monitor.

Page 302: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 302

Registro OSCTUNE

Los cambios del registro OSCTUNE afectan a la frecuencia del oscilador

HFINTOSC, pero no a la frecuencia del LFINTOSC. No hay ninguna

indicación de que haya ocurrido desplazamiento de frecuencia durante el

funcionamiento del microcontrolador.

TUN4 - TUN0 Frequency Tuning bits. (bits de calibrar la frecuencia). Al

combinar estos cinco bits, la frecuencia del oscilador de 8Mhz se reduce o

Page 303: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 303

se aumenta. De este modo, las frecuencias obtenidas por la división en el

post-escalador cambian también.

T U N 4 T U N 3 T U N 2 T U N 1 T U N 0 F R E C U E N C I A

0 1 1 1 1 Máxima

0 1 1 1 0

0 1 1 0 1

0 0 0 0 1

0 0 0 0 0 Calibrada

1 1 1 1 1

1 0 0 1 0

1 0 0 0 1

1 0 0 0 0 Mínima

La EEPROM es un segmento de memoria separado, que no pertenece a la

memoria de programa (ROM), tampoco a la memoria de datos (RAM).

Aunque a estas localidades de memoria no se les puede acceder fácil y

rápidamente, su propósito es insustituible. Los datos almacenados en la

EEMPROM están permanentemente guardados incluso al apagar la fuente

de alimentación, y pueden ser cambiados en cualquier momento. Por estas

características excepcionales cada byte de la EEPROM se considera

valioso.

3.11 MEMORIA EEPROM

El microcontrolador PIC16F887 dispone de 256 localidades de memoria

EEPROM controlados por los bits de los siguientes registros:

EECON1 (registro de control);

EECON2 (registro de control);

EEDAT (almacena los datos listos para escritura y lectura); y

Page 304: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 304

EEADR (almacena la dirección de la EEPROM a la que se accede).

Además, el registro EECON2 no es un registro verdadero, no existe

físicamente en el chip. Se utiliza sólo durante la escritura de los datos en la

memoria.

Los registros EEDATH y EEADRH se utilizan durante la escritura y lectura

de la EEPROM. Los dos se utilizan también durante la escritura y lectura de

la memoria de programa (FLASH).

Por considerar esto una zona de riesgo (por supuesto usted no quiere que

el microcontrolador borre su propio programa por casualidad), no vamos a

discutirlo aquí, no obstante le avisamos que tenga cuidado.

Registro EECON1

EEPGD - Program/Data EEPROM Select bit (bit de selección de

memorias)

1 - Acceso a la memoria Flash de programa.

0 - Acceso a la memoria de datos EEPROM.

WRERR - EEPROM Error Flag bit (bit de error de escritura)

1 - Se produce un error de escritura de forma prematura y ha ocurrido

un error.

0 - Se ha completado la operación de escritura.

WREN - EEPROM Write Enable bit (bit de habilitación de escritura)

1 - Escritura de datos en la EEPROM habilitada.

0 - Escritura de datos en la EEPROM deshabilitada.

WR - Write Control bit (bit de control de escritura)

1 - Se ha iniciado una operación de escritura de datos en la EEPROM.

Page 305: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 305

0 - Se ha completado una operación de escritura de datos en la

EEPROM.

RD - Read Control bit (bit de control de lectura)

1 - Inicia una lectura de la memoria EEPROM.

0 - Lectura de la memoria EEPROM deshabilitada.

LECTURA DE LA MEMORIA EEPROM

Para leer los datos de la memoria EEMPROM, siga los siguientes pasos:

Paso 1: Escribir la dirección (00h - FFh) en el registro EEADR.

Paso 2: Seleccionar el bloque de memoria EEPROM al poner a cero

el bit EEPGD del registro EECON1.

Paso 3: Poner a uno el bit RD del mismo registro para leer el

contenido de la localidad.

Paso 4: El dato se almacena en el registro EEDAT y está listo para su

uso.

El siguiente ejemplo muestra el procedimiento anteriormente descrito al

escribir un programa en lenguaje ensamblador:

BSF STATUS,RP1 ;

BCF STATUS,RP0 ; Acceder al banco 2

MOVF ADDRESS,W ; Mover la dirección al registro W

MOVWF EEADR ; Escribir la dirección

BSF STATUS,RP0 ; Acceder al banco 3

BCF EECON1,EEPGD ; Seleccionar la EEPROM

BSF EECON1,RD ; Leer los datos

BCF STATUS,RP0 ; Acceder al banco 2

MOVF EEDATA,W ; Dato se almacena en el registro W

La misma secuencia de programa escrita en C se parece a lo siguiente:

Page 306: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 306

W = EEPROM_Read(ADDRESS);

Las ventajas del uso del lenguaje C se han hecho más obvias, no lo cree?

ESCRITURA EN LA MEMORIA EEPROM

Antes de escribir los datos en la memoria EEPROM es necesario escribir la

dirección en el registro EESADR y los datos en el registro EESAT. Sólo ha

quedado seguir a una secuencia especial para iniciar la escritura para cada

byte. Durante el proceso de escritura las interrupciones deben estar

deshabilitadas.

El ejemplo que sigue muestra el procedimiento anteriormente descrito al

escribir un programa en lenguaje ensamblador:

BSF STATUS,RP1

BSF STATUS,RP0

BTFSC EECON,WR1 ; Esperar a que se complete la escritura anterior

GOTO $-1 ;

BCF STATUS,RP0 ; Banco 2

MOVF ADDRESS,W ; Mover la dirección a W

MOVWF EEADR ; Escribir la dirección

MOVF DATA,W ; Mover los datos a W

MOVWF EEDATA ; Escribir los datos

BSF STATUS,RP0 ; Banco 3

BCF EECON1,EEPGD ; Seleccionar la EEPROM

BSF EECON1,WREN ; Escritura a la EEPROM habilitada

BCF INCON,GIE ; Todas las interrupciones deshabilitadas

Page 307: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 307

MOVLW 55h

MOVWF EECON2

MOVLW AAh

MOVWF EECON2

BSF EECON1,WR

BSF INTCON,GIE ; Interrupciones habilitadas

BCF EECON1,WREN ; Escritura a la EEPROM deshabilitada

La misma secuencia de programa escrita en C se parece a lo siguiente:

W = EEPROM_Write(ADDRESS, W);

No hace falta comentar nada.

Vamos a hacerlo en mikroC...

// El ejemplo muestra cómo utilizar la librería EEPROM en el compilador

mikroC PRO for PIC.

char ii; // La variable ii utilizada en el bucle

void main(){

ANSEL = 0; // Configuración de los pines AN como E/S

digitales

ANSELH = 0;

PORTB = 0;

PORTC = 0;

PORTD = 0;

TRISB = 0;

Page 308: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 308

TRISC = 0;

TRISD = 0;

for(ii = 0; ii < 32; ii++) // Llenar el búfer con los datos

EEPROM_Write(0x80+ii, ii); // Escribir los datos en la dirección

0x80+ii

EEPROM_Write(0x02,0xAA); // Escribir un dato en la dirección 2 de

la EEMPROM

EEPROM_Write(0x50,0x55); // Escribir un dato en la dirección 0x50

// de la EEMPROM

Delay_ms(1000); // Diodos en los puertos PORTB y PORTC

PORTB = 0xFF; // para indicar el comienzo de la lectura

PORTC = 0xFF;

Delay_ms(1000);

PORTB = 0x00;

PORTC = 0x00;

Delay_ms(1000);

PORTB = EEPROM_Read(0x02); // Leer los datos de la dirección 2

de la EEPROM y

// visualizarla en el puerto PORB

PORTC = EEPROM_Read(0x50); // Leer los datos de la dirección

0x50 de la EEPROM y

// visualizarla en el puerto PORC

Delay_ms(1000);

Page 309: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 309

for(ii = 0; ii < 32; ii++) { // Leer el bloque de 32 bytes de la dirección

PORTD = EEPROM_Read(0x80+ii); // 0x80 y visualizarla en el puerto

PORTD

Delay_ms(250);

}

}

Aprimera vista, basta con encender una fuente de alimentación para hacer

funcionar un microcontrolador. A primera vista, basta con apagar una fuente

de alimentación para detenerlo. Sólo a primera vista. En realidad, el

arranque y el final del funcionamiento son las fases críticas de las que se

encarga una señal especial denominada RESET.

3.12 ¡REINICIO! ¿BLACK-OUT, BROWN-OUT O RUIDOS?

Al producirse un reinicio el microcontrolador detiene su funcionamiento

inmediatamente y borra sus registros. Una señal de reinicio se puede

generar externamente en cualquier momento (nivel lógico bajo en el pin

MCLR). Si se necesita, una señal también puede ser generada por la lógica

de control interna. Al encender una fuente de alimentación siempre se

produce un reinicio. Por muchos eventos de transición que ocurren al

encender una fuente de alimentación (centelleos y fogonazos de contactos

eléctricos en interruptores, subida de voltaje lenta, estabilización de la

frecuencia de señal de reloj graduada etc.) es necesario proporcionar un

cierto tiempo muerto antes de que el microcontrolador se ponga a funcionar.

Dos temporizadores internos PWRT y OST se encargan de eso. El PWRT

puede estar habilitado/ deshabilitado durante el proceso de escribir un

programa. Vamos a ver cómo funciona todo.

Page 310: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 310

Cuando el voltaje de la fuente de alimentación alcanza entre 1.2 y 1.7V, un

circuito denominado temporizador de arranque (Power-up timer) mantiene al

microcontrolador reiniciado durante unos 72mS. Tan pronto como transcurra

el tiempo, otro temporizador denominado temporizador de encendido del

oscilador (Oscillator start-up timer) genera otra señal de reinicio durante la

duración de 1024 períodos del oscilador de cuarzo. Al expirar el tiempo

muerto (marcado con Reset T en la Figura) y al poner a alto el pin MCLR,

todas las condiciones se han cumplido y el microcontrolador se pone a

ejecutar la primera instrucción en el programa.

Aparte de este reinicio "controlado" que ocurre al encender una fuente de

alimentación, hay dos tipos de reinicio denominados Black-out y Brown-out

que pueden producirse durante el funcionamiento del microcontrolador así

como al apagar una fuente de alimentación.

REINICIO BLACK-OUT

El reinicio black out ocurre al apagar una fuente de alimentación

correctamente. El microcontrolador no tiene tiempo para hacer nada

imprevisible puesto que el voltaje cae muy rápidamente por debajo de su

valor mínimo. En otras palabras, ¡se apaga la luz, las cortinas bajan y el

espectáculo ha terminado!

Page 311: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 311

REINICIO BROWN-OUT

Cuando el voltaje de la fuente de alimentación cae lentamente (un ejemplo

típico es descarga de baterías, aunque el microcontrolador experimentaría

unas caídas mucho más rápidas como un proceso lento) los componentes

internos detienen su funcionamiento gradualmente y ocurre el así llamado

reinicio Brownout. En tal caso, antes de que el microcontrolador detenga su

funcionamiento completamente, hay un peligro real de que los circuitos que

funcionan a frecuencias altas se pongan a funcionar de forma imprevisible.

El reinicio brown-out puede causar cambios fatales en el programa ya que

se almacena en la memoria flash incorporada en el chip.

RUIDO ELÉCTRICO

Es un tipo especial del reinicio Brownout que ocurre en un ambiente

industrial cuando voltaje de alimentación “parpadea” por un momento y cae

por debajo del valor mínimo. Aunque es corto, este ruido producido en una

línea de conducción eléctrica puede afectar desfavorablemente al

funcionamiento del dispositivo.

Page 312: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 312

PIN MCLR

Un cero lógico (0) al pin MCLR causa un reinicio inmediato y regular. Es

recomendable conectarlo de la forma mostrada en la Figura a la derecha.

La función de los componentes adicionales es de mantener un uno lógico

"puro" durante el funcionamiento normal. Si sus valores se seleccionan de

manera que proporcionen un nivel lógico alto en el pin después de que haya

transcurrido el tiempo muerto reset T, el microcontrolador se pondrá a

funcionar inmediatamente. Esto puede ser muy útil cuando se necesita

sincronizar el funcionamiento del microcontrolador con los componentes

adicionales o con el funcionamiento de varios microcontroladores.

Para evitar posibles errores al producirse el reinicio Brown-out, el PIC

16F887 tiene un “mecanismo de protección” incorporado. Es un circuito

simple, pero eficaz que reacciona cada vez que el voltaje de alimentación

cae por debajo de 4V (si se utiliza un voltaje de alimentación de 5V) y

mantiene este nivel de voltaje por más de 100 microsegundos. Este circuito

genera una señal después de que todo el microcontrolador funcionará como

si hubiera sido encendido por primera vez.

Page 313: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 313

Capitulo 4: Ejemplos

El propósito de este capítulo es de proporcionar la información básica que

necesita saber para ser capaz de utilizar microcontroladores con éxito en la

práctica. Por eso, este capítulo no contiene ningún programa muy

elaborado, tampoco dispone de un esquema de dispositivo con soluciones

extraordinarias. Por el contrario, los siguientes ejemplos son la mejor

prueba de que escribir un programa no es un privilegio ni cosa de talento,

sino una habilidad de “poner las piezas juntas del rompecabezas” al utilizar

directivas. Tenga la seguridad de que el diseño y el desarrollo de los

dispositivos generalmente siguen al método “probar-corregir-repetir”. Por

supuesto, cuánto más ahonde sobre el tema, más se complica, ya que tanto

los niños como los arquitectos de primera línea, ponen las piezas juntas del

rompecabezas.

4.1 CONEXIÓN BÁSICA

4.2 COMPONENTES ADICIONALES

4.3 EJEMPLO 1 - Escribir cabecera, configurar pines de E/S, utilizar la

función Delay y el operador Switch

4.4 EJEMPLO 2 - Utilizar instrucciones en ensamblador y el oscilador

interno LFINTOSC...

4.5 EJEMPLO 3 - Timer0 como un contador, declarar variables

nuevas, constantes de enumeración, utilizar relés...

4.6 EJEMPLO 4 - Utilizar los temporizadores Timer0, Timer1 y Timer2.

4.7 EJEMPLO 5 - Utilizar el temporizador perro - guardián

4.8 EJEMPLO 6 - Módulo CCP1 como generador de señal PWM

4.9 EJEMPLO 7 - Utilizar el convertidor A/D

4.10 EJEMPLO 8 - Utilizar memoria EEPROM

4.11 EJEMPLO 9 - Contador de dos dígitos LED, multiplexión

4.12 EJEMPLO 10 - Utilizar el visualizador LCD

4.13 EJEMPLO 11 - Comunicación serial RS-232

4.14 EJEMPLO 12 - Medición de temperatura por medio del sensor

DS1820. Uso del protocolo '1-wire'...

Page 314: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 314

4.15 EJEMPLO 13 - Generación de sonido, librería de sonido...

4.16 EJEMPLO 14 - Utilizar el visualizador LCD gráfico

4.17 EJEMPLO 15 - Utilizar el panel táctil...

4.1 CONEXIÓN BÁSICA

Para que un microcontrolador funcione apropiadamente es necesario

proporcionar lo siguiente:

Alimentación;

Señal de reinicio; y

Señal de reloj.

Como se muestra en la figura anterior, se trata de circuitos simples, pero no

tiene que ser siempre así. Si el dispositivo destino se utiliza para controlar

las máquinas caras o para mantener funciones vitales, todo se vuelve

mucho más complicado.

Page 315: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 315

ALIMENTACIÓN

Aunque el PIC16F887 es capaz de funcionar a diferentes voltajes de

alimentación, no es recomendable probar la ley de Murphy. Lo más

adecuado es proporcionar un voltaje de alimentación de 5V DC. Este

circuito, mostrado en la página anterior, utiliza un regulador de voltaje

positivo de tres terminales LM7805. Es un regulador integrado y barato que

proporciona una estabilidad de voltaje de alta calidad y suficiente corriente

para habilitar el funcionamiento apropiado del controlador y de los

periféricos (aquí suficiente significa una corriente de 1A).

SEÑAL DE REINICIO

Para que un microcontrolador pueda funcionar apropiadamente, un uno

lógico (VCC) se debe colocar en el pin de reinicio. El botón de presión que

conecta el pin MCLR a GND no es necesario. Sin embargo, este botón casi

siempre está proporcionado ya que habilita al microcontrolador volver al

modo normal de funcionamiento en caso de que algo salga mal. Al pulsar

sobre el botón RESET, el pin MCLR se lleva un voltaje de 0V, el

microcontrolador se reinicia y la ejecución de programa comienza desde el

principio. Una resistencia de 10k se utiliza para impedir un corto circuito a

tierra al presionar este botón.

SEÑAL DE RELOJ

A pesar de tener un oscilador incorporado, el microcontrolador no puede

funcionar sin componentes externos que estabilizan su funcionamiento y

determinan su frecuencia (velocidad de operación del microcontrolador).

Dependiendo de los elementos utilizados así como de las frecuencias el

oscilador puede funcionar en cuatro modos diferentes:

LP - Cristal de bajo consumo;

XT - Cristal / Resonador;

HS - Cristal/Resonador de alta velocidad; y

RC - Resistencia / Condensador.

Page 316: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 316

¿Por qué son estos modos importantes? Como es casi imposible construir

un oscilador estable que funcione a un amplio rango de frecuencias, el

microcontrolador tiene que “saber” a qué cristal está conectado, para poder

ajustar el funcionamiento de sus componentes internos. Ésta es la razón por

la que todos los programas utilizados para escribir un programa en el chip

contienen una opción para seleccionar el modo de oscilador. Vea la figura

de la izquierda.

Cristal de cuarzo

Al utilizar el cristal de cuarzo para estabilizar la frecuencia, un oscilador

incorporado funciona a una frecuencia determinada, y no es afectada por

los cambios de temperatura y de voltaje de alimentación. Esta frecuencia se

etiqueta normalmente en el encapsulado del cristal. Aparte del cristal, los

condensadores C1 y C2 deben estar conectados como se muestra en el

siguiente esquema. Su capacitancia no es de gran importancia. Por eso, los

valores proporcionados en la siguiente tabla se deben tomar como

recomendación y no como regla estricta.

Page 317: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 317

Resonador cerámico

Un resonador cerámico es más barato y muy similar a un cuarzo por la

función y el modo de funcionamiento. Por esto, los esquemas que muestran

su conexión al microcontrolador son idénticos. No obstante, los valores de

los condensadores difieren un poco debido a las diferentes características

eléctricas. Refiérase a la tabla que está a continuación.

Estos resonadores se conectan normalmente a los osciladores en caso de

que no sea necesario proporcionar una frecuencia extremadamente precisa.

Oscilador RC

Si la frecuencia de operación no es de importancia, entonces no es

necesario utilizar los componentes caros y adicionales para la

estabilización. En vez de eso, basta con utilizar una simple red RC,

mostrada en la siguiente figura. Como aquí es utilizada sólo la entrada del

oscilador local, la señal de reloj con la frecuencia Fosc/4 aparecerá en el pin

OSC2. Ésta es la frecuencia de operación del microcontrolador, o sea la

velocidad de ejecución de instrucciones.

Page 318: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 318

Oscilador externo

Si se requiere sincronizar el funcionamiento de varios microcontroladores o

si por alguna razón no es posible utilizar ninguno de los esquemas

anteriores, una señal de reloj se puede generar por un oscilador externo.

Refiérase a la siguiente figura.

Apesar del hecho de que el microcontrolador es un producto de la

tecnología moderna, no es tan útil sin estar conectado a los componentes

adicionales. Dicho de otra manera, el voltaje llevado a los pines del

microcontrolador no sirve para nada si no se utiliza para llevar a cabo

ciertas operaciones como son encender/apagar, desplazar, visualizar etc.

4.2 COMPONENTES ADICIONALES

Esta parte trata los componentes adicionales utilizados con más frecuencia

en la práctica, tales como resistencias, transistores, diodos LED,

visualizadores LED, visualizadores LCD y los circuitos de comunicación RS-

232.

Page 319: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 319

INTERRUPTORES Y BOTONES DE PRESIÓN

Los interruptores y los botones de presión son los dispositivos simples para

proporcionar la forma más simple de detectar la aparición de voltaje en un

pin de entrada del microcontrolador. No obstante, no es tan simple como

parece... Es por un rebote de contacto. El rebote de contacto es un

problema común en los interruptores mecánicos.

Al tocarse los contactos, se produce un rebote por su inercia y elasticidad.

Por consiguiente, la corriente eléctrica es rápidamente pulsada en lugar de

tener una clara transición de cero a la corriente máxima. Por lo general, esto

ocurre debido a las vibraciones, los desniveles suaves y la suciedad entre

los contactos. Este efecto no se percibe normalmente al utilizar estos

componentes en la vida cotidiana porque el rebote ocurre demasiado rápido

para afectar a la mayoría de los dispositivos eléctricos. Sin embargo,

pueden surgir problemas en algunos circuitos lógicos que responden lo

suficientemente rápido de manera que malinterpreten los pulsos producidos

al tocarse los contactos como un flujo de datos. De todos modos, el proceso

entero no dura mucho (unos pocos micro - o milisegundos), pero dura lo

suficiente para que lo detecte el microcontrolador. Al utilizar sólo un botón

de presión como una fuente de señal de contador, en casi 100% de los

casos ocurren los errores.

El problema se puede resolver con facilidad al conectar un simple circuito

RC para suprimir rápidos cambios de voltaje. Como el período del rebote no

está definido, los valores de los componentes no están precisamente

determinados. En la mayoría de los casos es recomendable utilizar los

valores que se muestran en la siguiente figura.

Page 320: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 320

Si se necesita una estabilidad completa, entonces hay que tomar medidas

radicales. La salida del circuito, mostrado en la siguiente figura (biestable

RS, también llamado flip flop RS), cambiará de estado lógico después de

detectar el primer pulso producido por un rebote de contacto. Esta solución

es más cara (interruptor SPDT), pero el problema es resuelto.

Aparte de estas soluciones de hardware, hay también una simple solución

de software. Mientras el programa prueba el estado de circuito lógico de un

pin de entrada, si detecta un cambio, hay que probarlo una vez más

después de un cierto tiempo de retardo. Si el programa confirma el cambio,

esto significa que un interruptor/botón de presión ha cambiado de posición.

Las ventajas de esta solución son obvias: es gratuita, se borran los efectos

del rebote de contacto y se puede aplicar a los contactos de una calidad

más baja también.

RELÉ

Un relé es un interruptor eléctrico que se abre y se cierra bajo el control de

otro circuito electrónico. Por eso está conectado a los pines de salida del

microcontrolador y utilizado para encender/apagar los dispositivos de alto

consumo tales como: motores, transformadores, calefactores, bombillas etc.

Estos dispositivos se colocan casi siempre lejos de los componentes

sensibles de la placa. Hay varios tipos de relés, pero todos funcionan de la

misma manera. Al fluir la corriente por la bobina, el relé funciona por medio

Page 321: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 321

de un electromagneto, abriendo y cerrando uno o más conjunto de

contactos. Similar a los optoacopladores no hay conexión galvánica

(contacto eléctrico) entre los circuitos de entrada y salida. Los relés

requieren con frecuencia tanto un voltaje más alto y una corriente más alta

para empezar a funcionar. También hay relés miniatura que se pueden

poner en marcha por una corriente baja obtenida directamente de un pin del

microcontrolador.

La figura que sigue muestra la solución utilizada con más frecuencia.

Para prevenir la aparición de un alto voltaje de autoinducción, causada por

una parada repentina del flujo de corriente por la bobina, un diodo

polarizado invertido se conecta en paralelo con la bobina. El propósito de

este diodo es de “cortar” este pico de voltaje.

Page 322: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 322

DIODOS LED

Probablemente sepa todo lo que necesita saber sobre los diodos LED, pero

también debe pensar en los jóvenes... A ver, ¿cómo destruir un LED?

Bueno...muy fácil.

Quemar con rapidez

Como cualquier otro diodo, los LEDs tienen dos puntas - un ánodo y un

cátodo. Conecte un diodo apropiadamente a la fuente de alimentación y va

a emitir luz sin ningún problema. Ponga al diodo al revés y conéctelo a la

misma fuente de alimentación (aunque sea por un momento). No emitirá luz

- ¡nunca más!

Quemar lentamente

Hay un límite de corriente nominal, o sea, límite de corriente máxima

especificada para cada LED que no se deberá exceder. Si eso sucede, el

diodo emitirá luz más intensiva, pero sólo por un período corto de tiempo.

Algo para recordar

De manera similar, todo lo que tiene que hacer es elegir una resistencia

para limitar la corriente mostrada a continuación. Dependiendo de voltaje de

alimentación, los efectos pueden ser espectaculares.

Page 323: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 323

VISUALIZADOR LED

Básicamente, un visualizador LED no es nada más que varios diodos LED

moldeados en la misma caja plástica. Hay varios tipos de los visualizadores

y algunos de ellos están compuestos por varias docenas de diodos

incorporados que pueden visualizar diferentes símbolos. No obstante, el

visualizador utilizado con más frecuencia es el visualizador de 7 segmentos.

Está compuesto por 8 LEDs. Los siete segmentos de un dígito están

organizados en forma de un rectángulo para visualizar los símbolos,

mientras que el segmento adicional se utiliza para el propósito de visualizar

los puntos decimales. Para simplificar la conexión, los ánodos y los cátodos

de todos los diodos se conectan al pin común así que tenemos

visualizadores de ánodo común y visualizadores de cátodo común,

respectivamente. Los segmentos están etiquetados con letras de a a g y dp,

como se muestra en la siguiente figura. Al conectarlos, cada diodo LED se

trata por separado, lo que significa que cada uno dispone de su propia

resistencia para limitar la corriente.

Aquí le presentamos unas cosas importantes a las que debe prestar

atención al comprar un visualizador LED:

Como hemos mencionado, dependiendo de si ánodos o cátodos están

conectados al pin común, tenemos visualizadores de ánodo común y

visualizadores de cátodo común. Visto de afuera, parece que no hay

ninguna diferencia entre estos visualizadores, pues se le recomienda

comprobar cuál se va a utilizar antes de instalarlo.

Cada pin del microcontrolador tiene un límite de corriente máxima que

puede recibir o dar. Por eso, si varios visualizadores están conectados

al microcontrolador, es recomendable utilizar así llamados LEDs de

Bajo consumo que utilizan solamente 2mA para su funcionamiento.

Page 324: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 324

Los segmentos del visualizador están normalmente etiquetados con

letras de a a g, pero no hay ninguna regla estrictaa cuáles pines del

visualizador estarán conectados. Por eso es muy importante

comprobarlo antes de empezar a escribir un programa o diseñar un

dispositivo.

Los visualizadores conectados al microcontrolador normalmente ocupan un

gran número de los pines de E/S valiosos, lo que puede ser un problema

sobre todo cuando se necesita visualizar los números compuestos por

varios dígitos. El problema se vuelve más obvio si, por ejemplo, se necesita

visualizar dos números de seis dígitos (un simple cálculo muestra que en

este caso se necesitan 96 pines de salida). La solución de este problema es

denominada multiplexión.

Aquí es cómo se ha hecho una ilusión óptica basada en el mismo principio

de funcionamiento como una cámara de película. Un sólo dígito está activo

a la vez, pero se tiene la impresión de que todos los dígitos de un número

están simultáneamente activos por cambiar tan rápidamente de las

condiciones de encendido/apagado.

Page 325: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 325

Veamos la figura anterior. Primero se aplica un byte que representa

unidades al puerto PORT2 del microcontrolador y se activa el transistor T1 a

la vez. Después de poco tiempo, el transistor T1 se apaga, un byte que

representa decenas se aplica al puerto PORT2 y el transistor T2 se activa.

Este proceso se está repitiendo cíclicamente a alta velocidad en todos los

dígitos y transistores correspondientes.

Lo decepcionante es que el microcontrolador es sólo un tipo de

computadora miniatura diseñada para interpretar el lenguaje de ceros y

unos, lo que se pone de manifiesto al visualizar cualquier dígito.

Concretamente, el microcontrolador no conoce cómo son unidades,

decenas, centenas, ni diez dígitos a los que estamos acostumbrados. Por

esta razón, cada número a visualizar debe pasar por el siguiente

procedimiento:

Antes que nada, un número de varios dígitos debe ser dividido en unidades,

centenas etc. en una subrutina específica. Luego, cada de estos dígitos se

debe almacenar en los bytes particulares. Los dígitos se hacen reconocibles

al realizar "enmascaramiento". En otras palabras, el formato binario de cada

dígito se sustituye por una combinación diferente de los bits por medio de

una subrutina simple. Por ejemplo, el dígito 8 (0000 1000) se sustituye por

el número binario 0111 1111 para activar todos los LEDs que visualizan el

número 8. El único diodo que queda inactivo aquí está reservado para el

punto decimal.

Page 326: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 326

Si un puerto del microcontrolador está conectado al visualizador de tal

manera que el bit 0 active el segmento 'a', el bit 1 active el segmento 'b', el

bit 2 active el segmento 'c' etc, entonces la tabla que sigue muestra la

"máscara" para cada dígito.

D Í G I T O S A V I S U A L I Z A R

S E G M E N T O S D E L V I S U A L I Z A D O R

dp a b c d e f g

0 0 1 1 1 1 1 1 0

1 0 0 1 1 0 0 0 0

2 0 1 1 0 1 1 0 1

3 0 1 1 1 1 0 0 1

4 0 0 1 1 0 0 1 1

5 0 1 0 1 1 0 1 1

6 0 1 0 1 1 1 1 1

7 0 1 1 1 0 0 0 0

8 0 1 1 1 1 1 1 1

9 0 1 1 1 1 0 1 1

Page 327: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 327

Además de los dígitos de 0 a 9, hay algunas letras -A, C, E, J, F, U, H, L, b,

c, d, o, r, t - que se pueden visualizar al enmascarar.

En caso de que se utilicen los visualizadores de ánodo común, todos los

unos contenidos en la tabla anterior se deben sustituir por ceros y

viceversa. Además, los transistores PNP se deben utilizar como

controladores.

OPTOACOPLADORES

Un optoacoplador es un dispositivo frecuentemente utilizado para aislar

galvánicamente el microcontrolador de corriente o voltaje potencialmente

peligroso de su entorno. Los optoacopladores normalmente disponen de

una, dos o cuatro fuentes de luz (diodos LED) en su entrada mientras que

en su salida, frente a los diodos, se encuentra el mismo número de los

elementos sensibles a la luz (foto-transistores, foto-tiristores, foto-triacs). El

punto es que un optoacoplador utiliza una corta ruta de transmisión óptica

para transmitir una señal entre los elementos de circuito, que están aislados

eléctricamente. Este aislamiento tiene sentido sólo si los diodos y los

elementos foto-sensitivos se alimentan por separado. Así, el

microcontrolador y los componentes adicionales y caros están

completamente protegidos de alto voltaje y ruidos que son la causa más

frecuente de destrucción, daño y funcionamiento inestable de los

dispositivos electrónicos en la práctica. Los optoacopladores utilizados con

más frecuencia son aquéllos con foto-transistores en sus salidas. En los

optoacopladores con la base conectada al pin 6 interno (también hay

optoacopladores sin ella), la base puede quedarse desconectada.

Page 328: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 328

La red R/C representada por una línea quebrada en la figura anterior indica

una conexión opcional de la base de transistores dentro del optoacoplador,

que reduce los efectos de ruidos al eliminar los pulsos muy cortos.

VISUALIZADOR LCD

Este componente está específicamente fabricado para ser utilizado con los

microcontroladores, lo que significa que no se puede activar por los circuitos

integrados estándar. Se utiliza para visualizar los diferentes mensajes en un

visualizador de cristal líquido miniatura. El modelo descrito aquí es el más

utilizado en la práctica por su bajo precio y grandes capacidades. Está

basado en el microcontrolador HD44780 (Hitachi) integrado y puede

visualizar mensajes en dos líneas con 16 caracteres cada una. Puede

visualizar todas las letras de alfabeto, letras de alfabeto griego, signos de

puntuación, símbolos matemáticos etc. También es posible visualizar

símbolos creados por el usuario. Entre otras características útiles es el

desplazamiento automático de mensajes (a la izquierda y a la derecha),

aparición del cursor, retroiluminación LED etc.

Page 329: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 329

Pines del visualizador LCD

A lo largo de un lado de una placa impresa pequeña del visualizador LCD se encuentran los pines que le permiten

estar conectado al microcontrolador. Hay 14 pines en total marcados con números (16 si hay retroiluminación). Su

función se muestra en la tabla que sigue:

F U N C I Ó N N Ú M E R O N O M B R E E S T A D O L Ó G I C O

D E S C R I P C I Ó N

Tierra 1 Vss - 0V

Alimentación 2 Vdd - +5V

Contraste 3 Vee - 0 - Vdd

Control de funcionamiento

4 RS 0 1

D0 – D7 considerados como comandos D0 – D7 considerados como datos

5 R/W 0 1

Escribir los datos (del microcontrolador al LCD) Leer los datos (del LCD al microcontrolador)

6 E

0 1

Transición de 1 a 0

Acceso al visualizador LCD deshabilitado Funcionamiento normal Datos/comandos se están transmitiendo al LCD

Datos / comandos

7 D0 0/1 Bit 0 LSB

8 D1 0/1 Bit 1

9 D2 0/1 Bit 2

Page 330: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 330

10 D3 0/1 Bit 3

11 D4 0/1 Bit 4

12 D5 0/1 Bit 5

13 D6 0/1 Bit 6

14 D7 0/1 Bit 7 MSB

Page 331: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 331

Pantalla LCD

Una pantalla LCD puede visualizar dos líneas con 16 caracteres cada una.

Cada carácter consiste en 5x8 o 5x11 píxeles. Este libro cubre un

visualizador de 5x8 píxeles que es utilizado con más frecuencia.

El contraste del visualizador depende del voltaje de alimentación y de si los

mensajes se visualizan en una o dos líneas. Por esta razón, el voltaje

variable 0-Vdd se aplica al pin marcado como Vee. Un potenciómetro trimer

se utiliza con frecuencia para este propósito. Algunos de los visualizadores

LCD tienen retroiluminación incorporada (diodos LED azules o verdes). Al

utilizarlo durante el funcionamiento, se debe de conectar una resistencia en

serie a uno de los pines para limitar la corriente (similar a diodos LED).

Si no hay caracteres visualizados o si todos los caracteres están

oscurecidos al encender el visualizador, lo primero que se debe hacer es

comprobar el potenciómetro para ajustar el contraste. ¿Está ajustado

apropiadamente? Lo mismo se aplica si el modo de funcionamiento ha sido

cambiado (escribir en una o en dos líneas).

Memoria LCD

El visualizador LCD dispone de tres bloques de memoria:

Page 332: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 332

DDRAM Display Data RAM (RAM de datos de visualización);

CGRAM Character Generator RAM (generador de caracteres RAM); y

CGROM Character Generator ROM (generador de caracteres ROM)

Memoria DDRAM

La memoria DDRAM se utiliza para almacenar los caracteres a visualizar.

Tiene una capacidad de almacenar 80 caracteres. Algunas localidades de

memoria están directamente conectadas a los caracteres en el visualizador.

Todo funciona muy simple: basta con configurar el visualizador para

incrementar direcciones automáticamente (desplazamiento a la derecha) y

establecer la dirección inicial para el mensaje que se va a visualizar (por

ejemplo 00 hex).

Luego, todos los caracteres enviados por las líneas D0-D7 se van a

visualizar en el formato de mensaje al que nos hemos acostumbrado - de la

izquierda a la derecha. En este caso, la visualización empieza por el primer

campo de la primera línea ya que la dirección inicial es 00hex. Si se envía

más de 16 caracteres, todos se memorizarán, pero sólo los primeros 16

serán visibles. Para visualizar los demás, se debe utilizar el comando shift.

Virtualmente, parece como si el visualizador LCD fuera una ventana,

desplazándose de la izquierda a la derecha sobre las localidades de

memoria con diferentes caracteres. En realidad, así es cómo se creó el

efecto de desplazar los mensajes sobre la pantalla.

Si se habilita ver el cursor, aparecerá en la localidad actualmente

direccionada. En otras palabras, si un carácter aparece en la posición del

cursor, se va a mover automáticamente a la siguiente localidad

direccionada.

Esto es un tipo de memoria RAM así que los datos se pueden escribir en

ella y leer de ella, pero su contenido se pierde irrecuperablemente al apagar

la fuente de alimentación.

Page 333: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 333

Memoria CGROM

La memoria CGROM contiene un mapa estándar de todos los caracteres

que se pueden visualizar en la pantalla. A cada carácter se le asigna una

localidad de memoria:

Las direcciones de las localidades de memoria CGROM corresponden a los

caracteres ASCII. Si el programa que se está actualmente ejecutando llega

al comando „enviar el carácter P al puerto‟, el valor binario 0101 0000

aparecerá en el puerto. Este valor es el equivalente ASCII del carácter P. Al

escribir este valor en un LCD, se visualizará el símbolo de la localidad 0101

Page 334: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 334

0000 de la CGROM. En otras palabras, se visualizará el carácter P. Esto se

aplica a todas las letras del alfabeto (minúsculas y mayúsculas), pero no se

aplica a los números.

Como se muestra en el mapa anterior, las direcciones de todos los dígitos

se desplazan por 48 en relación con sus valores (dirección del dígito 0 es

48, dirección del dígito 1 es 49, dirección del dígito 2 es 50 etc.). Por

consiguiente, para visualizar los dígitos correctamente es necesario añadir

el número decimal 48 a cada uno antes de enviarlos a un LCD.

¿Qué es un código ASCII? Desde su aparición hasta hoy en día, las

computadoras han sido capaces de reconocer solamente números, y no las

letras. Esto significa que todos los datos que una computadora intercambia

con un periférico, reconocidos como letras por los humanos, en realidad

están en el formato binario (el teclado es un buen ejemplo). En otras

palabras, a cada carácter le corresponde la combinación única de ceros y

unos. El código ASCII representa una codificación de caracteres basada en

el alfabeto inglés. El ASCII especifica una correspondencia entre los

símbolos de caracteres estándar y sus equivalentes numéricos.

Page 335: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 335

Memoria CGRAM

Además de los caracteres estándar, el visualizador LCD puede visualizar

símbolos definidos por el usuario. Esto puede ser cualquier símbolo de 5x8

píxeles. La memoria RAM denominada CGRAM de 64 bytes lo habilita.

Los registros de memoria son de 8 bits de anchura, pero sólo se utilizan 5

bits más bajos. Un uno lógico (1) en cada registro representa un punto

oscurecido, mientras que 8 localidades agrupados representan un carácter.

Esto se muestra en la siguiente figura:

Los símbolos están normalmente definidos al principio del programa por una

simple escritura de ceros y unos de la memoria CGRAM así que crean las

formas deseadas. Para visualizarlos basta con especificar su dirección.

Preste atención a la primera columna en el mapa de caracteres CGROM.

No contiene direcciones de la memoria RAM, sino los símbolos de los que

Page 336: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 336

se está hablando aquí. En este ejemplo „visualizar 0‟ significa visualizar

„sonrisa‟, „visualizar 1‟ significa - visualizar „ancla‟ etc.

Comandos básicos del visualizador LCD

Todos los datos transmitidos a un visualizador LCD por las salidas D0-D7

serán interpretados como un comando o un dato, lo que depende del estado

lógico en el pin RS:

RS = 1 - Los bits D0 - D7 son direcciones de los caracteres a

visualizar. El procesador LCD direcciona un carácter del mapa de

caracteres y lo visualiza. La dirección DDRAM especifica la localidad

en la que se va a visualizar el carácter. Esta dirección se define antes

de transmitir el carácter o la dirección del carácter anteriormente

transmitido será aumentada automáticamente.

RS = 0 - Los bits D0 - D7 son los comandos para ajustar el modo del

visualizador.

En la siguiente tabla se muestra una lista de comandos reconocidos por el

LCD:

Page 337: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 337

C O M A N D O R S R W D 7 D 6 D 5 D 4 D 3 D 2 D 1 D 0

T I E M P O D E

E J E C U C I ÓN

Borrar el visualizador 0 0 0 0 0 0 0 0 0 1 1.64mS

Poner el cursor al inicio 0 0 0 0 0 0 0 0 1 x 1.64mS

Modo de entrada 0 0 0 0 0 0 0 1 I/D S 40uS

Activar/desactivar el visualizador

0 0 0 0 0 0 1 D U B 40uS

Desplazar el cursor/visualizador

0 0 0 0 0 1 D/C R/L x x 40uS

Modo de funcionamiento 0 0 0 0 1 DL N F x x 40uS

Establecer la dirección CGRAM

0 0 0 1 Dirección CGRAM 40uS

Establecer la dirección DDRAM

0 0 1 Dirección CGRAM 40uS

Leer la bandera "BUSY"(ocupado) (BF)

0 1 BF Dirección CGRAM -

Escribir en la CGRAM o en la DDRAM

1 0 D7 D6 D5 D4 D3 D2 D1 D0 40uS

Leer la CGRAM o la DDRAM

1 1 D7 D6 D5 D4 D3 D2 D1 D0 40uS

Page 338: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 338

I/D 1 = Incremento (por 1) R/L 1 = Desplazamiento a la

derecha

0 = Decremento (por 1) 0 = Desplazamiento a la

izquierda

S 1 = Desplazamiento del visualizador activado DL 1 = Bus de datos

de 8 bits

0 = Desplazamiento del visualizador desactivado 0 = Bus de datos

de 4 bits

D 1 = Visualizador encendido N 1 = Visualizador de dos

líneas

0 = Visualizador apagado 0 = Visualizador en una

línea

U 1 = Cursor activado F 1 = Carácter de 5x10 puntos

0 = Cursor desactivado 0 = Carácter de 5x7 puntos

B 1 = Parpadeo del cursor encendido D/C 1 = Desplazamiento

del visualizador

0 = Parpadeo del cursor apagado 0 = Desplazamiento del

cursor

¿QUÉ ES UNA BANDERA DE OCUPADO (BUSY FLAG)?

En comparación al microcontrolador, el LCD es un componente

extremadamente lento. Por esta razón, era necesario proporcionar una

señal que, al ejecutar un comando, indicaría que el visualizador estaba listo

para recibir el siguiente dato. Esta señal denominada bandera de ocupado

(busy flag) se puede leer de la línea D7. El visualizador está listo para

recibir un nuevo dato cuando el voltaje en esta línea es de 0V (BF=0).

Page 339: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 339

Conectar al visualizador LCD

Dependiendo de cuántas líneas se utilizan para conectar un LCD al

microcontrolador, hay dos modos de LCD, el de 8 bits y el de 4 bits. El

modo apropiado se selecciona en el inicio del funcionamiento en el proceso

denominado „inicialización‟. El modo de LCD de 8 bits utiliza los pines D0-

D7 para transmitir los datos, como hemos explicado en la página anterior. El

propósito principal del modo de LCD de 4 bits es de ahorrar los valiosos

pines de E/S del microcontrolador. Sólo los 4 bits más altos (D4-D7) se

utilizan para la comunicación, mientras que los demás pueden quedarse

desconectados. Cada dato se envía al LCD en dos pasos - primero se

envían 4 bits más altos (normalmente por las líneas D4- D7), y luego los 4

bits más bajos. La inicialización habilita que el LCD conecte e interprete los

bits recibidos correctamente.

Pocas veces se leen los datos del LCD (por lo general se transmiten del

microcontrolador al LCD) así que, con frecuencia, es posible guardar un pin

de E/S de sobra. Es simple, basta con conectar el pin L/E a Tierra. Este

“ahorro” del pin tiene su precio. Los mensajes se visualizarán normalmente,

pero no será posible leer la bandera de ocupado ya que tampoco es posible

leer los datos del visualizador. Afortunadamente, hay una solución simple.

Después de enviar un carácter o un comando es importante dar al LCD

suficiente tiempo para hacer su tarea. Debido al hecho de que la ejecución

de un comando puede durar aproximadamente 1.64mS, el LCD tarda como

máximo 2mS en realizar su tarea.

Page 340: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 340

Inicializar al visualizador LCD

Al encender la fuente de alimentación, el LCD se reinicia automáticamente.

Esto dura aproximadamente 15mS. Después de eso, el LCD está listo para

funcionar. Asimismo, el modo de funcionamiento está configurado por

defecto de la siguiente manera:

1. Visualizador está borrado.

2. Modo

DL = 1 - Bus de datos de 8 bits

N = 0 - LCD de una línea

F = 0 - Carácter de 5 x 8 puntos

3. Visualizador/Cursor encendido/apagado

D = 0 - Visualizador apagado

U = 0 - Cursor apagado

B = 0 - Parpadeo del cursor apagado

4. Introducción de caracteres

ID = 1 Direcciones visualizadas se incrementan automáticamente en 1

S = Desplazamiento del visualizador desactivado

Por lo general, el reinicio automático se lleva a cabo sin problemas. ¡En la

mayoría de los casos, pero no siempre! Si por cualquier razón, el voltaje de

alimentación no llega a su máximo valor en 10mS, el visualizador se pone a

funcionar de manera completamente imprevisible. Si la unidad de voltaje no

es capaz de cumplir con las condiciones o si es necesario proporcionar un

funcionamiento completamente seguro, se aplicará el proceso de

inicialización. La inicialización, entre otras cosas, reinicia de nuevo al LCD,

al habilitarle un funcionamiento normal.

Hay dos algoritmos de inicialización. Cuál se utilizará depende de si la

conexión al microcontrolador se realiza por el bus de datos de 4 o 8 bits. En

ambos casos, después de inicialización sólo queda especificar los

comandos básicos y, por supuesto, visualizar los mensajes.

Refiérase a la Figura que sigue para el procedimiento de inicialización por el

bus de datos de 8 bits:

Page 341: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 341

¡Esto no es un error! En este algoritmo, el mismo valor se transmite tres

veces en fila.

El procedimiento de inicialización por el bus de datos de 4 bits:

Page 342: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 342

Vamos a hacerlo en mikroC...

/* En mikroC for PIC, basta con escribir sólo una función para realizar

todo el proceso

de la inicialización del LCD. Antes de llamar esta función es necesario

declarar los

bits LCD_D4-LCD_D7, LCD_RS y LCD_EN. */

...

Lcd_Init(); // Inicializar el LCD

Page 343: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 343

...

EJEMPLOS PRÁCTICOS

El proceso de crear un proyecto nuevo es muy simple. Seleccione la

opción New Project del menú Project como se muestra en la Figura de la

derecha.

Aparecerá una ventana que le guiará a través del proceso de creación de

un proyecto nuevo. La ventana de entrada de este programa contiene una

lista de acciones a realizar para crear un proyecto nuevo. Pulse el

botón Next.

Page 344: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 344

El proceso de creación de un proyecto nuevo consiste en cinco pasos:

1. Seleccione el tipo de microcontrolador a programar. En este caso se

trata del PIC16F887.

2. Seleccione la frecuencia de reloj del microcontrolador. En este caso el

valor seleccionado es 8 MHz.

3. Seleccione el nombre y la ruta del proyecto. En este caso, el nombre del

proyecto es First_Project. Está guardado en la carpeta C:\My projects.

Al nombre del proyecto se le asigna automáticamente la extensión

.mcppi. Se creará en el proyecto el archivo fuente con el mismo nombre

(First_Project .c.h).

4. Si el nuevo proyecto consiste de varios archivos fuente, se necesita

especificarlos y pulse sobre el botón Add para incluirlos. En este

ejemplo no hay archivos fuente adicionales.

5. Por último, se necesita confirmar todas las opciones seleccionadas.

Pulse sobre Finish.

Después de crear el proyecto, aparecerá una ventana blanca en la que

debe escribir el programa. Vea la siguiente figura:

Page 345: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 345

Una vez creado el programa, es necesario compilarlo en un código .hex.

Seleccione una de las opciones para compilar del menú Project:

Para crear un archivo .hex, seleccione la opción Build (Ctrl+F9) del

menú Project o pulse sobre el icono Build de la barra de herramientas

Project.

Por medio de la opción Build All Projects (Shift+F9) se compilan todos

los archivos del proyecto, librerías (si el código fuente contiene alguna

de ellas) y los archivos def para el microcontrolador utilizado.

La opción Build + Program (Ctrl+F11) es importante ya que permite al

compilador mikroC PRO for PIC cargar automáticamente el programa

en el microcontrolador después de la compilación. El proceso de la

programación se realiza por medio del programador PICFlash.

Todos los errores encontrados durante la compilación aparecerán en la

ventana Message. Si no hay errores en el programa, el compilador mikroC

PRO for PIC generará los correspondientes archivos de salida.

4.3 EJEMPLO 1

Escribir cabecera, configurar pines de E/S, utilizar la función Delay y el

operador Switch

El único propósito de este programa es de encender varios diodos LED en

el puerto B. Utilice este ejemplo para examinar cómo es un programa real.

La siguiente figura muestra el esquema de conexión, mientras que el

programa se encuentra en la siguiente página.

Page 346: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 346

Al encender la fuente de alimentación, cada segundo, el diodo LED en el

puerto B emite luz, lo que indica que el microcontrolador está conectado

correctamente y que funciona normalmente.

En este ejemplo se muestra cómo escribir una cabecera correctamente. Lo

mismo se aplica a todos los programas descritos en este libro. Para no

repetir, en los siguientes ejemplos no vamos a escribir la cabecera. Se

considera estar en el principio de cada programa, marcada como

"Cabecera".

Page 347: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 347

Para hacer este ejemplo más interesante, vamos a habilitar que los LEDs

conectados al puerto PORTB parpadeen. Hay varios modos de hacerlo:

1. Tan pronto como se encienda el microcontrolador, todos los LEDs

emitirán la luz por un segundo. La función Delay se encarga de eso en

el programa. Sólo se necesita ajustar la duración del tiempo de retardo

en milisegundos.

2. Después de un segundo, el programa entra en el bucle for, y se queda

allí hasta que la variable k sea menor que 20. La variable se incrementa

en 1 después de cada iteración. Dentro del bucle for, el operador switch

monitorea el estado lógico en el puerto PORTB. Si PORTB=0xFF, su

estado se invierte en 0x00 y viceversa. Cualquier cambio de estos

estados lógicos hace todos los LEDs parpadear. El ciclo de trabajo es

5:1 (500mS:100mS).

3. Al salir del bucle for, el estado lógico del puerto POTRB cambia (0xb

01010101) y el programa entra en el bucle infinito while y se queda allí

Page 348: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 348

hasta que 1=1. El estado lógico del puerto PORTB se invierte cada

200mS.

4.4 EJEMPLO 2

Utilizar instrucciones en ensamblador y el oscilador interno

LFINTOSC...

En realidad, esto es una continuación del ejemplo anterior, pero se ocupa

de un problema un poco más complicado... El propósito era hacer los LEDs

en el puerto PORTB parpadear lentamente. Se puede realizar al introducir

Page 349: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 349

un valor suficiente grande para el parámetro del tiempo de retardo en la

función Delay. No obstante, hay otra manera más eficiente para ejecutar el

programa lentamente. Acuérdese de que este microcontrolador tiene un

oscilador incorporado LFINTOSC que funciona a una frecuencia de 31kHz.

Ahora llegó la hora de “darle una oportunidad”.

El programa se inicia con el bucle do-while y se queda allí por 20 ciclos.

Después da cada iteración, llega el tiempo de retardo de 100ms, indicado

por un parpadeo relativamente rápido de los LEDs en el puerto PORTB.

Cuando el programa salga de este bucle, el microcontrolador se inicia al

utilizar el oscilador LFINTOSC como una fuente de señal de reloj. Los LEDs

parpadean más lentamente aunque el programa ejecuta el mismo bucle do-

while con un tiempo de retardo 10 veces más corto.

Con el propósito de hacer evidentes algunas situaciones potencialmente

peligrosas, se activan los bits de control por medio de las instrucciones en

ensamblador. Dicho de manera sencilla, al entrar o salir una instrucción en

ensamblador en el programa, el compilador no almacena los datos en un

banco actualmente activo de la RAM, lo que significa que en esta sección

de programa, la selección de bancos depende del registro SFR utilizado. Al

volver a la sección de programa escrito en C, los bits de control RP0 y RP1

deben recuperar el estado que tenían antes de „la aventura en

ensamblador‟. En este programa, el problema se resuelve al utilizar la

variable auxiliar saveBank, lo que guarda el estado de estos dos bits.

/* Cabecera *********************************************/

int k = 0; // Variable k es de tipo int

char saveBank; // Variable saveBank es de tipo char

void main() {

ANSEL = 0; // Todos los pines de E/S se configuran como

digitales

ANSELH = 0;

PORTB = 0; // Todos los pines del puerto PORTB se ponen

a 0

Page 350: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 350

TRISB = 0; // Pines del puerto PORTB se configuran como

salidas

do {

PORTB = ~PORTB; // Invertir el estado lógico del puerto

PORTB

Delay_ms(100); // Tiempo de retardo de 100mS

k++; // Incrementar k en 1

}

while(k<20); // Quedarse en bucle hasta que k<20

k=0; // Reiniciar variable k

saveBank = STATUS & 0b01100000; // Guardar el estado de los bits

RP0 y RP1

// (bits 5 y 6 del registro STATUS)

asm { // Inicio de una secuencia en ensamblador

bsf STATUS,RP0 // Seleccionar el banco de memoria que

contiene el

bcf STATUS,RP1 // registro OSCCON

bcf OSCCON,6 // Seleccionar el oscilador interno LFINTOSC

bcf OSCCON,5 // de frecuencia de 31KHz

bcf OSCCON,4

bsf OSCCON,0 // Microcontrolador utiliza oscilador interno

} // Final de la secuencia en ensamblador

STATUS &= 0b10011111; // Bits RP0 y RP1 recuperan el estado

original

Page 351: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 351

STATUS |= saveBank;

do {

PORTB = ~PORTB; // Invertir el estado lógico del puerto

PORTB

Delay_ms(10); // Tiempo de retardo de 10 mS

k++; // Incrementar k en 1

}

while(k<20); // Quedarse en el bucle hasta que k<20

}

4.5 EJEMPLO 3

Timer0 como un contador, declarar variables nuevas, constantes de

enumeración, utilizar relés...

En cuanto a los ejemplos anteriores, el microcontrolador ha ejecutado el

programa sin haber sido afectado de ninguna forma por su entorno. En la

práctica, hay pocos dispositivos que funcionen de esta manera (por

ejemplo, un simple controlador de luz de neón). Los pines de entrada se

utilizan también en este ejemplo. En la siguiente figura se muestra un

esquema, mientras que el programa está en la siguiente página. Todo sigue

siendo muy simple. El temporizador Timer0 se utiliza como un contador. La

entrada del contador está conectada a un botón de presión, así que cada

vez que se presiona el botón, el temporizador Timer0 cuenta un pulso.

Cuando el número de pulsos coincida con el número almacenado en el

registro TEST, un uno lógico (5V) aparecerá en el pin PORTD.3. Este

voltaje activa un relé electromecánico, y por eso este bit se le denomina

„RELÉ‟ en el programa.

Page 352: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 352

/*Cabecera****************************************************/

void main() {

char TEST = 5; // Constante TEST = 5

enum salidas {RELÉ = 3}; // Constante RELAY = 3

ANSEL = 0; // Todos los pines de E/S se configuran como

digitales

ANSELH = 0;

PORTA = 0; // Reiniciar el puerto PORTA

TRISA = 0xFF; // Todos los pines del puerto PORTA se

configuran como entradas

PORTD = 0; // Reiniciar el puerto PORTD

Page 353: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 353

TRISD = 0b11110111; // Pin RD3 se configura como salida, mientras

que los demás

// se configuran como entradas

OPTION_REG.F5 = 1; // Contador TMR0 recibe los pulsos por el pin

RA4

OPTION_REG.F3 = 1; // Valor del pre-escalador 1:1

TMR0 = 0; // Reiniciar el temporizador/contador TMR0

do {

if (TMR0 == TEST) // ¿Coincide el número en el temporizador con la

// constante TEST?

(PORTD.RELAY = 1); // Números coinciden. Poner el bit RD3 a uno

(salida RELÉ)

}

while (1); // Quedarse en el bucle infinito

}

Sólo una constante de enumeración RELÉ se utiliza en este ejemplo. Se le

asigna un valor mediante la declaración.

enum salidas {RELÉ = 3}; // Constante RELÉ = 3

Si varios pines del puerto PORTD están conectados a los relés, la expresión

anterior se puede escribir de la siguiente manera también:

enum salidas {RELÉ=3, CALENTADOR, MOTOR=6, SURTIDOR};

A todas las constantes, precedidas por las constantes con valores

asignados (RELÉ=3 y MOTOR=6), se les asignan automáticamente los

valores de las constantes precedentes, incrementados en 1. En este

Page 354: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 354

ejemplo, a las constantes CALENTADOR y SURTIDOR se les asignan los

valores 4 y 7, es decir (CALENTADOR=4 y SURTIDOR=7),

respectivamente.

4.6 EJEMPLO 4

Utilizar los temporizadores Timer0, Timer1 y Timer2. Utilizar

interrupciones, declarar nuevas funciones...

Al analizar los ejemplos anteriores, es probable que se haya fijado en la

desventaja de proporcionar tiempo de retardo por medio de la función

Delay. En estos casos, el microcontrolador se queda „estático‟ y no hace

nada. Simplemente espera que transcurra una cierta cantidad de tiempo.

Tal pérdida de tiempo es un lujo inaceptable, por lo que se deberá aplicar

otro método.

¿Se acuerda usted del capítulo de los temporizadores? ¿Se acuerda de lo

de interrupciones? Este ejemplo los conecta de una manera práctica. El

esquema se queda inalterada, y el desafío sigue siendo presente. Es

necesario proporcionar un tiempo de retardo suficiente largo para darse

cuenta de los cambios en el puerto. Para este propósito se utiliza el

temporizador Timer0 con el pre-escalador asignado. Siempre que se genere

una interrupción con cada desbordamiento en el registro del temporizador,

la variable cnt se aumenta automáticamente en 1 al ejecutarse cada rutina

de interrupción. Cuando la variable llega al valor 400, el puerto PORTB se

incrementa en 1. Todo el procedimiento se lleva a cabo “entre bastidores”,

lo que habilita al microcontrolador hacer otra tarea.

Page 355: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 355

/*Cabecera******************************************************/

unsigned cnt; // Definir la variable cnt

void interrupt() {

cnt++; // Con una interrupción la cnt se incrementa en 1

TMR0 = 96; // El valor inicial se devuelve en el temporizador TMR0

INTCON = 0x20; // Bit T0IE se pone a 1, el bit T0IF se pone a 0

}

void main(){

OPTION_REG = 0x84; // Pre-escalador se le asigna al temporizador

TMR0

Page 356: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 356

ANSEL = 0; // Todos los pines de E/S se configuran como digitales

ANSELH = 0;

TRISB = 0; // Todos los pines de puerto PORTB se configuran

// como salidas

PORTB = 0x0; // Reiniciar el puerto PORTB

TMR0 = 96; // Temporizador T0 cuenta de 96 a 255

INTCON = 0xA0; // Habilitada interrupción TMR0

cnt = 0; // A la variable cnt se le asigna un 0

do { // Bucle infinito

if (cnt == 400) { // Incrementar el puerto PORTB después 400

interrupciones

PORTB = PORTB++; // Incrementar número en el puerto PORTB en 1

cnt = 0; // Reiniciar la variable cnt

}

} while(1);

}

Siempre que se produzca un desbordamiento en el registro del

temporizador TRM0, ocurre una interrupción.

/*Cabecera******************************************************/

unsigned short cnt; // Definir la variable cnt

Page 357: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 357

void interrupt() {

cnt++ ; // Con una interrupción la cnt se incrementa en 1

PIR1.TMR1IF = 0; // Reiniciar el bit TMR1IF

TMR1H = 0x80; // El valor inicial se devuelve en los registros

TMR1L = 0x00; // del temporizador TMR1H y TMR1L

}

void main() {

ANSEL = 0; // Todos los pines de E/S se configuran como digitales

ANSELH = 0;

PORTB = 0xF0; // Valor inicial de los bits del puerto PORTB

TRISB = 0; // Pines del puerto PORTB se configuran como salidas

T1CON = 1; // Configurar el temporizador TMR1

PIR1.TMR1IF = 0; // Reiniciar el bit TMR1IF

TMR1H = 0x80; // Ajustar el valor inicial del temporizador TMR1

TMR1L = 0x00;

PIE1.TMR1IE = 1; // Habilitar la interrupción al producirse un

desbordamiento

cnt = 0; // Reiniciar la variable cnt

INTCON = 0xC0; // Interrupción habilitada (bits GIE y PEIE)

do { // Bucle infinito

if (cnt == 76) { // Cambiar el estado del puerto PORTB después de 76

interrupciones

PORTB = ~PORTB; // Número en el puerto PORTB está invertido

cnt = 0; // Reiniciar la variable cnt

}

} while (1);

Page 358: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 358

}

En este caso, una interrupción se habilita después de que se produzca un

desbordamiento en el registro del temporizador TMR1 (TMR1H, TMR1L).

Además, la combinación de los bits que varía en el puerto POTRB difiere de

la en el ejemplo anterior.

/*Cabecera******************************************************/

unsigned short cnt; // Definir la variable cnt

void Reemplazar() {

PORTB = ~PORTB; // Definir nueva función „Reemplazar‟

} // Función invierte el estado del puerto

void interrupt() {

if (PIR1.TMR2IF) { // Si el bit TMR2IF = 1,

cnt++ ; // Incrementar variable la cnt en 1

PIR1.TMR2IF = 0; // Reiniciar el bit y

TMR2 = 0; // Reiniciar el registro TMR2

}

}

// main

void main() {

cnt = 0; // Reiniciar la variable cnt

ANSEL = 0; // Todos los pines de E/S se configuran como digitales

Page 359: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 359

ANSELH = 0;

PORTB = 0b10101010; // Estado lógico en los pines del puerto PORTB

TRISB = 0; // Todos los pines del puerto PORTB se configuran

como salidas

T2CON = 0xFF; // Configurar el temporizador T2

TMR2 = 0; // Valor inicial del registro del temporizador TMR2

PIE1.TMR2IE = 1; // Interrupción habilitada

INTCON = 0xC0; // Bits GIE y PEIE se ponen a 1

while (1) { // Bucle infinito

if (cnt > 30) { // Cambiar el estado del puerto PORTB después de

// más de 30 interrupciones

Reemplazar(); // Función Reemplazar invierte el estado del puerto

PORTB

cnt = 0; // Reiniciar la variable cnt

}

}

}

En este ejemplo, una interrupción ocurre después de que se produce un

desbordamiento en el registro del temporizador TMR2. Para invertir el

estado lógico de los pines del puerto se utiliza la función Reemplazar, que

normalmente no pertenece al lenguaje C estándar.

4.7 EJEMPLO 5

Utilizar el temporizador perro - guardián

Page 360: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 360

Este ejemplo muestra cómo NO se debe utilizar el temporizador perro-

guardián. Un comando utilizado para reiniciar este temporizador se omite a

propósito en el bucle del programa principal, lo que habilita al temporizador

perro guardián “ganar la batalla del tiempo” y reiniciar al microcontrolador.

Por consiguiente, el microcontrolador se va a reiniciar sin parar, lo que

indicará el parpadeo de los LEDs del puerto PORTB.

/*Cabecera******************************************************/

void main() {

OPTION_REG = 0x0E; // Pre-escalador se le asigna al temporizador

WDT (1:64)

asm CLRWDT; // Comando en ensamblador para reiniciar el

temporizador WDT

PORTB = 0x0F; // Valor inicial del registro PORTB

Page 361: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 361

TRISB = 0; // Todos los pines del puerto PORTB se configuran

como salidas

Delay_ms(300); // Tiempo de retardo de 30mS

PORTB = 0xF0; // Valor del puerto PORTB diferente del inicial

while (1); // Bucle infinito. El programa se queda aquí hasta que el

// temporizador WDT reinicie al microcontrolador

}

Para que este ejemplo funcione apropiadamente, es necesario habilitar al

temporizador perro-guardián al seleccionar la opción Tools/mE

Programmer/Watchdog Timer - Enabled.

4.8 EJEMPLO 6

Módulo CCP1 como generador de señal PWM

Este ejemplo muestra el uso del módulo CCP1 en modo PWM. Para hacer

las cosas más interesantes, la duración de los pulsos en la salida P1A

(PORTC,2) se puede cambiar por medio de los botones de presión

simbólicamente denominados „OSCURO‟ y „CLARO‟. La duración ajustada

se visualiza como una combinación binaria en el puerto PORTB. El

funcionamiento de este módulo está bajo el control de las funciones

pertenecientes a la librería especializada PWM. Aquí se utilizan las tres de

ellas:

1. PWM1_init tiene el prototipo: void Pwm1_Init(long freq);

El parámetro freq ajusta la frecuencia de la señal PWM expresada en

hercios. En este ejemplo equivale a 5kHz.

2. PWM1_Start tiene el prototipo: void Pwm1_Start(void);

Page 362: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 362

3. PWM1_Set_Duty tiene el prototipo: void Pwm1_Set_Duty(unsigned

short duty_ratio);

El parámetro duty_ratio ajusta la duración de pulsos en una secuencia

de pulsos.

La librería PWM también contiene la función PWM_Stop utilizada para

deshabilitar este modo. Su prototipo es: void Pwm1_Stop(void);

/*Cabecera******************************************************/

// Definir las variables ciclo_de_trabajo_actual,

// ciclo_de trabajo_anterior

unsigned short ciclo_de_trabajo_actual;

unsigned short ciclo_de trabajo_anterior;

void initMain() {

ANSEL = 0; // Todos los pines de E/S se configuran como digitales

ANSELH = 0;

PORTA = 255; // Estado inicial del puerto PORTA

Page 363: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 363

TRISA = 255; // Todos los pines del puerto PORTA se configuran

como entradas

PORTB = 0; // Estado inicial del puerto PORTB

TRISB = 0; // Todos los pines del puerto PORTB se configuran como

salidas

PORTC = 0; // Estado inicial del puerto PORTC

TRISC = 0; // Todos los pines del puerto PORTC se configuran

// como salidas

PWM1_Init(5000); // Inicialización del módulo PWM (5KHz)

}

void main() {

initMain();

ciclo_de_trabajo_actual = 16; // Valor inicial de la variable

ciclo_de_trabajo_actual

ciclo_de trabajo_anterior = 0; // Reiniciar la variable ciclo_de

trabajo_anterior

PWM1_Start(); // Iniciar el módulo PWM1

while (1) { // Bucle infinito

if (Button(&PORTA, 0,1,1)) // Si se presiona el botón conectado al

RA0

ciclo_de_trabajo_actual++ ; // incrementar el valor de la variable

current_duty

if (Button(&PORTA, 1,1,1)) // Si se presiona el botón conectado al

RA1

Page 364: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 364

ciclo_de_trabajo_actual-- ; // decrementar el valor de la variable

current_duty

if (old_duty != ciclo_de_trabajo_actual) { // Si

ciclo_de_trabajo_actual y

// ciclo_de trabajo_anterior no son iguales

PWM1_Set_Duty(ciclo_de_trabajo_actual); // ajustar un nuevo

valor a PWM,

ciclo_de trabajo_anterior = ciclo_de_trabajo_actual; // Guardar el

nuevo valor

PORTB = ciclo_de trabajo_anterior; // y visualizarlo en el

puerto PORTB

}

Delay_ms(200); // Tiempo de retardo de 200mS

}

}

Para que este ejemplo funcione apropiadamente, es necesario marcar las

siguientes librerías en la ventana Library Manager antes de compilar el

programa:

PWM

Button

4.9 EXAMPLE 7

Utilizar el convertidor A/D

El convertidor A/D del microcontrolador PIC16F887 se utiliza en este

ejemplo. ¿Hace falta decir que todo es pan comido? Una señal analógica

variable se aplica al pin AN2, mientras que el resultado de la conversión de

Page 365: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 365

10 bits se muestra en los puertos POTRB y PORTD (8 bits menos

significativos en el puerto PORTD y 2 bits más significativos en el puerto

PORTB). La Tierra (GND) se utiliza como voltaje de referencia bajo Vref-,

mientras que el voltaje de referencia alto se aplica al pin AN3. Esto habilita

que la escala de medición se estire y encoja.

IEn otras palabras, el convertidor A/D siempre genera un resultado binario

de 10 bits, lo que significa que reconoce 1024 niveles de voltaje en total

(210=1024). La diferencia entre dos niveles de voltaje no es siempre la

misma. Cuánto menor sea la diferencia entre Vref+ y Vref-, tanto menor

será la diferencia entre dos de 1024 niveles. Como hemos visto, el

convertidor A/D es capaz de detectar pequeños cambios de voltaje.

/*Cabecera******************************************************/

unsigned int temp_res;

Page 366: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 366

void main() {

ANSEL = 0x0C; // Pines AN2 y AN3 se configuran como

analógicos

TRISA = 0xFF; // Todos los pines del puerto PORTA se

configuran

// como entradas

ANSELH = 0; // Los demás pines se configuran como digitales

TRISB = 0x3F; // Pines del puerto PORTB, RB7 y RB6 se

configuran

// como salidas

TRISD = 0; // Todos los pines del PORTD se configuran como

salidas

ADCON1.F4 = 1 ; // Voltaje de referencia es llevado al pin RA3.

do {

temp_res = ADC_Read(2); // Resultado de la conversión A/D es

copiado a temp_res

PORTD = temp_res; // 8 bits menos significativos se mueven al

puerto PORTD

PORTB = temp_res >> 2; // 2 bits más significativos se mueven a los

bits RB6 y RB7

} while(1); // Bucle infinito

}

Para que este ejemplo funcione apropiadamente, es necesario marcar la

librería ADC en la ventana Library Manager antes de compilar el programa:

ADC

Page 367: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 367

4.10 EJEMPLO 8

Utilizar memoria EEPROM

Este ejemplo muestra cómo escribir y leer la memoria EEPROM

incorporada. El programa funciona de la siguiente manera. El bucle principal

lee constantemente el contenido de localidad de la memoria EEPROM en la

dirección 5 (decimal). Luego el programa entra en el bucle infinito en el que

el puerto PORTB se incrementa y se comprueba el estado de entradas del

puerto PORTA.2. En el momento de presionar el botón denominado MEMO,

un número almacenado en el puerto PORTB será guardado en la memoria

EEPROM, directamente leído y visualizado en el puerto PORTD en forma

binaria.

Page 368: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 368

/*Cabecera******************************************************/

void main() {{

ANSEL = 0; // Todos los pines de E/S se configuran como

digitales

ANSELH = 0;

Page 369: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 369

PORTB = 0; // Valor inicial del puerto PORTB

TRISB = 0; // Todos los pines del puerto PORTB se configuran

// como salidas

PORTD = 0; // Valor inicial del puerto PORTB

TRISD = 0; // Todos los pines del puerto PORTD se configuran

// como salidas

TRISA = 0xFF; // Todos los pines del puerto PORTA se

configuran

// como entradas

PORTD = EEPROM_Read(5); // Leer la memoria EEPROM en la

dirección 5

do {

PORTB = PORTB++; // Incrementar el puerto PORTB en 1

Delay_ms(100); // Tiempo de retardo de 100mS

if (PORTA.F2)

EEPROM_Write(5,PORTB); // Si se pulsa el botón MEMO, guardar el

puerto PORTB

PORTD = EEPROM_Read(5); // Leer el dato escrito

do {

while (PORTA.F2); // Quedarse en este bucle hasta que el botón

esté pulsado

Page 370: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 370

}

}

while(1); // Bucle infinito

}

Para comprobar el funcionamiento de este circuito, basta con pulsar el

botón MEMO y apagar el dispositivo. Después de reiniciar el dispositivo, el

programa visualizará el valor guardado en el puerto PORTD. Acuérdese de

que en el momento de escribir, el valor fue visualizado en el puerto PORTB.

Para que este ejemplo funcione apropiadamente, es necesario marcar la

librería EEPROM en la ventana Library Manager antes de compilar el

programa:

EEPROM

4.11 EJEMPLO 9

Contador de dos dígitos LED, multiplexión

En este ejemplo el microcontrolador funciona como un contador de dos

dígitos. La variable i se incrementa (suficiente lentamente para ser visible) y

su valor se visualiza en un visualizador de dos dígitos LED (99-0). El punto

es habilitar una conversión de un número binario en un decimal y partirlo en

dos dígitos (en decenas y unidades). Como los segmentos del visualizador

LED se conectan en paralelo, es necesario asegurar que alternen

rápidamente para tener una impresión de que emiten la luz

simultáneamente (multiplexión por división en tiempo).

En este ejemplo, el temporizador TMR0 está encargado de la multiplexión

por división en tiempo, mientras que la función mask convierte un número

binario a formato decimal.

Page 371: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 371

/*Cabecera******************************************************/

unsigned short mask(unsigned short num);

unsigned short digit_no, digit10, digit1, digit, i;

void interrupt() {

if (digit_no == 0) {

PORTA = 0; // Apagar ambos visualizadores

PORTD = digit1; // Colocar máscara para visualizar unidades en el

// puerto PORTD

PORTA = 1; // Encender el visualizador para las unidades (LSD)

digit_no = 1;

}else{

Page 372: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 372

PORTA = 0; // Apagar ambos visualizadores

PORTD = digit10; // Colocar máscara para visualizar decenas en el

// puerto PORTD

PORTA = 2; // Encender el visualizador para las decenas (MSD)

digit_no = 0;

}

TMR0 = 0; // Reiniciar el contador TMRO

INTCON = 0x20; // Bit T0IF=0, T0IE=1

}

void main() {

OPTION_REG = 0x80; // Ajustar el temporizador TMR0

TMR0 = 0;

INTCON = 0xA0; // Deshabilitar las interrupciones

PEIE,INTE,RBIE,T0IE

PORTA = 0; // Apagar ambos visualizadores

TRISA = 0; // Todos los pines del puerto PORTA se configuran

// como salidas

PORTD = 0; // Apagar todos los segmentos del visualizador

TRISD = 0; // Todos los pines del puerto PORTD se configuran

// como salidas

do {

for (i = 0; i<=99; i++) { // Contar de 0 a 99

digit = i % 10u;

Page 373: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 373

digit1 = mask(digit); // Preparar la máscara para visualizar unidades

digit = (char)(i / 10u) % 10u;

digit10 = mask(digit); // Preparar la máscara para visualizar decenas

Delay_ms(1000);

}

} while (1); // Bucle infinito

}

mask.c

/*Cabecera******************************************************/

unsigned short mask(unsigned short num) {

switch (num) {

case 0 : return 0x3F;

case 1 : return 0x06;

case 2 : return 0x5B;

case 3 : return 0x4F;

case 4 : return 0x66;

case 5 : return 0x6D;

case 6 : return 0x7D;

case 7 : return 0x07;

case 8 : return 0x7F;

case 9 : return 0x6F;

}

}

Para que este ejemplo funcione apropiadamente, es necesario incluir el

archivo mask.c en el proyecto (aparte del archivo example9.c) en la ventana

Project Manager antes de compilar el programa:

Page 374: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 374

Example9.mcppi - Sources - Add File To Project

mask.c

example9.c

4.12 EJEMPLO 10

Utilizar el visualizador LCD

Este ejemplo muestra cómo utilizar un visualizador LCD alfanumérico. Las

librerías de funciones simplifican este programa, lo que significa que al final

el esfuerzo para crear el software vale la pena.

Un mensaje escrito en dos líneas aparece en el visualizador:

mikroElektronika

LCD example

Dos segundos más tarde, el mensaje en la segunda línea cambia, y se

visualiza el voltaje presente en la entrada del convertidor A/D (el pin RA2).

Por ejemplo:

mikroElektronika

voltage:3.141V

En un dispositivo real se puede visualizar temperatura actual o algún otro

valor medido en vez de voltaje.

Page 375: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 375

Para que este ejemplo funcione apropiadamente, es necesario marcar las

siguientes librerías en la ventana Library Manager antes de compilar el

programa:

ADC

LCD

/*Cabecera*****************************************************/

// Conexiones del módulo LCD

sbit LCD_RS at RB4_bit;

sbit LCD_EN at RB5_bit;

sbit LCD_D4 at RB0_bit;

sbit LCD_D5 at RB1_bit;

sbit LCD_D6 at RB2_bit;

sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;

sbit LCD_EN_Direction at TRISB5_bit;

sbit LCD_D4_Direction at TRISB0_bit;

sbit LCD_D5_Direction at TRISB1_bit;

sbit LCD_D6_Direction at TRISB2_bit;

sbit LCD_D7_Direction at TRISB3_bit;

// Final de las conexiones del módulo LCD

// Declarar variables

unsigned char ch;

unsigned int adc_rd;

char *text;

long tlong;

Page 376: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 376

void main() {

INTCON = 0; // Todas las interrupciones deshabilitadas

ANSEL = 0x04; // Pin RA2 se configura como una entrada

analógica

TRISA = 0x04;

ANSELH = 0; // Los demás pines se configuran como

digitales

Lcd_Init(); // Inicialización del visualizador LCD

Lcd_Cmd(_LCD_CURSOR_OFF); // Comando LCD (apagar el

cursor)

Lcd_Cmd(_LCD_CLEAR); // Comando LCD (borrar el LCD)

text = "mikroElektronika"; // Definir el primer mensaje

Lcd_Out(1,1,text); // Escribir el primer mensaje en la primera

línea

text = "LCD example"; // Definir el segundo mensaje

Lcd_Out(2,1,text); // Definir el primer mensaje

ADCON1 = 0x82; // Voltaje de referencia para la conversión

A/D es VCC

TRISA = 0xFF; // Todos los pines del puerto PORTA se

configuran como entradas

Delay_ms(2000);

text = "voltage:"; // Definir el tercer mensaje

Page 377: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 377

while (1) {

adc_rd = ADC_Read(2); // Conversión A/D. Pin RA2 es una

entrada.

Lcd_Out(2,1,text); // Escribir el resultado en la segunda línea

tlong = (long)adc_rd * 5000; // Convertir el resultado en milivoltios

tlong = tlong / 1023; // 0..1023 -> 0-5000mV

ch = tlong / 1000; // Extraer voltios (miles de milivoltios)

// del resultado

Lcd_Chr(2,9,48+ch); // Escribir resultado en formato ASCII

Lcd_Chr_CP('.');

ch = (tlong / 100) % 10; // Extraer centenas de milivoltios

Lcd_Chr_CP(48+ch); // Escribir resultado en formato ASCII

ch = (tlong / 10) % 10; // Extraer decenas de milivoltios

Lcd_Chr_CP(48+ch); // Escribir resultado en formato ASCII

ch = tlong % 10; // Extraer unidades de milivoltios

Lcd_Chr_CP(48+ch); // Escribir resultado en formato ASCII

Lcd_Chr_CP('V');

Delay_ms(1);

}

}

4.13 EJEMPLO 11

Comunicación serial RS-232

Este ejemplo muestra cómo utilizar el módulo EUSART del

microcontrolador. La conexión a una PC se habilita por medio del estándar

de comunicación RS-232. El programa funciona de la siguiente manera.

Cada byte recibido por medio de la comunicación serial se visualiza al

Page 378: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 378

utilizar los LEDs conectados al puerto PORTB y después se devuelve

automáticamente al transmisor. Si ocurre un error en recepción, se lo

indicará al encender el diodo LED. La manera más fácil es comprobar el

funcionamiento del dispositivo en la práctica al utilizar un programa estándar

de Windows denominado Hyper Terminal.

/*Cabecera******************************************************/

unsigned short i;

void main() {

UART1_Init(19200); // Inicializar el módulo USART

Page 379: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 379

// (8 bits, tasa de baudios 19200, no hay bit

// de paridad...)

while (1) {

if (UART1_Data_Ready()) { // si se ha recibido un dato

i = UART1_Read(); // leerlo

UART1_Write(i); // enviarlo atrás

}

}

}

Para que este ejemplo funcione apropiadamente, es necesario marcar la

librería UART en la ventana Library Manager antes de compilar el

programa:

UART

4.14 EJEMPLO 12

Medición de temperatura por medio del sensor DS1820. Uso del

protocolo ‘1-wire’...

La medición de temperatura es una de las tareas más frecuentes realizadas

por el microcontrolador. En este ejemplo, se utiliza un sensor DS1820 para

medir. Es capaz de medir en el rango de 55 °C a 125 °C con exactitud de

0.5 °C. Para transmitir los datos al microcontrolador se utiliza un tipo

especial de la comunicación serial denominado 1-wire. Debido al hecho de

que estos sensores son simples de utilizar y de grandes capacidades, los

comandos utilizados para hacerlos funcionar y controlarlos tienen la forma

de funciones almacenadas en la librería One_Wire. En total son las

siguientes tres funciones:

Ow_Reset se utiliza para reiniciar el sensor;

Ow_Read se utiliza para recibir los datos del sensor; y

Ow_Write se utiliza para enviar los comandos al sensor

Page 380: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 380

Este ejemplo muestra la ventaja de utilizar librerías con las funciones listas

para ser utilizadas. Concretamente, no tiene que examinar la

documentación proporcionada por el fabricante para utilizar el sensor. Basta

con copiar alguna de estas funciones en el programa. Si le interesa saber

cómo se declaran, basta con pulsar sobre alguna de ellas y seleccione la

opción Help.

/*Cabecera******************************************************/

// Conexiones del módulo LCD

sbit LCD_RS at RB4_bit;

sbit LCD_EN at RB5_bit;

sbit LCD_D4 at RB0_bit;

sbit LCD_D5 at RB1_bit;

sbit LCD_D6 at RB2_bit;

sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;

sbit LCD_EN_Direction at TRISB5_bit;

sbit LCD_D4_Direction at TRISB0_bit;

Page 381: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 381

sbit LCD_D5_Direction at TRISB1_bit;

sbit LCD_D6_Direction at TRISB2_bit;

sbit LCD_D7_Direction at TRISB3_bit;

// Final de conexiones del módulo LCD

const unsigned short TEMP_RESOLUTION = 9;

char *text = "000.0000";

unsigned temp;

void Display_Temperature(unsigned int temp2write) {

const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;

char temp_whole;

unsigned int temp_fraction;

// comprobar si la temperatura es negativa

if (temp2write & 0x8000) {

text[0] = '-';

temp2write = ~temp2write + 1;

}

// extraer temp_whole

temp_whole = temp2write >> RES_SHIFT ;

// convertir temp_whole en caracteres

if (temp_whole/100)

text[0] = temp_whole/100 + 48;

else

text[0] = '0';

Page 382: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 382

text[1] = (temp_whole/10)%10 + 48; // Extraer dígito de decenas

text[2] = temp_whole%10 + 48; // Extraer dígito de unidades

// extraer temp_fraction y convertirlo en unsigned int

temp_fraction = temp2write << (4-RES_SHIFT);

temp_fraction &= 0x000F;

temp_fraction *= 625;

// convertir temp_fraction en caracteres

text[4] = temp_fraction/1000 + 48; // Extraer dígito de miles

text[5] = (temp_fraction/100)%10 + 48; // Extraer dígito de centenas

text[6] = (temp_fraction/10)%10 + 48; // Extraer dígito de decenas

text[7] = temp_fraction%10 + 48; // Extraer dígito de unidades

// Visualizar temperatura en el LCD

Lcd_Out(2, 5, text);

}

void main() {

ANSEL = 0; // Configurar los pines AN como digitales

ANSELH = 0;

C1ON_bit = 0; // Deshabilitar los comparadores

C2ON_bit = 0;

Lcd_Init(); // Inicializar el LCD

Lcd_Cmd(_LCD_CLEAR); // Borrar el LCD

Lcd_Cmd(_LCD_CURSOR_OFF); // Apagar el cursor

Page 383: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 383

Lcd_Out(1, 1, " Temperatura: ");

// Visualizar el carácter de grado, 'C' para centígrados

Lcd_Chr(2,13,223); // distintos visualizadores LCD tienen diferentes

códigos

// de caracteres para el grado

// si ve la letra griega Alfa, intente introducir 178 en vez de 223

Lcd_Chr(2,14,'C');

//--- bucle principal

do {

//--- realizar lectura de temperatura

Ow_Reset(&PORTE, 2); // Señal de reinicio de Onewire

Ow_Write(&PORTE, 2, 0xCC); // Ejecutar el comando SKIP_ROM

Ow_Write(&PORTE, 2, 0x44); // Ejecutar el comando CONVERT_T

Delay_us(120);

Ow_Reset(&PORTE, 2);

Ow_Write(&PORTE, 2, 0xCC); // Ejecutar el comando SKIP_ROM

Ow_Write(&PORTE, 2, 0xBE); // Ejecutar el comando

READ_SCRATCHPAD

temp = Ow_Read(&PORTE, 2);

temp = (Ow_Read(&PORTE, 2) << 8) + temp;

//--- Formatear y visualizar el resultado en el LCD

Display_Temperature(temp);

Delay_ms(500);

} while (1);

Page 384: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 384

}

Para que este ejemplo funcione apropiadamente, es necesario marcar las

siguientes librerías en la ventana Library Manager antes de compilar el

programa:

One_Wire

LCD

4.15 EXAMPLE 13

Generación de sonido, librería de sonido...

Las señales de audio se utilizan con frecuencia cuando se necesita llamar la

atención de usuario, confirmar que alguno de los botones se ha pulsado,

avisar que se ha llegado hasta los valores mínimos o máximos etc. Pueden

ser una simple señal de pitido así como melodías de una duración más

larga o más corta. En este ejemplo se muestra la generación de sonido por

medio de funciones que pertenecen a la librería Sound.

Page 385: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 385

Además de estas funciones, la función Button que pertenece a la misma

librería se utiliza para probar los botones de presión.

/*Cabecera******************************************************/

void Tone1() {

Sound_Play(659, 250); // Frecuencia = 659Hz, duración = 250ms

}

void Tone2() {

Sound_Play(698, 250); // Frecuencia = 698Hz, duración = 250ms

}

void Tone3() {

Sound_Play(784, 250); // Frecuencia = 784Hz, duración = 250ms

}

void Melody1() { // Componer una melodía divertida 1

Tone1(); Tone2(); Tone3(); Tone3();

Tone1(); Tone2(); Tone3(); Tone3();

Tone1(); Tone2(); Tone3();

Tone1(); Tone2(); Tone3(); Tone3();

Tone1(); Tone2(); Tone3();

Tone3(); Tone3(); Tone2(); Tone2(); Tone1();

}

void ToneA() { // Tono A

Sound_Play( 880, 50);

}

Page 386: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 386

void ToneC() { // Tono C

Sound_Play(1046, 50);

}

void ToneE() { // Tono E

Sound_Play(1318, 50);

}

void Melody2() { // Componer una melodía divertida 2

unsigned short i;

for (i = 9; i > 0; i--) {

ToneA(); ToneC(); ToneE();

}

}

void main() {

ANSEL = 0; // Todos los pines de E/S son digitales

ANSELH = 0;

TRISB = 0xF0; // Pines RB7-RB4 se configuran como entradas

// RB3 se configura como salida

Sound_Init(&PORTB, 3);

Sound_Play(1000, 500);

while (1) {

if (Button(&PORTB,7,1,1)) // RB7 genera Tono1

Page 387: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 387

Tone1();

while (PORTB & 0x80) ; // Esperar que se suelte el botón

if (Button(&PORTB,6,1,1)) // RB6 genera Tono2

Tone2();

while (PORTB & 0x40) ; // Esperar que se suelte el botón

if (Button(&PORTB,5,1,1)) // RB5 genera melodía 2

Melody2();

while (PORTB & 0x20) ; // Esperar que se suelte el botón

if (Button(&PORTB,4,1,1)) // RB4 genera melodía 1

Melody1();

while (PORTB & 0x10) ; // Esperar que se suelte el botón

}

}

Para que este ejemplo funcione apropiadamente, es necesario marcar las

siguientes librerías en la ventana Library Manager antes de compilar el

programa:

Button

Sound

4.16 EJEMPLO 14

Utilizar el visualizador LCD gráfico

Un LCD gráfico (GLCD) proporciona un método avanzado para visualizar

mensajes. Mientras que un LCD de caracteres puede visualizar sólo

caracteres alfanuméricos, el LCD gráfico puede visualizar los mensajes en

forma de dibujos y mapas de bits. El LCD gráfico utilizado con más

frecuencia tiene una resolución de pantalla de 128x64 píxeles. El contraste

de un GLCD se puede ajustar por medio del potenciómetro P1.

Page 388: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 388

En este ejemplo el GLCD visualiza una secuencia de imágenes, de las que

un mapa de bits representa un camión almacenado en otro archivo

denominado truck_bmp.c. Para habilitar que este programa funcione

apropiadamente, usted debe añadir este archivo como archivo fuente a su

proyecto.

Las directivas del preprocesador incluidas en este ejemplo le permiten elegir

si quiere visualizar toda la secuencia de imágenes o sólo una secuencia

corta. Por defecto se visualizará toda la secuencia de imágenes. Sin

embargo, al añadir un comentario delante de la directiva#define

COMPLETE_EXAMPLE se deshabilita visualizar algunas imágenes de la

secuencia. Si se comenta (o si se borra) esta directiva, las sentencias entre

las directivas #ifdef COMPLETE_EXAMPLE y #endif no serán compiladas,

así que no se ejecutarán.

/*Cabecera******************************************************/

//Declaraciones-----------------------------------------------------------------

const code char truck_bmp[1024]; // Declarar la constante definida en

truck_bmp.c

// para utilizarla en este archivo

//--------------------------------------------------------final-de-declaraciones

Page 389: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 389

// Conexiones del módulo Glcd

char GLCD_DataPort at PORTD;

sbit GLCD_CS1 at RB0_bit;

sbit GLCD_CS2 at RB1_bit;

sbit GLCD_RS at RB2_bit;

sbit GLCD_RW at RB3_bit;

sbit GLCD_EN at RB4_bit;

sbit GLCD_RST at RB5_bit;

sbit GLCD_CS1_Direction at TRISB0_bit;

sbit GLCD_CS2_Direction at TRISB1_bit;

sbit GLCD_RS_Direction at TRISB2_bit;

sbit GLCD_RW_Direction at TRISB3_bit;

sbit GLCD_EN_Direction at TRISB4_bit;

sbit GLCD_RST_Direction at TRISB5_bit;

// Final de conexiones del módulo Glcd

void delay2S(){ // Función de tiempo de retardo de 2 segundos

Delay_ms(2000);

}

void main() {

unsigned short ii;

char *someText;

/* Esta directiva define un macro denominado COMPLETE_EXAMPLE.

Más tarde en el

programa, la directiva ifdef prueba si este macro está definido. Si se

borra esta

Page 390: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 390

línea o si se transforma en un comentario, las secciones del código entre

las

directivas ifdef y endif no serán compiladas. */

#define COMPLETE_EXAMPLE // Poner esta línea como un comentario

si quiere

// visualizar la versión corta de la secuencia

ANSEL = 0; // Configurar los pines AN como digitales

ANSELH = 0;

C1ON_bit = 0; // Deshabilitar comparadores

C2ON_bit = 0;

Glcd_Init(); // Inicializar el GLCD

Glcd_Fill(0x00); // Borrar el GLCD

while(1) { // bucle infinito, la secuencia se repite

/* Dibujar la primera imagen */

#ifdef COMPLETE_EXAMPLE

Glcd_Image(truck_bmp); // Dibujar la imagen

delay2S(); delay2S();

#endif

Glcd_Fill(0x00); // Borrar el GLCD

/* Dibujar la segunda imagen */

Glcd_Box(62,40,124,56,1); // Dibujar la caja

Glcd_Rectangle(5,5,84,35,1); // Dibujar el rectángulo

Glcd_Line(0, 0, 127, 63, 1); // Dibujar la línea

Page 391: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 391

delay2S();

for(ii = 5; ii < 60; ii+=5 ){ // Dibujar líneas horizontales y verticales

Delay_ms(250);

Glcd_V_Line(2, 54, ii, 1);

Glcd_H_Line(2, 120, ii, 1);

}

delay2S();

Glcd_Fill(0x00); // Borrar el GLCD

/* Dibujar la tercera imagen */

#ifdef COMPLETE_EXAMPLE

Glcd_Set_Font(Character8x7, 8, 7, 32); // Seleccionar la fuente, ver

// __Lib_GLCDFonts.c en la carpeta Uses

#endif

Glcd_Write_Text("mikroE", 1, 7, 2); // Escribir la cadena

for (ii = 1; ii <= 10; ii++) // Dibujar los círculos

Glcd_Circle(63,32, 3*ii, 1);

delay2S();

Glcd_Box(12,20, 70,57, 2); // Dibujar la caja

delay2S();

/* Dibujar la cuarta imagen */

Page 392: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 392

#ifdef COMPLETE_EXAMPLE

Glcd_Fill(0xFF); // Llenar el GLCD

Glcd_Set_Font(Character8x7, 8, 7, 32); // Cambiar de la fuente

someText = "8x7 Font";

Glcd_Write_Text(someText, 5, 0, 2); // Escribir la cadena

delay2S();

Glcd_Set_Font(System3x5, 3, 5, 32); // Cambiar de la fuente

someText = "3X5 CAPITALS ONLY";

Glcd_Write_Text(someText, 60, 2, 2); // Escribir la cadena

delay2S();

Glcd_Set_Font(font5x7, 5, 7, 32); // Cambiar de la fuente

someText = "5x7 Font";

Glcd_Write_Text(someText, 5, 4, 2); // Escribir la cadena

delay2S();

Glcd_Set_Font(FontSystem5x7_v2, 5, 7, 32); // Cambiar de la fuente

someText = "5x7 Font (v2)";

Glcd_Write_Text(someText, 5, 6, 2); // Escribir la cadena

delay2S();

#endif

}

}

truck_bmp.c:

/*Cabecera*****************************************************/

Page 393: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 393

unsigned char const truck_bmp[1024] = {

0, 0, 0, 0, 0,248, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12,

12, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9,

9, 9, 9, 9, 9, 9, 9, 9, 9, 9,137,137,137,137,137,137,

137,137,137,137,137,137,137, 9, 9, 9, 9, 9, 9, 9, 9, 9,

9, 9, 13,253, 13,195, 6,252, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

240,240,240,240,240,224,224,240,240,240,240,240,224,192,192,224,

240,240,240,240,240,224,192, 0, 0, 0,255,255,255,255,255,195,

195,195,195,195,195,195, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0,255,240, 79,224,255, 96, 96, 96, 32, 32, 32, 32, 32,

32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64,128, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

255,255,255,255,255, 0, 0, 0, 0,255,255,255,255,255, 0, 0,

0, 0,255,255,255,255,255, 0, 0, 0,255,255,255,255,255,129,

129,129,129,129,129,129,128, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0,255, 1,248, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,

8, 8, 8, 8, 16,224, 24, 36,196, 70,130,130,133,217,102,112,

160,192, 96, 96, 32, 32,160,160,224,224,192, 64, 64,128,128,192,

64,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 63, 96, 96, 96,224, 96, 96, 96, 96, 96, 96,

Page 394: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 394

99, 99, 99, 99, 99, 96, 96, 96, 96, 99, 99, 99, 99, 99, 96, 96,

96, 96, 99, 99, 99, 99, 99, 96, 96, 96, 99, 99, 99, 99, 99, 99,

99, 99, 99, 99, 99, 99, 99, 96, 96, 96, 96, 96, 96, 96, 64, 64,

64,224,224,255,246, 1, 14, 6, 6, 2, 2, 2, 2, 2, 2, 2,

2, 2, 2, 2,130, 67,114, 62, 35, 16, 16, 0, 7, 3, 3, 2,

4, 4, 4, 4, 4, 4, 4, 28, 16, 16, 16, 17, 17, 9, 9, 41,

112, 32, 67, 5,240,126,174,128, 56, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,

1, 1,127,127,127,127,255,255,247,251,123,191, 95, 93,125,189,

189, 63, 93, 89,177,115,243,229,207, 27, 63,119,255,207,191,255,

255,255,255,255,255,255,255,127,127,127,127,127,127,127,127,255,

255,255,127,127,125,120,120,120,120,120,248,120,120,120,120,120,

120,248,248,232,143, 0, 0, 0, 0, 0, 0, 0, 0,128,240,248,

120,188,220, 92,252, 28, 28, 60, 92, 92, 60,120,248,248, 96,192,

143,168,216,136, 49, 68, 72, 50,160, 96, 0, 0, 0, 0, 0, 0,

0, 0, 0,128,192,248,248,248,248,252,254,254,254,254,254,254,

254,254,254,254,254,255,255,255,255,255,246,239,208,246,174,173,

169,128,209,208,224,247,249,255,255,252,220,240,127,255,223,255,

255,255,255,255,255,254,254,255,255,255,255,255,255,255,254,255,

255,255,255,255,255,255,254,254,254,254,254,254,254,254,254,254,

254,254,254,254,255,255,255,255,255,255,254,255,190,255,255,253,

240,239,221,223,254,168,136,170,196,208,228,230,248,127,126,156,

223,226,242,242,242,242,242,177, 32, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 1, 1, 1, 1, 3, 3, 3, 7, 7, 7, 7, 7, 15,

15, 15, 7, 15, 15, 15, 7, 7, 15, 14, 15, 13, 15, 47, 43, 43,

43, 43, 43, 47,111,239,255,253,253,255,254,255,255,255,255,255,

191,191,239,239,239,191,255,191,255,255,255,255,255,255,255,255,

255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,

Page 395: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 395

255,255,255,255,127,127,127,127,255,255,191,191,191,191,255,254,

255,253,255,255,255,251,255,255,255,127,125, 63, 31, 31, 31, 31,

31, 31, 63, 15, 15, 7, 7, 3, 3, 3, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,

1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,

1, 1, 1, 1, 3, 3, 3, 11, 11, 11, 11, 7, 3, 14, 6, 6,

6, 2, 18, 19, 19, 3, 23, 21, 21, 17, 1, 19, 19, 3, 6, 6,

14, 15, 15, 7, 15, 15, 15, 11, 2, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

};

Para que este ejemplo funcione apropiadamente, es necesario marcar la

librería GLCD en la ventana Library Manager antes de compilar el

programa. Asimismo, es necesario incluir el documento truck_bmp.c en el

proyecto.

4.17 EJEMPLO 15

Utilizar el panel táctil...

Un panel táctil es un panel fino, autoadhesivo y transparente, colocado

sobre la pantalla de un LCD gráfico. Es muy sensible a la presión así que un

suave toque provoca algunos cambios en la señal de salida. Hay diferentes

tipos de paneles táctiles. El más sencillo es el panel táctil resistivo del que

se hablará aquí.

Page 396: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 396

Un panel táctil está compuesto por dos láminas rígidas, formando una

estructura de „sándwich‟ que tiene capas resistivas en sus caras internas.

La resistencia de estas capas no excede normalmente de 1Kohm. Los lados

opuestos de las láminas disponen de los contactos para acceder a un cable

plano.

El procedimiento para determinar las coordenadas de la posición del panel

que ha sido presionado se puede dividir en dos pasos. El primero es

determinación de la coordenada X, y el segundo es de determinar la

coordenada Y de la posición.

Para determinar la coordenada X, es necesario conectar el contacto

izquierdo en la superficie A a la masa (tierra) y el contacto derecho a la

fuente de alimentación. Esto permite obtener un divisor de voltaje al

presionar el panel táctil. El valor de voltaje obtenido en el divisor se puede

leer en el contacto inferior de la superficie B. El voltaje variará en el rango

de 0V al voltaje suministrado por la fuente de alimentación y depende de la

coordenada X. Si el punto está próximo al contacto izquierdo de la

superficie A, el voltaje estará próximo a 0V.

Page 397: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 397

Para la determinación de la coordenada Y, es necesario conectar el

contacto inferior de la superficie B a masa (tierra), mientras que el contacto

superior se conectará a la fuente de alimentación. En este caso, el voltaje

se puede leer en el contacto izquierdo de la superficie A .

Para conectar un panel táctil al microcontrolador es necesario crear un

circuito para el control del panel táctil. Por medio de este circuito, el

microcontrolador conecta los contactos adecuados del panel táctil a masa y

a la voltaje de alimentación (como describimos anteriormente) para

determinar las coordenadas X y Y. El contacto inferior de la superficie B y el

contacto izquierdo de la superficie A están conectados al convertidor A/D

del microcontrolador. Las coordenadas X e Y se determinan midiendo el

voltaje en los respectivos contactos. El software consiste en mostrar un

menú en una pantalla LCD gráfica, conmutar de encendido a apagado del

panel táctil (control del panel táctil) y leer los valores del convertidor A/D que

representan realmente las coordenadas X e Y de la posición.

Una vez determinadas las coordenadas, es posible decidir qué es lo que

deseamos que haga el microcontrolador. En este ejemplo se explica cómo

conmutar entre encendido y apagado dos pines digitales del

microcontrolador, conectados a los LEDs A y B.

En este ejemplo se utilizan las funciones que pertenecen a las librerías Glcd

y ADC.

Teniendo en cuenta que la superficie del panel táctil es ligeramente mayor

que la del LCD gráfico, en caso de requerir una mayor precisión en la

determinación de las coordenadas, es necesario incluir el software de

calibración del panel táctil.

/* Cabecera ***************************************************/

Page 398: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 398

// Conexiones del módulo Glcd

char GLCD_DataPort at PORTD;

sbit GLCD_CS1 at RB0_bit;

sbit GLCD_CS2 at RB1_bit;

sbit GLCD_RS at RB2_bit;

sbit GLCD_RW at RB3_bit;

sbit GLCD_EN at RB4_bit;

sbit GLCD_RST at RB5_bit;

sbit GLCD_CS1_Direction at TRISB0_bit;

sbit GLCD_CS2_Direction at TRISB1_bit;

sbit GLCD_RS_Direction at TRISB2_bit;

sbit GLCD_RW_Direction at TRISB3_bit;

sbit GLCD_EN_Direction at TRISB4_bit;

sbit GLCD_RST_Direction at TRISB5_bit;

// Final de conexiones del módulo Glcd

// Declaración de la cadena a visualizar en el GLCD

char msg1[] = "TOUCHPANEL EXAMPLE";

char msg2[] = "MIKROELEKTRONIKA";

char msg3[] = "BUTTON1";

char msg4[] = "BUTTON2";

char msg5[] = "RC6 OFF";

char msg6[] = "RC7 OFF";

char msg7[] = "RC6 ON ";

char msg8[] = "RC7 ON ";

// Declaración de variables globales

Page 399: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 399

long x_coord, y_coord, x_coord128, y_coord64; // almacenar la posición

de las

// coordenadas x e y

// Leer la coordenada X

unsigned int GetX() {

//reading X

PORTC.F0 = 1; // DRIVEA = 1 (electrodo izquierdo (LEFT)

conectado, electrodo

// derecho (RIGHT) conectado, electrodo superior

(TOP)desconectado)

PORTC.F1 = 0; // DRIVEB = 0 (electrodo inferior (BOTTOM)

desconectado)

Delay_ms(5);

return ADC_Read(0); // leer el valor de X de RA0(BOTTOM)

}

// Leer la coordenada Y

unsigned int GetY() {

//Leer la Y

PORTC.F0 = 0; // DRIVEA = 0 (electrodo izquierdo (LEFT)

desconectado, electrodo

// derecho (RIGHT) desconectado, electrodo superior (TOP)

conectado)

PORTC.F1 = 1; // DRIVEB = 1 (electrodo inferior (BOTTOM)

conectado)

Delay_ms(5);

Page 400: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 400

return ADC_Read(1); // leer el valor de Y de RA1 (del eléctrodo

izquierdo LEFT)

}

void main() {

PORTA = 0x00;

TRISA = 0x03; // RA0 y RA1 son entradas analógicas

ANSEL = 0x03;

ANSELH = 0; // Configurar otros pines AN como digitales de E/S

PORTC = 0 ; // Todos los pines del puerto PORTC están a 0

(incluyendo los

// pines RC6 y RC7)

TRISC = 0 ; // PORTC es una salida

// Inicialización del GLCD

Glcd_Init(); // Glcd_Init_EP5

Glcd_Set_Font(FontSystem5x7_v2, 5, 7, 32); // Seleccionar el tamaño

de fuente 5x7

Glcd_Fill(0); // Borrar GLCD

Glcd_Write_Text(msg1,10,0,1);

Glcd_Write_Text(msg2,17,7,1);

// Visualizar botones en el GLCD:

Glcd_Rectangle(8,16,60,48,1);

Glcd_Rectangle(68,16,120,48,1);

Glcd_Box(10,18,58,46,1);

Glcd_Box(70,18,118,46,1);

Page 401: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 401

// Visualizar los mensajes en los botones

Glcd_Write_Text(msg3,14,3,0);

Glcd_Write_Text(msg5,14,4,0);

Glcd_Write_Text(msg4,74,3,0);

Glcd_Write_Text(msg6,74,4,0);

while (1) {

// leer X-Y y convertirlo en la resolución de 128x64 píxeles

x_coord = GetX();

y_coord = GetY();

x_coord128 = (x_coord * 128) / 1024;

y_coord64 = 64 -((y_coord *64) / 1024);

//Si BUTTON1 ha sido presionado

if ((x_coord128 >= 10) && (x_coord128 <= 58) && (y_coord64 >= 18)

&&

(y_coord64 <= 46)) {

if(PORTC.F6 == 0) { // Si RC6 = 0

PORTC.F6 = 1; // Invertir el estado lógico del pin RC6

Glcd_Write_Text(msg7,14,4,0); // Visualizar un nuevo mensaje: RC6

ON

}

else { // Si RC6 = 1

PORTC.F6 = 0; // Invertir el estado lógico del pin RC6

Glcd_Write_Text(msg5,14,4,0); // Visualizar un nuevo mensaje: RC6

OFF

}

Page 402: Libro MIKROC Milan Verle

P r o g r a m a c i ó n e n C - M i k r o C P á g i n a | 402

}

// Si BUTTON2 ha sido presionado

if ((x_coord128 >= 70) && (x_coord128 <= 118) && (y_coord64 >= 18)

&&

(y_coord64 <= 46)) {

if(PORTC.F7 == 0) { // Si RC7 = 0

PORTC.F7 = 1; // Invertir el estado lógico del pin RC7

Glcd_Write_Text(msg8,74,4,0); // Visualizar un nuevo mensaje: RC7

ON

}

else { // Si RC7 = 1

PORTC.F7 = 0; // Invertir el estado lógico del pin RC7

Glcd_Write_Text(msg6,74,4,0); // Visualizar un nuevo mensaje: RC7

OFF

}

}

Delay_ms(100);

}

}

Para que este ejemplo funcione apropiadamente, es necesario marcar las

siguientes librerías en la ventana Library Manager antes de compilar el

programa.

GLCD

ADC

C_Stdlib