Programacion Uc Con Mikrobasic Milan Verle

288
El mundo de los microcontroladores - Capítulo 1 - Libro: Microcontroladores PIC - Programación en BASIC Capítulo 1: 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 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 otros componentes, en primer lugar con la memoria. 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.

Transcript of Programacion Uc Con Mikrobasic Milan Verle

El mundo de los microcontroladores - Capítulo 1 - Libro: Microcontroladores PIC - Programación en BASIC

Capítulo 1: 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

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 otros componentes, en primer lugar con la memoria. 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.

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.

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 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. ¿Hasta cuándo? Hasta quedar satisfecho. Eso puede realizarse sin ningún problema.

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.

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).

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. Es más 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 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. Co-rresponde 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. 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.

CÓNVERSIÓN DE SISTEMAS DE NUMERACIÓ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 DecimalesLos mismos 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 contener 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 los dígitos (0 o 1) con su ponderación de posición (20, 21, 22, 23 etc.) 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. Para los números mayores, se deben utilizar los dígitos binarios adicionales. 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 = 15Por 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. Después, el resultado obtenido se debe sumar. Por ejemplo:

CONVERSIÓN DE NÚMEROS HEXADCIMALES 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:

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.

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. Los prefijos $ y 0x marcan los números hexadecimales. Por ejemplo, el número hexadecimal 10AF se puede escribir como $10AF o 0x10AF. De manera similar, los números binarios normalmente obtienen el prefijo %. Si un número no tiene ni sufijo ni prefijo se considera decimal. Desafortunadamente, esta forma de marcar los números no es estandarizada, por consiguiente depende de la aplicación concreta.

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 re-presentados 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...”?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. 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.

CIRCUITOS LÓGICOS

Algunas instrucciones de programa funcionan de la misma manera que las compuertas lógicas. 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 muestra la relación entre las entradas y salidas de la compuerta Y.

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.

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 lógico.

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.

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.

