huborarduino.com

La web de Hubor para la simulación de Arduino con Proteus

Banner Guia Programacion Arduino Con Proteus

[Proteus versión 8.1]

Dado el éxito cosechado con nuestro trabajo de las dos primeras lecciones, en esta tercera nos hemos crecido y vamos a introducir cuatro nuevos conceptos. Vamos a ver cómo podemos tener una entrada digital, a conocer la utilización de las variables, a utilizar una primera instrucción de control (el bloque if..else) y a generar notas musicales con nuestro Arduino.

En lecciones anteriores hemos visto cómo podíamos actuar sobre otros dispositivos utilizando las salidas digitales. Activando una salida podíamos encender un led y desactivándola podíamos apagarlo. Aunque sea de forma muy rudimentaria todavía, lo cierto es que ya sabemos cómo nuestro equipo Arduino puede utilizarse para gobernar dispositivos.

El siguiente paso importante consiste en lograr que nuestro Arduino sepa cómo es el mundo de su alrededor. Para ello uno de los caminos disponibles es la utilización de las entradas digitales. Con una entrada digital somos capaces de saber si un determinado dispositivo está activado o desactivado. Es muy importante que nos fijemos en el matiz. Con una entrada digital sólo podemos saber si un dispositivo está en uno de los dos estados posibles: activado o desactivado. No hay término medio. El caso más simple es la utilización de un interruptor. Un interruptor puede estar abierto o cerrado. Con una entrada digital nuestro Arduino es capaz de saber si el interruptor está abierto o cerrado.

Proteus nos posibilita simular un interuptor utilizando el dispositivo "SWITCH". 

Lec03 001

Como podemos observar, junto al interruptor hay dos pequeños botones con una flecha apuntando para arriba y otra para abajo. Si pulsamos sobre la primera simulamos el cierre del interruptor y si pulsamos sobre la segunda simulamos su apertura.

Lec03 002

El estado inicial del interruptor (abierto o cerrado) se puede establecer editando sus propiedades utilizando en el menú contextual la opción "Editar las propiedades". Para abrir el menú contextual en Proteus debemos pulsar con el botón derecho del ratón sobre el dispositivo en cuestión. En la ventana de diálogo que se abre, debemos seleccionar la casilla "Editar todas las propiedades como texto" y entonces podremos ver la variable STATE. Si le asignamos el valor 1 el dispositivo se inicia cerrado y si le asignamos el valor 0 lo hará abierto.

Lec03 003

Para conocer el estado de nuestro interruptor con una de las entradas digitales de nuestro Arduino tenemos que dar los siguientes pasos. Primero definir que vamos a utilizar ese pin como una entrada. Segundo conectarlo eléctricamente a nuestro pin. Y, tercero y último, leer el estado del pin desde nuestro programa. Vamos a dar los tres pasos.

Ya vimos que para definir si un pin va a funcionar como entrada o salida, utilizábamos la instrucción pinMode() dentro de la función setup(). En nuestro caso deseamos conectar nuestro interruptor al pin 5, así que nuestro código deberá ser:

Lec03 004

Para conectar eléctricamente nuestro interruptor con el pin 5 de nuestro Arduino podríamos tener la tentación de utilizar un esquema como el siguiente.

Lec03 005

Sin embargo esta forma de conectar una entrada es una mala práctica que debemos erradicar desde el principio de nuestros diseños. Aunque a primera vista puede parecer que todo es correcto, existe un problema serio en utilizar las entradas de esta forma. Cuando el interruptor está cerrado el pin 5 está en un estado conocido, +5V, y la entrada estará activa. Pero, ¿qué pasa cuando el interruptor está abierto? La respuesta rápida podría ser que la entrada está a 0V y, por lo tanto, desactivada. Pero esta respuesta no es correcta. En realidad cuando el interruptor está abierto la entrada se encuentra en un estado indeterminado puesto que no está conectada a ningún potencial conocido. Para entendernos, que un cable no esté conectado al positivo de la fuente no significa que esté conectado al negativo. Los denominados "ruidos" o interferencias en el circuito pueden generar potenciales indeterminados en nuestro pin de entrada. Para evitar esta indefinición el circuito que debemos utilizar es el siguiente que fija claramente el estado del pin a +5V o a 0V.

Lec03 006

Para conocer desde nuestro programa si el pin está activo o desactivado, utilizamos la función digitalRead(). La sintaxis de esta función es la siguiente:

digitalRead( <número de pin> )

La función devolverá un valor 1 cuando el pin esté activo y un valor 0 cuando el pin esté desactivado.

Ahora ya estamos en condiciones de utilizar en el código del programa nuestra primera entrada digital para conocer el estado del interruptor y decidir si debemos encender el led o apagarlo. Aunque sería más preciso decir casi estamos en condiciones. Porque la frase incluye la palabra "decidir" que hasta ahora no habíamos utilizado. Tomar decisiones es una de las tareas más importantes de los ordenadores y precisamente su potencia viene de esta capacidad de decisión. Para tomar decisiones, utilizamos las instrucciones de control.

La instrucción de control más básica son los bloques de código if...else. El objeto de un bloque de código if...else es evaluar una determinada condición y en función de que sea verdadera o falsa ejecutar sentencias diferentes. La sintaxis de un bloque if...else es la siguiente.

if( <condición> )

{

   instrucciones que se ejecutan si la condición se cumple (vale 1)

}

else

{

   instrucciones que se ejecutan si la condición no se cumple (vale 0)

}

Un ejemplo nos ayudará a entenderlo mejor. Nuestro objetivo es encender el led situado en el pin 0 cuando el interruptor situado en el pin 5 esté activo y apagarlo cuando esté desactivado. El código de nuestro programa sería el siguiente.

Lec03 007

Y el funcionamiento lo podemos probar con el siguiente circuito. Con el pulsador S1 gobernamos el estado del led D2.

Lec03 008

Hasta ahora nos hemos limitado a que nuestro Arduino sea capaz de encender o apagar leds. Es decir que somos capaces de hacer señales luminosas con nuestro Arduino. Pero también podemos generar señales acústicas si en lugar de conectar un led a un pin de nuestro Arduino, le conectamos un altavoz piezoléctrico. El altavoz piezoeléctrico es un tipo de altavoz basado en la propiedades de los cristales piezoeléctricos (poliéster o cerámica), que se deforman cuando se les aplica una tensión entre sus caras y que actuando como transductor electroacústico es utilizado para la reproducción de sonido. También se le suele conocer con el nombre de "chicharra".

Lec03 009

En Proteus podemos simular un altavoz piezoeléctrico con el dispositivo SPEAKER.

Lec03 010

Por defecto, el dispositivo SPEAKER viene configurado para funcionar a 1V. Para adaptarlo a nuestra tensión de 5V debemos editar sus propiedades y cambiar este valor en la variable "Nominal Input".

Lec03 011

