INFORMÁTICA FÍSICA E INTERNET DE LAS COSAS EN ESO
CRIF Las Acacias Noviembre 2015 Juan Félix Mateos
[email protected]
Contenidos del curso ● ● ●
● ●
● ●
Entradas analógicas Displays (matrices de LED y LCD) Comunicaciones (Serial, RC5, RFID, 1-wire, I2C y SPI) Sensores (analógicos, ambientales, inerciales) Almacenamiento de datos (EEPROM, FLASH y SD Card) Conexión a Internet (Ethernet y WiFi) IoT (Interner of Things) ● Arquitectura de los proyectos IoT ● Conceptos básicos sobre el protocolo TCP/IP ● Servicios online de IoT (ThinkSpeak, SmartCity Thing …) ● Introducción a NodeJS
Principios básicos de electrónica ●
¿Cómo afecta la electricidad al cuerpo humano? ●
●
●
●
●
Puede producir quemaduras, fibrilación, tetanización y asfixia. La resistencia del cuerpo humano varía en función de múltiples factores (humedad de la piel, tensión de corriente, frecuencia de la corriente, ...), pero en general para una trayectoria mano-mano es del orden de los kiloohmios. Los daños pueden producirse a partir de corrientes de 10mA. Consecuentemente, las tensiones pueden empezar a ser peligrosas a partir de V = I x R = 0.01 x 1000 = 10V.
¿Cómo afecta el cuerpo humano a los circuitos electrónicos? ●
Nuestro cuerpo puede acumular carga eléctrica, alcanzando incluso tensiones de decenas de miles de voltios respecto a tierra. Si nos aproximamos a un circuito, es posible que nuestra carga se fugue a través del circuito (incluso provocando un arco eléctrico a través del aire) y lo dañe (algunos componentes electrónicos no soportan tensiones tan elevadas... incluso aunque duren muy poco tiempo)
Contenidos del kit 1pcs x for Arduino UNO board 1 pcsx Breadboard 1pcs x LED emitter kit (red / blue / yellow; each 5pcs) 1 pcsx 74hc595 2 pcsx Buzzers 1pcs x Seven-segment display (1-digit) 1pcs x Seven-segment display (4-digit) Matriz de LEDs 8x8 4 pcs Push button switches 3pcs x Light dependent resistors 5pcs x 10K resistors 5pcs x 1K resistors 8pcs x 220R resistors 1pcs x Adjustable resistor 1pcs x LM35 temperature sensor 1 o 2pcs x Mercury switches/Interruptor de bola 1pcs x Flame sensor 1pcs x Infrared receiver 1pcs x RGB module + 1 LED tricolor 1pcs x 1602 LCD display 1pcs x 2.54mm pin header para el LCD 1pcs x PS2 joystick 1pcs x Stepping motor 1pcs x Stepping motor driver board 1pcs x Steering engine/Servomotor
Breadboard cables 10pcs x Dupont lines 1pcs x USB cable (80cm) 1pcs x Remote control (1*CR2025 included) 1pcs x Conector batería RTC Rele Sensor de agua resistivo Sensor de sonido/Micrófono Matriz de botones 4x4 Sensor de temperatura y humedad DHT11 Módulo RFID Conversor I2C para el LCD Sensor PIR Sensor ultrasonidos
Componentes en Arduino UNO
Características del ATMEGA328P ● ● ●
● ● ● ● ● ● ● ● ● ● ● ●
Flash (Kbytes):32 Kbytes Pin Count:32 Max. Operating Freq. (MHz):20 MHz CPU:8-bit AVR # of Touch Channels:16 Max I/O Pins:23 Ext Interrupts:24 USB Interface:No SPI:2 TWI (I2C):1 UART:1 Graphic LCD:No ADC channels:8 ADC Resolution (bits):10 ADC Speed (ksps):15
● ● ● ● ● ● ● ●
● ● ● ● ● ● ●
Analog Comparators:1 Temp. Sensor:Yes SRAM (Kbytes):2 EEPROM (Bytes):1024 Self Program Memory:YES picoPower:Yes Temp. Range (deg C):-40 to 85 Operating Voltage (Vcc):1.8 to 5.5 Timers:3 Output Compare channels:6 Input Capture Channels:1 PWM Channels:6 32kHz RTC:Yes Calibrated RC Oscillator:Yes Watchdog:Yes
Los pines de Arduino ●
●
Pines digitales [0..13] ● Pueden suministrar/engullir hasta 40mA (se recomienda no superar 20mA) ● En total pueden suministrar/engullir 200mA. ● Algunos de ellos [3, 5, 6, 9, 10, 11] pueden generar señales PWM ● Disponen de resistencias pull-up internas que podemos activar/desactivar por software ● Pueden configurarse en modo INPUT u OUTPUT; por defecto se encuentran en modo INPUT Pines analógicos [A0..A5] ● Utilizan un conversor A/D de 10 bits ● La referencia máxima puede elegirse entre: – DEFAULT: 5V – INTERNAL: 1.1V – EXTERNAL: pin 21 ● También pueden usarse en modo digital y disponen de resistencias pull-up
Componentes en Arduino UNO
Principios básicos de electrónica Niveles de tensión ●
¿Cómo se decide en una señal binaria qué es un 1 y qué es un 0? ●
●
Básicamente depende de la tecnología del componente que maneje la señal: CMOS (Complementary metal-oxide-semiconductor) o TTL (transistor-transistor logic) El microcontrolador del Arduino UNO (Atmega328P) es CMOS
Principios básicos de electrónica Soldadura con estaño
Arduino LLC vs Arduino SRL ●
●
●
●
Arduino LLC formada por Massimo Banzi, David Cuartielles, David Mellis, Tom Igoe y Gianluca Martino en 2009 → Equipo genuino fundador de Arduino Smart Project (fabricante de placas Arduino) dirigido por Gianluca Martino y que cambia su nombre en 2014 a Arduino SRL, cuando Gianluca la vende a Gheo y Federico Musto se convierte en su director. Gianluca había registrado la marca Arduino en Italia. Arduino LLC → arduino.cc ●
●
Genuino (fuera de EEUU)
Arduino SRL → arduino.org
Estructura básica de un sketch/programa
Configurar el IDE
Sintáxis del lenguaje Arduino ●
Similar a C
●
Todas las instrucciones deben terminar con ;
●
Los comentarios pueden ser
● ●
●
de una sola línea //
●
de varias líneas /* ..... */
Distingue entre mayúsculas y minúsculas Los nombres de las funciones predefinidas usan camelCase
Instrucciones básica ●
●
●
●
pinMode(pin,modo) ● pin: número del pin digital [0..13] ● modo – INPUT – OUTPUT – INPUT_PULLUP digitalWrite(pin,valor) ● pin: número del pin ● valor – HIGH – LOW delay(milisegundos) ● milisegundos: número de milisegundos de la pausa – Este valor es un unsigned int [0..4.294.967.295] millis() ●
Milisegundos desde la puesta en marcha del Arduino (overflow cada 50 días)
Variables – Tipos de datos ● ● ● ● ● ● ● ●
boolean: true o false – ocupa un byte byte (8 bits): 0..255 char (8bits): -128..127 Caracteres ASCII short (16 bits): -32.768 .. 32,767 word (16 bits): 0..65.535 long (32 bits): -2.147.483.648 .. 2.147.483.647 unsigned long (32 bits): 0 .. 4.294.967.295 int (16 o 32 bits): ● ●
●
Uno: -32.768 .. 32,767 Due: -2.147.483.648 .. 2.147.483.647
float (32 bits): ● ● ●
-3.4028235E+38 .. 3.4028235E+38 Sólo 7 cifras de precisión Lento
Variables - Alcance ●
Las variables son reconocidas dentro de la función en la que son definidas (locales), y son destruidas al finalizar la ejecución de la función. ●
●
Si la declaración de una variable va precedida de static, no se destruirá al finalizar la ejecución de la función.
Para que una variable sea reconocida en todas las funciones (global) tendremos que declararla fuera de cualquier función.
Control de flujo ●
if(condición){...}else{...}
●
for(inicialización;comprobación;incremento){...}
●
break
●
continue
Operadores = Asignación
!= ¿No igual?
== ¿Igual?
< ¿Menor?
+ Suma
> ¿Mayor?
- Resta
= ¿Mayor o igual?
/ División
&& Y lógico
% Módulo
|| O lógico
Las operaciones aritméticas se realizan en el tipo de datos de los operandos. Ej 7 / 2 = 3, pero 7.0 / 2 = 3.5
! Negación lógica
¿Para qué sirve una pull-up? ●
●
●
●
La pull-up es una resistencia (interna de unos 15kohm) que une el pin a la tensión de alimentación. Sin esta resistencia, si leemos el pin sin nada conectado a él (al aire) obtendremos un valor indeterminado (unas veces 0 y otras 1). La pull-up nos garantiza que en ausencia de una tensión nula, siempre leeremos un 1. ¿Qué leeriamos en el pin con el botón sin pulsar y si no existiera la resistencia pull-up?
Pulse-Width Modulation (PWM) ●
analogWrite(pin,cicloDetrabajo) ●
●
cicloDeTrabajo: 0..255
Pines PWM ●
3, 5, 6, 9, 10, 11
●
3, 9, 10 y 11: 490Hz
●
5 y 6: 980Hz
PWM + Botón ●
LED: Pin 3
●
Botón: Pin 4 con la pull-up habilitada
●
Inicialmente el LED con cicloDeTrabajo = 0
●
Incrementar el cicloDeTrabajo en +64 con cada pulsación del botón [0-64-128-1920(0=192+64)…]
●
Usar antirrebote de 25ms
●
Variables ●
byte cicloDeTrabajo
●
boolean estadoActual
●
boolean ultimoEstado
PWM + Botón Ejercicio ●
Crear y simular este circuito con 123d circuits
PWM + Botón Código fuente
Arrays ●
Declaración [y asignación] ●
tipoDeDato nombre [tamaño];
●
tipoDeDato nombre [tamaño] = {..., ..., ...};
●
El índice del primer elemento es el 0
●
Se pueden usar arrays de varias dimensiones ●
byte[2][2]={{0,1},{2,3}};
PWM + Botón + Array Ejercicio ●
Modificar el ejemplo anterior para que el ciclo de trabajo adopte uno de los valores {0, 64, 128, 192, 255} con cada pulsación, utilizando el siguiente Array: ●
byte valoresCicloDeTrabajo[]={0,64,128,192,255};
PWM + Botón + Array Código fuente
13d circuits depuración Ejercicio ●
Si en el código anterior cambiamos la línea 15 de ●
●
a ●
● ●
cicloDeTrabajo=(cicloDeTrabajo+1)%5; cicloDeTrabajo=(cicloDeTrabajo++)%5;
el programa deja de funcionar Averiguar con la depuración de 123d circuits por qué pasa esto
Cadenas de caracteres ●
●
●
●
En Arduino las cadenas de caracteres son arrays de tipo char Los datos char pueden indicarse como números (-128..127) o como caracteres entre comillas simples 'A' Las cadenas siempre tienen que terminar con el carácter NULL '\0' ¿Cómo se declaran? ●
char cadena[7] = {'c','a','d','e','n','a','\0'};
●
char cadena[7] = “cadena”; ¡OJO comillas dobles!
●
char cadena[] = “cadena”; Lo más fácil
Entrada analógica ●
●
analogRead(pin) ●
Pin: nº del pin analógico que queremos leer [0..5]
●
10bit ADC: Devuelve un valor entre 0 y 1023
●
Cada medida requiere aprox. 100uS
analogReference(referencia) ●
●
●
referencia –
DEFAULT: 5V
–
INTERNAL: 1.1V
–
EXTERNAL: A Ref (pin 21) ¡Importante 500m
●
Capacidad → Sensores de gas
●
Carga eléctrica → Sensores piezoeléctricos
Principios básicos de electrónica El divisor de tensión
Principios básicos de electrónica LDR ¿Cómo elegir el pull-down óptimo? ●
●
●
Como nos interesa maximizar el rango de tensión, buscaremos los extremos de la función Vmax-Vmin, es decir, aquéllos puntos donde su derivada es nula. Vmax=5(R2/ (Rmin+R2)) Vmin=5(R2/
Principios básicos de electrónica LDR ¿Cómo elegir el pull-down óptimo? ●
●
●
Haciendo ●
x=R2
●
a=Rmin
●
b=Rmax
Y entrando en un programa matemático como Wolfram obtenemos
De modo que la resistencia R2 óptima es la raíz cuadrada del producto Rmin·Rmax
Principios básicos de electrónica LDR ¿Cómo elegir el pull-down óptimo? ●
Para nuestro LDR tenemos ●
Rmin= 3 kohm
●
Rmax= 15 kohm
●
Roptima= 6.8 kohm
Sensor crepuscular: LDR + PWM Ejercicio ●
Leer el valor del LDR con el pin A0 y aplicar un PWM inversamente proporcional a un LED conectado en el pin 3. ●
Cuanta más luz, más apagado estará el LED; cuanto más oscuro con más intensidad brillará el LED
Sensor crepuscular: LDR + PWM Ejercicio
Sensor crepuscular: LDR + PWM Ejercicio
Entrada analógica LM35DZ ●
Sensor de temperatura lineal
●
10mV/ºC
●
0ºC..100ºC
●
EJERCICIO: Se propone desarrollar un termómetro de confort con los siguientes rangos: ●
22-26ºC: Enciende LED amarillo
●
26ºC: Enciende LED rojo
Entrada analógica Solución termómetro
Entrada analógica Solución termómetro
Entrada analógica ●
¿Cómo mejorar la precisión del termómetro? Si el LM35DZ puede medir hasta 100ºC ¿cuál será la tensión máxima? ●
●
¿Qué tensión de referencia estamos usando? ●
●
5V
¿Qué implicaciones tiene esto? ●
●
1V
Estamos desaprovechando 4/5 de la resolución del ADC
¿Podemos mejorarlo? ●
Sí, utilizando la referencia interna de 1.1V
Entrada analógica ¿Cómo mejorar la precisión del termómetro?
Comunicaciones serie ●
●
●
Arduino UNO tiene un puerto serie en los pines 0 y 1, compartido además con el puerto USB. Este puerto opera a 5V ¡CUIDADO con conectarlo a un ordenador que funciona a +/12V! Utilizar un MAX232 Funciones de interés ●
Serial.begin(velocidad) –
●
Velocidad = 9600, 14400, ..., 115200
Serial.print(cadena)
Comunicaciones serie ●
EJERCICIO ●
●
Modificar el ejemplo del termómetro para que además muestre la temperatura en el terminal serie Probarlo con el Serial Monitor de – –
El IDE de Arduino 123d circuits
Comunicaciones serie
Comunicaciones serie Envío de datos a Arduino ●
●
●
Arduino tiene un buffer con capacidad para un máximo de 64 bytes. Los datos que enviamos se van almacenando en ese buffer hasta que los leemos y, si se llena, se van perdiendo los datos más antiguos. Instrucciones de interés ●
●
Serial.available(): Nos indica el número de bytes pendientes de leer del buffer Serial.read(): Lee el primer byte del buffer (devuelve -1 si el buffer está vacío). –
Devuelve un int
–
¿Por qué no un byte? Porque entiende la tabla ASCII extendida[0..255] + el dato “-1” (buffer vacío)
Comunicaciones serie Envío de datos a Arduino ●
Ejercicio: Modificar el ejemplo anterior para que al enviar una “i” se active la referencia analógica interna, al enviar una “d” se active la referencia analógica predeterminada, y al recibir cualquier otro carácter se conteste “No le he entendido\n”
Comunicaciones serie Envío de datos a Arduino ●
Solución del ejercicio
Comunicaciones serie Envío de datos a Arduino ●
Otros métodos interesantes del objeto Serial: ●
●
●
Serial.write(): Escribe un valor binario (byte) por el puerto serie. Por ejemplo, puede utilizarse para mostrar caracteres más allá de la tabla ASCII. Por ejemplo, el valor 186 corresponde a º Serial.parseInt(): Lee un número entero por la entrada serie. –
Si no se ha introducido un número durante un segundo, devuelve 0.
–
En cuanto encuentra algo que no forma parte de un entero, lo ignora. Por ejemplo, si escribimos 8.5, devolverá 8 la primera vez que lo ejecutemos, y 5 la segunda.
–
Devuelve un int [-32,768 .. 32,767]
Serial.parseFloat(): Lee un número de coma flotante
Otros formatos de bucles ●
●
while(expresión){...} ●
Sólo se inicia el bucle si la condición es true.
●
Comprobación pre-iteración
do{...}while(expresion) ●
El bucle ejecuta siempre al menos una iteración.
●
Comprobación post-iteración
La bifurcación switch...case switch (valor){
●
case referencia1: ...
Sólo sirve para comprobar con referencias concretas (no con rangos). ●
break; case referencia2: ... break; ... default: ... }
●
Aunque si como valor utilizamos una expresión del tipo numero>propuesto, podremos usar como referencias true y false.
Sin el break, se ejecutaría todo el código de los casos posteriores hasta el final, o hasta que se encontrase otro break.
Funciones personalizadas ●
Una función es un bloque de código al que asignamos un nombre para poder ejecutarlo simplemente mencionando ese nombre en el código. ●
Por ejemplo, podemos crear una función que se llame activarReferenciaExterna, y podremos ejecutarla escribiendo activarReferenciaExterna(). –
●
¡Ojo a los paréntesis!
Las funciones, opcionalmente, pueden recibir argumentos y devolver un valor (sólo un valor).
Funciones personalizadas Declaración La instrucción return sirve para devolver un valor desde una función.
Si una función no devuelve nada, se declara con el tipo void.
Número pseudo-aleatorios ●
Arduino puede generar números enteros pseudo-aleatorios ●
●
randomSeed(entero): Establece la semilla o cadena de números pseudo-aleatorios que queremos utilizar. Suele recomendarse utilizar como argumento el valor leído en una entrada analógica conectada “al aire”. random(min,max): Devuelve el siguiente número de la cadena establecida por randomSeed() dentro del rango min (incluido, o por defecto 0), max (excluido)
Ejercicio pseudo-aleatorios ●
Crear un programa en el que Arduino elija un número al azar entre 1 y 100, y el usuario tenga que adivinarlo. ●
●
Crear una función llamada iniciar() que espere hasta que se pulse la tecla 's' y, entonces, elija un número al azar entre 1 y 100, y pregunte “Adivine qué número he pensado del 1 al 100”. En la sección loop(), comprobar si el número sugerido (con Serial.parseInt()) es menor o mayor que el elegido, y contestar con « (Serial.write(171);) o » (Serial.write(187);) ,respectivamente. –
Si acierta, indicar “Has acertado” y volver a ejecutar la función iniciar()
Solución pseudo-aleatorios ●
SOLUCIÓN
Displays 7 segmentos ● ● ● ●
Existen de ánodo común y de cátodo común. 5611AH/5161AS – Cátodo común 5161BS – Ánodo común Escribir un programa que encienda los 7 segmentos con los pines del 2 al 8. ● 2 al segmento A, 3 al segmento B...
Displays 7 segmentos ●
●
Falta conectar el común a 5V o GND según sea de ánodo común o cátodo común, respectivamente. El display que hay en 123d circuits es de ánodo común.
Displays 7 segmentos
Escribir un programa que encienda los 7 segmentos ●
¿Podríamos utilizar una sola resistencia? ●
Para que una luz no parezca parpadeante debe encenderse unas 150 veces por segundo.
Displays 7 segmentos Multiplexado de segmentos
Displays 7 segmentos Multiplexado de segmentos ●
●
●
¿Qué delay máximo podemos realizar sin que se note parpadeo?
¿Existe conflicto entre las variables i de setup y loop? ● No porque son locales en cada función ¿Qué ventaja tiene multiplexar? ● Menos componentes (sólo hay un LED encendido en cada instante, por lo que sólo necesitamos una resistencia limitadora (que incluso podríamos evitárnosla porque el tiempo de encendido es muy corto)). ● Menos consumo instantáneo (el UNO puede suministrar a lo sumo 200mA, es decir, unos 10 LEDs) ¿Inconvenientes? ● Requiere más tiempo de procesamiento. Puede llegar a parpadear si tenemos que atender tareas largas entre actualizaciones. – Hemos visto que con 2 ms no se nota parpadeo... una conversión A/D requiere unos 100us
OJO con la SALUD Parpadeo imperceptible ●
●
●
●
Según estudios, alrededor de 1 en 4000 personas es altamente susceptible al parpadeo de las luces en ciclos de rango de 3 a 70 Hz. Dicho parpadeo obvio puede desencadenar trastornos tan serios como ataques de epilepsia. Menos conocido es sin embargo que la exposición prolongada al parpadeo con mayor frecuencia (inintencional) (en el rango de 70 a 160 Hz) también puede provocar malestar, dolores de cabeza y problemas visuales. Las pruebas han demostrado que es difícil para los humanos detectar directamente el parpadeo de la luz a estas frecuencias mayores, pero parece que no tiene prácticamente importancia. Los científicos han realizado pruebas que indican que la retina del hombre puede resolver el parpadeo de la luz de 100 a 150 Hz incluso si el sujeto no se ha percatado de dicho parpadeo y esto lleva a la conclusión de que el cerebro podría estar reaccionando bien. Algunos investigadores incluso afirman que la retina puede soportar un parpadeo de hasta 200 Hz, pero las pruebas han demostrado que por encima de los 160 Hz los efectos para la salud son insignificantes.¹ En 2009, la especificación sobre el parpadeo se cambió para establecer que la frecuencia de funcionamiento mínima del LED se cambiaba de 120 Hz, tal como se estableció en la versión anterior de las especificaciones, a 150 Hz. Los fabricantes de LED y semiconductores no estuvieron felices con la medida porque el cambio que debían realizar a sus productos para adaptarse a la nueva frecuencia era muy costoso. En una carta enviada a las partes interesadas con fecha Marzo de 2010,³ la EPA cedió y regresó la especificación al 120 Hz original donde permanece hasta estos días.
Displays 7 segmentos
Escribir un programa que muestre los números del 0 al 9 ●
●
Definir un array de 10x7 elementos en el que se definan las salidas necesarias para mostrar cada dígito ¿Con qué tipo definimos el array?¿Boolean? ●
●
Realmente no supone ninguna ventaja respecto a usar byte porque la variables booleanas ocupan realmente 1 byte.
Queremos que cada dígito se muestre durante 1 segundo ●
do{...}while(condicion)
●
millis()
Displays 7 segmentos
Escribir un programa que muestre los dígitos del 0 al 9
Otros detalles de interés sobre los puertos ●
●
●
●
Si hacemos un digitalWrite(pin,HIGH) sobre un pin configurado como entrada se activará su pull-up; inversamente, con un digitalWrite(pin,LOW) se desactivará la pull-up. Si ponemos un pin configurado como salida en HIGH y luego lo configuramos como entrada, su pull-up estará activada. Los pines analógicos también pueden utilizarse como digitales, refiriéndonos a ellos con los números del 14 al 19, o como A0..A5. Si configuramos un pin analógico como salida, para posteriormente realizar sobre él un analogRead previamente tendremos que reconfigurarlo como entrada.
Display 4 dígitos 7 segmentos ●
●
●
5641AH/5461AS – Cátodo común HS410561K – Ánodo común Cambiar el montaje del ejemplo anterior para que utilice el primer dígito del display de 4 dígitos
Display 4 dígitos 7 segmentos ●
Alimentar los 4 dígitos ●
¿Qué ocurre? –
●
Que todos realizan la misma cuenta
Supongamos ahora que queremos utilizar los 4 dígitos ¿cómo lo hacemos? ●
Supongamos que decidimos multiplexar los dígitos pero no los segmentos (es lo más habitual) ¿Cómo conseguimos entregar/asumir 20x7=140 mA –
Arrays de transistores Darlington ●
●
ULN2003/ULN2803 → Sumideros de corriente – Interruptor del lado de baja tensión UDN2983 → Fuentes de corriente – Interruptor del lado de alta tensión
ULN2003 ●
Podemos usarlo como un sumidero de corriente para superar el límite que admiten los pines del Arduino (40mA máximo absoluto por pin)
El pin 9 del ULN sólo hay que conectarlo a Vcc cuando se usen cargas inductivas
UDN2983/TLC59213 ●
Podemos usarlo como una fuente de corriente para superar el límite que admiten los pines del Arduino (40mA máximo absoluto por pin)
Display 4 dígitos 7 segmentos Multiplexado de dígitos ●
●
●
Introducir resistencias limitadoras entre los segmentos y los pines 2..8 Cátodo común: Conectar el cátodo de cada dígito a una salida del ULN2003 y usar los pines 9..12 para controlar sus correspondientes entradas. Ánodo común: Conectar el ánodo de cada dígito a una salida del UDN2983 y usar los pines 9..12 para controlar sus correspondientes entradas.
Display 4 dígitos 7 segmentos Ejercicio ●
Escribir un programa que cuente de 1000 a 2999 con una pausa de 150ms entre número y número.
Display 4 dígitos 7 segmentos Solución 1/2
Display 4 dígitos 7 segmentos Solución 2/2
Notaciones numéricas ●
Decimal: El número sin más ●
●
Binaria: Prefijo B ●
●
0x38
Octal: Prefijo 0 ●
●
B111000
Hexadecimal: Prefijo 0x ●
●
56
070
Los 4 ejemplos anteriores son distintas formas de escribir el decimal 56.
74HC595 8-bit serial-in, serial or parallel-out shift register with output latches; 3-state ●
Dos relojes: ●
Uno para el registro Shift
●
Otro para el registro Storage
74HC595 8-bit serial-in, serial or parallel-out shift register with output latches; 3-state ●
●
En el flanco de subida del SHCP se traslada el valor presentado en el pin DS al estado 0 del registro de desplazamiento (es un registro interno), desplazando los estados previos anteriores una posición hacia la derecha. En el flanco de subida de STCP, los estados del registro de desplazamiento se presentan en las salidas Q0..Q7
74HC595 8-bit serial-in, serial or parallel-out shift register with output latches; 3-state ●
Ejercicio ●
●
Conectar el display de un 1 dígito al 74HC595 y hacer que cuente de 0 a 9 sin multiplexión (necesitaremos una resistencia para cada ánodo/cátodo del display) ¿Sin multiplexión? ¿Pero no habíamos dichos que necesitamos multiplexión porque el Arduino no puede dar corriente a todos los LEDs? –
Ahora la corriente la entrega el 74HC595
En realidad el 74HC595 no es ideal para entregar más de 70mA; convendría usar su variante de alta corriente TPIC6C595 Instucciones de interés ●
●
●
shiftOut(dataPin, clockPin, bitOrder, value) –
bitOrder puede ser MSBFIRST o LSBFIRST
74HC595 8-bit serial-in, serial or parallel-out shift register with output latches; 3-state ●
Ejercicio ●
Obsérvese que 123d circuits nos avisa de que estamos superando los límites del 74HC595
74HC595 8-bit serial-in, serial or parallel-out shift register with output latches; 3-state ●
Solución
DHT11 Sensor de temperatura (resistivo) y humedad (capacitivo) ●
● ● ●
Nuestro sensor DHT11 viene con conexión keyes y ya trae integrada una resistencia pull-up de la línea de datos a la tensión positiva de alimentación, por lo que podemos conectarlo directamente como se indica en la figura. Rango lectura humedad 20-80% con 5% de precisión Rango lectura temperatura 0-50º C con +/-2º de precisión Realiza una lectura cada dos segundos
DHT11 Protocolo de comunicaciones ● ●
●
●
●
Un solo cable de comunicaciones bidireccional. El Arduino inicia la comunicación poniendo a LOW la línea de datos durante 20ms, y después se queda escuchando la línea. Tras la inicialización, el DHT11 genera un pulso LOW de 80us seguido de otro alto de 80uS. A continuación el DHT11 trasmite 40 bits: ● 8 para la parte entera de la humedad ● 8 para la parte decimal de la humedad ● 8 para la parte entera de la temperatura ● 8 para la parte decimal de la temperatura ● 8 para el checksum, que se calcula sumando los 4 valores anteriores y quedándose con los 8 bits menos significativos. Cada bit se codifica mediante un pulso LOW de 50us seguido de un pulso HIGH, de 28us si es un 0, o de 70us si es un 1.
DHT11 Ejercicio ●
Crear un programa que espere a que el usuario envíe por el terminal serie la letra “l” y muestre: ●
Los 41 pulsos de la comunicación (toma del control del DHT11 y 40 bits de datos)
●
La humedad en formato legible.
●
La temperatura en formato legible.
●
El checksum recibido y el calculado.
DHT11 Solución ●
En el setup ●
Configurar el pin 2 como entrada
●
Iniciar la comunicación serie
●
Enviar las instrucciones al terminal
DHT11 Solución ●
En el loop declarar las siguientes variables de tipo byte: ● contador para utilizarlo como índice en los bucles ● humedadEntera para la parte entera de la humedad ● humedadDecimal para la parte decimal de la humedad ● temperaturaEntera para la parte entera de la temperatura ● temperaturaDecimal para la parte decimal de la temperatura ● lectura[41] para almacenar la longitud de los 41 pulsos HIGH emitidos por el DHT11
DHT11 Solución
●
En el loop, esperar a que se reciba la tecla “l” y, a continuación: ● Solicitar la comunicación manteniendo la línea de datos LOW durante 20ms, devolviéndola a HIGH, y pasando inmediatamente al modo de entrada (escucha). ● Esperar a la escucha hasta que el DHT11 baje la línea de datos a LOW. ● Mediante un bucle y la instrucción pulsein(pin,tipoDePulso) medir la duración de los 41 pulsos HIGH enviados por el DHT11. – pulsein devuelve la duración en us – tipoDePulso en nuestro caso debe ser HIGH
DHT11 Solución
●
Enviar al terminal serie las duraciones de los 41 pulsos recibidos, y aprovechar para sustituirlos por 0 o 1 en el array lectura en función de que su longitud sea mayor o menor que 50us
Operadores a nivel de bit ●
& (Y)
●
| (O)
●
^ (O exclusivo)
●
~ (no)
●
●
> (desplazamiento a la derecha - división)
DHT11 Solución
●
Obtener los valores de la humedad, la temperatura y el checksum almacenándolos en las variables correspondientes.
DHT11 Solución
●
Imprimir en el terminal todos los resultados e indicar si el checksum recibido coincide con el calculado. ● Usar el modificador BIN en printlh para mostrar los checksum en formato binario.
DS1302
Real Time Clock (RTC) ● ●
●
Está organizado en 9 registros de 8 bits Cada registro está identificado por dos direcciones: una para leer su contenido y otra para escribir su contenido La comunicación es muy lenta: requiere que el reloj tenga una frecuencia menor que 500kHz.
DS1302
Real Time Clock (RTC) ●
●
No obstante, también podemos leer o escribir todos los registros consecutivamente accediendo a las direcciones 0xBF o 0xBE, respectivamente; esto se denomina modo BURST. ● Al escribir es obligatorio escribir al menos los 8 primeros registros. Comunicación a través de 3 pines ● DAT: Línea de datos ● RST o CE: Debe mantenerse en HIGH durante la comunicación con el RTC. ● CLK o SCLK: Reloj – Al escribir en el RTC el dato debe estar ya presente antes del flanco de subida del CLK. – Al leer del RTC debemos tomar el dato después del ciclo de bajada del CLK.
DS1302
Real Time Clock (RTC)
DS1302
Real Time Clock (RTC) ● ●
●
Ejemplo de lectura de la hora y fecha 10:57:49 15-04-13 Obsérvese que la comunicación comienza con el LSB (less significative bit), la unidad de la F de la dirección 0xBF Obsérvese también que el bit 63, correspondiente al valor WP está en alto; esto implicaría que no podemos escribir en el DS1302.
DS1302
Real Time Clock (RTC) ●
●
El bit 8 corresponde al registro CH (Clock Halt), y si contiene un 1 detiene el funcionamiento del reloj. El problema es que al arrancar el DS1302, el valor de este registro no está definido. Puede ser 1, como en la imagen inferior y eso impide que el reloj eche a andar.
DS1302
Real Time Clock (RTC) ●
Dado que el estado inicial de los bits WP y CH no está definido, lo primero que deberemos hacer para arrancar el DS1302 es: ● Borrar el bit WP si está en HIGH para así poder escribir en el resto de los registros ●
Borrar el bit CH si está en HIGH para que el reloj eche a andar.
DS1302 Ejercicio
●
Crear un guión que: ● Al iniciarse compruebe que están a 0 los bits WP y CH, y los ponga a LOW en caso contrario. ●
●
Al recibir por el terminal serie 1 muestre la hora y fecha del DS1302 Al recibir por el terminal serie 2 pregunte por una hora y fecha con el formato hh:mm:ss dd-mm-aa y la establezca como hora y fecha actual del DS1302
DS1302 Solución
●
●
Usamos #define para indicar que vamos a usar la siguiente configuración de pines ● 2- CLK ●
3- DAT
●
4- RST
Creamos las siguientes variables de tipo byte: ●
●
●
indice para los bucles dirección para las direcciones del modo burst (0xBF y 0xBE) trama[64] para almacenar los 8 registros del DS1302
DS1302 Solución
●
En el setup ● Configuramos el estado inicial de los pines ●
Mostramos las instrucciones en el terminal serie
DS1302 Solución
●
Creamos una función llamada escribirDS1302 que escriba trama[64] en modo burst en el DS1302
DS1302 Solución
●
Creamos una función llamada leerDS1302(boolean mostrar) que lea en trama[64] los 64 primeros bits del DS1302 y los muestre en el terminal serie si mostrar=true
DS1302 Solución
●
En el setup: ● Leemos el DS1302 ●
Si WP=1, lo ponemos a cero en trama y lo escribimos al DS1302
●
Si CH=1, lo ponemos a cero en trama y lo escribimos al DS1302
DS1302 Solución
●
En el loop: ● Mostrar la hora y fecha si se recibe un 1 por el terminal serie
DS1302 Solución
●
En el loop: ● Si se recibe un 2 –
solicitar que se escriba la fecha hora con el formato hh:mm:ss dd-mm-aa
–
esperar a que haya 17 caracteres disponibles en el buffer
–
Extraer las horas al array trama
DS1302 Solución
●
Continuando de la diapositiva anterior: ● Extraer los minutos y los segundos al array trama
DS1302 Solución
●
Continuando de la diapositiva anterior: ● Extraer el día y el mes al array trama
DS1302 Solución
●
Continuando de la diapositiva anterior: ● Extraer el año al array trama
Displays de texto LCD ●
Características ●
Muy económicos
●
Gran capacidad para mostrar textos largos –
●
1x8
●
2x16
●
4x20
●
2x50
Aunque si en necesario usar la retroalimentación, consume bastante.
Difíciles de manejar. La tecnología de cristal líquido requiere tensiones alternas que cambian constantemente para mantener visibles los puntos. –
●
●
Consumen muy poca energía –
●
Los tamaños más comunes suelen ser (líneas x caracteres)
Afortunadamente existe CI específicos para manejarlos, como el popular HD44780.
Muy flexibles porque permiten crear caracteres personalizados
Displays de texto LCD HD44780 ●
Características ●
Muy popular
●
Puede manejar hasta 2x8 caracteres –
Por eso nuestra pantalla de 2x16 tiene 2 HD44780
●
Compatible con matrices de puntos de 5x8 y 5x10
●
Bus de datos de 4 u 8 bits
●
Permite configurar hasta 8 caracteres personalizados de 5x8
●
Cursor y parpadeo (blink)
●
Existe una librería oficial de Arduino llamada LiquidCrystal que nos permite manejarlo muy fácilmente.
Displays de texto LCD Conexiones ●
●
Nuestro LCD posee 2 entradas de alimentación: ●
Una para el backlight: pines 15 y 16
●
Otra para los caracteres: pines 1 y 2
En el pin 3 VEE/V0 (bias voltage) podemos aportar una tensión que sea inversamente proporcional al contraste que queramos para los caracteres ●
Usaremos nuestro potenciómetro de 50kohm
Displays de texto LCD Comunicación con el display ●
●
●
En principio podríamos leer o escribir datos en el HD44780, pero nosotros sólo los vamos a escribir, así que deberemos poner a masa el pin R/W (pin número 5) Nosotros vamos a utilizar un bus de 4 bits (consumimos menos pines del Arduino, pero la comunicación es la mitad de rápida). ●
D4: pin 5 del Arduino
●
D5: pin 4 del Arduino
●
D6: pin 3 del Arduino
●
D7: pin 2 del Arduino
Además de los 4 pines de datos necesitamos 2 para el control de la comunicación: ●
RS (register selection) –
●
Al pin 12 del Arduino
E (enable) –
Al pin 11 del Arduino
Displays de texto LCD La librería LiquidCrystal ●
Incluir la librería ●
●
Crear un objeto de la clase LiquidCrystal ●
●
●
LiquidCrystal miLCD(rs, enable, d4, d5, d6, d7); Es como declarar una variable local; hay que hacerlo fuera de setup() y loop()
Indicar la configuración del display con begin(columnas,filas) ●
●
#include
miLCD.begin(16,2);
Enviar cadenas al display con print (cadena). ●
miLCD.print(“¡Hola Juanfe!”);
Displays de texto LCD La librería LiquidCrystal ●
¿Por qué no aparece el signo de abrir exclamación? ●
El carácter ¡ no pertenece al estándar ASCII, por lo que se codifica en UTF-8 mediante 2 bytes: –
C2 (1100_0010): Carácter 194
–
A1 (1010_0001): Carácter 161
Displays de texto LCD La librería LiquidCrystal ●
Métodos para usar caracteres personalizados ●
●
Se pueden crear hasta 8 caracteres personalizados de 5x8. miLCD.createChar(numero,representacion): Sirve para crear un carácter personalizado. Número es un valor del 0 al 7 que indica cuál de los 8 caracters prosibles queremos crear. representacion es un array de 8 elementos en el que se define el aspecto del carácter fila por fila, de arriba a abajo (la última fila es el valor 0 para poder usar el cursor). –
●
Los caracteres tienen que crearse antes de llamar al método miLCD.begin()
miLCD.write(numero): Sirve para mostrar un carácter pesonalizado. –
Es recomendable aportar el argumento numero como una variable en lugar de escribiendo directamente un valor; por ejemplo, si se escribie miLCD.write(0) se producirá un error de compilación.
Displays de texto LCD La librería LiquidCrystal ●
●
Ejercicio: Modificar el ejemplo anterior para que se muestre correctamente el signo de exclamación inicial (crearlo como un carácter personalizado).
http://www.villatic.org/carpetaJuanfe/generadorCaracteres.html
Displays de texto LCD La librería LiquidCrystal ●
Solución del ejercicio anterior
Displays de texto LCD La librería LiquidCrystal ●
Métodos para realizar scroll ●
●
●
●
●
●
miLCD.scrollDisplayLeft(): Desplaza el contenido del LCD una posición hacia la izquierda. miLCD.scrollDisplayRight(): Desplaza el contenido del LCD una posición hacia la derecha. miLCD.leftToRight(): Establece la dirección del texto de izquierda a derecha. miLCD.rightToLeft(): Establece la dirección del texto de derecha a izquierda. miLCD.autoscroll(): Al mostrar cada carácter, desplaza el resto del LCD (hacia la izquierda o hacia la derecha según la dirección establecida para el texto). miLCD.noAutoscroll(): Desactiva el scroll automático del método autoscroll().
Displays de texto LCD La librería LiquidCrystal ●
Ejercicio: Modificar el ejemplo anterior para que el texto se mueva alternativamente hacia la derecha hasta llegar al borde, y después hacia la izquierda hasta llegar a la posición inicial. ●
Utilizar scrollDisplayLeft() y scrollDisplayRight()
Displays de texto LCD La librería LiquidCrystal ●
Solución del ejercicio
Displays de texto LCD La librería LiquidCrystal ●
Métodos para el manejo del cursor ●
●
●
●
●
miLCD.cursor(): Muestra el cursor en la posición en la que se imprimirá el siguiente carácter miLCD.noCursor(): Oculta el cursor miLCD.setCursor(columna,fila): Coloca el cursor en la posición indicada. Tanto columna como fila usan index zero. miLCD.home(): Coloca el cursor en la primera posición del LCD, pero sin borrar su contenido miLCD.clear(): Borra el contenido del LCD y coloca el cursor en la primera posición.
●
miLCD.blink(): Hace parpadear el cursor.
●
miLCD.noBlink(): Detiene el parpadeo del cursor
Displays de texto LCD Ejercicio: Reloj ●
Montar un dispositivo con display LCD y 3 botones: ●
Mostrar la hora en el reloj (hora:minutos:segundos)
●
Botón 1: SET (pin 8) Al mantenerlo pulsado más de 1 segundo, activará el modo de configuración de hora, mostrando el cursor en el primer dígito de la hora. Con cada pulsación posterior pasará al dígito siguiente. Al alcanzar el último dígito de los segundos saldrá del modo de configuración. Botones UP (pin 7) y DOWN (pin 6): Servirán para cambiar los dígitos en el modo de configuración. –
●
Displays de texto LCD Ejercicio: Reloj ●
●
●
●
Crear variables globales ● De tipo byte llamadas: hora, minuto y segundo ● De tipo boolean: configurando=false y botonSetPulsado ● De tipo unsigned long: ultimaActualizacion y botonSetPulsadoDesde Declarar las funciones ● void mostrarHora(byte h, byte m, byte s) ● void sumarUnSegundo() En setup(), asignar a ultimaActualizacion el valor de millis() En setup(), declarar como entrada los pines 6, 7 y 8
Displays de texto LCD Ejercicio: Reloj ●
Desarrollar la función mostrarHora(byte h, byte m, byte s)
Displays de texto LCD Ejercicio: Reloj ●
Desarrollar la función sumarUnSegundo()
Displays de texto LCD Ejercicio: Reloj ●
En loop() escribir el código necesario para que se incremente un segundo la hora por cada segundo transcurrido desde la última actualización
Displays de texto LCD Ejercicio: Reloj ●
En loop() escribir el código necesario para que se detecte si el botón SET lleva más de un segundo pulsado y, en caso afirmativo, se asigne a la variable configurando el valor true
Displays de texto LCD Ejercicio: Reloj ●
En loop() escribir el código necesario para que si configurando==true se muestre el cursor parpadeando sobre las unidades de las horas y se espere a que se despulse el botón SET
Displays de texto LCD Ejercicio: Reloj ●
Dentro del mismo si de la diapositiva anterior, desarrollar el código necesario para que la hora se incremente/decremente pulsando los botones UP/DOWN
Displays de texto LCD Ejercicio: Reloj ●
Repetir el código de las 2 diapositivas anteriores adaptándolo para los minutos y los segundos.
Displays de texto LCD Ejercicio: Reloj ●
Tras la última pulsación del botón SET, añadir el código necesario para salir de modo de configuración: ● Ocultar el cursor ●
●
Actualizar ultimaActualizacion para que no se “recupere” todo el tiempo perdido durante la configuración Actualizar botonSetPulsadoDesde para que no se vuelva a entrar inmediatamente en el modo Configuración por culpa de un rebote.
Motores ●
En Arduino se utilizan básicamente 3 tipos de motores: ●
●
●
●
Motores de corriente continua: Giran continuamente mientras se les aplica corriente. El sentido de la corriente determina el sentido del giro. Servomotores: Giran buscando igualar la señal analógica generada por un potenciómetro unido solidariamente a su eje con la señal de entrada recibida (generalmente PWM). Al alcanzar ese equilibrio de setienen, por lo que son muy utilizados en robótica (brazos robóticos). Motores PaP (paso a paso): En lugar de girar continuamente, lo hacen a saltos. Son muy útiles para fijar ángulos concretos, aunque son más lentos que los servomotores.
La mayor dificultad al usar motores en Arduino es que son cargas inductivas que requieren protección (diodos) y que generalmente consumen más corriente de la que puede generar el arduino (se recurre a transistores).
Motores de corriente continua Diodo protector ●
El diodo protege frente a la Back EMF (fuerza contraelectromotriz).
Motores de corriente continua Transistor de control ●
El transistor actúa como un interruptor para poner en marcha o detener el motor.
Servomotores ●
Suelen controlarse con señales PWM de 50 Hz, y pulsos de 1 a 2ms.
Servomotores Arduino ●
Arduino nos ofrece la librería Servo (esta librería anula la función analogWrite de los pines 9 y 10, por lo que es conveniente utilizarlos precisamente para controlar los servos), con los siguientes métodos de interés: ●
●
●
●
miServo.attach(pin,min,max): min es el ancho mínimo y max el máximo en microsengundos. Generalmente estos valores son 1000 y 2000, pero ¡OJO! por defecto la librería los configura en 544 y 2400. miServo.write(angulo): Gira el ángulo indicado entre 0 y 180 miServo.read(): Devuelve el último giro indicado al servo (un valor entre 0 y 180). MiServo.detach(): Deshabilita el servo recuperando la función analogWrite en los pines 9 y 10.
Servomotores Arduino: Ejercicio ●
●
Escribir un programa que haga girar el servo a la posición introducida mediante el terminal serie.
Tener en cuenta que nuestro servo (SG90) utiliza como mínimo y máximo 1000 y 2000 us.
Servomotores Arduino: Solución
EEPROM interna ●
●
●
Los microcontroladores de Arduino poseen memoria EEPROM interna (1kB en el caso de Arduino UNO). Esta memoria tiene la cualidad de no perder su contenido aunque se desconecte la alimentación eléctrica. Algunos de sus inconvenientes son su lentitud (3ms para escribir un byte) y su desgaste (cada posición se puede escribir unas 100.000 veces). Arduino nos ofrece la librería EEPROM.h con los siguientes métodos de interés: ●
●
EEPROM.read(dirección): Devuelve el byte almacenado en la dirección indicada [0,1023]. Si no se ha almacenado ningún valor en esa dirección devuelve el valor 255. EEPROM.write(dirección,valor): Escribe el valor indicado en la dirección.
EEPROM interna Ejercicio ●
Modificar el ejercicio anterior del servo para que recuerde su último ángulo aunque se desconecte la alimentación eléctrica. ●
OJO con EEPROM.read() -> Devuelve 255 cuando leemos una posición en la que no se ha escrito ningún valor.
EEPROM interna Solución
Motores PaP ●
●
Unipolares: 5, 6 u 8 cables La corriente circula siempre en el mismo sentido, pero sólo por media bobina.
●
●
Bipolares: 4 cables La corriente puede circular en ambos sentidos por cualquiera de las bobinas.
Motores PaP ●
Unipolares: Se suelen manejar con drenadores como el ULN2003
●
Bipolares: Se suelen manejar con ICs específicos (puentes H) como el L293D.
Motores PaP Half versus Full stepping ●
Full step
●
Half step
Motores PaP 28BYJ-48 ●
Unipolar
●
5V
●
64 pasos en modo half-step
●
32 pasos en modo full-step
●
Caja reductora de relación 64:1 (68.68395:1)
Motores PaP La placa SBT0811
Motores PaP Half step ●
Alimentamos la primera bobina
●
Alimentamos la primera y segunda bobina
●
Alimentamos sólo la segunda bobina
●
...
Motores PaP Ejercicio ●
●
Escribir un programa que haga girar el motor una vuelta completa en un sentido, luego una vuelta completa en sentido contrario, y que se repita constantemente. ¿Qué velocidad máxima conseguimos con el motor?
Motores PaP Solución
Comunicaciones infrarrojas ●
Los sensores infrarrojos, como el AX-1838HS, incluyen un fotodiodo, amplificador y filtro para entregarnos una señal directamente manejable por Arduino.
Comunicaciones infrarrojas Codificación de señales
Comunicaciones infrarrojas RC-5 ● ● ●
Desarrollado por Philips Portadora 36kHz Comandos 14 bits ● ●
Bit de inicio = 1 Bit de campo –
●
Toggle bit; cambia con cada pulsación –
●
Permite manejar 32 dispositivos
Comando: 6 bits Cada bit requiere 32 ciclos de portadora El comando se repite cada 114ms si la tecla se mantiene pulsada ●
●
Permite distinguir pulsaciones consecutivas de pulsaciones mantenidas
Id de sistema: 5 bits –
●
2 campos de 64 comandos cada uno
Comunicaciones infrarrojas NEC ● ●
●
Fabricantes japoneses Comandos ● Pulso inicial de 9ms para establecer ganancia ● Espacio de 4.5ms ● 8 bits address del dispositivo ● 8 bits address invertida ● 8 bits de comando ● 8 bits de comando invertido ● Pulso final de 562.5us El código de tecla aún pulsada se retransmite cada 40ms con este formato: ● Pulso inicial de 9ms ● Espacio de 2.25ms ● Pulso final de 562.5us
I2C (Inter-Integrated Circuit) Topología ●
●
●
●
Sólo requiere dos hilos ● SDA: Datos ● SCL: Reloj Se pueden conectar varios dispositivos a las mismas 2 líneas SDA y SCL (hasta 127), de modo que se consumen muy pocos pines del Arduino. Cada dispositivo I2C está identificado por una dirección o matrícula única de 7 bits (por esto el máximo son 127). ● En algunos dispositivos viene prefijada y en otros podemos establecerla mediante jumpers. Las líneas SDA y SCL requieren resistencia pull-up
I2C Protocolo comunicaciones ●
●
●
En cada instante, un dispositivo de la cadena actúa como maestro, y los demás como esclavos. El maestro inicia la comunicación bajando SDA antes que SCL Luego envía un byte comupuesto por el address del esclavo con el que quiere comunicar y el LSB que indica lectura (1) o escritura (0)
●
●
●
El esclavo contesta con un bit de aceptación (ACK) que consiste en mantener la línea de datos en LOW. A partir de ese instante comienza la comunicación, debiéndose realizar un ACK cada 8 bits. Para dar por concluida la comunicación, el maestro sube SCL antes que SDA
I2C Protocolo comunicaciones ●
Ejemplo de una escritura en un sensor inercial MPU6050 ● La dirección/matrícula de este sensor es 0x68 ●
El Arduino solicita escribir (8º bit = 0)
●
El Arduino escribe la dirección 0x3B
I2C La librería Wire ● ●
Arduino incluye la librería Wire especializada en comunicaciones I2C Sus principales métodos son: ● Wire.begin(): Inicializa la librería e identifica al Arduino como maestro de la cadena I2C ● Para escribir: – Wire.beginTransmission(matrícula): Inicia una comunicación de escritura con el esclavo identificado por matrícula. – Wire.write(cadena): Escribe una cadena de caracteres hacia el esclavo. – Wire.endTransmission(liberar): Termina la transmisión liberando el bus de de comunicaciones si liberar es true o manteniéndolo ocupado para que no pueda ser usado por otro maestro si es false. ● Para leer como maestro: – Wire.requestFrom(matrícula,cantidad,liberar): Inicia una comunicación de lectura con el esclavo identificado por matrícula y, a continuación, emite los pulsos de reloj necesarios para almacenar en el búfer la cantidad de bytes indicada, y termina la comunicación liberando o no el bus. – Wire.read(): Lee un byte del buffer de entrada I2C.
I2C La librería Wire ●
●
La librería Wire está diseñada para utilizar el módulo I2C hardware del Arduino, que presenta las líneas SDA y SCL en los pines que se resaltan en la siguiente imagen. No son dos parejas de pines SDA/SCL independientes, sino una sola que se presenta a través de pines duplicados. Consecuentemente, si utilizamos I2C no podemos usar los pines analógicos A4 ni A5.
Módulo sensores I2C Barómetro BMP180 – Inercial MPU6050 – Magnético HMC5883L ●
Obsérvese que este módulo incluye conversor para obtener alimentación de 3v3 y conversores de tensión para las líneas SDA y SCL
MPU6050 ¿Qué mide un acelerómetro? ●
●
Si dejamos el acelerómetro en reposo sobre una mesa y nos fijamos en la dirección vertical, sobre el acelerómetro estarán actuando la fuerza de la gravedad y la fuerza de reacción de la mesa, que se anulan entre sí y consecuentemente producen una aceleración total vertical nula… pero ésta no es la aceleración que mide el acelerómetro. El acelerómetro mide la fuerza que ejerce el muelle sobre la masa interior, que es igual a la gravedad de la masa pero de sentido contrario.
MPU6050 ¿Puede un acelerómetro indicarnos la actitud de un cuerpo? ●
Suponiendo el centro de gravedad del cuerpo no se desplazase, como la gravedad mantendría una dirección constante (hacia el centro de la Tierra) y el acelerómetro puede medir la descomposición de la gravedad en el sistema de referencia ligado a él, podríamos pensar que sí, pero existen 2 impedimentos para conocer la actitud con precisión: ● El acelerómetro no solo capta la gravedad, sino también cualquier otra aceleración que actúe sobre él, como el temblor de las manos de quién lo sujeta. ●
●
El acelerómetro no puede detectar giros alrededor de la dirección de la gravedad (giros de giñada), pues éstos no producen ninguna variación en las medidas. Pero sí puede medir cabeceo y alabeo.
MPU6050 ¿Qué mide un acelerómetro? ●
●
Mide la fuerza que muelles dispuestos a lo largo de cada uno de los ejes ejercen sobre una masa que hay en el interior del acelerómetro. Si un muelle se comprime, indica una aceleración en sentido contrario. ● Por ejemplo, en la imagen de la derecha, el acelerómetro registrará una aceleración positiva en sentido ascendente.
MPU6050 Sensor inercial I2C ●
● ● ●
Utiliza ADC de 16 bits para leer un acelerómetro de 3 ejes (con escalas de ±2g, ±4g, ±8g, y ±16g) y un giróscopo de 3 ejes (con escalas de ±250, ±500, ±1000, y ±2000°/sec). También incluye un sensor de temperatura. La matrícula de este sensor es 0x68 Registros de interés ● ● ● ● ● ●
107: Debemos escribir en él 0 para arrancar el sensor 27: Configuración del giróscopo 28: Configuración del acelerómetro 59 a 64: Lectura acelerómetro XYZ 65 y 66: Lectura termómetro 67 a 72: Lectura giróscopo XYZ
MPU6050 ¿Puede un acelerómetro indicarnos la actitud de un cuerpo? ●
●
●
●
●
El acelerómetro mide el resultado sobre los muelles de todas las fuerzas que intervienen sobre él, no sólo de la gravedad (no puede distinguirse la gravedad del efecto de esas otras fuerzas), y además no es capaz de captar los giros alrededor de la dirección de la gravedad, y por esto no puede indicarnos por sí solo la actitud. Por este motivo, el acelerómetro suele utilizarse en combinación con un giróscopo, que mide la velocidad angular de rotación del cuerpo. El giróscopo por sí solo sí sería capaz de indicarnos la actitud de un cuerpo con sólo integrar la velocidad angular, pero desafortunadamente esa integración introduce un corrimiento/error en los resultados que crece rápidamente con el tiempo. El giróscopo permite conocer la actitud a corto plazo; el acelerómetro permite conoce el cabeceo y alabeo cuando no hay otras fuerzas interviniendo aparte de la gravedad. Combinando la información del acelerómetro y del giróscopo a través de un filtro complementario, o mejor aún, de un filtro de Kalman puede obtenerse la actitud con mucha precisión. Para resolver el problema de que el acelerómetro no puede medir el ángulo de guiñada suele recurrirse a un magnetómetro.
MPU6050 Ejercicio: Cabeceo y alabeo con acelerómetro ●
Si asumimos que la única fuerza que actúa sobre el acelerómetro es la gravedad, resulta [muy] sencillo calcular los ángulos de cabeceo y alabeo recurriendo a la trigonometría ( http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf). ● cabeceo=atan2(Gx,sqrt(Gy*Gy+Gz*Gz))*180.0/pi; ●
●
alabeo=atan2(Gy,Gz)*180.0/pi;
Las lecturas que proporciona el MPU6050 están siempre en el rango -32768..32767, pero dependen de la escala que tengamos seleccionada. ●
En nuestro caso elegiremos la escala 2g, de modo que si la gravedad está perfectamente alineada con uno de los ejes, la lectura en ese eje debería ser la mitad de escala, es decir, aproximadamente 16.384.
MPU6050 Solución: Cabeceo y alabeo con acelerómetro ●
Empezamos conectando el módulo al Arduino como se indica en la siguiente figura. No es necesario añadir los pull-up de las líneas I2C porque están ya incluidos en el módulo.
MPU6050 Solución: Cabeceo y alabeo con acelerómetro ●
Tras importar la librería Wire para poder comunicarnos fácilmente mediante I2C, en el setup escribimos 0 en los registros 107 y 28 del MPU6050 para arrancarlo y configurar la escala 2g, respectivamente.
MPU6050 Solución: Cabeceo y alabeo con acelerómetro ●
En el loop, leemos los registros a partir del 59 para obtener la medidas del acelerómetro y calculamos los ángulos.
BMP180 Sensor de temperatura y presión I2C ●
●
●
Los sensores que utilizan comunicaciones más avanzadas (I2C y SPI) suelen hacerlo porque son más complejos; por ejemplo, incluyen decenas de registros (configuración, lecturas, cálculos…). En las diapositivas anteriores manejamos directamente la comunicación I2C para comunicarnos con el sensor MPU6050, pero ahora con el BMP180 vamos a recurrir a una librería para abstraernos de los detalles de más bajo nivel y poder concentrarnos en cuestiones más relevantes. La librería que vamos a utilizar es la desarrollada por la empresa Sparkfun: ● https://github.com/sparkfun/BMP180_Breakout ● Descargar el archivo BMP180_Breakout-master.zip ● Crear en la carpeta de librerías de Arduino una subcarpeta llamada BMP180 y copiar en ella los archivos/carpeta que se muestran en la figura.
BMP180 Para qué sirve un sensor de presión ● ●
El BMP180 puede medir la temperatura y la presión absoluta. La presión absoluta puede utilizarse para: ● Realizar predicciones meteorológicas si conocemos la altitud a la que nos encontramos: Altas presiones: Tiempo estable anticiclónico. – Bajas presiones: Tiempo borrascoso ciclónico. Calcular la altitud si conocemos la presión absoluta p0 al nivel de mar en el lugar donde nos encontramos. –
●
BMP180 La librería de Sparkfun ● ● ● ● ● ● ●
●
●
●
●
#include #include SFE_BMP180 miBMP180; //Crear un objeto double T,P;//Declarar esta variables como locales del loop miBMP180.begin(); //Inicializar el sensor Hay que conocer la temperatura para poder conocer la presión. miBMP180.startTemperature(); //Inicializa una medida de temperatura y devuelve el número de milisegundos que debemos esperar para obtener la lectura miBMP180.getTemperature(T); //Almacena en T la lectura de temperatura expresada en ºC miBMP180.startPressure(precision);//Inicia una medida de presión con la precisión indicada (del 0 al 3; la 3 es la máxima) y devuelve el número de milisegundos que debemos esperar para obtener la lectura. miBMP180.getPressure(P,T);//Almacena la presión expresada en hPa (hectopascales) en la variable P, utilizando para su cálculo el valor de temperatura aportado por T. miBMP180.sealevel(P,altitud);//Devuelve el valor corregido de la presión al nivel del mar del P obtenido a la altitud indicada. Este valor es el que se utiliza para las predicciones meteorológicas.
BMP180 Ejercicio ●
Crear un programa que muestre en el terminal serie la temperatura y la presión al nivel del mar del CRIF ● La altitud aproximada del CRIF es 635m
BMP180 Solución
SPI (Serial Peripheral Interface) El estándar SPI se diferencia del I2C fundamentalmente en: ● Sólo puede haber un maestro; el resto de los dispositivos de la cadena de comunicación son esclavos. ● La comunicación es full-duplex porque existe una línea para comunicación del maestro a los esclavos (MOSI-Master Out Slave In) y otra de contestación de los esclavos al maestro (MISO-Master In Slave Out). Puede haber comunicación en ambos sentidos simultáneamente ● Los esclavos no se identifican mediante matrículas, sino que se activan poniendo en LOW una línea individual para cada uno llamada SS (Slave Select). ● Consecuentemente, la comunicación SPI requiere 2 hilos de datos, un hilo para el reloj, y un hilo SS para cada esclavo. ● En general el estándar SPI se utiliza cuando se requieren velocidades de transmisión más rápidas que las alcanzables mediante I2C.
SPI (Serial Peripheral Interface) La librería SPI ●
Arduino incluye la librería SPI para facilitarnos las comunicaciones SPI, y sus principales métodos son: ● SPI.begin(): Inicializa la librería y los pines MO, MI y SCK, pero no el pin SS, que nos deberemos encargar de configurar manualmente como salida. ● SPI.beginTransaction(SPISettings(velocidad, orden, modo)): para iniciar la comunicación – Velocidad: Es la velocidad máxima de comunicación del dispositivo con el que queremos comunicarnos expresada en hercios. Por ejemplo, el ENC28J60 admite una velocidad máxima de 20.000.000 Hz. – Orden: Adquiere los valores MSBFIRST o LSBFIRST según queramos enviar primero los bits más significativos o los menos significativos, respectivamente. – Modo: Existen cuatro modos de comunicación SPI en función de cuándo se considera que el reloj está en reposo y en qué flanco se leen los datos. Este parámetro puede tener los valores SPI_MODE0, SPI_MODE1, SPI_MODE2 o SPI_MODE3, en función del dispositivo que utilicemos. Por ejemplo, el ENC28J60 usa el SPI_MODE0. ●
●
SPI.transfer(valor): Envía un valor al esclavo y devuelve la respuesta de éste. SPI.endTransaction(): Finaliza la comunicación SPI.
SPI (Serial Peripheral Interface) Pines en Arduino UNO ●
Las placas Arduino UNO incluyen un puerto SPI hardware que expone sus líneas en los pines destacados en la siguiente imagen.
Internet ●
●
Es una red en la que dispositivos diversos pueden intercambiar información. Fue diseñada para permitir la comunicación incluso aunque nodos intermedios dejen de estar disponibles (sean destruidos por fuerzas enemigas): ●
●
La información se fragmenta en paquetes de menor tamaño que requieren individualmente menor tiempo de transmisión. Los paquetes se enrutan a través de caminos que pueden ser diferente.
Internet La pila de protocolos TCP/IP ●
Para gobernar la comunicación en Internet se utiliza una pila de protocolos (stack) organizados en 4 capas: ● Aplicación: Formatea los datos adaptándolos a los humanos u otras aplicaciones ● Transporte: Vela por la integridad de la comunicación ● Internet: Se encarga del enrutamiento. ● Enlace: Gestiona los detalles físicos de la comunicación (direcciones MAC, electricidad, pulsos de luz...)
Internet Ejemplo de comunicación
Internet Direcciones IP ●
La versión 4 del protocolo TCP/IP utiliza direcciones de 4 bytes ●
●
El número máximo de direcciones diferentes (unos 4.000 millones) es insuficiente para la cantidad de dispositivos conectados a Internet actualmente. Como muchos de estos dispositivos no se conectan directamente a Internet, sino que conforman subredes menores que se conectan a Internet a través de un dispositivo denominado Router, no requieren que su dirección IP sea única en todo Internet, sino sólo dentro de su red menor. –
Dirección privada: Dirección IP de cada dispositivo dentro de su subred.
–
Dirección pública: Dirección IP del router, que sí es única en la red Internet.
Internet Gateway ●
Cada router es responsable de redirigir los paquetes que recibe a sus respectivos destinatarios, tanto desde Internet hacia la subred, como desde la subred a Internet, y también dentro de la propia subred. ● NAT – Network Address Translation ● Pero ¿Cómo sabe el router a quién tiene que enrutar los paquetes que van de la subred a Internet? – No lo sabe. Sólo sabe que se los tiene que enviar a un dispositivo especial, llamado Gateway, que ya sabrá qué hacer con ellos.
Internet Máscaras de subred ●
¿Cómo sabe un router si una dirección de destino pertenece a la propia subred o debe gestionarla el gateway? ● Dentro de las direcciones privadas se establece que una parte de la dirección es común para toda la subred, y otra parte diferente. Por ejemplo, en una red pequeña puede establecerse que los 24 bits más significativos sean comunes para todos los dispositivos y los 8 menos significativos identifiquen a cada dispositivo. – La máscara de subred establece qué parte es común y cuál variable. Un paquete dirigido a una dirección que no comparte la parte común de la subred, será dirigido al gateway para que se encargue de su transmisión. –
●
Internet Clases de subredes ●
Por convenio, en función del tamaño de las subredes se utilizan ciertos rangos de direcciones privadas: ● Clase C: Subredes de hasta 254 dispositivos ●
Clase B: Subredes de hasta 65.534 dispositivos
●
Clase A: Subredes de hasta 16.777.214 dispositivos.
Internet Puertos IP ●
●
Un mismo dispositivo puede atender peticiones de distintas aplicaciones; por ejemplo, peticiones HTTP y FTP. ¿Cómo distingue entre unas y otras? ●
●
Las peticiones deben ir acompañadas de un número de 16 bits, llamado puerto, que indique a qué servicio van destinadas. Por ejemplo, los servidores HTTP suelen usar el puerto 80 y los FTP el 21.
Internet Direcciones MAC ● ●
MAC: Machine Access Control Los routers y gateways se encargan de enrutar los paquetes hacia y desde Internet utilizando las direcciones IP, pero ¿cómo se realizan las comunicaciones internamente dentro de cada subred? Especialmente si tenemos en cuenta que la dirección IP de un dispositivo puede cambiar por distintos motivos. ● Cada dispositivo tiene asignada una dirección de 48 bits única y que no es modificable (en principio), llamada dirección MAC. ● Cada dispositivo conoce la relación entre las direcciones IP y las direcciones MAC de los dispositivos con los que se relaciona directamente, y así la capa de enlace sabe qué dirección MAC debe utilizar en el paquete. Estas relaciones se almacenan en una tabla llamada ARP (Address Resolution Protocol). ● En otras palabras: la dirección MAC se utiliza a nivel de subred, mientras que la dirección IP se utiliza para enrutar entre distintas redes.
Internet Direcciones IP vs MAC
Internet DNS ●
Como recordar los 32 bits de una dirección IP puede resultar difícil para una persona, se utilizan pseudónimos llamados nombres de dominio. ●
Por ejemplo, la dirección IP del servidor web de la comunidad de Madrid es 8.254.34.126, y su nombre de dominio es madrid.org.
Internet DHCP ●
●
En algunas redes de topología muy variable (por ejemplo, en redes WiFi en las que los usuarios cambian constantemente), en lugar de usar direcciones IP fijas, es preferible que un servidor se encargue de asignar una dirección IP a cada cliente cuando se conecte. Este proceso se realiza a través de un protocolo denominado DHCP. IP fija vs IP variable: Al contratar un servicio de acceso a Internet podemos solicitar que nos asignen una dirección IP fija (tiene un coste adicional) o consentir que se nos asigne una variable cada vez que nos conectemos.
Internet DDNS ●
Si un dispositivos tiene una dirección IP variable y necesitamos conectar con él pasados unos días, cuando posiblemente su dirección ya ha cambiado, ¿cómo lo conseguimos? ●
●
●
En lugar de dirigirnos a él por su dirección IP lo hacemos por su nombre de dominio. El dispositivo con IP variable debe hacer uso de un servicio llamado DDNS (con un coste adicional), que consiste en un servidor DNS al que envía su nueva IP cada vez que ésta cambia. De este modo, cuando nuestra petición de resolver el nombre de dominio llega a ese servidor DNS, éste sabe exactamente cuál es la dirección IP actual del destinatario.
Internet Resumen
ENC28J60 ●
●
●
●
●
El ENC28J60 es un dispositivo que se encarga de la capa de enlace para comunicaciones Ethernet de 10 Mb/s (10Base-T). Funciona a 3.3V, pero sus entradas son tolerantes a 5V. Requiere más de 100mA, por lo que no podemos alimentarlo a través de los pines de un Arduino si éste está alimentado por un puerto USB. Utiliza el protocolo de comunicaciones SPI. En nuestro módulo la línea SI está rotulada como ST.
ENC28J60 Librerías ●
●
●
●
●
Aunque el ENC28J60 nos resuelve la capa de enlace, aún tendríamos que encargarnos en el Arduino de las capas de Internet, Transporte y Aplicación, y esto no es ni mucho menos trivial. Por este motivo se recurre a librerías. Actualmente, la ideal para utilizar nuestro módulo ENC28J60 es la UIPEthernet, de la que existen ramas para Arduino 1 y Arduino 1.5 (aún no para Arduino 1.6). https://github.com/ntruchsess/arduino_uip/tree/Arduino_1.5.x Las librerías permiten que el Arduino actúe de servidor o de cliente, pero como consumen casi toda la memoria disponible, para utilizarlo como servidor suele ser necesario recurrir a sistemas de almacenamiento externo como tarjetas SD.
ENC28J60 Librería UIPEthernet ●
Los elementos fundamentales para usar esta librería son: ● #include ● Ethernet.begin(mac, ip, gateway, subnet); – Donde los parámetros son arrays de tipo byte; por ejemplo: ● byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; ● Ethernet.localIP() ● EthernetClient miCliente; – Crear un cliente que permite comunicarse con servidores IP . – miCliente.connect(URL, port): Conecta con el servidor. – miCliente.connected(): Indica si el cliente está conectado con el servidor. – miCliente.println(): Envía cadenas de caracteres al servidor. – miCliente.available(): Indica cuántos bytes aún no se han leído de la contestación del servidor al cliente. – miCliente.read(): Lee el primer byte disponible en el buffer de entrada. – miCliente.stop(): Detiene la conexión con el servidor.
ENC28J60 Librería UIPEthernet-Conexión Módulo ENC28J60
Arduino UNO
5V
5V
GND
GND
SO
Pin 12
SCK
Pin 13
SI/ST
Pin 11
RST
Reset
CS
Pin 10
ThingSpeak ●
Crear una cuenta en thingspeak.com
●
Crear un canal privado llamado Curso IoT
●
●
●
Configurar en ese canal un campo llamado Temperatura y otro Presión Obtener el ID y la clave del canal (API KEY). Introducir un par de datos en el canal accediendo con el navegador web a la dirección ●
●
http://api.thingspeak.com/update?key=[API KEY]&field1=[dato]&field2=[dato]
Comprobar el resultado accediendo a la dirección ●
https://api.thingspeak.com/channels/[ID CANAL]/feed.json?key=[API KEY]
SmartCityThing ●
Este servicio sólo acepta peticiones PUT
if (client.connect("www.smartcitything.es", 8081)) { client.print("PUT /data/OE_JUAN_FELIX/temperatura/"); client.print(String(T)); client.println(" HTTP/1.1"); client.println("Accept: */*"); client.println("Connection: Keep-Alive"); client.println("Host: www.smartcitything.es:8081"); client.println("IDENTITY_KEY: escribir_aqui_el_id"); client.println(); client.println();
Internet de las cosas ●
El módulo ESP8266
●
¡CUIDADO FUNCIONA A 3V3! No a 5V
ESP8266 Conexión básica ● ●
●
Usamos un LM1117 para conseguir 3v3 Con una red resistencia+Zener3v3 limitamos la tensión en el pin RX del ESP8266 El pin CH_PD del ESP8266 debe conectarse a +3V3
ESP8266 Comando básicos ●
● ● ● ● ● ● ● ● ● ●
http://wiki.iteadstudio.com/ESP8266_Serial_WIFI_Mod ule AT: Debe contestar OK AT+RST: Reset AT+GMR: Versión del firmware AT+CWMODE: Modo 1 station, 2 AP, 3 ambos AT+CWLAP: Listado de AP detectados AT+CWJAP: Unirse a un AP AT+CIFSR: Obtener la dirección IP AT+CIPSTAR: Configura una conexión TCP/UDP AT+CIPSEND: Envía datos AT+CIPCLOSE: Cierra la conexión TCP/UDP
ESP8266 Sesión con un programa Terminal ● ●
● ● ● ● ● ● ●
CoolTerm, RealTerm, Putty… IMPORTANTE: El ESP8266 conecta por defecto a 115200 AT+GRM AT+CWMODE=3 AT+CWLAP AT+CWJAP="SSID","PASSWORD" AT+CIFSR AT+CIPSTART="TCP","184.106.153.149",80 AT+CIPSEND=44 (Longitud de la cadena que vamos a mandar + 2 (\r\n) ●
●
GET /update?key=[API_KEY]&field1=[dato]
AT+CIPCLOSE
ESP8266 y ahora con Arduino ●
El ESP8266 consume tanto que tenemos que alimentarlo con su propio LMS1117-3v3 obteniendo la tensión del Vin del Arduino, que deberá tener conectado un pack de baterías o un transformador. ●
●
●
Si utilizamos un hub usb posiblemente no sea capaz de suministrar la corriente que el ESP8266 necesita.
El pin RX del ESP8266 tiene que emparejarse con el pin 1 del Arduino (a través de la resistencia y el diodo zener): El pin TX del ESP8266 tiene que conectarse directamente al pin 0 del Arduino.
ESP8266 y ahora con Arduino
¿Y si no me gusta escribir programas? ●
Scratch for Arduino ●
●
http://s4a.cat/
Minibloq ●
http://blog.minibloq.org/
Acceso directo a los puertos ●
●
Aunque Arduino crea una capa de abstracción sobre los pines, estos están internamente organizados en puertos. ●
Puerto B: B0..B5 en pines 8 a 15
●
Puerto C: C0..C6 en pines analógicos (A0..A5) y el reset (C6)
●
Puerto D: D0..D7 en pines 0 a 7
Para controlar cada puerto disponemos de 3 registros de 8 bits ●
●
●
DDRx (lectura y escritura): Un 1 configura el pin correspondiente como salida, un 0 como entrada PORTx (lectura y escritura): Establece el estado de salida de los pines (HIGH o LOW). No la tensión presente en el pin si está configurado como entrada. Al leerlo en un pin de entrada nos indica si está activada o no la pull-up. PINx (lectura): Nos indica el estado de un pin configurado como entrada. –
Aunque no puede escribirse, una escritura de un 1 a un bit de este puerto se traducirá en un cambio de estado del bit correspondiente el registro PORTx.
¿Por qué acceder directamente a los puertos? ● ●
●
●
Es mucho más rápido que hacerlo pin a pin. Cuando necesitamos cambiar el estado de varios pins exactamente en el mismo instante. Para conseguir que un pin cambie de estado muy rápidamente (realizar una escritura sobre PINx). Para ahorrar algo de memoria.