REGISTRO

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. Esto 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.

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 pe-rifé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). 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 (0 o 1 lógico, respectivamente).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. 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...

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 EEPROM (ROM 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 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 AcMemoria 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. 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.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 cables de ancho. Se utiliza para conectar todos los circuitos dentro del microcontrolador.

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;

Unidad lógica aritmética (Arithmetical Logical Unit - ALU) realiza todas las operaciones matemáticas y lógicas sobre datos. El “conjunto de instrucciones” que es diferente para cada familia de microcontrolador expresa las capacidades de este circuito; y

Acumulador o registro de trabajo. Es un registro SFR estrechamente relacionado con el funcionamiento de la ALU. Es un tipo de escritorio de trabajo 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. El acumulador es denominado registro de trabajo (working register), o sea, registro W o solamente W.

COMUNICACIÓN 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, 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?

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 DE DATOS

La velocidad de transmisión de datos (data 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-IntegradoCircuito inter-integrado es un sistema para el intercambio de datos serial entre los microcontroladores y los circuitos integrados de nueva 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 de datos es normalmente 100 Kb/seg (el modo estándar) o 10 Kb/seg (modo de velocidad de transmisión de datos baja). Recientemente han aparecido los sistemas con la velocidad de transmisión de datos de 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 tres de cuatro líneas - 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 de datos máxima es mayor que en el módulo de conexión I2C.

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

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 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 TEMRPORIZADORES?

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. Al incorporar al cuarzo que oscila con una frecuencia de 4 MHz se aplica lo siguiente: 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).

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 PRE-ESCALADOR 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-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.

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.

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 capaz de funcionar en dos modos diferentes. 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 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 (con frecuencia por los ruidos eléctricos) 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 y el programa será ejecutado desde el principio!

CONVERTIDOR A/D

Las señales externas son muy diferentes de las que “entiende” el microcontrolador (solamente 0V y 5V), así que deben ser convertidas para que el microcontrolador pueda entenderlas. Un convertidor analógico-digital es un 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 (voltaje analógico). 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.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 al intercambiar los datos entre la CPU y la memoria.

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 esta arquitectura 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.

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 informació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 llamado Juego de Instrucciones. Cuando se escribe un 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 normalmente elijen entre una de dos soluciones opuestas y diseñan los microcontroladores que aplican el mayor o el menor número posible de instrucciones. En otras palabras, elijen entre dos juegos de instrucciones - RISC o CISC, respectivamente.

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. 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 JUEGO DE INTRUCCIONES 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 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 que pertenece a la misma familia...

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

El nombre verdadero de este microcontrolador es PICmicro - controlador de interfaz periférico (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. Aproximadamente diez años más tarde, al añadir una memoria EEPROM, este circuito se convirtió en un verdadero microcontrolador PIC.

Si está interesado en aprender más sobre eso, siga leyendo.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. 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 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..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 siguiente tabla rmuestra las características principales de estas tres categorías de los microcontroladores PIC.

FamiliaROM

[Kbytes]

RAM [bytes

]

Pines

Frecuencia

de reloj[MHz]

Entradas

A/D

Resolución del

convertidor A/D

Compar- adores

Temporizadores

de 8/16 bits

Com.

serial

Salidas

PWMOtros

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 - - EEPROM

PIC16FXXX 0.75 - 3 25 - 134

14 - 44

20 0 - 3 8 0 - 2 1 x 8 - - EEPROM

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 EEPROM

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

0 - 5 -

I2C SPI

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 -

PIC18FXXKXX

8 - 64 768 - 3936

28 - 44

64 10 - 13 10 2 1 x 8 3 x 16 USART I2C SPI

2 -

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. La desventaja 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 Basic, 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.

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 1mS. 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:

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

RLF f,dRotar 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

*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 el contador de programa está modificado o el resultado de prueba es un uno lógico (1), la instrucción tiene una duración de dos ciclos. El segundo ciclo se ejecuta como un NOP

Arquitectura de los microcontroladores PIC de 8 bits. Cuáles de estos módulos pertenecerán al microcontrolador, dependerá del tipo de microcontrolador.

Capítulo 2: Programación de los microcontroladores

Usted seguramente sabe que no solo es suficiente 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 para que sea capaz de hacer algo útil. Este capítulo trata de la programación en Basic, por lo que vamos a presentar lo básico que tiene que saber para escribir un programa. Le puede parecer complicado, sobre todo si no tiene experiencia en este campo. no se rinda, respire profundamente y empiece a programar...

2.1 LENGUAJES DE PROGRAMACIÓN 2.2 CARACTERÍSTICAS PRINCIPALES DEL LENGUAJE DE PROGRAMACIÓN BASIC 2.3 COMPILADOR MIKROBASIC 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 es interpretada por la CPU como una instrucción a ser ejecutada durante el funcionamiento del microcontrolador. 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. A todas las instrucciones que el microcontrolador puede reconocer y ejecutar se le denominan colectivamente Juego de instrucciones. En los microcontroladores PIC con las palabras de programa de 14 bits de anchura, el conjunto de instrucciones tiene 35 instrucciones diferentes.

Normalmente los programas se escriben en el lenguaje ensamblador cuando se requiere controlar completamente la ejecución de programa.

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). El proceso de programación se hizo un poco más complicado. Por otro lado, el proceso de escribir un programa dejó de ser una pesadilla. Las instrucciones en ensamblador consisten en las abreviaturas con significado. Un programa denominado ensamblador instalado en la PC compila las instrucciones del lenguaje ensamblador a código máquina (código binario). Este programa compila instrucción a instrucción sin optimización. La ventaja principal del lenguaje ensamblador es su simplicidad y el hecho de que a cada instrucción cle orresponde una localidad de memoria. Como permite

controlar todos los procesos puestos en marcha dentro del microcontrolador, este lenguaje de programación todavía sigue siendo popular.

Por otro lado, los programas se ejecutan siempre a alta velocidad y en la mayoría de casos no es necesario saber en detalle qué ocurre dentro del microcontrolador. A pesar de todos los lados buenos del lenguaje ensamblador, los programadores siempre han necesitado un lenguaje de programación similar al lenguaje utilizado en el habla cotidiana. Por último, los lenguajes de programación de alto nivel (Basic entre otros) fueron creados. La ventaja principal de estos lenguajes es la simplicidad de escribir un programa. Varias instrucciones en ensamblador se sustituyen por una sentencia en Basic. El programador ya no tiene que conocer el conjunto de instrucciones 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.

El proceso de escribir un programa en Basic. Al seleccionar la opción apropiada, el programa será compilado en el ensamblador y luego en el código hex que será cargado en el microcontrolador.

Similar al lenguaje ensamblador, un programa especializado e instalado en la PC se encarga de compilar un programa a código máquina. A diferencia del ensamblador, los compiladores para los lenguajes de programación de alto nivel crean un código ejecutable que no es siempre tan corto como el código escrito en ensamblador.

La figura anterior describe el proceso de la compilación de programa escrito en Basic en código hex.

Ejemplo de un programa simple escrito en Basic:

VENTAJAS DE LOS LENGUAJES DE PROGRAMACIÓN DE ALTO NIVEL

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, este problema se puede resolver gracias a la aritmética que permite realizar las operaciones complejas al descomponerlas en un gran número de 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 Basic, 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.

2.2 CARACTERÍSTICAS PRINCIPALES DEL LENGUAJE DE PROGRAMACIÓN BASIC

Similar al uso de cualquier lengua que no está limitada a los libros y a las revistas, el lenguaje de programación Basic no está estrechamente relacionado a un tipo particular de ordenador, procesador o sistema operativo. Esto puede ser un problema, ya que Basic varía ligeramente dependiendo de su aplicación (como diferentes dialectos de una lengua). Por consiguiente, en este libro no vamos a darle una descripción detallada de todas las características de Basic, sino presentar una aplicación muy concreta de Basic, lenguaje de programación utilizado en el compilador mikroBasic PRO for PIC.

El Basic es un lenguaje de programación simple y fácil de entender. Para utilizarlo correctamente, basta con conocer sólo unos pocos elementos básicos en los que consiste cada programa. Estos son:

Identificadores Comentarios Operadores Expresiones Instrucciones Constantes Variables Símbolos Directivas Etiquetas Procedimientos y funciones Módulos

Aquí está un ejemplo de cómo no se debe escribir un programa. Los comentarios no están incluidos, nombres de etiquetas no tienen significado, secciones del código no están agrupadas...Este programa funciona correctamente, pero sólo el programador que lo escribió conoce su propósito y modo de ejecución (como máximo uno o dos días).

En la siguiente figura se muestra la estructura de un programa simple escrito en Basic, destacando las partes en las que consiste. Esto es un ejemplo de cómo se debe escribir un programa. Las diferencias son más que obvias...

ESTRUCTURA DE PROGRAMA

Similar a los otros lenguajes de programación, Basic dispone de un conjunto de reglas estrictamente definidas que se deben observar al escribir un programa. Para escribir un programa en Basic, es necesario instalar un software que proporciona el entorno de trabajo apropiado y entiende estas reglas en la PC... Al escribir una carta, se necesita un programa para procesar palabras. En este caso, se necesita el compilador mikroBasic PRO for PIC. A diferencia de la mayoría de programas a los que está acostumbrado a manejar, el proceso de escribir programas en el compilador no empieza por seleccionar la opción File>New, sino Project>New. ¿Por qué? Bueno, usted escribe un programa en un documento con extensión .mbas (mikroBasic). Una vez que se ha escrito el programa, el mismo se debe compilar en código HEX para crear un nuevo documento con extensión .hex. Al mismo tiempo el compilador generará automáticamente varios documentos aparte de ése. Por ahora el propósito de estos documentos no importa. Por supuesto, hay algo para conectarlos todos. Usted ya lo adivina - se trata de un proyecto. El programa que escribe es sólo una parte del proyecto.

Sólo para estar seguro de que estamos hablando en los mismos términos... A partir de ahora la palabra módulo se refiere a un documento con extensión .mbas. El texto que contiene se refiere a un programa. Cada proyecto escrito en el compilador mikroBasic

PRO for PIC es de extensión .mbppi (microBasic Project for PIC) y consiste en un módulo como mínimo (módulo principal - Main Module).

Cada proyecto en el mikroBasic PRO for PIC requiere un solo módulo principal. Lo identifica la palabra clave program y ordena al compilador por dónde empezar el proceso de la compilación. Al crear con éxito un proyecto vacío en Project Wizard, el módulo principal (main module) será visualizado automáticamente en la ventana Code Editor:

program MyProject ' El módulo principal es denominado MyProject main: ' Procedimiento principal... '*... '* Escribir el código de programa aquí... '*end.A la palabra clave program no le puede preceder nada, excepto comentarios. Como hemos mencionado anteriormente, el proyecto puede incluir a otros módulos que, a diferencia del módulo principal, empiezan por la palabra clave module.

module MyModule ' Módulo auxiliar Auxiliary es denominado MyModule... '*... '* Implementos... '*end.

Para que el compilador pueda reconocer todos los módulos que pertenecen a un proyecto, es necesario especificarlos en el módulo principal por medio de la palabra clave include seguida por un nombre del módulo entre comillas. La extensión de estos ficheros no se debe incluir. Se permite sólo un módulo por cláusula include. El número de las cláusulas include no está limitado, pero todas ellas deben estar especificadas inmediatamente después del nombre del programa (módulo principal). Ejemplo:

program MyProgram ' Inicio de programa (módulo principal denominado ‘MyProgram’) ' Otros módulos incluidos son: include "utils" ' Módulo ‘utils’include "strings" ' Módulo ‘strings’include "MyUnit" ' Módulo ‘MyUnit’...

ORGANIZACIÓN DEL MÓDULO PRINCIPAL

El módulo principal se puede dividir en dos secciones: declaraciones y el cuerpo de programa. ¿Qué es una declaración en la programación? Una declaración es un proceso de definir las propiedades de los identificadores que se utilizarán en el programa. Como la mayoría de los demás lenguajes de programación, Basic también requiere que todos los identificadores estén declarados antes de ser utilizados en el programa. Si no es así, el compilador no puede interpretarlos correctamente. Ejemplo de la declaración de una variable denominada distancia:

dim distance as float ' Declarar la variable distancia

Como se puede ver, es una variable de punto flotante, o sea un número con posición decimal opcional. Las otras dos variables están declaradas y nombradas velocidad y tiempo. Ahora, se pueden utilizar en el siguiente programa:

Esto es un ejemplo de cómo escribir el módulo principal correctamente:

ORGANIZACIÓN DE OTROS MÓDULOS

Los otros módulos empiezan por la palabra clave module. Cada módulo consiste en tres secciones: include, interface e implementation. Solo la sección implementation es obligatoria. Empieza por la palabra clave implements. Vea el siguiente ejemplo:

IDENTIFICADORES

Los identificadores son los nombres arbitrarios asignados a los objetos básicos del lenguaje teles como constantes, variables, funciones, procedimientos etc. A alguien se le ocurrió utilizar la palabra identificador en vez de utilizar el nombre. Así de simple. Aquí están las reglas a observar al utilizar los identificadores.

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 primer carácter de un identificador no puede ser un dígito. Ningún identificador puede contener caracteres especiales tales como ! [{ # $ % & etc. Basic no es sensible a la diferencia entre minúsculas y mayúsculas, lo que significa que FIRST, first y First son identificadores

idénticos. El símbolo ^ (signo de intercalación) se utiliza para denotar un operador exponencial, el símbolo * (asterisco) se utiliza para

denotar la multiplicación, mientras que los demás símbolos tienen el significado común. Las palabras clave ya utilizadas por el compilador no deben ser utilizadas como identificadores. Lista alfabética de las

palabras clave en Basic: Abstract And Array As At Asm Assembler Automated Bdata Begin Bit Case Cdecl Class Code Compact

Const Constructor Contains Data Default Deprecated Destructor Dispid Dispinterface Div Do Downto Dynamic Else End Except Export Exports External Far File Finalization Finally For Forward Function Goto Idata If Ilevel Implementation

In Index Inherited Initialization Inline Interface Io Is Label Large Library Message Mod Name Near Nil Not Object Of On Or Org Out Overload Override Package Packed Pascal Pdata Platform Private

Procedure Program Property Protected Public Published Raise Read Readonly Record Register Reintroduce Repeat Requires Resourcestring Rx Safecall Sbit Set Sfr Shl Shr Small Stdcall Stored String Stringresource Then Threadvar To Try

Type Unit Until Uses Var Virtual Volatile While With Write Writeonly Xdata Xor

Una lista de identificadores que no deben ser utilizados en el programa

COMENTARIOS

Los comentarios son las partes del programa utilizados para aclarar las instrucciones de programa o para proporcionar más información al respecto. En Basic, cualquier texto que sigue a un apóstrofo (') se considera un comentario, Los comentarios no se compilan al código ejecutable. 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. 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.

ETIQUETAS

Las etiquetas proporcionan el modo más fácil de controlar el flujo de programa. Se utilizan para denotar las líneas particulares en el programa donde se deben ejecutar la instrucción de salto y la subrutina apropiada. Todas las etiquetas deben terminar por ‘:’ así que el compilador las puede reconocer con facilidad.

CONSTANTES

Las constantes son los números o caracteres cuyo valor no puede ser cambiado durante la ejecución de programa. A diferencia de las variables, las constantes se almacenan en la memoria ROM del microcontrolador para guardar el mayor espacio posible de la memoria RAM. El compilador reconoce las constantes por sus nombres y el prefijo const. Cada constante se declara bajo un nombre único que debe ser un identificador válido. Las constantes pueden ser en formatos decimal, hexadecimal o binario. El compilador los distingue por su prefijo. Si una constante no lleva prefijo, se considera decimal por defecto.

F O R M A T O P R E F I J O E J E M P L O

Decimal const MAX = 100

Hexadecimal 0x o $ const MAX = 0xFF

Binario Punto flotante const MAX = %11011101

Las constantes se declaran en la parte de declaración del programa o de la rutina. La sintaxis es la siguiente:

const nombre_de_constante [as type] = valor

Los nombres de las constantes se escriben normalmente con mayúsculas. El tipo de una constante se reconoce automáticamente por su tamaño. En el siguiente ejemplo, la constante MINIMUM se considera un entero con signo y ocupa dos bytes de la memoria Flash (de 16 bits):

const MINIMUM = -1000 ' Declarar la constante MINIMUM

El tipo de constante se especifica opcionalmente. En la ausencia de tipo, el compilador lo considera “el menor” tipo conveniente al valor de constante.

const MAX as longint = 10000const MIN = 1000 ' Compilador supone el tipo wordconst SWITCH = "n" ' Compilador supone el tipo char

En el siguiente ejemplo, una constante denominada T_MAX se declara de modo que tenga el valor fraccional 32.60. Ahora, el programa puede comparar la temperatura anteriormente medida con la constante con el nombre con significado en vez del número 32.60.

const T_MAX = 32.60 ' Declarar temperatura T_MAXconst T_MAX = 3.260E1 ' Otra forma de declarar la constante T_MAX

Una constante de cadena consiste en una secuencia de caracteres. Debe estar encerrada entre comillas. Un espacio en blanco se puede incluir en la constante de cadena y representa un carácter. Las constantes de cadena se utilizan para representar cantidades no numéricas tales como nombres, direcciones, mensajes etc.

const Message_1 = "Press the START button" ' Mensaje 1 para LCDconst Message_2 = "Press the RIGHT button" ' Mensaje 2 para LCDconst Message_3 = "Press the LEFT button" ' Mensaje 3 para LCD

En este ejemplo, al enviar la constante Message_1 al LCD, el mensaje ‘press the START button’ aparecerá en la pantalla.

VARIABLES

Una variable es un objeto nombrado capaz de contener un dato que puede ser modificado durante la ejecución de programa. Cada variable se declara bajo un nombre únicoque debe ser un identificador válido. Por ejemplo, para sumar dos números (número1 + número2) en el programa, es necesario tener una variable para representar qué es lo que llamamos suma en vida cotidiana. En este caso, número1, número2 y suma son variables. La sintaxis es la siguiente:

dim nombre_de_variable as type

Las variables en Basic son de un tipo, lo que significa que es necesario especificar el tipo de dato que se asignará a la variable. Las variables se almacenan en la memoria RAM y el espacio de memoria ocupado (en bytes) depende de su tipo. Aparte de las declaraciones de una sola variable, las variables del mismo tipo, se pueden declarar en forma de una lista. Aquí, lista de identificadores es una lista de identificadores válidos delimitados por comas, mientras que tipo puede ser cualquier tipo de dato.

dim i, j, k as byte 'Definir variables i, j, kdim counter, temp as word 'Definir variables contador y temp

SÍMBOLOS

Los símbolos en Basic permiten crear los macros simples sin parámetros. Cualquier línea de código se puede reemplazar por un solo identificador. Los símbolos pueden aumentar legibilidad y reutilización de código cuando se utilizan correctamente.

Los símbolos deben ser declarados al principio del módulo, bajo el nombre del módulo y la directiva opcional include. El ámbito de un símbolo es siempre limitado al módulo en el que ha sido declarado.

symbol nombre_de_símbolo = código

Aquí, nombre_de_símbolo debe ser un identificador válido que se utilizará por todo el código. El especificador código puede ser cualquier línea de código (literales, asignaciones, llamadas de función etc.)

symbol MAXALLOWED = 216 ' Símbolo MAXALLOWED para el valor numéricosymbol OUT = PORTA ' Símbolo OUT para SFRsymbol MYDELAY = Delay_ms(762) ' Símbolo MYDELAY para llamada de procedimiento

dim cnt as byte ' Variable cntmain:if cnt > MAXALLOWED then ' Programa comprueba si cnt > 216

cnt = 0 ' Si lo es,OUT.1 = 0 ' los siguientes tres comandos MYDELAY ' se ejecutarán

end if... ' Si no lo es, el programa continúa aquí

Los símbolos no se almacenan en la memoria RAM. El compilador reemplaza los símbolos por las líneas del código apropiadas asignadas durante la declaración.

TIPOS DE DATOS EN BASIC

Hay varios tipos de datos que se pueden utilizar en el lenguaje de programación Basic. La siguiente tabla muestra el rango de valores que estos datos pueden tener cuando se utilizan en su forma básica

.

T I P O D E D A T O

D E S C R I P C I Ó N T A M A Ñ O ( N Ú M E R O D E B I T S )

R A N G O D E V A L O R E S

bit Un bit 1 0 o 1

sbit Un bit 1 0 o 1

byte, char Carácter 8 0 ... 255

short Entero con signo corto -127 ... 128

word Entero sin signo 16 0 ... 65535

integer Entero con signo 16 -32768 ... 32767

longword Palabra de 32 bits 32 0 ... 4294967295

longint Palabra de 32 bits asignada

32 -2147483648 ... 2147483647

float Punto flotante 32 ±1.17549435082*10-38 ... ±6.80564774407*1038

CONVERSIÓN DE TIPOS DE DATOS AUTOMÁTICA

El compilador automáticamente realiza la conversión implícita en los siguientes casos:

si una sentencia requiere una expresión del tipo particular, y se utiliza la expresión de tipo diferente; si un operador requiere un operando de tipo particular, y se utiliza un operando de tipo diferente; si una función requiere un parámetro formal de tipo particular, y se le asigna el objeto de tipo diferente; y si el resultado de una función no corresponde al tipo del valor devuelto de la función declarada.

PROMOCIÓN

Cuando los operandos son de tipos diferentes, mediante la conversión implícita se realiza la promoción de tipo más bajo a tipo más alto, de la siguiente manera:

bit → byte short, byte/char → integer, word, longint, longword integer, word → longint, longword short, byte/char, integer, word, longint, longword → float

RECORTE DE DATOS

En las sentencias de asignación y en las sentencias que requieren una expresión de tipo particular, el valor correcto será almacenado en el destino sólo si el resultado de expresión no excede al rango del destino. Al contrario, si el resultado de la expresión resulta en un tipo más complejo de lo esperado, los datos que exceden se recortarán, o sea los bytes más altos se pierden.

dim i as byte 'Variable i ocupa un solo byte de la memoria RAMdim j as word ' Variable j ocupa dos bytes de la memoria RAM

...j = $FF0Fi = j ' i se convierte en $0F, el byte más alto $FF se pierde

CONVERSIÓN DE DATOS EXPLÍCITA

La conversión explícita se puede ejecutar bajo cualquier expresión en cualquier punto al escribir la palabra clave de tipo deseado (byte, word, short, integer, longint, float...) delante de la expresión que será convertida. La expresión debe estar encerrada entre paréntesis. La conversión explícita no puede ser realizada bajo el operando de la izquierda del operador de asignación.

a = word(b) ' Conversión explícita de la expresión bword(b) = a ' Compilador informa de un error

Como no afecta a la representación binaria de los datos, un caso especial es una conversión entre tipos de datos con signo y sin signo.

dim a as bytedim b as short'...b = -1a = byte(b) ' a is 255, not -1

' El dato no cambia su representación binaria %11111111 ' pero el compilador la interpreta de la manera diferente

OPERADORES

Un operador es un símbolo que denota una operación aritmética, lógica u otra operación particular. Cada operación se realiza sobre uno o más operandos (variables o constantes) en una expresión. Además, cada operador dispone de la ejecución de prioridad y de la asociatividad. Si una expresión contiene más de un operando, los operandos se ejecutarán en orden de su prioridad. Hay 4 categorías de prioridad en Basic. Los operadores que pertenecen a la misma categoría tienen igual prioridad. Si dos o más operandos tienen el mismo nivel de prioridad, las operaciones se realizan de izquierda a derecha. Los paréntesis se utilizan para definir la prioridad de la operación dentro de la expresión. A cada categoría se le asigna una de dos reglas de asociatividad: de izquierda a derecha o de derecha a izquierda. Refiérase a la siguiente tabla:

P R I O R I D A D O P E R A D O R E S A S O C I A T I V I D A D

Alta @ not + - de derecha a izquierda

* / div mod and << >> de izquierda a derecha

+ - or xor de izquierda a derecha

Baja = <> < > <= >= de izquierda a derecha

OPERADORES ARITMÉTICOS

Los operadores aritméticos se utilizan para realizar operaciones aritméticas. Estas operaciones se realizan sobre los operandos numéricos y siempre devuelven los resultados numéricos. Las operaciones binarias se realizan sobre dos operandos, mientras que las operaciones unitarias se realizan sobre un operando. Todos los operadores aritméticos se asocian de izquierda a derecha.

O P E R A D O R O P E R A C I Ó N

+ Adición

- Resta

* Multiplicación

/ División - punto flotante

div División - redondear

mod Remanente

DIVISIÓN POR CERO

Si un cero (0) se utiliza explícitamente como el segundo operando en la operación de división (x div 0), el compilador informa de un error y no generará un código. En caso de una división implícita, o sea, en el caso de que el segundo operando sea un objeto cuyo valor es 0 (x div y, w y=0), el resultado será indefinido.

OPERADORES RELACIONALES

Los operadores relacionales se utilizan para comparar dos variables y determinar la validez de su relación. En mikroBasic, todos los operadores relacionales devuelven 255 si la expresión es evaluada como verdadera (true). Si una expresión es evaluada como falsa (false), el operador devuelve 0. Lo mismo se aplica a las expresiones tales como ‘si la expresión es evaluada como verdadera, entonces...’

O P E R A D O R S I G N I F I C A D O E J E M P L O C O N D I C I Ó N D E V E R A C I D A D

> es mayor que b > a si b es mayor que a

>= es mayor o igual que a >= 5 si a es mayor o igual que 5

< es menor que a < b si a es menor que b

<= es menor o igual que a <= b si a es menor o igual que b

= es igual que a = 6 si a es igual que 6

<> no es igual que a <> b si a no es igual que b

OPERADORES LÓGICOS DE MANEJO DE BITS

Los operadores lógicos de manejo de bits se realizan sobre los bits de un operando. Se asocian de izquierda a derecha. La única excepción es el complemento not que realiza un desplazamiento de derecha a izquierda. Los operadores de manejo de bits se enumeran en la siguiente tabla:

O P E R A N D O S I G N I F I C A D O E J E M P L O R E S U L T A D O

<< desplazamiento a la izquierda A = B << 2 B = 11110011 A = 11001100

>> desplazamiento a la derecha A = B >> 3 B = 11110011 A = 00011110

and Y lógico para manejo de bits C = A and B A=11100011B=11001100

C = 11000000

or O lógico para manejo de bits C = A or B A=11100011B=11001100

C = 11101111

not NO lógico para manejo de bits A = not B B = 11001100 A = 00110011

xor EXOR lógico para manejo de bits C = A xor B A = 11100011B = 11001100

C = 00101111

Los operadores de manejo de bits y (and), o (or) y xor realizan las operaciones lógicas sobre los pares de bits de operandos apropiados. El operador not complementa cada bit de un solo operando.

$1234 and $5678 ' resultado es $1230 porque:' $1234 : 0001 0010 0011 0100

' $5678 : 0101 0110 0111 1000' ----------------------------' y : 0001 0010 0011 0000 ... eso es, $1230$1234 or $5678 'equivale a $567C$1234 xor $5678 ' equivale a $444Cnot $1234 ' equivale a $EDCB

OPERADORES DE DESPLAZAMIENTO

Hay dos operadores de desplazamiento de bits en mikroBasic. Son el operador << que realiza un desplazamiento de bits a la izquierda y el operador >> que realiza un desplazamiento de bits a la derecha. Los operadores de desplazamiento de bits tienen dos operandos cada uno. El operando izquierdo es un objeto que se desplaza, mientras que el derecho indica el número de posiciones a mover el objeto. Los dos operandos deben ser de tipo entero. El operando derecho debe ser el valor positivo.

Al desplazar a la izquierda los bits que salen por la izquierda se pierden, mientras que los ‘nuevos’ bits a la derecha se rellenan con ceros. Por lo tanto, el desplazamiento del operando que carece de signo a la izquierda por n posiciones equivale a multiplicarlo por 2n si todos los bits descartados son ceros. Lo mismo se puede aplicar a los operandos con signo si todos los bits descartados son iguales que el signo de bit.

dim num as word ' declarar la variable num como word num = 1 ' asignarle el valor decimal 1 (00000000 00000001 bin.)num << 5 ' equivale a 32 (00000000 00100000 bin.)

Al desplazar a la derecha los bits que salen por la derecha se pierden, mientras que los ‘nuevos’ bits a la izquierda se rellenan con ceros (en caso del operando sin signo) o con el signo de bit (en caso del operando con signo). El desplazamiento del operando a la derecha por n posiciones equivale a dividirlo por 2n.

dim num as integer ' declarar variable num como signed integer num = 0xFF56 'asignarle el valor hex FF56 (11111111 01010110 bin.)num >> 4 ' equivale a 0xFFF5 (11111111 11110101 bin.)

SENTENCIAS 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, se debe hacer (...)’. Una sentencia condicional puede ser seguida por una sola sentencia o por un bloque de sentencias a ser ejecutadas.

SENTENCIA CONDICIONAL IF

La sintaxis en una forma simple de la sentencia if es:

if expresión thenoperacionesend if

Si el resultado de la expresión es verdadero (distinto de 0), las operaciones se realizan y el programa continúa con la ejecución. Si el resultado de la expresión es falso (0), las operaciones no se realizan y el programa continúa inmediatamente con la ejecución.

El operador if se puede utilizar en combinación con el operador else:

if expresión thenoperaciones1elseother operaciones2end if

Si el resultado de la expresión es verdadero (distinto de 0), las operaciones1 se realizan. De lo contrario, las operaciones2 se realizan. Después de realizar estas operaciones, el programa continúa con la ejecución.

SENTENCIAS IF ANIDADAS

La sentencia if anidada necesita una atención adicional. Es una sentencia utilizada dentro de otra sentencia if. Siguiendo la regla, se descomponen empezando por la sentencia if más anidada, mientras que cada sentencia else se enlaza a la más cercana sentencia if disponible a la izquierda.

SENTENCIA CASE STATEMENT

La sentencia select case es una sentencia condicional de ramificación múltiple. Consiste en una expresión (condición) selector y una lista de los valores posibles de la expresión. La síntaxis de la sentencia select case es la siguiente:

El especificador selector es una expresión evaluada como un valor entero.

Los especificadores value_1...value_n representan los valores posibles del selector. Pueden ser literales, constantes o expresiones de constantes. Los especificadores statements_1 ...statements_n pueden ser cualquier sentencia. La cláusula case else es opcional.

Primero se evalúa el valor de la expresión selector. Después se compara con todos los valores disponibles. Si los valores son iguales (selector y uno de valores), se ejecutarán las sentencias que siguen a los valores iguales y termina la sentencia select case. En el caso de que coincidan los valores múltiples se ejecutarán las sentencias que siguen a los primeros valores iguales. Si no coincide ningún valor con el selector, se ejecutarán las sentencias_por_defecto en la cláusula case else (si hay alguna).

Ejemplo de la sentencia select case:

select case decimal_digit 'El valor del dígito decimal se está comprobandocase 0mask = %01111110 'Visualizar "0"case 1mask = %00110000 'Visualizar "1"case 2mask = %01101101case 3mask = %01111001case 4mask = %00110011case 5mask = %01011011case 6mask = %01011111case 7mask = %01110000case 8mask = %01111111case 9mask = %01111011end select

Esta rutina de programa convierte los dígitos decimales en la combinación binaria apropiada en el puerto para visualizarlos en el LED.

BUCLES DE PROGRAMA

Algunas instrucciones (operaciones) deben ejecutarse más de una vez 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 aparece cuando el número de iteraciones no está especificado. Es necesario comprobar la condición de iteración antes de ejecutar un bucle. En otras palabras, el bucle while se ejecuta una vez cumplidas todas las condiciones necesarias para su ejecución. La sintaxis del bucle while se parece a lo siguiente:

while expresiónsentenciaswend

El especificador sentencias representa un grupo de sentencias que se ejecutan repetidamente hasta que el valor del especificador expresión que representa una expresión siga siendo verdadero. En otras palabras, el programa se queda en el bucle hasta que la expresión llegue a ser falsa. El valor de la expresión se comprueba antes de que se ejecute la siguiente iteración. Si el valor de la expresión es falso antes de entrar el bucle, no se ejecuta ninguna iteración, esto es las sentencias no se ejecutarán nunca. El programa continúa con la ejecución desde el fin del bucle while (desde las instrucciones que siguen a la instrucción wend).Un tipo especial del bucle de programa es un bucle infinito. Se forma si la condición para salir del bucle sigue sin cambios dentro del bucle. La ejecución es simple en este caso ya que el resultado es siempre verdadero (1 siempre será diferente de 0), lo que significa que el programa se queda en el bucle:

while 1 ' Se puede escribir ‘verdadero’ en vez de ‘1’... ' Las expresiones se ejecutarán repetidamente (bucle infinito) ...wend

BUCLE FOR

El bucle for se utiliza cuando el número de iteraciones está especificado. La sintaxis del bucle for es la siguiente:

for contador = valor_inicial to valor_final [step valor_de_paso]sentenciasnext contador

La variable contador se incrementa por el valor de paso con cada iteración de bucle. El parámetro valor_de_paso es un valor entero opcional, que es igual a 1 si es omitido. Antes de ejecutar la primera iteración el

contador se pone al valor_inicial y se incrementa hasta llegar o exceder al valor_ final. Con cada iteración se ejecutan las sentencias. Las expresiones valor_inicial y valor_final deben ser compatibles con el contador. El especificador sentencia puede ser cualquier sentencia que no afecta al valor del contador. El parámetro valor_de_paso puede ser negativo, lo que permite contar atrás.

for k=1 to 5 ' La variable k se incrementa cinco veces (de 1 a 5) y operation ' cada vez sigue ejecutándose la "operación" ...next k

Un conjunto de instrucciones (operación) se ejecutará cinco veces. Después, al comprobar que k<5 sea falsa (después de 5 iteraciones k=5) y el programa saldrá del bucle for.

BUCLE DO

La sentencia do se utiliza cuando el número de iteraciones no está especificado. El bucle se ejecuta repetidamente hasta que la expresión siga siendo verdadero. La sintaxis del bucle do es la siguiente:

dosentenciasloop until expresión

En este caso, el especificador sentencias representa un grupo de sentencias que se ejecutarán hasta que la expresión siga siendo verdadera. Las condiciones del bucle se comprueban al final del bucle, así que el bucle se ejecuta al menos una vez, sin reparar en si la condición es verdadera o falsa. En el siguiente ejemplo, el programa se queda en el bucle do hasta que la variable a alcance 1E06 (un millón de iteraciones).

a = 0 ' Establecer el valor inicial do

a = a+1 ' Operación en marchaloop until a <= 1E06 ' Comprobar la condición

ESCRIBIR CÓDIGO EN LENGUAJE ENSAMBLADOR

A veces el proceso de escribir un programa en Basic requiere las partes del código escritas en ensamblador. Esto permite ejecutar algunas partes 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 escribir el código ensamblador en la parte del programa que controla la duración de pulsos.El comando asm se utiliza para introducir una o más instrucciones en ensamblador en el programa escrito en Basic:

asminstrucciones en ensamblador...end asm

Las instrucciones en ensamblador pueden utilizar los objetos (constantes, variables, rutinas etc.) anteriormente declarados en Basic. Por supuesto, como el programa entero está escrito en Basic, sus reglas se aplican al declarar estas constantes y variables. Veamos al siguiente ejemplo:

MATRICES

Una matriz es una lista organizada y limitada de variables del mismo tipo denominadas elementos. Este tipo es denominado tipo básico. Cada elemento es referenciado por un índice único así que los diferentes elementos pueden tener el mismo valor. 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:

dim nombre_de_matriz as tipo_de_componente [número_de_componentes]

Los elementos de una matriz se identifican por su posición. Los índices van desde 0 (el primer elemento de una matriz) a N-1 (N es el número de elementos contenidos en la matriz). El compilador tiene que “saber” cuántas localidades de memoria debe alojar al declarar una matriz. Por eso, el tamaño de una matriz no puede ser variable.

Para explicar con más claridad, una matriz puede ser pensada como una lista más o menos larga o corta de variables del mismo tipo en la que a cada una se le asigna un número ordinal que siempre empieza por cero. A esta matriz se le denomina vector. En la tabla de la derecha se muestra una matriz denominada estante que contiene 100 elementos.

E L E M E N T O S D E L A M A T R I Z C O N T E N I D O D E E L E M E N T O S

estante[0] 7

estante[1] 23

estante[2] 34

estante[3] 0

estante[4] 0

estante[5] 12

estante[6] 9

... ...

... ...

estante[99] 23

En este caso, el contenido de una variable (elemento) representa un número de productos que contiene el estante. A los elementos se les puede acceder por medio de la indexación, o sea, al especificar sus índices encerrados entre corchetes:

dim shelf as byte [100] ' Declarar la matriz "estante" con 100 elementosshelf [4] = 12 ' 12 elementos están ‘colocados’ en el estante [4]temp = shelf [1] ' Variable estante [1] se copia a la variable temp

En las matrices de constantes, a los elementos se les pueden asignar sus contenidos durante la declaración de matriz. En el siguiente ejemplo, una constante de matriz denominada CALENDARIO se declara y a cada elemento se le asigna un número específico de días:

const CALENDARIO as byte [12]= (31,28,31,30,31,30,31,31,30,31,30,31)

El número de los valores asignados no debe exceder la longitud de la matriz especificada, solo puede ser menor. En este caso, a los elementos ”de sobra” se les asignarán ceros.

SENTENCIA GOTO

La sentencia goto le permite hacer un salto absoluto a 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 dos puntos (:). La sintaxis de la sentencia goto es:

goto: nombre_de_etiqueta

La sentencia ejecuta un salto al especificador nombre_de_etiqueta que representa una etiqueta. La sentencia goto puede preceder o seguir a una etiqueta. Por lo tanto, no es posible hacer un salto hacia o desde un procedimiento o función. La sentencia goto se puede utilizar para salir de cualquier nivel de las estructuras anidadas. No es recomendable saltar a bucles u otras sentencias estructuradas, ya que se pueden producir resultados inesperados.

SENTENCIA GOSUB

Una subrutina es una parte del código dentro de un programa largo ejecutado a petición. Realiza una tarea específica, es relativamente independiente del resto del código. El intérprete del compilador salta a la subrutina, la ejecuta y vuelve al programa principal. Las palabras clave gosub y return se utilizan en Basic para denotar el inicio y el final de la subrutina:

gosub nombre_de_etiqueta.........nombre_de_etiqueta:...return

Las subrutinas se consideran difíciles de mantener, leer y manejar, igual que la sentencia goto. Es recomendable utilizarla solo si no hay otra solución.

ACCESO A LOS BITS INDIVIDUALES

El compilador mikroBasic PRO for PIC instalado en la PC, incluye una lista de los microcontroladores PIC soportados, con todos los registros, sus direcciones exactas y los nombres de bits. El compilador le permite acceder a los bits individuales de estos registros por sus nombres, sin especificar sus posiciones (el compilador ya las ‘conoce’). Hay muchas formas de acceder y modificar a un bit individual dentro de un registro. Por ejemplo, vamos a acceder al bit GIE (Global Interrupt Enable - Habilitación global de interrupciones) por ejemplo. Es el séptimo bit del registro INTCON. A este bit se le puede acceder por su nombre, al escribir lo siguiente:

INTCON.GIE = 0 ' Poner a cero el bit GIE

Para denotar la posición de bit en un registro en lugar de un nombre de bit se pueden utilizar una variable, una constante, una llamada a función o una expresión encerrada entre paréntesis. Además, para acceder a los bits individuales se utilizan las constantes globales predefinidas B0, B1, … , B7, o 0, 1, … 7, donde 7 se considera el bit más significante.

INTCON.B0 = 0 ' Poner a cero el bit 0 del registro INTCONADCON0.5 = 1 ' Poner a uno el bit 5 del registro ADCON0i = 5STATUS.(i+1) = 1 ' Poner a uno el bit 6 del registro STATUS

Por fin, a un bit deseado se le puede acceder al utilizar un nombre “alias”. En este caso, es el GIE_bit:

GIE_bit = 1 ' Poner a uno el bit GIE

TIPO SBIT

El compilador mikroBasic PRO for PIC tiene un tipo de dato sbit. Esto es un tipo de dato más corto que se refiere a un solo bit. Si al tipo sbit se le asigna una variable, el bit apropiado de un registro será cambiado al cambiar esta variable sin especificar el nombre y la localidad del registro. La variable sbit se comportará como un puntero. Para declarar la variable sbit, basta con escribir:

dim Nombre_de_bit as sbit at Nombre_de_registro.Posición_de_bit program MyProgram ' Módulo principal...dim Output1 as sbit at PORTB.0 ' Variable Output1 es de tipo sbit ...Output1 = 1 ' Pin del puerto PORTB.0 está a uno (5V)

Si una variable de tipo sbit no está definida en el mismo módulo donde se utiliza, la palabra clave external debe ser utilizada. Además, el especificador de memoria apropiado se debe añadir:

dim nombre_de_bit as sbit sfr external

module MyModule ' Esto no es el módulo principal y el bit Output1 ... ' no está definido aquídim Output1 as sbit sfr external ...Output1 = 1 ' Pin PORTB.0 (definido en el ejemplo anterior como Output1) está a uno (5V)

TIPO BIT

El compilador mikroBasic PRO for PIC proporciona un tipo de dato bit que se puede utilizar para declarar las variables.

dim bf as bit

A diferencia de variables de tipo sbit, solo el nombre de bit está declarado aquí, mientras que el compilador almacena una variable bit en algunos de los registros libres de la RAM. Como se puede ver, no es necesario especificar un bit de algún registro específico. La localidad exacta de la variable de tipo bit es desconocida al usuario.

Los tipos Bit y sbit se utilizan con los siguientes limitaciones:

No pueden ser utilizados para las listas de argumentos y como valores devueltos de funciones No pueden ser utilizados como un miembro de estructuras No pueden ser utilizados como elementos de matrices No pueden ser inicializados No se puede apuntar a ellos Sus direcciones no se pueden leer, por eso el operador unitario @ no se puede utilizar con variable de este tipo

dim ptr as ^bit ' inválidodim arr as array[5] of bit ' inválido

FUNCIONES Y PROCEDIMIENTOS

Las funciones y los procedimientos, denominados bajo el nombre común de rutinas, son subprogramas (bloques de sentencias autónomos) que ejecutan ciertas tareas a base de un número de los parámetros de entrada. Las funciones devuelven un valor después de la ejecución, mientras que los procedimientos no devuelven un valor.

PROCEDIMIENTOS

Un procedimiento es un bloque de código nombrado, o sea, una subrutina con algunas características adicionales. Por ejemplo, puede aceptar parámetros. Los procedimientos se declaran de la siguiente manera:

sub procedure ´nombre_de_procedimiento (lista_de_parámetros) [ declaraciones locales ] cuerpo de procedimientoend sub

El especificador nombre_de_procedimiento representa un nombre de procedimiento y debe ser un indentificador válido. La lista_ de_parámetros entre paréntesis representa una lista de parámetros formales declarados de manera similar a

variables. En mikroBasic PRO for PIC, los parámetros se le pasan a un procedimiento por valor. Para pasar los parámetros por dirección, es necesario añadir la palabra clave byref al principio de la declaración de los parámetros.

Las declaraciones locales son declaraciones opcionales de variables y constantes que se refieren sólamente al procedimiento dado.

El cuerpo de procedimiento es una secuencia de sentencias que se ejecutarán después de llamar al procedimiento.Una llamada a procedimiento se realiza al especificar su nombre seguido por los parámetros actuales colocados en el mismo orden que los parámetros formales correspondientes. Después de llamar a procedimiento, todos los parámetros formales se crean como los objetos locales inicializados por los valores de los argumentos actuales.

'Añadir dos números sub procedure add (dim byref sum as word, dim x, y as byte)sum = x + y ' añadir los números x e y y almacenar el resultado en la variable sum end sub ' fin del subprocedimiento

Ahora, podemos llamar al procedimiento add para hacer cálculo del peso total de una carga, por ejemplo:

add (peso_bruto, peso_neto, peso_tara)

FUNCIONES

Las funciones deben estar declaradas apropiadamente para ser interpretadas correctamente durante el proceso de la compilación.

sub function nombre_de_función (lista_de_parámetros) as valor_devuelto [ declaraciones locales ] cuerpo de función end sub

Cada declaración contiene los siguientes elementos:

Nombre_de_función es un identificador utilizado para llamar a función (nombre_de_función en el ejemplo) Tipo de resultado (valor devuelto) es un tipo de dato de los datos devueltos (tipo_devuelto en el ejemplo) Declaración de los parámetros: cada parámetro consiste en una variable, constante, puntero o matriz precedidos por su tipo

de dato especificado similar a una declaración de variable regular (lista_de_parámetros en este ejemplo). Se utilizan para pasar la información de la función al llamarla.

Declaraciones locales son declaraciones opcionales de variables y constantes que se refieren solamente a la función dada. Cuerpo de función es una secuencia de sentencias que serán ejecutadas después de llamar a la función.

Aquí está un ejemplo de cómo definir y utilizar la función power:

'función que hace cálculo de xn basado en los parámetros de entrada x y n (n > 0)sub function power(dim x, n as byte) as longint ' x y n son bytes, resultado es longint

dim i as byte ' i es un byteresult = 1 ' resultado = 1 si n = 0if n > 0 then

for i = 1 to nresult = result*x

next iend if

end sub

Ahora, podemos llamar a la función power para hacer cálculo de 312 por ejemplo:

tmp = power(3, 12) ' Hacer cálculo de 3*12

LIBRERÍAS DE FUNCIONES Y PROCEDIMIENTOS

Las declaraciones de todas las funciones y procedimientos utilizados en Basic se almacenan normalmente en los ficheros de módulo especial y se les denominan librerías. Antes de utilizar una librería en el programa, es necesario especificar el módulo apropiado por medio de la cláusula include al principio de programa. Esto es una regla general. Si escribe un programa en el compilador mikroBasic PRO for PIC basta con marcar la librería deseada en la lista y el módulo apropiado será automáticamente incluido en el proyecto. El compilador ya contiene un gran número de estas librerías. Si el compilador encuentra una función o procedimiento desconocidos durante la ejecución de programa, primero va a buscar su declaración en las librerías anteriormente marcadas.

RUTINAS INTEGRADAS EN EL COMPILADOR MIKROBASIC PRO FOR PIC

Aparte de las librerías de funciones y procedimientos, el compilador mikroBasic PRO for PIC proporciona un conjunto de las funciones integradas y útiles:

Lo Hi Higher Highest Inc Dec Chr Ord SetBit ClearBit TestBit Delay_us Delay_ms

Vdelay_Advanded_ms Vdelay_ms Delay_Cyc Clock_KHz Clock_MHz Reset ClrWdt DisableContextSaving SetFuncCall SetOrg GetDateTime GetVersion

Las rutinas Delay_us y Delay_ms se generan en la parte del programa de la que se llaman.

Vdelay_ms, Delay_Cyc y Get_Fosc_kHz son las rutinas actuales en Basic. Sus fuentes se pueden encontrar en el archivo Delays.mbas ubicado en el archivo uses del compilador.

PREPROCESADOR

Un preprocesador es una parte integral de cada compilador. Su función es de reconocer y ejecutar las instrucciones del preprocesador. ¿Qué son instrucciones del preprocesador? Son instrucciones especiales que no pertenecen al lenguaje Basic, sino que están integrados en el compilador. Antes de compilar, el compilador inicia al preprocesador que pasa por el programa en búsqueda de estas instrucciones. Si encuentra una, el preprocesador las sustituirá por otro texto que, dependiendo del tipo de comando, puede ser un archivo (comando include) o sólo una corta sentencia de caracteres (comando define). Entonces, el proceso de compilar puede empezar. Las instrucciones pueden estar en cualquier parte del programa fuente y se refieren solamente a la parte del programa en la que aparecen hasta el final del programa.DIRECTIVA DEL PREPROCESADOR INCLUDE

Muchos programas repiten con frecuencia el mismo conjunto de comandos un par de veces. Para escribir un programa más rápidamente, estos comandos y declaraciones se agrupan normalmente en los módulos particulares que se pueden incluir en el

programa con facilidad por medio de la directiva include. Para decir con más precisión, la directiva include importa el texto del otro documento en el programa, sea un conjunto de comandos o bien un conjunto de comentarios etc.

COMPILACIÓN CONDICIONAL

Las directivas de la compilación condicional se utilizan generalmente para facilitar la modificación y compilación de los programas fuente para los diferentes microcontroladores. El compilador mikroBasic PRO for PIC soporta a la compilación condicional. Todas las directivas de la compilación condicional deben terminar dentro del módulo en el que han empezado.

DIRECTIVAS #IF, #ELIF, #ELSE, Y #ENDIF

Las directivas condicionales #if, #elif, #else y #endif se ejecutan de manera similar a las sentencias condicionales comunes en Basic. Si una expresión escrita después de #if tiene un valor distinto de cero, las líneas de programa que siguen a la directiva #if serán interpretadas como un código de programa válido y compiladas en código hex. La sintaxis es la siguiente:

#if constant_expression_1 'Si expresión_de_constante_1 no es cero,<section_1> 'sección_1 será compilada[#elif constant_expression_2 'Si expresión_de_constante_2 no es cero,<section_2>] 'sección_2 será compilada...[#elif constant_expression_n 'Si expresión_de_constante_n no es cero,<section_n>] 'sección_n será compilada[#else 'Si no se compila ninguna de las secciones anteriores<final_section>] 'sección_final será compilada#endif 'Final de la directiva #if

Cada directiva #if en un archivo fuente debe terminar por una directiva #endif de cierre correspondiente. Entre las directivas #if y #endif puede haber cualquier número de las directivas #elif, pero sólo se permite una directiva #else. Si está presente la directiva #else, debe ser la última directiva antes de la directiva #endif.

Sección puede ser cualquier código de programa reconocido por el compilador o preprocesador. El preprocesador selecciona una sección al evaluar la expresión_de_constante que sigue a cada directiva #if o #elif hasta encontrar una expresión_de_constante verdadera (distinta de cero).

Si todas las expresiones-constantes son evaluadas como falsas o no aparecen ninguna directiva #elif, el preprocesador selecciona la sección_final que sigue a la cláusula #else. Si se omite la cláusula #else y todas las expresiones_constantes en el bloque #if son evaluadas como falsas, no se seleccionará ninguna sección para un procesamiento posterior.

Por último, resulta que solamente una sección del código será compilada, aunque esté vacía.

PUNTEROS Como ya hemos mencionado, a cada objeto en el programa (variable, procedimiento, subrutina etc.) se le asigna una dirección de memoria particular. Al declarar una variable en el programa el compilador le asigna automáticamente una localidad de la memoria RAM libre. Durante la programación, estas direcciones no son visibles para los programadores. La posibilidad de acceder a los diferentes objetos por sus nombres (identificadores) en vez de por sus direcciones es una de las ventajas principales de los

lenguajes de programación de alto nivel. En realidad, es más fácil manejar las palabras (nombres) que los números. Además, el compilador se encarga de los objetos asociados y de sus direcciones. Direccionar los objetos al especificar sus nombres es denominado direccionamiento directo.

Sin embargo, a veces se necesita utilizar las direcciones de localidades de memoria. En este caso se utilizan los punteros - variables que almacenan la dirección de memoria de un objeto. Entonces, es posible acceder a los objetos que utilizan solamente los punteros. Por eso esta forma de direccionar es denominada direccionamiento indirecto.

Antes de utilizar un puntero es necesario declarar su tipo de datos. Solo hay que anteponer el signo de intercalación (^) al tipo.

dim pointer_p as ^word ' puntero_p apunta al dato de tipo word

Se le recomienda almacenar una varible en una localidad de memoria RAM específica, luego se debe utilizar la directiva absolute en el programa de la siguiente manera:

dim variable_a as word absolute 12 ' variable_a ocupará una palabra ' (16 bits) en la dirección 12

Para acceder a los datos en la localidad de memoria del puntero, necesita posponer el signo de la intercalación (^) al nombre del puntero. Veamos el ejemplo de la declaración del anteriormente mencionado puntero puntero_p , que apunta a la palabra (en este caso, es anteriormente definida variable_a almacenada en la dirección 12 en la RAM). A la variable apuntada variable_a se le asigna el valor 26:

dim pointer_p as ^word 'Puntero_p a punta al dato de tipo word......pointer_p = 12 'Puntero_p apunta a la dirección de memoria 12

... puntero_p^ = 26 'Variable a en la localidad de memoria 12 tiene valor 2'Similar a la directiva absolute utilizada para las variables, la 'directiva org especifica la dirección inicial de una rutina en la 'memoria ROM. Se añade a la declaración de la rutina. Por ejemplo: sub procedure proc(dim par as word) org 0x200 ' El procedimiento empezará... ' en la dirección 0x200end sub

En este caso, al puntero puntero_p se le asigna el valor 12 (puntero_p =12), lo que significa que la dirección de memoria 12 está especificada.

Si quiere cambiar el valor de una variable apuntada, basta con cambiar el valor del puntero y posponer el signo de intercalación (^) al valor. Veamos la figura a la derecha: a la variable variable_a en la dirección 12 se le asigna el valor 26 por medio del puntero puntero_p.Los punteros pueden apuntar a los datos almacenados en cualquier espacio de memoria disponible y pueden residir en cualquier espacio de memoria disponible menos en el espacio de memoria de programa (ROM).@ OPERADOR El operador @ devuelve la dirección de un objeto, o sea, crea un puntero sobre su operando. Las siguientes reglas se aplican al operando @:

Si X es una variable, @X devuelve la dirección de X. Si F es una rutina (función o procedimiento), @F crea un puntero a F.

dim temp as wordptr_b as ^byteptr_arr as ^byte[10]arr as byte[10]main:ptr_b = @arr ' operador @ devolverá ^bytetemp = @arr ' operador @ devolverá ^byteptr_arr = @arr ' operador @ devolverá ^byte[10]end.

Si la variable X es de tipo matriz, el operador @ devolverá el puntero a su primer elemento básico, excepto en el caso de que la parte izquierda de la expresión en la que se utiliza X sea el puntero a matriz. En este caso, el operador @ devolverá el puntero a matriz, y no a su primer elemento básico.

Estructura de programa en mikroBasic PRO for PIC:

1. Cada programa normalmente empieza con un comentario que proporciona información sobre el propósito del programa, fecha de programa, programador, versión, cambios a la versión anterior etc. Estos comentarios (cabecera) no son obligatorios, pero es una buena costumbre escribirlos y tenerlos en el programa.

2. Cada programa empieza con una directiva de programa seguida por el nombre de programa.3. Si el programa contiene otros módulos, aparte del módulo principal, sus nombres se deben especificar al utilizar la directiva

include (una directiva inlcude para cada módulo). Por consiguiente, si el compilador durante la compilación del módulo principal llega a un objeto que no es declarado (función, variable etc.), primero va a buscar su declaración dentro de los módulos declarados. Si no encuentra la declaración apropiada, el compilador informará de error.

4. La directiva include (si hay alguna) es seguida por la parte de código que sirve de declarar variables, constantes, procedimientos, subprogramas, funciones y otros objetos que se utilizarán más tarde en el programa. Estas declaraciones se utilizan para reservar los registros de la memoria RAM para almacenar los datos así como para enseñar al compilador cómo

ejecutar una función o un procedimiento. Por ejemplo, un dato de tipo byte ocupa un solo registro, mientras que un dato de tipo float ocupa cuatro registros.

5. El programa principal empieza con la directiva main: (siempre seguida por dos puntos). También es llamada ‘cuerpo de programa’.

6. Cada programa termina con la directiva end. (siempre seguida por un punto).

2.3 COMPILADOR MIKROBASIC PRO FOR PIC

Todo lo que usted ha leído hasta ahora sobre la programación en Basic es sólo teoría. Es útil saberlo, pero no se olvide de que este lenguaje de programación no está tan relacionado con algo concreto y tangible. Podrá experimentar muchos problemas con los nombres exactos de los registros, sus direcciones, nombres de los bits de control particulares, y muchos más al empezar a escribir su primer programa en Basic. El punto es que usted necesita más que una teoría para que el microcontrolador haga algo útil.

Teniendo en cuenta de que “Es mejor prevenir que curar”, hay que avisarle de todas las cosas por resolver antes de que empiece a escribir un programa para el microcontrolador. Antes que nada, necesita un programa instalado en la PC que “eniende” el lenguaje de programación a utilizar y que proporciona un entorno de trabajo apropiado. No hay un compilador apropiado para un tipo de compilador, tampoco para todos los microcontroladores. Normalmente se utiliza un software para programar los similares microcontroladores de un fabricante. En las secciones anteriores hemos presentado el lenguaje mikroBasic, especialmente diseñado para programar los PIC. Ahora, cuando sabe lo suficiente sobre ese lenguaje, 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.).Como implica su nombre, mikroBasic PRO for PIC está pensado para escribir los programas para los microcontroladores PIC en Basic. Este compilador contiene las informaciones de arquitectura de los microcontroladores PIC (registros, sus direcciones exactas, módulos de memoria, funcionamiento de sus módulos, juego de instrucciones, disposición de pines etc.). Además incluye las herramientas apropiadas para programar los microcontroladores PIC. Lo primero que tiene que hacer al iniciar el compilador es seleccionar el chip y frecuencia de operación de la lista. Esto no es un final, sino un comienzo. Por fin puede empezar a escribir el programa en Basic.

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).INSTALAR MIKROBASIC PRO FOR PIC

La instalación del mikroBasic 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? Como ya hemos dicho, el compilador compila un programa escrito en Basic en código hex. El siguiente paso es cargar ese código en el microcontrolador. Por eso es necesario instalar el programador PICFLASH. ¡Hágalo! Una vez más: Next, OK, Next, Next...

Una vez completada la instalación del PICFLASH, el sistema operativo le preguntará a instalar otro programa similar. Es un software para programar una familia 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)!

Un controlador es un programa que permite al sistema operativo comunicarse con un periférico. En este caso, este dispositivo es el programador (hardware) del sistema de desarrollo. Lo necesita seguramente. Pulse sobre Yes.

El controlador a instalar depende del sistema operativo utilizado. En este caso, el ordenador utiliza el sistema operativo de 32 bits Windows XP. Seleccione la carpeta Win 2000, XP, 2003 32-bit que contiene el controlador apropiado e inicie la instalación.

Otra vez, Next, OK, Next, Next...Bueno, ¡todo está instalado para iniciar a programar!

IDE DEL MIKROBASIC PRO FOR PIC

Al iniciar el IDE del compilador mikroBasic PRO for PIC por primera vez, aparecerá una ventana como se muestra a continuación:

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 mikroBasic PRO for PIC. De todos modos, para obtener más información presione el botón de Ayuda (Help) [F1]. En el capítulo cuatro se presentan varios ejemplos y se da una explicación detallada de cómo crear un nuevo proyecto y escribir un programa.

PROJECT MANAGER (Administrador de proyecto)

Un programa escrito en el compilador mikroBasic PRO for PIC no es un archivo autónomo, sino que forma parte de un proyecto que incluye un código hex, un código ensamblador y otros archivos. Algunos de ellos se requieren para compilar el programa, mientras que otros se crean durante el proceso de compilación. La ventana Project Manager le permite manejar todos los ficheros del proyecto. Basta con pulsar con el botón derecho del ratón sobre una carpeta y seleccionar la opción que necesita para su proyecto.

LIBRARY MANAGER

Las librerías contienen un gran número de funciones listas para ser utilizadas. Las librerías en mikroBasic proporcionan muchas facilidades para escribir programas para los microcontroladores PIC. El compilador debe “conocer” todas las dependencias del archivo fuente de mikroBasic para compilarlo apropiadamente. 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 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.

CODE EXPLORER (Explorador de 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.

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 ya 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 del microcontrolador a utilizar permite al compilador extraer el archivo de definición asociado. El archivo de definición de un microcontrolador contiene la información específica de sus registros SFR, de sus direcciones de memoria y algunas variables de 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.Build type - 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.Build type - ICD debug: El archivo .hex generado contiene los datos adicionales que permiten el funcionamiento del depurador. 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. 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 del microcontrolador.El simulador software se puede utilizar en ambos modos de compilación para el propósito de depurar. Le permite simular su programa al reproducir el comportamiento del microcontrolador. 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.EDITAR Y COMPILAR PROGRAMAS

CODE EDITOR (Editor de código)

El proceso de escribir y editar programas se debe realizar dentro de la ventana principal del IDE denominada Code Editor. Un gran número de opciones utilizadas para configurar sus funciones y el diseño se encuentran en el menú Tools/Options [F12]. Al escribir el programa no se 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 extensión, no vacile en utilizar los espacios en blanco para hacer su código más legible.

Al escribir un programa, 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. De este modo, resulta más fácil solucionar los errores de programa. De lo contrario, usted tendrá que editar el programa entero.

COMPILAR Y SOLUCIONAR 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 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 el programa informa de un error de sintaxis en la línea 80. La compilación le permite corregir su programa por medio de solucionar todos los errores en mikroBasic. 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

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

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

SIMULADOR SOFTWARE

Si quiere ser un programador y dedicarse a programar los microcontroladores, tenga en cuenta de que los programas nunca funcionan al primer intento. Por eso, empiece a funcionar un simulador. El simulador es una parte integral del compilador utilizado para simular el funcionamiento del microcontrolador.

Antes de empezar a utilizar el simulador, seleccione el modo de funcionamiento en la ventana Project Settings (Build type - release), compile el programa y pulse sobre la opción Run /Start Debugger. El compilador se pone automáticamente en el modo de simulación. En este modo se monitorea el estado de todos los bits de registros y se le permite ejecutar el programa paso a paso durante el monitoreo del funcionamiento del microcontrolador en la pantalla. Hay varios iconos, utilizados para el funcionamiento del simulador, que aparecerán en la barra de herramientas cuando el compilador entre en este modo.

Estos iconos tienen el siguiente significado:

Step Into: Ejecuta una sola instrucción. Cuando la instrucción es una llamada a una subrutina, el depurador hará un salto a la subrutina y se detendrá después de ejecutar la primera instrucción dentro de la subrutina.

Step Over: Se ejecuta una sola instrucción. Cuando la instrucción es una llamada a una subrutina, el depurador no hará un salto a la subrutina, sino que se ejecutará toda la subrutina. El depurador se detiene a la primera instrucción después de la llamada a la subrutina. Parece como si se saltara una línea de programa aunque se ha ejecutado toda la subrutina. El estado de todos los registros será cambiado. Este comando se ejecuta cuando es necesario acelerar la ejecución de los bucles de programa largos.

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

subrutina.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.

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 saltar directamente a los puntos 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 el microcontrolador. 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 el archivo list durante el proceso de la depuración. Para visualizar esta ventana es necesario seleccionar la opción View/Windows/Watch Values. Entonces usted puede hacer una lista de re-gistros/variables que quiere monitorear.

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.

DEPURADOR EN CIRCUITO

La otra forma de comprobar la ejecución de programa es al utilizar el depurador mikroICD (depurador en circuito). El mikroICD (depurador en circuito) es una parte integral del programador PICflash. Se utiliza con el propósito de probar y depurar los programas. El proceso de probar y depurar se realiza al monitorizar los estados de todos los registros dentro del microcontrolador durante su funcionamiento en entorno real. Para habilitar la depuración, es necesario seleccionar las opciones Build Type-ICD Debug y Debugger-mikroICD antes de cargar el programa en el microcontrolador. Tan pronto como se inicie el depurador mikroICD, aparecerá una ventana como se muestra en la siguiente Figura. El depurador mikroICD se comunica con el microcontrolador PIC por sus pines utilizados para la programación. Por eso no se pueden utilizar como pines de E/S durante la ejecución de la depuración de programa. Durante la operación del depurador mikroICD, el programador y la PC deben estar conectados al utilizar un cable USB.

Opciones del depurador mikroICD:

Start Debugger [F9] Run/Pause Debugger [F6] Stop Debugger [Ctrl+F2] Step Into [F7] Step Over [F8] Step Out [Ctrl+F8] Toggle Breakpoint [F5] Show/Hide Breakpoints [Shift+F4] Clear Breakpoints [Ctrl+Shift+F4]

Cada de estos comandos se activa por medio de los atajos de teclado o al pulsar sobre el icono apropiado en la ventana Watch Values.

El depurador mikroICD también ofrece funciones tales como ejecutar el programa paso a paso, detener la ejecución de programa para monitorear el estado de los registros actualmente activos por medio de los puntos de ruptura, monitorear los valores de algunas variables etc. El siguiente ejemplo muestra una ejecución de programa paso a paso utilizando el comando Step Over.

Paso1:

En este ejemplo la línea de programa 31 está marcada por el azul, lo que quiere decir que es la siguiente en ser ejecutada. El estado actual de todos los registros dentro del microcontrolador se puede visualizar en la ventana Watch Values del mikroICD.

Paso 2:

Después de ejecutar el comando Step Over [F8] el microcontrolador ejecutará la línea de programa 31. La siguiente línea en ser ejecutada (32) está marcada por el azul. El estado de los registros cambiados durante la ejecución de esta instrucción se puede visualizar en la ventana Watch Values.

CARGAR EL PROGRAMA EN 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 una herramienta diseñada para programar todos los tipos de microcontroladores PIC. Está compuesto por dos partes:

La parte hardware se utiliza para poner en el búfer 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. Se activa 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.

HERRAMIENTAS DEL COMPILADOR

El compilador mikroBasic 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.

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.

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.

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.

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

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.

LIBRERÍAS

Uno de los elementos más importantes del compilador mikroBasic PRO for PIC es Library Manager, que por supuesto merece nuestra atención. Para que una función o un procedimiento realice una cierta tarea al escribir un programa, basta con encontrarla/encontrarlo en una de las librerías incluidas en el compilador y utilizarla. Una librería representa un archivo llamado cabecera. Contiene un conjunto de variables y constantes escritas en mikroBasic. Cada librería tiene un propósito específico. Por ejemplo, para que un procedimiento genere una señal de audio, abra la librería Sound en la ventana Library Manager y pulse dos veces sobre el procedimiento apropiado Sound_Play. Una descripción detallada de este procedimiento aparece en la pantalla. Copíelo en su programa y ajuste los

parámetros apropiados. Al marcar esta librería, sus funciones estarán disponibles y no será necesario utilizar la librería include.

El mikroBasic PRO for PIC incluye las librerías misceláneas y las librerías para el hardware.LIBRERÍAS MISCELÁNEAS

Las librerías misceláneas contienen algunas funciones de propósito general:

L I B R A R Í A D E S C R I P C I Ó N

Button Library Eliminar la influencia del rebote de contacto

Conversions Library Rutinas para conversiones de números en cadenas y BCD/decimal

C Type Library Probar y convertir los caracteres

String Library Automatizar las tareas relacionadas con las cadenas

Time Library Rutinas para calcular el tiempo en el formato de tiempo UNIX

Trigon Library Funciones trigonométricas

LIBRARIES LIBRERÍAS PARA EL HARDWARE

Las librerías para el hardware incluyen las funciones utilizadas para controlar el funcionamiento de los módulos hardware:

L I B R A R Í A D E S C R I P C I Ó 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

EEPROM Library Utilizada para las operaciones con la memoria EEPROM incorporada

Ethernet PIC18FxxJ60 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

I²C 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

OneWire 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 I²C 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)

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

Capítulo 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 4.4 EJEMPLO 2 - Utilizar instrucciones en ensamblador y el oscilador interno LFINTOSC... 4.5 EJEMPLO 3 - Timer0 como un contador, declarar variables nuevas, utilizar símbolos, utilizar relés... 4.6 EJEMPLO 4 - Utilizar los temporizadores Timer0, Timer1 y Timer2. Utilizar interrupciones, declarar nuevos

procedimientos... 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 cuatro dígitos LED, multiplexión

4.12 EJEMPLO 10 - Utilizar el visualizador LCD 4.13 EJEMPLO 11 - Comunicación serial RS232 4.14 EJEMPLO 12 - Medición de temperatura por medio del sensor DS1820. Uso del protocolo ‘1-wire’... 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.18 EJEMPLO 16 - Utilizar el teclado 4x4

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.

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 - Crystal / Resonator; HS - Cristal/Resonador de alta velocidad; y RC - Resistencia / Condensador.

¿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.

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 C1 y C2 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 de reloj del microcontrolador, 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.

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.

4.2 COMPONENTES ADICIONALES

A pesar 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.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.

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. El rebote ocurre demasiado rápido, asi que no es posible percibirlo al utilizar estos componentes en la vida cotidiana. Sin embargo, pueden surgir problemas en algunos circuitos analógicos y 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.

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ÉS

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 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 en caso de conectar un relé a los dispositivos alimentados por la red eléctrica.

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.

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.

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 conecta dos 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.

Los segmentos del visualizador están normalmente etiquetados con letras de a a g, pero no hay ninguna regla estricta a 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 LED 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.

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 di-señ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 pa-labras, 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.

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

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.

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.

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 D E S C R I P C I Ó N

L Ó G I C O

Tierra 1 Vss - 0V

Alimentación 2 Vdd - +5V

Contraste 3 Vee - 0 - Vdd

Control de funcionamiento

4 RS 01

D0 – D7 considerados como comandosD0 – D7 considerados como datos

5 R/W01

Escribir los datos (del microcontrolador al LCD)

Leer los daots (del LCD al microcontrolador)

6 E Transición de 1 a 0

Acceso al visualizador LCd deshabilitadoFuncionamiento 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

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

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:

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.

El principio de funcionamiento de la memoria DDRAM 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.

Como sugiere su nombre, la memoria DDRAM 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.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 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 pe-rifé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.

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 deno-minada 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 escri-tura 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 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 relacionados con la operación del LCD:

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 DDRAM 40uS

Leer la bandera “BUSY”(ocupado)(BF)

0 1 BF Dirección DDRAM -

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

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 = Visualizar en dos líneas 0 = Visualizador encendido 0 = Visualizar 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).