El esquema que utilizaremos en nuestro diseño es el siguiente:

Lec03 012

Y el código de nuestro programa:

Lec03 013

Podemos realizar la simulaicón. Si actuamos sobre el interruptor S1 se encenderá el led D2 y se escuchará un sonido en el altavoz. Si actuamos sobre el interrumptor S2 cuando el S1 está activado, provocaremos que la nota que se escucha en el altavos sea una octava diferente. Si desactivamos el interruptor S1 el led se apaga y el altavoz deja de sonar.

Una vez que hemos entendido el funcionamiento de nuestro programa, podemos analizarlo en detalle. La primera parte la dedicamos a declarar variables. Una variable está formada por un espacio en el sistema de almacenaje (memoria principal de un ordenador) y un nombre simbólico (un identificador) que está asociado a dicho espacio. Ese espacio contiene una cantidad o información conocida o desconocida, es decir un valor. El nombre de la variable es la forma usual de referirse al valor almacenado: esta separación entre nombre y contenido permite que el nombre sea usado independientemente de la información exacta que representa. En nuestro caso, hemos definido ocho variables que las usamos para identificar los pines 0 a 7 de nuestro Arduino. Las variables las hemos utilizado para inicializar los pines indicando si los utilizaremos como entrada o salida, y dentro de las funciones de escritura y lectura de su estado. Como las variables contienen valores numéricos al definirlas hemos puesto delante la palabra clave INT. Con ello indicamos que esa variable almacenará un valor numérico de tipo entero.

En este ejemplo todavía no hemos sacado mucho partido a la utilización de las variables, porque en realidad las estamos utilizando como si fueran constantes (les asignamos un valor al principio que no cambia a lo largo de toda la vida del programa). Pero en lecciones posteriores iremos utilizando y aprovechando muchos más el uso de las variables.

El núcleo del programa se basa en el uso de un primer bloque if...else. Con él evaluamos el estado del pin5 y ejecutamos un código u otro en función del resultado. En caso de que el pin5 esté activo, encendemos el led conectado al pin0 y volvemos a evaluar un segundo bloque if...else. De esta manera acabamos de descubrir una importante características de los bloques de control: que pueden anidarse. Anidar varios bloques de control significa que podemos utilizar unos dentro de otros que se irán ejecutando o no en función de las condiciones.

Para generar las dos notas diferentes que suenan en el altavoz hemos hecho lo siguiente. Cuando el interruptor conectado al pin6 está activo, activamos y desactivamos el altavoz con un espacio de 2272 microsegundos entre cada operación. La función delayMicrosegundos() tiene una sintaxis muy similar a la función delay() ya estudiada en lecciones anteriores, sólo que, en este caso, el intervalo de tiempo que mantenemos dormido al procesador viene expresado en microsegundos en lugar de segundos.

Para generar la nota una octava más alta cuando el interruptor S2 no está pulsado, lo que hacemos es activar y desactivar el altavoz con un espacio de separación de 1136 microsegundos.¿Por qué se produce este cambio con estos valores? Vamos a estudiarlo con detalle para entenderlo.

Un sonido tiene un determinado tono que depende de la frecuencia a la cual vibra el aire. Las notas musicales son vibraciones de frecuencias determinadas. Una vibración a una frecuencia concreta, produce un sonido puro que nosotros percibimos como un pitido de un determinado tono. En el sistema musical occidental, se ha acordado utilizar sólo unas frecuencias concretas, a las cuales llamamos notas.Dividimos las posibles frecuencias en porciones que llamamos "octavas", y cada octava en 12 porciones que llamamos notas. Cada nota de una octava tiene exactamente la mitad de frecuencia que la misma nota en la octava superior. El oido humano capta sólamente frecuencias que estén por encima de los 20Hz y por debajo de los 20.000 (muy aproximadamente). Así pues, y con mucha suerte, sólo podemos oir unas 10 octavas como mucho, con doce notas cada una. La nota "La" sirve como referencia para todas las demás. A menudo se denomina "nota de afinar". Se produce un "La" de afinar cuando el aire vibra 440 veces por segundo, es decir a 440 hertzios. Por convención, a la octava que contiene esta nota "La" se le suele considerar la cuarta.Hay otra nota "La", de una "octava" superior (la quinta octava) cuando el aire vibra a 880 hertzios. Del mismo modo, hay un "La" que se produce cuando el aire vibra a 220Hz (tercera octava).

Por lo tanto, para conseguir una determinada nota, sólo tenermos que hacer vibrar nuestro altavoz a una determinada frecuencia. La tabla que identifica cada nota con su frecuencia y toda la teoría relativa a este tema la podemos encontrar muy bien explicada en el siguiente enlace: http://latecladeescape.com/t/Frecuencia+de+las+notas+musicales.

Una vez que sabemos que queremos emitir un La4 y un La5 tenemos que hacer vibrar nuestro altavoz a unas frecuencia de 440Hz y 220Hz respectivamente, ya podemos hacer los cálculos necesarios para escribir nuestro código. Para obtener una frecuencia de 440Hz necesitamos activar y desactivar nuestro altavoz con una separación de tiempo entre ambas órdenes (es decir, con un periodo) de 2.272 µsegundos:

frecuencia = 1 / periodo.

440 = 1 / x   ---> x = 1 /440 = 0,002272 segundos = 2.272µsegundos.

Como la mitad de ese tiempo tiene que estar el altavoz encendido y la otra mitad apagado, la separación entre ambas órdenes debe ser:

2.272 / 2 = 1.136

Ese es el valor que hemos escrito cuando nuestro pulsador está desactivado. Para obtener un La5 (una octava superior) utilizamos el valor 2.272 porque:

220 = 1 / x  ---> x = 1 / 220 = 0,004545µsegundos. La mitad de ese valor 4.545 / 2 = 2.272.

Acabamos de enseñarle los rudimentos de la música a nuestro Arduino, pero todavía nos queda un largo trecho hasta que consigamos que Arduino funcione como un instrumento musical y podamos interpretar una melodía con él. Pero es que hay que dejar algo para las próximas lecciones.

 

[Proteus versión 8.1]

En la primera lección de este curso vimos como activar una salida digital con nuestro equipo Arduino. Como es lógico, en la primera lección sacrificamos algunas cosas importantes para no confundir demasiado al lector en su primer acercamiento a la programación en Arduino. Es evidente que utilizar un microprocesador para mantener un led encendido todo el tiempo no es una acción de la que podamos sentirnos muy orgullosos. Pero Roma no se hizo en un día y aprender de forma paulatina es muy importante para no agobiarnos demasiado.

Vamos a continuar con nuestro curso modificando el estado de nuestra salida al tiempo que conocemos nuevas funciones disponibles en Arduino y progresamos en el aprendizaje del uso de Proteus. En este caso vamos a empezar utilizando únicamente el módulo principal de nuestro equipo Arduino. Nuestro esquema sería el siguiente:

Lec02 001

 

Observemos  que en la zona inferior existe un led conectado, en serie con una resistencia, al conector rotulado IO13. Este conector está también conectado al pin 19 (PB6) de nuestro microprocesador. Como vimos en la primera lección para encender dicho led, tendríamos que escribir el siguiente programa, donde inicializamos el pin 13 y lo activamos.

 Lec02 002

Si ejecutamos la simulación tendríamos como resultado el led encendido.

Lec02 003

Hagamos ahora que nuestro led parpadee con una frecuencia de un encendido y apagado cada segundo. Para hacerlo tendremos que utilizar una función nueva llamada delay() que detiene la ejecución del funcionamiento del microprocesador durante un determinado tiempo. Su formato es el siguiente:

delay( <numero de milisegundos>)

Donde el numero de milisegundos indica el tiempo que estará detenido el microprocesador esperando.

Modifiquemos nuestro programa utilizando esta función para activar y desactivar la salida donde se conecta el led de forma cíclica.

Lec02 004

En la línea 15 indicamos que la salida se active. En la línea 16 detenemos la ejecución del programa durante un segundo. En la línea 17 desactivamos la salida. Y en la línea 18 volvemos a detener el programa durante otro segundo. Como la función loop() se ejecuta de forma cíclica, volveremos a ejecutar de nuevo las cuatro sentencias produciéndose el parpadeo deseado. Si ejecutamos la simulación, podremos compobar que todo funciona como deseamos.

Lec02 005

    Lec02 006

 

 

 

 

Observe además una característica importante que nos ofrece Proteus para ayudarnos en la simulación. al lado de los componentes aparecen unos cuadros rojos y azules. Con ellos, Proteus nos indica el esado actual del circuito en ese punto. Si está rojo indica que hay tensión en ese punto y si está azúl indica que está al nivel del potencial de tierra. Por eso el cuadro situado a la izquierda del led siempre está azúl (ese punto está conectado a masa) y en cambio los cuadros situados a ambos lados de la resistencia y a la derecha de led adquieren el color en función de su estado en ese momento. Esta ayuda que nos brinda Proteus puede ser muy útil.

Modifiquemos ahora nuestro esquema para colocar cinco nuevos leds en los pines IO0 a IO4. Lo primero que tenemos que hacer es colocar un conector con el nombre IO0. Para ello utilizaremos en la barra de herramientas lateral, el botón 'Modo terminales'.

Lec02 007

En la ventana de terminales, seleccionaremos uno del tipo default y lo situaremos debajo de nuestra placa.

Lec02 008

Situaremos el cursor sobre él y pulsaremos el botón derecho del ratón para que aparezca el menú contextual, donde seleccionaremos la opción "editar las propiedades".

Lec02 009

En la ventana de diálogo que aparece, asignamos como nombre del terminal el valor IO0

Lec02 010

De esta forma tan sencilla ya tenemos un terminal enlazado eléctricamente con el pin PD0 (pin físico 2) del microprocesador.

Lec02 011

Ahora conectaremos a él un led y una resistencia en serie.Siempre conviene conectar los leds a nuestro microprocesador en serie con una resistencia. De esta forma nos aseguramos que la intensidad de la corriente que pasa a través del led no supera nunca el máximo que puede soportar y nos aseguramos que no se estropeará. Cuanto mayor sea el valor de la resistencia, menor será la intensidad de corriente y, por lo tanto, el led lucirá con menos intensidad. Puesto que, normalmente, un led funciona en el rango aproximado de 5 a 25mA de corriente y la tensión de salida en los pines de nuestro microprocesador son 5V, podemos utilizar una resistencia desde 200Ω a 1kΩ dependiendo de la intensidad con la que deseemos que luzca y el consumo que queremos.

Para colocar la resistencia seleccionaremos el botón "modo componente" de la barra de herramientas de la izquierda.

Lec02 012

Puesto que ya existe una resistencia en nuestro circuito, en la ventana "DEVICES" ya podemos seleccionar el dispositivo RES (resistencia). Pero de todas formas, vamos a seleccionar una resistencia de 220Ω para aprender como se seleccionar dispositivos. Pulsaremos sobre la letra "P" situada en la zona superior de la ventana "DEVICES" y se abrirá la ventana de diálogo para selecionar componentes. En el cuadro de diálogo "Categoría" seleccionaremos la opción "resistors". En el cuadro "Sub-Categoría" seleccionaremos "0.6W Metal Film". Y en el cuadro de resultados seleccionaremos "MINRES220" que se corresponde con una resistencia de 220Ω y 0,6Watios.

 Lec02 013

Pulsamos sobre el botón "Aceptar" y ya encontramos nuestro componente en la ventana "DEVICES". Como acabamos de comprobar, "comprar" componentes en Proteus para utilizarlos en nuestros prototipos es muy sencillo y barato. A continuación, seleccionamos nuestro componente desde la ventana "DEVICES" y colocamos el ratón donde queremos posicionar nuestra resistencia.

Lec02 014

Cuando nos guste el emplazamiento, volvemos a pulsar el botón izquierdo del ratón y la resistencia quedará colocada en ese lugar.

Lec02 015

Para tender un cable entre el terminal y la resistencia seguiremos el siguiente proceso. Colocaremos el cursor del ratón sobre el extremo del terminal, pulsaremos el botón izquierdo, desplazaremos el cursor hasta el extermo de la resistencia y pulsaremos de nuevo el botón izquierdo del ratón.

Lec02 016                                             

    Lec02 017 

 Lec02 018 

Ahora podemos conectar nuestro led en el otro extermo de la resistencia. Ya existe en la ventana "DEVICES" un dispositivo llamado "LED-YELLOW" porque ya está utilizado en nuestra placa del microprocesador. Pero para practicar le invitamos a que seleccione un led del tipo LED-GREEN, LED-RED o LED-BLUE siguiendo los mismos pasos que hicimos para seleccionar nuestra resistencia.

Lec02 019

Seleccionemos el dispositivo desde la ventana "DEVICES" y coloquemos el cursor donde queremos situarlo. Observe que esta vez el led por defecto se ha puesto en posición vertical y nosotros lo queremos horizontal. Utilizando las teclas "+" y "-" del teclado numérico podemos girarlo antes de colocarlo en su emplazamiento definitivo pulsando con el botón izquierdo del ratón.

Lec02 020

  Lec02 021

  Lec02 022

Debemos conectar el led y la resistencia de la misma forma que antes conectamos el terminal con la resistencia.

A continuación tenemos que poner el terminal libre del led a tierra para cerrar el circuito. Para hacerlo, tenemos que seleccionar la herramienta "modo terminal" de la barra lateral, elegir un terminal de tipo "GROUND" en la ventana "TERMINALS", colocar el cursor del ratón donde deseamos colocarlos y pulsar el botón derecho para emplazarlo definitivamente. Además tenemos que conectar el extermo libre del led con el nuevo terminal de tierra que acabamos de poner.

Lec02 023

Podemos repetir el proceso y colocar los otro cuatro leds.

Lec02 024b

A partir de este momento, en el resto de lecciones, daremos por sentado que el lector es capaz de colocar y conectar los componentes que utilicemos. Si tiene dudas de como utilizar Proteus para hacerlo puede consultar el tutorial "esquema electrónico" que se encuentra en la sección "Primeros pasos" de la pestaña "inicio" de proteus.

Modificaremos el programa para activar las nuevas salidas conectadas a los leds que acabamos de colocar.

Lec02 025

Y ejecutaremos la simulacion para comprobar que todos los leds parpadean correctamente.

Lec02 026

Para terminar la clase, podemos probar el siguiente programa que provoca el encendido de todos los leds en secuencia tipo árbol de navidad. Ahora ya empieza a tener sentido utilizar un microprocesador en nuestros diseños, sobre todo si utilizamos una herramienta económica como Arduino. Le invitamos a probar variaciones del programa para que practique con los conocimientos adquiridos.

Lec02 027

 

[Proteus versión 8.1]

En esta lección vamos a recopilar muchos de los conocimientos adquiridos durante el curso hasta este momento para realizar un proyecto que se encarge de la gestión de un depósito de agua alimentado por una bomba. El siguiente esquema muestra un esquema de los equipos y nos servirá para fijar nuestros objetivos.

Lec19 001

Nuestro depósito de agua se rellena con ayuda de una bomba y se vacía a medida que se va utilizando el agua de su interior.

Para conocer con exactitud el nivel del agua contamos con un sensor analógico de nivel del agua. Dicho sensor nos devuelve una salida comprendida entre 0 y 5V correspondiéndose el valor de 0 con el depósito vacío y el valor de 5 con un nivel de agua de 5mts (la altura de nuestro depósito). Por supuesto, las lecturas intermedias son proporcionales a la altura del agua dentro de nuestro depósito.

Además disponemos de cuatro boyas digitales que nos indican cuando el agua alcanza cuatro niveles concretos dentro del depósito y que utilizaremos para el mando de la bomba. Dos marcas en la zona inferior que denominamos nivel extra-bajo y nivel bajo. Y dos marcas en la zona superior que llamamos nivel alto y nivel extra-alto. En control industrial es una buena práctica utilizar siempre para el mando sensores digitales y para la medida sensores analógicos, puesto que los segundos están mucho más expuestos a las interferencias y pueden generar arranques o paradas intempestivas. El hecho de que utilicemos dos sensores para la zona superior y dos para la zona inferior es únicamente para implementar un sistema redundante y aumentar la seguridad de que el depósito no se quede vacío (evitando que no arranque la bomba porque el detector de nivel bajo se estropee) ni desborde por la parte superior (descartando que la bomba no se detenga porque el sensor del nivel alto no funcione correctamente).

Para el gobierno y protección eléctrico de nuestra bomba de carga del depósito, hemos diseñado un circuito formado por un interruptor magnetotérmico de mando manual y un contactor gobernado eléctricamente. El primero se encarga de la vigilancia eléctrica del motor de la bomba protegiéndolo de posibles sobrecargas y cortocircuitos. El segundo nos permite su gobierno mediante la alimentación o corte de la corriente. El contactor se gobierna de forma eléctrica para permitir su control por parte de nuestro ARDUINO. El interruptor sólo se gobierna de forma manual porque es conveniente que si se produce un fallo por cortocircuito o sobrecarga, el operador realice una inspección de la instalación para encontrar el motivo del fallo.

Las órdenes de marcha y parada de la bomba se realizan de dos formas:

Automáticamente, según el estado de los niveles digitales. Cuando se deje de recibir la señal de nivel bajo se procederá a arrancar la bomba para llenar el depósito. Ya hemos explicado que, por si acaso fallará el sensor, se ha dispuesto un segundo denominado nivel extra-bajo con la misma función. Cuando se reciba la señal de nivel alto se detendrá la bomba. Igual que en el caso de los niveles inferiores, se ha dispuesto un segundo nivel extra-alto con la misma función como sistema redundante de seguridad.

De forma manual, cuando se utiliza el pulsador de marcha del panel de mando (y siempre que no estén activos los niveles alto o extra-alto porque de otra forma, el agua desbordaría por la zona superior del depósito) se arrancará la bomba. Si la seta de emergencia de parada se pulsa, la bomba se detendrá en todo momento y la bomba no se arrancará aunque se pierda la señal de los niveles bajos.

Antes de proceder a arrancar la bomba, se genera un aviso (acústico o luminoso) de pre-arranque con objeto de prevenir de la maniobra a cualquier persona que pudiera estar trabajando en el depósito. Realmente en este caso es un poco exagerado generar un aviso de pre-arranque, puesto que la ley sólo obliga a hacerlo en los casos de máquinas móviles, pero nos resultará interesante por motivos pedagógicos.

En el panel de señalización se mostrará con ayuda de pilotos luminosos la siguiente información: fallo por cortocircuito en el interruptor, fallo por sobrecarga en el interruptor, estado del interruptor (cerrado o abierto) y estado del contactor (cerrado, abierto o intermitencia cuando se produjo un fallo de confirmación). Cuando el interruptor y el contactor estén cerrados, la bomba estará en marcha.

Por último, utilizaremos el terminal para enviar cada cinco segundos la información completa del estado de nuestros equipos. De esta forma podemos disponer a distancia de todos los datos para conocer en todo momento cómo se encuentra el sistema.

Para gestionar todo este conjunto con nuestro Arduino, necesitamos utilizar una entrada analógica (el medidor analógico de nivel de agua en el depósito), seis salidas digitales (una para el contactor, otra para el aviso de pre-arranque y cuatro para los indicadores luminosos del panel de señalización) y diez entradas digitales (sobrecarga, cortocircuito, estado interruptor, estado contactor, marcha, parada, nivel extra-alto, nivel alto, nivel bajo y nivel extra-bajo). Si alguien las ha contado, observará que nuestro Arduino no tiene suficientes pines digitales, pero encontraremos la forma de obviar esta dificultad.

En la imagen siguiente mostramos todo el conjunto.

Lec19 002

Los pines IO0 e IO1 los utilizamos para el terminal de datos que vamos a utilizar para enviar la información de monitorización del conjunto al exterior.

Lec19 007

Los pines IO2 a IO7 los utilizamos como entradas digitales. Los tres primeros para recibir la información del interruptor (fallo por sobrecarga, fallo por cortocircuito y estado). El cuarto para la información del estado del contactor. El quinto y sexto para el panel de mando (pulsador de marcha y seta de parada). 

Lec19 003

Los pines IO12 e IO13 como salidas digitales. Les conectaremos a dos relés con los que gobernaremos el contactor del motor de la bomba y la señal de pre-aviso. Para ayudar visualmente durante la simulación, hemos colocado una lámpara conectada al contactor normalmente abierto del relé que nos muestra la orden de cierre del contactor y del dispositivo de pre-aviso.