Conectar el 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.

Inicializar el 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á borrado2. Modo

DL = 1 - Bus de datos de 8 bitsN = 0 - Datos se visualizan en una líneaF = 0 - Formato fuente de caracteres es 5 x 8 píxeles

3. Visualizador/Cursor encendido/apagadoD = 0 - Visualizador apagadoU = 0 - Cursor apagadoB = 0 - Parpadeo del cursor apagado

4. Introducción de caracteresID = 1 Direcciones visualizadas se incrementan automáticamente en 1S = 0 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 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 después, será posible enviar los mensajes al visualizador LCD.Refiérase a la Figura que sigue para el procedimiento de inicialización por el bus de datos de 8 bits:

¡Esto no es un error! En este algoritmo el mismo valor se envía sucesivamente tres veces al visualizador LCD envía sucesivamente.

El procedimiento de inicialización por el bus de datos de 4 bits:

Vamos a hacerlo en mikroBasic...

' En mikroBasic 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 ' delarar los bits LCD_D4-LCD_D7, LCD_RS y LCD_EN.

...sub procedure Lcd_Init ' Inicializar el LCD

...

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.

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 .mbppi. Se creará en el proyecto el archivo fuente con el mismo nombre (First_Project .mbas).

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:

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 mikroBasic 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 Messages. Si no hay errores en el programa, el compilador mikroBasic 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