Lec19 004

Los pines IO8 a IO11 harán las funciones de salidas digitales para los pilotos luminosos del panel de señalización. Así podemos indicar cuándo se produce un fallo por cortocircuito, un fallo por sobrecarga y el estado del interruptor y del contactor. Este último lo utilizamos para mostrar tres estados: cuando el contactor está cerrado el piloto está encendido, cuando está abierto el piloto está apagado y cuando se ha producido un fallo de confirmación el piloto parpadeará.

Lec19 005 

Este es un buen momento para explicar que entendemos por fallo de confirmación del contactor y porque razón lo utilizamos.

Los contactores suelen venir provistos de un contacto auxiliar que sirve para monitorizar su estado. Este contacto es el que utilizamos para indicar si el contactor está cerrado o abierto. Seguimos aquí un procedimiento diferente al que siguen otros ingenieros de procesos que utilizan la salida de mando del Arduino como indicador del estado del contactor. Pero no siempre la activación de nuestra orden de mando significa que el contactor haya cerrado realmente. Un fallo en el contactor o en el cableado puede significar que estemos generando la orden y no se produzca el efecto deseado. Otro fallo puede provocar que el contactor siga cerrado (porque se han pegado sus contactos, por ejemplo) aunque la orden no se esté generando. Por esta razón es una buena práctica que la información de los estados de los dispositivos del proyecto se facilite siempre con datos procedentes de sensores y no suponer que una salida de nuestro Arduino suscita automáticamente el cambio del dispositivo gobernado.

Ahora ya se entiende mejor porque surge la necesdidad de utilizar un fallo de confirmación. Se produce este tipo de fallo cuando generamos la orden de cierre y no se recibe la señal de que el contactor está cerrado durante un segundo.

Por último, los cinco primeros pines analógicos (AD0-AD4) los utilizaremos para conocer el nivel de llenado del depósito. Los cuatro primeros para señalizar el estado de las boyas de nivel y el quinto para el indicador analógico de nivel.

Lec19 006 

En condiciones normales, deberíamos utilizar entradas digitales para las boyas de nivel, puesto que son elementos digitales. Pero como nuestro ARDUINO no dispone de pines digitales suficientes, utilizaremos para este fin los pines analógicos, aunque sólo indicaremos dos estados (cuando tengamos una medida de menos 2,5V entenderemos que la boya indica que no se alcanzó el nivel en ese punto y una medida superior a 2,5V que sí).

Ya podemos analizar el software que se encargará de controlar todo nuestro sistema. Como en ocasiones anteriores vamos a verlo por trozos para facilitar su comprensión. Algunas de las funciones que utilizamos ya se vieron en lecciones anteriores por lo que obviaremos su explicación.

Lec19 008

Lo primero que hacemos es llevar a cabo una serie de definiciones. Los tres operadores lógicos y cuatro valores que nos ayudarán a parametrizar nuestra aplicación de forma sencilla sin tener que navegar por el código. El primero es el tiempo de parpadeo que utilizaremos para gobernar un piloto informativo (encendido o apagado cada medio segundo). El segundo el tiempo que pasará entre cada refresco de la información que mandaremos al terminal (5 segundos). El tercero el tiempo del aviso de pre-arranque (3 segundos). Y el cuarto y último, el factor de conversion de la medida analógica.

Como nuestro Arduino tiene una entrada analógica que puede leer valores entre 0 y 1023 y el sensor de medida del nivel de agua en el depósito nos devuelve 0V cuando el nivel es 0 metros y 5V cuando el nivel es 5 metros, el factor de conversión se obtiene con una sencilla regla de tres.

Si 1023 unidades son 5 metros, cada unidad serán 5 / 1023, es decir que el factor de conversión es 0.004887.

El lector podrá adecuar estos valores a las necesidades reales de su proyecto de forma sencilla y cómoda.

Lec19 009

Luego definimos una estructura a la que le daremos el nombre de MotorDatosControl. Las estructuras en el lenguaje C se utilizan para agrupar variables que se usan para una misma finalidad y que se pueden pasar entre las funciones con un sólo paso. En este caso la estructura se utilizará para el control del motor. Más adelante veremos su uso.

Lec19 010

Luego definimos las variables que vamos a utilizar en el control de nuestro proceso. Llamamos especialmente la atención sobre la variable m1 que utilizamos para controlar el motor de la bomba y que es del tipo de la estructura que definimos con anterioridad.

Lec19 011

A continuación figura la función setup() con la configuración. En este caso definimos qué pines se utilizarán como entradas y cuáles de salida. Además fijamos la velocidad del terminal en 9600 baudios.

Lec19 012

La función loop() con el código del bucle de control repetitivo lo hemos dividido en cuatro partes. La primera se encarga de leer todas las entradas y almacenar en variables su estado. En primer lugar, las seis variables digitales. Luego las cuatro variables analógicas que utilizaremos como lecturas digitales para mostrar el estado de las boyas de nivel y, por último, la lectura del sensor de nivel del depósito. Destacar el uso de las funciones if() para recibir una señal digital a través de una entrada analógica.

Lec19 013

La segunda parte contiene la lógica de gobierno del motor de la bomba.

La línea 83 contiene las condiciones de arranque de la bomba (bien una orden manual o que no existe señales en las boyas Nivel bajo o Nivel extra-bajo).

La línea 84 las condiciones que generarán la parada de la bomba (seta de parada, fallos eléctricos, interruptor abierto o niveles alto y extra-alto).

Las líneas 85 y 86 generan el aviso de prearranque con un pulso de duración 5 segundos (recordar las definiciones) desde el momento que se genera la orden de arranque hasta que el motor se pone en marcha o se produce una orden de parada.

La línea 87 genera el parpadeo cuando se produce un fallo de confirmación para su utilización con el piloto de señalización del panel de estados.

Las líneas 88 a 91 se utilizan para llamar a la función ctrlMotor (más adelante la veremos cuando tratemos de las funciones auxiliares) con ayuda de la estructura m1 del tipo MotorDatosControl. La función ctrlMotor() se encarga de todo y nos facilita nuestro trabajo. El uso de la estructura nos permite pasar toda la información junta y no tener que ir especificando todos los datos cada vez. Además, si tuvieramos que controlar dos motores, aislarían totalmente la información de uno y otro motor, permitiéndonos utilizar el mismo código en la función auxiliar.

Lec19 014

La tercera parte se usa para activar las salidas digitales cuando las condiciones así lo determinan. Las líneas 93 a 95 gobiernan los pilotos que indican los fallos y el estado del interruptor. Las línes 96 y 97 los relés de mando. Y la línea 98 el piloto que indica el estado del contactor que será fijo o parpadeante según el estado del contactor o la variable que utilizamos para indicar un fallo de confirmación.