El único propósito de este programa es de encender varios diodos LED en el puerto PORTB. 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.

Al encender la fuente de alimentación, cada segundo, el diodo LED en el puerto PORTB 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.

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 ciclo de trabajo es 5:1 (500mS:100mS). Cualquier cambio de estos estados lógicos hace todos los LEDs parpadear.

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í hasta que 1=1 (bucle infinito). 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 es hacer los LEDs en el puerto PORTB parpadear lentamente. Se puede realizar al introducir 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 Basic, los bits de control RP0 y RP1 deben recuperar el estado que tenían antes de introducir la secuencia en ensamblador. En este caso se utiliza la variable auxiliar saveBank para guardar el estado de estos dos bits.

'Cabecera *********************************************program example_2 ' Nombre de programadim k as byte ' Variable k es de tipo bytedim saveBank as byte ' Variable saveBank es de tipo bytemain: ' Inicio del programak = 0 ' Valor inicial de la variable k

ANSEL = 0 ' Todos los pines de E/S se configuran como digitalesANSELH = 0PORTB = 0 ' Todos los pines del puerto PORTB se ponen a 0TRISB = 0 ' Pines del puerto PORTB se configuran como salidas

doPORTB = not PORTB ' Invertir el estado lógico del puerto PORTBDelay_ms(100) ' Tiempo de retardo de 100mSk = k+1 ' Incrementar k en 1loop until k=20 ' Quedarse en bucle hasta que k<20