Lec19 015

La cuarta parte envía la información por el puerto serie al terminal. Lo hace cada 5 segundos (definición de tiempoRefrescoMonitor) y, como vimos en lecciones anteriores, no utiliza la función delay() para no interrumpir el control de los dispositivos gobernados durante la espera.

Las funciones auxiliares que se utilizan en el programa son las siguientes:

Lec19 016

Las funciones iniTemp() y chkTemp() ya las vimos en lecciones anteriores y nos ayudan a implementar múltiples funciones temporales utilizando un único reloj maestro (timer) del microprocesador.

Lec19 017

La función báscula() implementa una báscula de tipo flip-flop con reset dominante que genera una salida desde que se produce la señal set hasta que se se produce la señal reset. En caso de que se reciban las dos señales al mismo tiempo, se impone el reset. Con ella se lograr implementar la utilización de 'memorias' (retención de un dato durante un determinado espacio de tiempo) en nuestro código. En nuestro caso la utilizamos para memorizar la pulsación sobre la marcha hasta que el aviso de prearranque concluye o se produce una condición de parada.

Lec19 018

La función pulso() genera una señal de una duración determinada mientras se produce una condición. Con ella conseguimos generar el aviso de pre-arranque de la duración deseada.

Lec19 019

La función parpadeo() nos ayuda a generar la intermitencia en los indicadores de salida. Genera un parpadeo de frecuencia constante mientras esté activa la señal de lanzamiento. Así, podemos generar una intermitencia en el piloto que muestra el estado del contactor cuando se ha producido un fallo de confirmación.

Lec19 020

Lec19 021

La función ctrlMotor() realiza todas las tareas de gobierno de un motor. Transforma la orden de arranque en un pulso, limpia el fallo de confirmación con cada nueva orden de arranque o parada, genera el fallo de confirmación cuando no llega la confirmación del contactor en el tiempo prefijado y genera la salida de control del motor.

Ya está todo listo para simular nuestro proyecto y comprobar que todo funciona. No es una simulación sencilla y daremos unas pautas para llevarla a cabo.

Lec19 022

Lo primero es asegurar todas las condiciones de inicio. Nos aseguraremos que no hay fallo de sobrecarga, ni de cortocircuito. Que el interruptor está cerrado y el contactor abierto. Que la seta de parada está cerrada (los dispositivos de parada siempre son normalmente cerrados por razones de seguridad). Las boyas de nivel estarán cerradas para los niveles EB y B y abiertas los niveles A y EA. El nivel del depósito lo situaremos a la mitad con ayuda del potenciómetro. Las dos lámparas que simulan el contactor y la señal de preaviso tienen que estar apagadas y el único piloto encendido será el que muestra el estado del interruptor (cerrado).

Ya podemos arrancar la bomba con el pulsador de marcha. Si lo hacemo se generará un aviso de prearranque durante 3 segundos y luego se generará la orden de cierre del contactor. Al segundo el contactor se abrirá y el piloto del estado del contactor parpadeará (se ha producido un fallo de confirmación).

Volvamos a generar la orden de marcha. Cuando observemos que se genera la salida de cierre del contactor, cerraremos el interruptor digital CONTACTOR. Ahora la bomba funciona normalemente.

Cuando la queramos parar, actuaremos sobre la PARADA abriendo el contacto. El relé de gobierno del contactor se abrirá (tenemos que simular manualmente que el contactor se abre, actuando sobre la señal del contactor).

También podemos probar a arrancar de forma automática abriendo las señales de las boyas de nivel B o EB. Y a parar de forma automática con las boyas de nivel A y EA. No se olvide de cerrar y abrir la señal del CONTACTOR cada vez.

También podemos simular el comportamiento del sistema cuando se produce un fallo o se abre el interruptor.

El sensor analógico nos indica (recordar que sólo indica y no gobierna) el nivel de agua del depósito. El potenciómetro nos ayuda a simularlo.

El monitor nos muestra toda la información del sistema. Si se modifica su altura se puede lograr que la información de cada refresco se muestre en una sóla pantalla.

En la siguiente pantalla se muestra la simulación en marcha con la bomba arrancada.

Lec19 023

Cuando todo funcione a nuestro gusto, ya podemos implementar la utilización de nuestro ARDUINO para el control del llenado de un depósito de agua por medio de una bomba. Esperamos que os haya gustado la lección de hoy.

 

[Proteus versión 8.1]

En esta lección encenderemos un led situado en una de las salidas de nuestra tarjeta Arduino y aprovecharemos para introducirnos en algunos de los conceptos generales de la programación de los equipos Arduino.

Para llevar a cabo esta lección utilizaremos un proyecto de Proteus basado en la tarjeta de desarrollo "Arduino328" con el shield "Led Bar". En la sección simulación encontrará toda la informacion necesaria para crear el proyecto con esta tarjeta y este shield y los conceptos básicos de la simulación de Arduino utilizando Proteus.

Por supuesto, si usted dispone de la tarjeta de desarrollo de hardware y las herramientas de programación también podrá utilizarlos para seguir esta lección. Nosotros hemos optado por utilizar el simulador en todas nuestras lecciones por la comodidad que esto supone.

El esquema electrónico de nuestro equipo, con la placa base y el shield, se recoge en la imagen siguiente. Recuerde que los terminales del mismo nombre están eléctricamente unidos. Así, que el terminal 1 de la barra de led está eléctricamente enlazado con el pin 17 del microprocesador ATMEGA328P, porque ambos están unidos a un terminal del mismo nombre, IO11.

Lec01 001

Al crear el proyecto, Proteus genera automáticamente para nosotros la estructura básica de nuestro código fuente. Sólo utilizaremos un fichero llamado Main.ino donde se albergará toda la lógica de nuestro primer proyecto.

Lec01 002

Por defecto, el editor nos presenta de color verde los comentarios. Los comentarios son ignorados por el programa y no ocupan espacio en la memoria.

El comentario puede ocupar una sola línea o un bloque formado por varias líneas. Para escribir un comentario de una línea utilizamos los caracteres // seguidos del texto que deseamos. Una línea de comentario puede empezar en una columna distinta de la primera, pero siempre termina en la siguiente línea de código. Por ejemplo, en nuestro código las líneas de comentario situadas en las líneas de código 9 y 13 no empiezan al principio. El compilador ejecutará el código de la línea hasta encontrar los caracteres // e ignorará todo lo que siga a partir de ahí considerándolo un comentario.

Para escribir un bloque de comentarios que ocupe más de una línea, insertamos el texto del comentario entre el código de inicio /* y el código de fin */.  En nuestro ejempo, las líneas de código 1 a 6 son un bloque de comentarios.

Los comentarios ayudan a escribir información que facilita la interpretación de lo que realiza cada parte de nuestro programa facilitando la depuración del mismo cuando ha transcurrido un tiempo o cuando lo lee una persona diferente a quien los escribió.

Además de los comentarios, el código contiene dos funciones. Una llamada setup y otra loop. Una función es un bloque de código que contiene una serie de sentencias o instrucciones, que tiene un nombre que la identifica de forma inequívoca y que se ejecuta cada vez que alguien utiliza una llamada a dicha función desde el programa. El formato de una función es el siguiente:

<valor devuelto> <nombre de la función>()

{

sentencias

}

En nuestro ejemplo, las funciones setup() y loop() no devuelven ningún dato. Por esta razón el <valor devuelto> es "void". Void es una palabra clave que indica que nuestra función no devuelve nada. Además, como dentro de las llaves, lo único que hay son comentarios, tal y como están no ejecutarían ninguna acción.

Todos los programas escritos para Arduino deben tener al menos dos funciones, las que acabamos de ver, llamadas setup() y loop(). Como es lógico, programas más complejos pueden contener muchas más funciones.

La función setup() contendrá la parte de código encargada de la configuración de nuestro equipo. En ella debemos poner la declaración de las variables que utilizaremos en nuestro programa (más adelante ahondaremos en el concepto de variable), la configuración de los diversos pines del microprocesador, la configuración de las comunicaciones, etc. Siempre es la primera función que se ejecuta al arrancar nuestro equipo.

La función loop() contiene la parte de código que se ejecutará de forma cíclica durante todo el tiempo que esté nuestro equipo en funcionamiento. El nombre loop en inglés significa bucle y expresa exactamente este concepto, sentencias que se ejecutan en bucle repetidamente una y otra vez. Aquí escribiremos el código que se encargará de leer el estado de las entradas, ejecutar la lógica de funcionamiento y escribir el estado de las salidas en función de los resultados calculados.

Vamos a empezar a escribir la primera línea de código de nuestro programa. Nuestro objetivo será encender el led 8 de la barra de leds. Para ello debemos configurar el pin llamado PD4 (el número 6) del microprocesador como salida. El led 8 y el pin PD4 están unidos por el conector llamado IO4.

Algunos de los pines del microprocesador ATMEGA328P pueden funcionar como entradas o como salidas. Para definir el uso que daremos a un determinado pin utilizaremos la función pinMode(). La sintaxis de esta función es la siguiente:

pinMode( <número de pin>,<modo de funcionamiento>)

Donde <modo de funcionamiento> puede tener dos valores, INPUT cuando queremos que funcione como entrada y OUTPUT cuando queremos que realice las funciones de salida. El párametro <número de pin> puede  tomar los valores de 0 a 13. El 0 se utiliza para el pin PD0 y el 13 para el pin PB5.

La terminología utilizada en el microprocesador para nombrar los pines puede resultar un poco confusa la primera vez que uno se acerca a un microprocesador. Agrupa los pines en conjuntos (puertos) de 8 pines. Por ejemplo, los pines 2 al 13 forman el puerto D. El primer pin del puerto D recibe el nombre de PD0 (el pin físico con el número 2) y así sucesivamente hasta llegar al PD7 (el pin número 13). Para simplificar el uso, los conectores a cada uno de los pines se han rotulado siguiendo otra convención. Los 13 pines digitales llevan los nombres IO0 a IO13. Los 6 pines analógicos llevan los nombres AD0 a AD5. Así es más fácil su identificación.

Modifiquemos nuestro programa para indicar que el pin IO4 funcionará como salida.

Lec01 003

Observe que hemos terminado la sentencia con un punto y coma. Para separar cada uno de los comandos que componen nuestro programa utilizamos el indicador punto y coma.

Ahora vamos a escribir el código para activar la salida IO4 y encender el segmento 8 de nuestra barra de leds. Para activar o desactivar una salida utilizamos la función digitalWrite(). Su formato es el siguiente:

digitalWrite( <número de pin> , <estado del pin>)

Donde <estado del pin> puede tener dos valores, HIGH cuando queremos activar la salida y LOW cuando la queremos desactivar.

Ya podemos modificar nuestro programa para activar la salida IO4.

Lec01 004

Note que hemos terminado la sentencia con un punto y coma y que la hemos escrito dentro de la función loop().

Para compilar nuestro programa, utilizaremos la opción "Construir proyecto" del menú "Construir" o el atajo de teclado "F7". 

Lec01 005

Si todo ha ido bien, recibiremos un mensaje diciendo "compilado ok" en la ventana "Salida VSM Studio". Si no sucede esto, repase con cuidado toda el código y vigile especialmente el uso de mayúsculas y minúsculas y los signos de puntuación.

Lec01 006

Volvamos a la pestaña "Esquema electrónico" y ejecutemos la simulación. Podremos observar que el led 8 de la barra de leds se enciende.

Lec01 007

Ya hemos terminado nuestro primer proyecto y hemos logrado encender un led de nuestra barra de leds.

Practique ahora usted escribiendo el programa para encender el resto de las barras de nuestro dispositivo de leds.

En esta primera lección no hemos entrado a fondo en el funcionamiento eléctrico de las salidas. Más adelante tendremos tiempo de profundizar en ello. En la sección de hardware podrá encontrar varios esquemas electrónicos con diferentes configuraciones de salidas del microprocesador.

 

 

[Proteus versión 8.1]

Como hemos hecho otras veces durante este curso vamos a intercalar una lección más teórica en nuestra trayectoria. Este es un buen momento para aprovechar y hacer un repaso de los tipos de datos númericos que podemos utilizar en la programación de nuestro ARDUINO y aprender cuál es el que mejor se adapta a cada necesidad.

En lenguaje C es obligatorio declarar todas las variables y constantes que vamos a utilizar en nuestro código antes de escribir el código que se ejecutará. Por eso, en todos los ejemplos que hemos ido viendo a lo largo del curso, hemos empezado todos los programas declarando las variables con sentencias como:

Lec20 001

Para definir una variable la sintaxis que tenemos que utilizar es:

<tipo> <identificador>;

Los identificadores son los nombres que les asignamos a las variables para referirnos a ellas en el resto del código. Un identificador puede tener entre uno y treinta y dos caracteres. El primer carácter debe ser una letra o el signo de subrayado (el guión bajo '_'). El lenguaje C, a diferencia de otros lenguajes, distingue entre las mayúsculas y las minúsculas, por lo que los dos identificadores 'm1_fallo' y 'M1_fallo' son distintos y harán referencia a variables diferentes. Por último, no se pueden utilizar como identificadores ciertas palabras reservadas del lenguaje C, como, por ejemplo, 'for', 'function', 'while', 'boolean', etc.

Los tipos indican al compilador qué tipo de dato vamos a almacenar en esa variable. Hay cuatro tipos básicos: carácter, numérico entero, numérico de coma flotante y sin definir. Además cada uno de estos tipos básicos admiten los denominadores modificadores de tipo que nos permiten definir el tamaño del almacenamiento y si guardará números sólo positivos (sin signo) o servirá para manejar números positivos y negativos.