k=0 ' Reiniciar variable ksaveBank = STATUS and %01100000 ' 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 elbcf STATUS,RP1 ' registro OSCCONbcf OSCCON,6 ' Seleccionar el oscilador interno LFINTOSCbcf OSCCON,5 ' de frecuencia de 31KHzbcf OSCCON,4bsf OSCCON,0 ' Microcontrolador utiliza oscilador internoend asm ' Final de la secuencia en ensamblador

STATUS = STATUS and %10011111 ' Bits RP0 y RP1 recuperan el estado originalSTATUS = STATUS or saveBank

doPORTB = not PORTB ' Invertir el estado lógico del puerto PORTBDelay_ms(10) ' Tiempo de retardo de 10 mSk = k+1 ' Incrementar k en 1

loop until k=20 ' Quedarse en el bucle hasta que k<20

stay_here: goto stay_here ' Bucle infinito

end. ' Final de programa

Usted ha notado que la señal de reloj ha sido cambiado al vuelo. Para asegurarse de eso, quite el cristal de cuarzo antes de encender al microcontrolador. El microcontrolador no podrá empezar a funcionar porque la Palabra de Configuración cargada en el programa requiere proporcionar el cristal de cuarzo. Al quitar el cristal más tarde durante el funcionamiento, no pasará nada, o sea, eso no afectará nada al microcontrolador.