En este punto hay que hacer una salvedad importante. El lenguaje C define el tipo entero en función del microprocesador que estemos utilizando. Por lo tanto, si trabajamos con el ARDUINO UNO el tamaño de un entero es de 16 bits (dos bytes) pero si trabajamos con el ARDUINO DUE el tamaño será de 32 bits (cuatro bytes). Por eso a partir de ahora nos vamos a referir siempre a los tipos para el ARDUINO UNO y el lector deberá buscar las equivalencias en el caso de usar otro equipo ARDUINO:

Empezaremos por ver los tipos que podemos utilizar para contener números enteros sin signo. Según su tamaño tenemos los siguientes.

  • boolean puede almacenar un bit. Es decir que sólo podemos almacenar 0 ó 1.
  • unsigned char puede almacenar números de un byte. Números comprendidos entre 0 y 255
  • unsigned int puede almacenar números de dos bytes. Números comprendidos entre 0 y 65.535.
  • unsigned long puede almacenar números de cuatro bytes. Números comprendidos entre 0 y 4.294.967.295.
  • unsigned long long puede almacenar números de ocho bytes. Números comprendidos entre 0 y 18.446.744.073.709.551.615.

Realmente es difícil pensar que podamos necesitar números más grandes para el 99,999999% de los proyectos que vayamos a realizar.

Cuando no utilizamos el modificador 'unsigned' y podemos almacenar números positivos o negativos, los rangos de los números que se pueden almacenar serían:

  • char puede almacenar números de un byte. Números comprendidos entre -128 y 127
  • int puede almacenar números de dos bytes. Números comprendidos entre -32.768 y 32.767
  • long puede almacenar números de cuatro bytes. Números comprendidos entre -2.147.483.648 y 2.147.483.648
  • long long puede almacenar números de ocho bytes. Números comprendidos entre -9.223.372.036.854.775.807 y 9.223.372.036.854.775.807.

Sin embargo, la gestión de todos los tipos disponibles no es igual de sencilla. En concreto los números grandes (long long) son más complicados de utilizar en nuestro código cuando trabajamos con ellos. Veamos un ejemplo de código donde definimos una variable númerica entera de cada tamaño y luego tratamos de mandar los valores por el terminal virtual.

Lec20 002

Si compilamos, recibiremos el siguiente error:

Lec20 003

Es decir, que no tenemos una función print() que nos permita enviar este tipo de datos al terminal. Más adelante, veremos la solución a este problema. Por ahora, nos sirve con saber que podemos definir variables de todos estos tipos.

Es muy importante definir bien el tamaño para nuestras variables. Si utilizamos un tipo 'unsigned int' para una variable que puede contener números mayores de 65.535 nuestro programa no funcionará bien y dará errores. Y si abusamos de los tipos grandes podemos llegar a tener problemas de ocupación de memoria y haremos trabajar a nuestro procesador de forma innecesaria puesto que los cálculos donde se utilizan números de tipos más grandes (long o long long) necesitan más ciclos de ejecución para llevarlos a cabo que los que utilizan tipos menores (char o int).

Este es el momento adecuado para hablar de las uniones. Una unión es una posición de memoria que se usa por varias variables similares que pueden ser de tipos diferentes. Pongamos un ejemplo que nos ayude a entender su uso.

Lec20 004

Imaginemos que tenemos una variable de tipo 'int' que ocupa dos bytes y que queremos poder hacer referencia a cada uno de ellos por separado. El programa de ejemplo nos ofrece la solución. En las líneas 6 a 10, definimos una unión (a la que le daremos el nombre de num). Dentro de la unión definimos dos variables que ocuparán, como hemos visto, la misma posición de memoria. La primera, de nombre num16bits, es de tipo entero. La segunda, es una matriz de dos posiciones de nombre num8bits de tamaño char cada una de ellas. Luego, en la línea 12, declaramos una variable de tipo num (la nueva unión que acabamos de definir) con el nombre de prueba. En la línea 16 asignamos a la parte entera de la unión el valor en hexadecimal 0xFA5C. Observe que la forma de referirnos a cada uno de los elementos que forma una unión es mediante la sintaxis <nombre union>.<elemento union>.

El resultado de todo ello es el siguiente. 

Lec20 005

El compilador almacenará en la posición de memoria correspodiente el valor FA5C. La variable num16bits devuelve el numero entero de dos bytes. La variable Num8bits[0] devuelve el valor del byte de menor peso (5C) y la variable Num8bits[1] el byte de mayor peso (FA).

Si simulamos el programa, comprobaremos que el resultado es el explicado aquí.

Lec20 006

Veamos ahora, otro ejemplo que nos servirá para explicar cómo podemos utilizar la función print() para visualizar números 'long long' y para profundizar en el entendimiento de las uniones.

Lec20 007

En este caso utilizamos la unión para almacenar en una misma posición de memoria un número de ocho bytes, una matriz de dos posiciones de cuatro bytes cada una, una matriz de cuatro posiciones de dos bytes cada una y una matriz de ocho posiciones de un byte cada una.

Declaramos dos variables numPrueba y numPrueba2 de tipo igual a la union que acabamos de definir. Con la primera mostramos un ejemplo en hexadecimal para mostrar el número en formato de 64 bits, en dos partes de 32 bits, en cuatro partes de 16 bits y en ocho partes de 8 bits. Como vimos antes no podemos utilizar la función print() para imprimir el número completo de 64 bits.

Con la segunda tenemos un ejemplo de uso en decimal de un número de 64bits y la forma de mostrarlo utilizando la función print().

El resultado de la simulación es el siguiente:

Lec20 008

Es importante observar que los para ordenar bien los bytes tenemos que mostrar primero los de mayor peso.

El siguiente código de ejemplo nos permite comprobar como nuestro ARDUINO es capaz de trabajar con números muy grandes. Observe que para asignar el número de gran tamaño a la variable de 64 bits, hemos tenido que utilizar el sufijo LL para indicarle al compilador que queremos usar un número 'long long'.

Lec20 009

El resultado de la compilación es una cuenta incremental manejando números muy muy grandes.

Lec20 010

Y de esta manera, con la lección de hoy, ya hemos conseguido que nuestro ARDUINO maneje números realmente grandes.

 


Esta página es propiedad de Hubor.

2014.

Guardar
Preferencias de usuario para las Cookies
Estamos utilizando las cookies para asegurarnos de que le podemos ofrecer el mejor servicio posible en este sitio web. Si rechaza el uso de las cookes, es posible que esta web no funcione como estaba previsto por el equipo de programadores.
Aceptar todo
Rechazar todo
Leer más
Estadísticas
Las cookies de preferencias permiten a la página web recordar información que cambia la forma en que la página se comporta o el aspecto que tiene, como su idioma preferido o la región en la que usted se encuentra.
Google Analytics
Aceptar
Rechazar