4.5 EJEMPLO 3

Timer0 como un contador, declarar variables nuevas, utilizar símbolos, 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 TMR0 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. En este ejemplo, el registro TEST almacena el número 5. Por supuesto, eso puede ser cualquier número obtenido al calcular o definido como una constante. Además, el microcontrolador puede activar algún otro dispositivo en vez de relé, mientras que el sensor se puede utilizar en vez del botón de presión. Este ejemplo muestra una de las aplicaciones más comunes del microcontrolador en la industria; al realizar una cosa el suficiente número de veces, otra cosa debe estar encendida o apagada.

' Cabecera ******************************************************program example_3 ' Nombre del programa symbol RELAY = PORTD.3 ' Pin del puerto PORTD.3 es denominado RELÉdim TEST as byte ' Variable TEST es de tipo bytemain: ' Inicio del programaTEST = 5 ' Constante TEST = 5ANSEL = 0 ' All I/O pins are configured as digitalANSELH = 0

PORTA = 0 ' Reiniciar el puerto PORTATRISA = 0xFF ' Todos los pines de E/S se configuran como digitales PORTD = 0 ' Reiniciar el puerto PORTDTRISD = %11110111 ' Pin RD3 se configura como una salida, mientras que los ' demás se configuran como entradasOPTION_REG.5 = 1 ' Contador TMR0 recibe los pulsos por el pin RA4OPTION_REG.3 = 1 ' Valor del pre-escalador es 1:1TMR0 = 0 ' Reiniciar el temporizador/contador TMR0

while 1if TMR0 = TEST then ' ¿Coincide el número en el temporizador con la constante TEST?

RELAY = 1 ' Números coinciden. Poner el bit RD3 a uno (salida RELÉ)end ifwend ' Quedarse en el bucle infinito

end. ' Final de programa

Sólo un símbolo (RELÉ) se utiliza aquí. Se le asigna el tercer pin del puerto PORTD en la declaración.

symbol RELAY = PORTD.3 ' Símbolo RELÉ = PORTD.3

4.6 EJEMPLO 4

Utilizar los temporizadores Timer0, Timer1 y Timer2. Utilizar interrupciones, declarar nuevos procedimientos...

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 TMR0 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 50, el puerto PORTB se incrementa en 1. Todo el procedimiento se lleva a cabo “entre bastidores”, lo que habilita al microcontrolador hacer otra tarea.

' Cabecera******************************************************program example_4a ' Inicio del programadim cnt as byte ' Definir la variable cnt como un byte

sub procedure interrupt ' Este subprocedimiento determina qué se lo que se ' debe hacer cuando se genere una interrupcióncnt = cnt + 1 ' Interrupción causa que la cnt se incremente en 1TMR0 = 96 ' El valor inicial se devuelve en el temporizador TMR0INTCON = 0x20 ' Bit T0IE se pone a 1, el bit T0IF se pone a 0end sub ' Final de la rutina de interrupción

main: ' Inicio del programaOPTION_REG = 0x84 ' Pre-escalador se le asigna al temporizador TMR0ANSEL = 0 ' Todos los pines de E/S se configuran como digitalesANSELH = 0TRISB = 0 ' Todos los pines de puerto PORTB se configuran como salidasPORTB = 0x0 ' Reiniciar el puerto PORTBTMR0 = 96 ' Temporizador T0 cuenta de 96 a 255INTCON = 0xA0 ' Habilitada interrupción TMR0cnt = 0 ' A la variable cnt se le asigna un 0

while 1 ' Bucle infinitoif cnt = 50 then ' Incrementar el puerto PORTB después 50 interrupciones PORTB = PORTB + 1 ' Incrementar número en el puerto PORTB en 1cnt = 0 ' Reiniciar la variable cntend ifwend

end. ' Final de programa

Siempre que se produzca un desbordamiento en el registro del temporizador TRM0, ocurre una interrupción.

'Cabecera******************************************************program example_4b ' Nombre del programadim cnt as byte ' Definir la variable cnt

sub procedure interrupt ' Definir el subprocedimiento de interrupcióncnt = cnt+1 ' Interrupción causa que la cnt se incremente en 1PIR1.TMR1IF = 0 ' Reiniciar el bit TMR1IFTMR1H = 0x80 ' El valor inicial se devuelve en los registrosTMR1L = 0x00 ' del temporizador TMR1H y TMR1Lend sub ' Final de la rutina de interrupción

main: ' Inicio del programaANSEL = 0 ' Todos los pines de E/S se configuran como digitalesANSELH = 0PORTB = 0xF0 ' Valor inicial de los bits del puerto PORTBTRISB = 0 ' Los pines del puerto PORTB se configuran como salidasT1CON = 1 ' Configurar el temporizador TMR1PIR1.TMR1IF = 0 ' Reiniciar el bit TMR1IFTMR1H = 0x80 ' Poner el valor inicial para el temporizador TMR1TMR1L = 0x00PIE1.TMR1IE = 1 ' Habilitar la interrupción al producirse un desbordamiento cnt = 0 ' Reiniciar la variable cntINTCON = 0xC0 ' Interrupción habilitada (bits GIE y PEIE)

while 1 ' Bucle infinito if cnt = 76 then ' Cambiar el estado del puerto PORTB después de 76 interrupcionesPORTB = not PORTB ' Número en el puerto PORTB está invertidocnt = 0 ' Reiniciar la variable cntend ifwend

end. ' Final de programa

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******************************************************program example_4c ' Nombre del programadim cnt as byte ' Definir la variable cnt como un byte

sub procedure Replace ' Definir el procedimiento ‘Reemplazar’PORTB = not PORTB ' Definir el nuevo procedimiento ‘Reemplazar’end sub ' Procedimiento invierte el estado del puerto

sub procedure interrupt ' Definir el subprocedimiento de interrupciónif PIR1.TMR2IF then ' Si el bit TMR2IF = 1,cnt = cnt +1 ' Incrementar variable la cnt en 1 PIR1.TMR2IF = 0 ' Reiniciar el bit y

TMR2 = 0 ' Reiniciar el registro TMR2end ifend sub ' Final de la rutina de interrupción

main: ' Inicio del programacnt = 0 ' Reiniciar la variable cntANSEL = 0 ' Todos los pines de E/S se configuran como digitalesANSELH = 0PORTB = %10101010 ' Estado lógico en los pines del puerto PORTBTRISB = 0 ' Todos los pines del puerto PORTB se configuran como salidasT2CON = 0xFF ' Configurar el temporizador T2TMR2 = 0 ' Valor inicial del registro del temporizador TMR2PIE1.TMR2IE = 1 ' Interrupción habilitadaINTCON = 0xC0 ' Bits GIE y PEIE se ponen a 1

while 1 ' Bucle infinito if cnt > 30 then ' Cambiar el estado del puerto PORTB después de más de 30 interrupciones Replace ' Subprocedimiento Reemplazar invierte el estado del puerto PORTB cnt = 0 ' Reset variable cnt end ifwend

end. ' Final de programa

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 el procedimiento Reemplazar, que normalmente no pertenece al lenguaje mikroBasic.

4.7 EJEMPLO 5

Utilizar el temporizador perro - guardián

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 ******************************************************program example_5 ' Nombre de programamain: ' Inicio del programaOPTION_REG = 0x0E ' Pre-escalador se le asigna al temporizador WDT (1:64)asm CLRWDT ' Comando en ensamblador para reiniciar el temporizador WDTend asmPORTB = 0x0F ' Valor inicial del registro PORTB TRISB = 0 ' Todos los pines del puerto PORTB se configuran como salidasDelay_ms(300) ' Tiempo de retardo de 30mSPORTB = 0xF0 ' Valor del puerto PORTB diferente del inicial

while 1 ' Bucle infinito. El programa se queda aquí hasta que elwend ' temporizador WDT reinicie al microcontroladorend. ' Final de programa

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: sub procedure PWM1_Init(const freq as longint)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: sub procedure PWM1_Start()3. PWM1_Set_Duty tiene el prototipo: sub procedure PWM1_Set_Duty(dim duty_ratio as byte)

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: sub procedurePWM1_Stop()

' Cabecera ******************************************************program example_6 ' Nombre de programadim current_duty, old_duty, oldstate as byte ' Definir las variables current_duty ' old_duty y oldstatemain: ' Inicio del programaANSEL = 0 ' Todos los pines de E/S se confguran como digitalesANSELH = 0PORTA = 255 ' Estado inicial del puerto PORTATRISA = 255 ' Todos los pines del puerto PORTA se configuran como entradasPORTB = 0 ' Estado inicial del puerto PORTBTRISB = 0 ' Todos los pines del puerto PORTB se configuran como salidas PORTC = 0 ' Estado inicial del puerto PORTCTRISC = 0 ' Todos los pines del puerto PORTC se configuran como salidas

PWM1_Init(5000) ' Inicialización del módulo PWM (5 KHz)current_duty = 16 ' Valor inicial de la variable current_dutyold_duty = 0 ' Reiniciar la variable old_dutyPWM1_Start() ' Inicialización del módulo PWM1

while 1 ' Bucle infinito if oldstate and Button(PORTA, 0,1,1) then ' Si se presiona el botón conectado al RA0 current_duty = current_duty + 1 ' incrementar el valor de la variable current_duty if Button(PORTA, 0, 1, 1) then oldstate = 255 end if end if if oldstate and Button(PORTA, 1,1,1) then ' Si se presiona el botón conectado al RA1 current_duty = current_duty - 1 ' decrementar el valor de la variable current_duty if Button(PORTA, 1, 1, 1) then oldstate = 255 end if end if if old_duty <> current_duty then ' Si current_duty y old_duty no son iguales PWM1_Set_Duty(current_duty) ' ajustar un nuevo valor a PWM, old_duty = current_duty ' guardar el nuevo valor PORTB = old_duty ' y visualizarlo en el puerto PORTB end if Delay_ms(200) ' Tiempo de retardo 200mSwend

end. ' Final de programa

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 EJEMPLO 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 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 VCC se utiliza como voltaje de referencia positivo.

Si se utiliza el voltaje variable como Vref+ (refiérase a la línea punteada), se habilita estirar y encojer la escala de medición.

En 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******************************************************program example_7 ' Nombre de programadim temp_res as word ' Variable temp_res es de tipo word main: ' Inicio del programaANSEL = 0x0C ' Pin AN2 se configura como analógicoTRISA = 0xFF ' Todos los pines del puerto PORTA se configuran como entradasANSELH = 0 ' Los demás pines se configuran como digitalesTRISB = 0x3F ' Pines del puerto PORTB, RB7 y RB6 se configuran como salidasTRISD = 0 ' Todos los pines del PORTD se configuran como salidasADCON1.B4 = 0 ' Voltaje de referencia positivo es VCC.

while 1 ' Bucle infinito 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 wend

end. ' Final de programa

Para que este ejemplo funcione apropiadamente, es necesario marcar la librería ADC en la ventana Library Manager antes de compilar el programa:

ADC

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. 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 en la dirección 5, directamente leído y visualizado en el puerto PORTD en forma binaria.

'Cabecera******************************************************program example_8 ' Nombre de programamain: ' Inicio del programaANSEL = 0 ' Todos los pines de E/S se configuran como digitalesANSELH = 0PORTB = 0 ' Valor inicial del puerto PORTBTRISB = 0 ' Todos los pines del puerto PORTB se configuran como salidasPORTD = 0 ' Valor inicial del puerto PORTBTRISD = 0 ' Todos los pines del puerto PORTD se configuran como salidasTRISA = 0xFF ' Todos los pines del puerto PORTA se configuran como entradasPORTD = EEPROM_Read(5) ' Leer la memoria EEPROM en la dirección 5

while 1 ' Bucle infinito PORTB = PORTB + 1 ' Incrementar el puerto PORTB en 1 Delay_ms(100) ' Tiempo de retardo de 100mS while not PORTA.B2 ' Quedar en este bucle hasta que el botón esté pulsado if not PORTA.B2 then EEPROM_Write(5,PORTB) ' Si se pulsa el botón MEMO, guardar el puerto PORTB PORTD = EEPROM_Read(5) ' Leer el dato escrito end if wendwend

end. ' Final de programa

Para que este ejemplo funcione apropiadamente, es necesario marcar la librería EEPROM en la ventana Library Manager antes de compilar el programa:

EEPROM

Para comprobar el funcionamiento de este programa, basta con pulsar el botón MEMO y apagar el microcontrolador. Después de reiniciar el dispositivo, el programa visualizará en el puerto PORTD el valor guardado en la memoria EEPROM en la dirección 5. Acuérdese de que en el momento de escribir, el valor fue visualizado en el puerto PORTB

.

4.11 EJEMPLO 9

Contador de cuatro 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 cuatro dígitos LED (9999-0). El punto es habilitar una conversión de un número binario en un decimal y partirlo en cuatro dígitos (en miles, centenas, 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.

'Cabecera******************************************************program example_9 ' Nombre de programadim shifter, portd_index as byte ' Variables shifter y portd_index son de tipo byte digit, number as word ' Variables digit y number son de tipo wordportd_array as word[4] ' Matriz portd_array tiene 4 miembros de tipo word sub function mask (dim num as Word) as Word ' Subrutina para enmascarar select case num ' utilizada para convertir case 0 result = $3F ' números binarios en la

case 1 result = $06 ' combinación de bits apropiada case 2 result = $5B ' que se visualizará en el LED case 3 result = $4F case 4 result = $66 case 5 result = $6D case 6 result = $7D case 7 result = $07 case 8 result = $7F case 9 result = $6F end select ' Final de la sentencia Caseend sub ' Final de la subrutina

sub procedure interrupt ' Inicio de la rutina de interrupción PORTA = 0 ' Apagar todos los visualizadores de 7 segmentos PORTD = portd_array [portd_index] ' Enviar el valor apropiado al puerto PORTD PORTA = shifter ' Encender el visualizador apropiado de 7 segmentos shifter = shifter << 1 ' Mover shifter al siguiente dígito if (shifter > 8) then shifter = 1 end if Inc(portd_index) ' Incrementar portd_index if (portd_index > 3) then portd_index = 0 ' Encender el primero, apagar el cuarto visualizador de 7 segmentos end if TMR0 = 0 ' Reiniciar el valor del TIMER0 T0IF_bit = 0 ' Borrar la bandera de interrupción del Timer0

end sub ' Final de la rutina de interrupción

main: ' Inicio del programaANSEL = 0 ' Configurar los pines analógicos como pines de E/S digitalesANSELH = 0OPTION_REG = $80 ' Configuración del Timer0 (Timer0 funciona como temporizador ' con el pre-escalador)digit = 0 ' Valor inicial de la variable digitportd_index = 0 ' Encender el primer visualizador LEDshifter = 1 ' Valor inicial de la variable shifterTMR0 = 0 ' Borrar el Timer0INTCON = $A0 ' Habilitar interrupción con los bits GIE y T0IEPORTA = 0 ' Borrar el PORTATRISA = 0 ' Configurar el PORTA como salidaPORTD = 0 ' Borrar el PORTDTRISD = 0 ' Configurar el PORTD como salidanumber = 6789 ' Un valor inicial en el visualizador LED

while TRUE ' Bucle infinito digit = number / 1000 ' Extraer miles portd_array[3] = mask(digit) ' y almacenarlo en la matriz PORTD digit = (number / 100) mod 10 ' Extraer centenas portd_array[2] = mask(digit) ' y almacenarlo en la matriz PORTD digit = (number / 10) mod 10 ' Extraer decenas portd_array[1] = mask(digit) ' y almacenarlo en la matriz PORTD digit = number mod 10 ' Extraer unidades portd_array[0] = mask(digit) ' y almacenarlo en la matriz PORTD Delay_ms(1000) ' Retardo de un segundo Inc(number) ' Incrementar número

if (number > 9999) then ' Empezar a contar de cero number = 0 end ifwend

end. ' Final de programa

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.

Dos mensajes escritos en dos líneas aparece en el visualizador:mikroElektronikaLCD exampleDos segundos más tarde, el segundo mensaje se susituye por el voltaje presente en la entrada del convertidor A/D (el pin RA2). Por ejemplo:

mikroElektronikavoltage:3.141VEn un dispositivo real se puede visualizar temperatura actual o algún otro valor medido en vez de voltaje.

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******************************************************program example_10 ' Nombre de programa

dim LCD_RS as sbit at RB4_bit ' Conexiones del módulo LcdLCD_EN as sbit at RB5_bitLCD_D4 as sbit at RB0_bit

LCD_D5 as sbit at RB1_bitLCD_D6 as sbit at RB2_bitLCD_D7 as sbit at RB3_bitLCD_RS_Direction as sbit at TRISB4_bitLCD_EN_Direction as sbit at TRISB5_bitLCD_D4_Direction as sbit at TRISB0_bitLCD_D5_Direction as sbit at TRISB1_bitLCD_D6_Direction as sbit at TRISB2_bitLCD_D7_Direction as sbit at TRISB3_bit ' Final de las conexiones del módulo Lcd dim text as string [16] ' Variable text es de tipo stringdim ch, adc_rd as word ' Variables ch y adc_rd son de tipo worddim tlong as longword ' Variable tlong es de tipo longwordmain: ' Inicio del programaTRISB = 0 ' Todos los pines del puerto PORTB se configuran como salidasPORTB = 0xFFINTCON = 0 ' Todas las interrupciones deshabilitadasANSEL = 0x04 ' Pin RA2 se configura como una entrada analógicaTRISA = 0x04ANSELH = 0 ' Los demás pines se configuran como digitalesLcd_Init() ' Inicialización del visualizador LCDLcd_Cmd(_LCD_CURSOR_OFF) ' Comando LCD (apagar el cursor)Lcd_Cmd(_LCD_CLEAR) ' Comando LCD (borrar el LCD)

text = "mikroElektronika" ' Definir el primer mensajeLcd_Out(1,1,text) ' Escribir el primer mensaje en la primera líneatext = "LCD example" ' Definir el segundo mensajeLcd_Out(2,1,text) ' Definir el segundo mensaje en la segunda líneaADCON1 = 0x80 ' Voltaje de referencia para la conversión A/D es VCCTRISA = 0xFF ' Todos los pines del puerto PORTA se configuran como entradasDelay_ms(2000)

text = "Voltage=" ' Definir el tercer mensaje

while 1 ' Bucle infinito 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 = adc_rd * 5000 ' Convertir el resultado en milivoltios tlong = tlong / 1023 ' 0..1023 -> 0-5000mV ch = (tlong / 1000) mod 10 ' Extraer voltios (miles de milivoltios) ' del resultado Lcd_Chr(2,9,48+ch) ' Escribir resultado en formato ASCII Lcd_Chr_CP(".") ' Escribir el punto decimal ch = (tlong / 100) mod 10 ' Extraer centenas de milivoltios Lcd_Chr_CP(48+ch) ' Escribir resultado en formato ASCII ch = (tlong / 10) mod 10 ' Extraer decenas de milivoltios Lcd_Chr_CP(48+ch) ' Escribir resultado en formato ASCII ch = tlong mod 10 ' Extraer unidades de milivoltios Lcd_Chr_CP(48+ch) ' Escribir resultado en formato ASCII Lcd_Chr_CP("V") ' Escribir etiqueta para el voltaje "V" Delay_ms(1) ' Retardo de 1mSwend

end. ' Final de programa

4.13 EJEMPLO 11

Comunicación serial RS232

Este ejemplo muestra cómo utilizar el módulo EUSART del microcontrolador. La conexión entre el microcontrolador y una PC se establece de acuerdo con el 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 utilizar los LEDs conectados al puerto PORTB y después se devuelve automáticamente al transmisor. 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******************************************************program example_11 ' Nombre de programadim i as byte ' Variable es de tipo bytemain: ' Inicio de programaUART1_Init(19200) ' Inicializar el módulo USART' 8 bits, tasa de baudios 19200, no hay bit de paridad...)while 1 ' Bucle infinito if UART1_Data_Ready() then ' Si se ha recibido un dato i = UART1_Read() ' leerlo UART1_Write(i) ' y enviarlo atrás end ifwend

end. ' Final de programa

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 con una amplia gama de aplicaciones, las funciones almacenadas en la librería One_Wire ponen en marcha y gobiernan estos sensores.

Esta librería contiene en total 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.

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 las funciones apropiadas en el programa. Si le interesa saber cómo se declaran, basta con pulsar sobre alguna de ellas y seleccionar la opción Help.

' Cabecera******************************************************program example_12 ' Nombre de programa

dim LCD_RS as sbit at RB4_bit ' Conexiones del módulo LCDLCD_EN as sbit at RB5_bitLCD_D4 as sbit at RB0_bitLCD_D5 as sbit at RB1_bitLCD_D6 as sbit at RB2_bitLCD_D7 as sbit at RB3_bitLCD_RS_Direction as sbit at TRISB4_bitLCD_EN_Direction as sbit at TRISB5_bitLCD_D4_Direction as sbit at TRISB0_bitLCD_D5_Direction as sbit at TRISB1_bitLCD_D6_Direction as sbit at TRISB2_bitLCD_D7_Direction as sbit at TRISB3_bit ' Final de conexiones del módulo LCD

' Ajustar la constante TEMP_RESOLUTION a la resolusión correspondiente del sensor: ' DS18x20 utilizado: 18S20: 9 (ajustes por defecto pueden ser 9,10,11 o 12); 18B20: 12

const TEMP_RESOLUTION as byte = 9 ' Constante TEMP_RESOLUTION es de tipo byte

dim text as char[9] ' Variable text es de tipo chartemp as word ' Variable temp es de tipo wordsub procedure Display_Temperature( dim temp2write as word ) const RES_SHIFT = TEMP_RESOLUTION - 8 dim temp_whole as byte ' Variable temp_whole rd fr tipo byte temp_fraction as word ' Variable temp_fraction es de tipo word text = "000.0000"

if (temp2write and 0x8000) then ' Comprobar si la temperatura es negativa text[0] = "-"

temp2write = not temp2write + 1 end if

temp_whole = word(temp2write >> RES_SHIFT) ' Extraer temp_whole if ( temp_whole div 100 ) then ' Convertir temp_whole en caracteres text[0] = temp_whole div 100 + 48 else text[0] = "0" end if

text[1] = (temp_whole div 10) mod 10 + 48 ' Extraer dígito de decenas text[2] = temp_whole mod 10 + 48 ' Extraer dígito de unidades temp_fraction = word(temp2write << (4-RES_SHIFT)) ' Extraer temp_fraction temp_fraction = temp_fraction and 0x000F ' y convertirlo en temp_fraction = temp_fraction * 625 ' unsigned int text[4] = word(temp_fraction div 1000) + 48 ' Extraer dígito de miles text[5] = word((temp_fraction div 100) mod 10 + 48) ' Extraer dígito de centenas text[6] = word((temp_fraction div 10) mod 10 + 48) ' Extraer dígito de decenas text[7] = word(temp_fraction mod 10) + 48 ' Extraer dígito de unidades Lcd_Out(2, 5, text) ' Visualizar temperatura en el Lcd

end sub

main: ' Inicio de programaANSEL = 0 ' Configurar pines analógicos como digitales de E/S ANSELH = 0text = "000.0000"Lcd_Init() ' Inicializar el LcdLcd_Cmd(_LCD_CLEAR) ' Borrar el LcdLcd_Cmd(_LCD_CURSOR_OFF) ' Apagar el cursor

Lcd_Out(1, 1, " Temperature: ")

Lcd_Chr(2,13,178) ' Visualizar el carácter de grado, 'C' para centígrados' Distintos visualizadores LCD tienen diferentes códigos de caracteres para el grado Lcd_Chr(2,14,"C") ' si ve la letra griega Alfa, introduzca 178 en vez de 223

while 1 ' Leer la temperatura en el bucle principal 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

Display_Temperature(temp) ' Formatear y visualizar el resultado en el LCD

Delay_ms(520) ' Retardo de 520 ms wendend. ' Final de programa

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 EJEMPLO 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 para hacer algo, 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 cómo generar un sonido por medio de funciones que pertenecen a la librería Sound.

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******************************************************program example_13 ' Nombre de programa

sub procedure Tone1() Sound_Play(659, 250) ' Frecuencia = 659Hz, duración = 250ms

end sub

sub procedure Tone2() Sound_Play(698, 250) ' Frecuencia = 698Hz, duración = 250msend sub

sub procedure Tone3() Sound_Play(784, 250) ' Frecuencia = 784Hz, duración = 250msend sub

sub procedure Melody() ' Tocar 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()end sub

sub procedure ToneA() ' Tonos utilizados en la función Melody2 Sound_Play( 880, 50)end sub

sub procedure ToneC() Sound_Play(1046, 50)

end sub

sub procedure ToneE() Sound_Play(1318, 50)end sub

sub procedure Melody2() ' Tocar Melody2 dim counter as byte for counter = 9 to 1 step -1 ToneA() ToneC() ToneE() next counterend sub

main: ' Inicio de programa

ANSEL = 0 ' Configurar pines analógicos como digitales de E/SANSELH = 0

C1ON_bit = 0 ' Deshabilitar los comparadoresC2ON_bit = 0

TRISB = 0xF0 ' Configurar los pines RB7..RB4 como entradas y RB3 como salida

Sound_Init(PORTD, 3)Sound_Play(880, 5000)

while TRUE ' Bucle infinito if (Button(PORTB,7,1,1)) then ' Si se presiona PORTB.7 tocar Tone1 Tone1()

while (RB7_bit <> 0) nop ' Esperar que se suelte el botón wend end if

if (Button(PORTB,6,1,1)) then ' Si se presiona PORTB.6 tocar Tone1 Tone2() while (RB6_bit <> 0) nop ' Esperar que se suelte el botón wend end if

if (Button(PORTB,5,1,1)) then ' Si se presiona PORTB.5 tocar Tone1 Melody2() while (RB5_bit <> 0) nop ' Esperar que se suelte el botón wend end if

if (Button(PORTB,4,1,1)) then ' Si se presiona PORTB.4 tocar Tone1

Melody() while (RB4_bit <> 0) nop ' Esperar que se suelte el botón wend end ifwend

end. ' Final de programa

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.

Aquí, el GLCD visualiza un camión cuyo mapa de bits se almacena en el archivo truck_bmp.mbas.

'Cabecera******************************************************

program example_14 ' Nombre de programa

dim GLCD_DataPORT as byte at PORTD

dim GLCD_CS1 as sbit at RB0_bit ' Conexiones del módulo GlcdGLCD_CS2 as sbit at RB1_bitGLCD_RS as sbit at RB2_bitGLCD_RW as sbit at RB3_bitGLCD_EN as sbit at RB4_bitGLCD_RST as sbit at RB5_bit

dim GLCD_CS1_Direction as sbit at TRISB0_bitGLCD_CS2_Direction as sbit at TRISB1_bitGLCD_RS_Direction as sbit at TRISB2_bitGLCD_RW_Direction as sbit at TRISB3_bitGLCD_EN_Direction as sbit at TRISB4_bitGLCD_RST_Direction as sbit at TRISB5_bit ' Final de conexiones del módulo Glcd

dim counter as bytesomeText as char[18]

sub procedure Delay2S() ' Subfunción de retardo de 2 segundos

Delay_ms(2000)end sub

main: ' Inicio de programaANSEL = 0 ' Configurar pines analógicos como digitales de E/S

ANSELH = 0Glcd_Init() ' Inicializar el GlcdGlcd_Fill(0x00) ' Borrar el Glcdwhile TRUE ' Bucle infinito Glcd_Image(@truck_bmp) ' Dibujar imagen Delay2S() delay2S()

Glcd_Fill(0x00) ' Borrar el Glcd

Glcd_Box(62,40,124,63,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

Delay2S() counter = 5

while (counter <= 59) ' Dibujar líneas horizontales y verticales Delay_ms(250) Glcd_V_Line(2, 54, counter, 1) Glcd_H_Line(2, 120, counter, 1) Counter = counter + 5 wend

Delay2S()

Glcd_Fill(0x00) ' Borrar el GLCD

Glcd_Set_Font(@Character8x7, 8, 7, 32) ' Seleccionar la fuente "Character8x7" Glcd_Write_Text("mikroE", 1, 7, 2) ' Escribir la cadena

for counter = 1 to 10 ' Dibujar los círculos Glcd_Circle(63,32, 3*counter, 1) next counter Delay2S()

Glcd_Box(10,20, 70,63, 2) ' Dibujar la caja

Delay2S()

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()wendend. ' Final de programa

truck_bmp.mbas file:

module bitmap ' Módulo con el código de mapa de bits

const truck_bmp as byte[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,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,25

5,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,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)

implements

end. ' Final del módulo

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 Bitmap.mbas 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.

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 1K. 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.

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******************************************************

program example_15 ' Nombre de programa

dim GLCD_DataPORT as byte at PORTD ' Conexiones del módulo Glcd

dim GLCD_CS1 as sbit at RB0_bitGLCD_CS2 as sbit at RB1_bitGLCD_RS as sbit at RB2_bitGLCD_RW as sbit at RB3_bitGLCD_EN as sbit at RB4_bitGLCD_RST as sbit at RB5_bit

dim GLCD_CS1_Direction as sbit at TRISB0_bitGLCD_CS2_Direction as sbit at TRISB1_bitGLCD_RS_Direction as sbit at TRISB2_bitGLCD_RW_Direction as sbit at TRISB3_bitGLCD_EN_Direction as sbit at TRISB4_bitGLCD_RST_Direction as sbit at TRISB5_bit ' Conexiones del módulo Glcd

dim x_coord, y_coord,x_coord128, y_coord64 as longint ' Almacenar la posición de las coordenadas x e y

sub function GetX() as word ' Leer la coordenada X

PORTC.0 = 1 ' DRIVEA = 1 (electrodo izquierdo (LEFT) conectado, electrodo ' derecho (RIGHT) conectado, electrodo superior (TOP) desconectado) PORTC.1 = 0 ' DRIVEB = 0 (electrodo inferior (BOTTOM) desconectado) Delay_ms(5) result = ADC_Read(0) ' LEER-X (BOTTOM)

end sub

sub function GetY() as word ' Leer la coordenada Y

PORTC.0 = 0 ' DRIVEA = 0 (electrodo izquierdo (LEFT) desconectado, electrodo ' derecho (RIGHT) desconectado, electrodo superior (TOP) conectado) PORTC.1 = 1 ' DRIVEB = 1 (electrodo inferior (BOTTOM) conectado)

Delay_ms(5) result = ADC_Read(1) ' LEER-X (LEFT)

end sub

main: ' Inicio de programa

PORTA = 0x00TRISA = 0x03 ' RA0 y RA1 son entradas analógicasANSEL = 0x03ANSELH = 0 ' Configurar otros pines analógicos como digitales de E/S

PORTC = 0TRISC = 0 ' Pines del puerto PORTC se configuran como salida

Glcd_Init() ' Glcd_Init_EP5Glcd_Set_Font(@font5x7, 5, 7, 32) ' Seleccionar el tamaño de fuente 5x7Glcd_Fill(0) ' Borrar el GLCD

Glcd_Write_Text("TOUCHPANEL EXAMPLE",10,0,1)Glcd_Write_Text("MIKROELEKTRONIKA",17,7,1)

Glcd_Rectangle(8,16,60,48,1) ' Visualizar 'dos botones' en el GLCD:Glcd_Rectangle(68,16,120,48,1)Glcd_Box(10,18,58,46,1)Glcd_Box(70,18,118,46,1)Glcd_Write_Text("BUTTON1",14,3,0)Glcd_Write_Text("RC6 OFF",14,4,0)Glcd_Write_Text("BUTTON2",74,3,0)Glcd_Write_Text("RC7 OFF",74,4,0)

while TRUE ' Leer X-Y y convertirlo en la resolución de 128x64 píxeles

x_coord = GetX()y_coord = GetY()x_coord128 = (x_coord * 128) / 1024y_coord64 = 64 -((y_coord *64) / 1024)

' Si BUTTON1 ha sido seleccionado:if ((x_coord128 >= 10) and (x_coord128 <= 58) and (y_coord64 >= 18) and (y_coord64 <= 46)) then if(PORTC.6 = 0) then PORTC.6 = 1 Glcd_Write_Text("RC6 ON ",14,4,0) else PORTC.6 = 0 Glcd_Write_Text("RC6 OFF",14,4,0) end ifend if

' Si BUTTON2 ha sido seleccionado:if ((x_coord128 >= 70) and (x_coord128 <= 118) and (y_coord64 >= 18) and (y_coord64 <= 46)) then if(PORTC.7 = 0) then PORTC.7 = 1 Glcd_Write_Text("RC7 ON ",74,4,0) else PORTC.7 = 0 Glcd_Write_Text("RC7 OFF",74,4,0) end ifend if

Delay_ms(100)wend ' Mientras verdadero

end. ' Final de programa

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

4.18 EJEMPLO 16

Utilizar el teclado 4x4

Un teclado representa un conjunto de botones de presión conectados de tal manera que formen 'filas' y 'columnas', así reduciendo el número de los pines de E/S necasarios para su conexión. En este ejemplo utilizaremos un teclado con 16 botones de presión organizados en cuatro filas y columnas. La librería Keypad 4x4 contiene todas las funciones necesarias para leer este teclado así como para inicializar el puerto al que está conectado. Para demostrar el funcionamiento del teclado 4x4, el mensaje será visualizado en un LCD.

'Cabecera******************************************************

program example_16 ' Nombre de programadim kp, curX, curY as bytedim keypadPORT as byte at PORTD ' Esta variable debe estar definida en todos los proyectos por ' medio de la librería Keypad. Así se define el puerto utilizado para conectar el teclado

dim LCD_RS as sbit at RB4_bit ' Conexiones del módulo LcdLCD_EN as sbit at RB5_bitLCD_D4 as sbit at RB0_bitLCD_D5 as sbit at RB1_bitLCD_D6 as sbit at RB2_bitLCD_D7 as sbit at RB3_bitLCD_RS_Direction as sbit at TRISB4_bitLCD_EN_Direction as sbit at TRISB5_bitLCD_D4_Direction as sbit at TRISB0_bitLCD_D5_Direction as sbit at TRISB1_bitLCD_D6_Direction as sbit at TRISB2_bitLCD_D7_Direction as sbit at TRISB3_bit ' Final de conexiones del módulo LCD

main: ' Inicio de programacurX=1 ' Memorizar de la posición del cursor en el visualizador LCD 2x16curY=1ANSEL = 0 ' Configurar pines analógicos como digitales ed E/SANSELH = 0TRISB = 0PORTB = 0xFFKeypad_Init() ' Inicializar el teclado en el puerto PORTCLcd_Init() ' Inicializar el LCD en el puerto PORTB, Lcd_Cmd(_LCD_CLEAR) ' Borrar el visualizador

while true ' Esperar que alguna tecla se presione y suelte

kp = 0 while kp = 0 kp = Keypad_Key_Click() Delay_ms(10) wend

select case kp ' Preparar el valor comoo salida case 1 kp = "1" case 2 kp = "2" case 3 kp = "3" case 4 kp = "A" case 5 kp = "4" case 6 kp = "5" case 7 kp = "6" case 8 kp = "B" case 9 kp = "7" case 10 kp = "8" case 11 kp = "9" case 12 kp = "C" case 13 kp = "*" case 14 kp = "0" case 15 kp = "#" case 16 kp = "D" end select

if (curY > 16) then ' Cambiar de posición del cursor if (curX = 1) then Lcd_Cmd(_LCD_SECOND_ROW) curX = 2

curY = 1 else Lcd_Cmd(_LCD_FIRST_ROW) curX = 1 curY = 1 end if end if Lcd_Chr_CP(kp) ' Visualizar en el LCD Inc(curY)wendend. ' Final de programa Para que este ejemplo funcione apropiadamente, es necesario marcar las siguientes librerías en la ventana Library Manager antes de compilar el programa. Keypad4x4 - LCD

Apéndice A: Es hora de divertirseUn microcontrolador se parece a un “genio en la botella”, y no se necesita saber mucho para utilizarlo. Para crear un dispositivo controlado por un microcontrolador, se necesita una PC, un programa para compilar y un dispositivo para transmitir el código de la PC al microcontrolador mismo. Aunque este proceso parece muy lógico, con frecuencia surgen las dudas, no por que es complicado, sino por un gran número de variaciones. A ver...

A.1 VAMOS A EMPEZAR... A.2 COMPILACIÓN DE PROGRAMA A.3 ¿SERÁ UN FINAL FELIZ? A.4 SISTEMAS DE DESARROLLO

A.1 VAMOS A EMPEZAR...

Los programas especializados para Windows (compiladores) se utilizan para escribir un programa para el microcontrolador. Este libro describe el programa denominado mikroBasic PRO for PIC. La ventaja principal de este programa son las herramientas adicionales instaladas para facilitar el proceso de desarrollo.

Si tiene experiencia en escribir programas, entonces sabe que se trata de escribir todas las instrucciones en el orden en el que se deben ejecutar por el microcontrolador y observar las reglas de programa. En otras palabras, sólo tiene que seguir su idea al escribir el programa. ¡Esto es todo!

A.2 COMPILACIÓN DE PROGRAMA

El microcontrolador no entiende los lenguajes de alto nivel de programación, de ahí que sea necesario compilar el programa en lenguaje máquina. Basta con pulsar sólo una vez sobre el icono apropiado dentro del compilador para crear un documento nuevo con extensión .hex. En realidad, es el mismo programa, pero compilado en lenguaje máquina que el microcontrolador entiende perfectamente. Este programa se le denomina con frecuencia un código HEX y forma una secuencia de números hexadecimales aparentemente sin significado. Una vez compilado, el programa se debe cargar en el microcontrolador. Usted necesita un hardware apropiado para hacerlo posible - un programador.

PROGRAMAR LOS MICROCONTROLADORES

Como hemos mencionado, para habilitar cargar un código hex en el microcontrolador es necesario proporcionar un dispositivo especial, denominado el programador, con software apropiado. Un gran número de programas y circuitos electrónicos utilizados con este propósito se pueden encontrar en internet. El procedimiento es básicamente el mismo para todos ellos y se parece a lo siguiente:

1. Coloque el microcontrolador en el zócalo apropiado del programador;2. Utilice un cable adecuado para conectar el programador a una PC;3. Abra el código hex dentro de software del programador, ajuste varios parámetros, y pulse sobre el icono para transmitir el

código. Pocos segundos después, una secuencia de ceros y unos se va a programar en el microcontrolador.

Sólo ha quedado instalar el microcontrolador programado en el dispositivo destino. Si es necesario hacer algunos cambios en el programa, el procedimiento anterior se puede repetir un número ilimitado de veces.

A.3 ¿SERÁ UN FINAL FELIZ?

Esta sección describe en breve el uso del compilador mikroBasic PRO for PIC y del software de programación (programador) PIC flash. Todo es muy simple...

Usted ya tiene instalado el mikroBasic PRO for PIC, ¿verdad? Al iniciarlo, abra un proyecto nuevo y un documento nuevo con extensión .mbas dentro del mismo. Escriba su programa...

De acuerdo. El programa ha sido escrito y probado con el simulador. ¿No ha informado de ningún error durante el proceso de compilación en el código hex? Parece que todo funciona perfecto...

El programa ha sido compilado con éxito. Sólo queda cargarlo en el microcontrolador. Ahora necesita el programador PICflash que está compuesto por software y hardware. Inicie el programa PICFlash.

La configuración es simple y no hacen falta explicaciones adicionales (tipo de microcontrolador, frecuencia de oscilador de reloj etc.). Lo que queda hacer es lo siguiente:

Conecte la PC con el hardware del programador por un cable USB; Coloque el microcontrolador en el zócalo apropiado del programador; Cargue el código HEX utilizando el comando: File a Load HEX; y Pulse sobre el botón Write dentro de la ventana principal del programa PICflash y espere...

¡Esto es todo! El microcontrolador está programado y todo está listo para su funcionamiento. Si no está satisfecho, haga algunos cambios en el programa y repita el procedimiento. ¿Hasta cuándo? Hasta quedar satisfecho...

A.4 SISTEMAS DE DESARROLLO

Un dispositivo que puede simular cualquier dispositivo en la fase de prueba, es denominado un sistema de desarrollo. Aparte del hardware del programador, unidad de alimentación, zócalo del microcontrolador, el sistema de desarrollo dispone de los componentes para activar los pines de entrada y monitorear los pines de salida. La versión más simple tiene cada pin conectado a su respectivo botón de presión y un LED. Una versión de calidad alta tiene los pines conectados a los visualizadores LED, visualizadores LCD, sensores de temperatura u otros componentes por los que puede estar compuesto un dispositivo destino a ser programado.

Si es necesario, todos estos módulos periféricos pueden estar conectados al microcontrolador por medio de los puentes. Esto permite probar el programa entero en la práctica aún durante el proceso de desarrollo, porque el microcontrolador no “sabe o no le interesa” si su entrada está activada por un botón de presión o un sensor incorporado en un dispositivo real. Teniendo en cuenta que el compilador (en su PC) y el hardware del programador (en su sistema de desarrollo) colaboran perfectamente, el proceso de compilar un programa y programar el microcontrolador se lleva a cabo en un simple paso - al pulsar sobre el icono apropiado dentro del compilador. Desde este momento, cualquier cambio en el programa afectará inmediatamente al funcionamiento de los componentes apropiados en la placa.

¿Es hora de divertirse?