Arduino Teoría
Arduino Teoría
Este documento se basa en la traducción realizada por de Don José Manuel Ruiz del original Arduino
Notebook: A Beginner’s Reference Written and compiledby Brian W. Evans
Debemos recordar la total compatibilidad tanto con Arduino (dentro de USA) como con Genuino (nueva
marca para comercializar los productos originales Arduino fuera de USA), y con la mayoría de los fabricantes
de placas basadas en Atmel y compatibles con Arduino.
Este documento está acogido a una licencia de código libre o código abierto (Open Source), lo que da derecho
a no pagar por él ni por ninguna de las futuras evoluciones del mismo.
1/
El Lenguaje de programación de Arduino deriva del lenguaje "wiring" (que desciende a su vez de processing).
Se basa en C/C++
Arduino = Processing
Toda la información con respecto al lenguaje de programación que se emplea en Arduino se puede
encontrar en: http://arduino.cc/es/Reference
2/
Estructura de un programa:
La estructura básica de un programa de Arduino es sencilla y se compone de tres partes:
- Zona global
- La función voidsetup()
- La función voidloop()
En la figura de abajo se pude ver estas zonas de color blanco, gris y verde respectivamente después de haber
cargado un programa – ejemplo llamado blink (parpadeo) [Archivo → Ejemplos →01.Basics→Blink].
voidsetup() {
statements 1 ;
}
voidloop() {
instrucciones;
}
3/
La zona global es donde se indican a Arduino las librerías necesarias en donde aparecen las funciones que
vamos a usar en el programa principal. Los nombres de los pines, si son de entrada o salida, declaración e
inicialización de constantes y/o variables que queramos que existan en todo el programa (globales), etc.
La primera función principal es setup() que es la parte encargada de establecer la configuración inicial de
pines y módulos que se vayan a ejecutar posteriormente y loop() la segunda función principal, es la que
contiene el programa que se ejecutará cíclicamente (de ahí el termino loop –bucle-).
En varios programas, la zona global puede no tener código debido a la sencillez del programa pero las
funciones setup() y loop() son absolutamente necesarias para que el programa trabaje.
Los estamentos son las declaraciones, instrucciones, funciones etc. que forman el programa también llamado
código. También pueden ser operaciones aritméticas, booleanas, lógicas, etc.
La función de configuración setup() se ejecuta cada vez que se inicia Arduino (incluyendo al pulsar RESET).
Una de las operaciones que se realiza en voidsetup() es la de configurar de los pines que vamos a utilizar. Es la
primera función a ejecutar en el programa, se ejecuta sólo una vez, y se utiliza para configurar o inicializar los
terminales o pines E/S (con la función pinMode() - modo de trabajo de las E/S), configuración de la
comunicación en serie y otras.
La función siguiente loop() significa bucle (loop) y contiene el código que se ejecutara continuamente (lectura
de entradas (sensores), activación de salidas (actuadores), etc) Esta función es el núcleo de todos los
programas de Arduino y la que realiza la mayor parte del trabajo.
setup()
La función setup() se invoca una sola vez cuando el programa empieza. Se utiliza para inicializar los modos de
trabajo de los pins, el puerto serie, el visualizador LCD, etc. Debe ser incluido en un programa aunque no haya
declaraciones que ejecutar.
voidsetup()
{
pinMode(pin1, OUTPUT); // configura el 'pin1' como salida
pinMode(pin2, OUTPUT); // configura el 'pin2' como salida
pinMode(pin3, OUTPUT); pinMode(pin4, OUTPUT); pinMode(pin5, OUTPUT);
configura los 'pin3', 'pin4' , 'pin5' como salida
pinMode(pin6, OUTPUT); // configura el 'pin6' como entrada
}
loop()
Después de llamar a setup(), la función loop() hace precisamente lo que sugiere su nombre, se ejecuta de
forma cíclica, lo que posibilita que el programa este respondiendo continuamente ante los eventos que se
produzcan en la tarjeta hasta que le falte la alimentación de tensión.
voidloop() {
digitalWrite(pin, HIGH); // pone en uno (on, 5v) el ´pin´
delay(1000); // espera un segundo (1000 ms)
digitalWrite(pin, LOW); // pone en cero (off, 0v.) el ´pin´
delay(1000);
}
4/
Funciones:
Uno de las instrucciones u objetos de código que más se usan son las funciones. Existen funciones que
forman parte de las librerías por defecto de Arduino, otras que hay que cargar como librerías externas y las
propias o particulares dentro del programa que se pueden declarar y definir para que realicen una
determinada tarea.
Una función es un bloque de código que tiene un nombre y un conjunto de instrucciones que son ejecutados
cuando se llama a la función. Son funciones setup() y loop() de las que ya se ha hablado. Las funciones de
usuario pueden ser escritas para realizar tareas repetitivas y para reducir el tamaño de un programa. Las
funciones se declaran asociadas a un tipo de valor “type”. Este valor será el que devolverá la función, por
ejemplo 'int' se utilizará cuando la función devuelva un dato numérico de tipo entero. Si la función no devuelve
ningún valor entonces se colocará delante la palabra “void”, que significa “función vacía”. Después de declarar
el tipo de dato que devuelve la función se debe escribir el nombre de la función y entre paréntesis se
escribirán, si es necesario, los parámetros que se deben pasar a la función para que se ejecute, es decir, los
datos con los que puede o no trabajar la función.
typenombreFunción (parámetros)
{
sentencias;
}
Por ejemplo, la función siguiente devuelve un número entero, delayVal() se utiliza para poner un valor de
retraso en un programa que lee una variable analógica de un potenciómetro conectado a una entrada de
Arduino. Al principio se declara como una variable local, ´v´ recoge el valor leído del potenciómetro que estará
comprendido entre 0 y 1023, luego se divide el valor por 4 para ajustarlo a un margen comprendido entre 0 y
255, finalmente se devuelve el valor ´v´ y se retornaría al programa principal. Esta función cuando se ejecuta
devuelve el valor de tipo entero ´v´
int suma(int a, int b) // la function suma devuelve un entero y se le pasan dos números enteros
{
int suma; // crea una variable temporal 'suma'
suma = a + b; // almacena el resultado de la operación aritmética 'suma'
return suma; // devuelve el valor final
}
5/
Sintaxys2 básica:
Las llaves ({} ), sirven para definir el principio “{“ y el final “}” de un bloque de instrucciones. Se utilizan para
los bloques de programación setup(), loop(), if, while,..., etc.
typefuncion() {
instrucciones;
}
Los paréntesis “()” pueden no contener nada, sentencias lógicas, parámetros de funciones o instrucciones, en
operaciones lógicas o aritméticas, etc., pero siempre que haya un paréntesis de apertura, habrá su
correspondiente de cierre.
El entorno de programación de Arduino incluye una herramienta de gran utilidad para comprobar el total de
llaves. Sólo tienes que hacer clic en el punto de inserción de una llave o paréntesis abierta/o e inmediatamente
se marca el correspondiente cierre de ese bloque (llave o paréntesis cerrada/o).
El punto y coma“;” se utiliza para separar instrucciones en el lenguaje de programación de Arduino. También
se utiliza para separar elementos en una instrucción de tipo “bucle for”.
Nota: Olvidarse de poner fin a una línea con un punto y coma se traducirá en un error de compilación. El texto
de error puede ser obvio, y se referirá a la falta de una coma, o puede que no. Si se produce un error raro y de
difícil detección lo primero que debemos hacer es comprobar que los puntos y comas están colocados al final
de las instrucciones.
Los bloques de comentarios (/*… */), o multi-línea de comentarios, son áreas de texto ignorados por el
programa que se utilizan para las descripciones del código o comentarios que ayudan a comprender el
programa. Comienzan con / * y terminan con */ y pueden abarcar varias líneas.
Nota: Dentro de una misma línea de un bloque de comentarios no se puede escribir otra
Una línea de comentario empieza con // y terminan con la siguiente línea de código (cambio de línea y retorno
de carro). Al igual que los comentarios de bloque, los de línea son ignorados por el programa y no ocupan
espacio en la memoria.
// ésto es un comentario
2
Nota: Hay un artículo en la documentación para leer titulado “Arduinostyle Guide” que, aunque está en inglés, ayuda con consejos para
mejorar la escritura de programas para Arduino.
6/
Una línea de comentario se utiliza a menudo después de una instrucción, para proporcionar más información
acerca de lo que hace ésta o para recordarla más adelante.
Variables:
Definición de una variable:
Una variable es un espacio de memoria que se reserva y nos permite almacenar en él datos que pueden ir
cambiando a lo largo del programa. El espacio de memoria reservado se denomina con un nombre y ocupa en
función del tipo de dato que se vaya a almacenar. Una variable debe ser declarada y, opcionalmente, asignarle
un valor. El siguiente código de ejemplo declara una variable llamada variableEntrada de tipo entero (que
puede almacenar un número enter) y luego le asigna el valor obtenido en la entrada analógica del PIN2:
'variableEntrada' es la variable en sí. La primera línea declara que será de tipo entero “int” y la inicializa con un
valor de 0. La segunda línea fija a la variable el valor correspondiente a la entrada analógica PIN2. Esto hace
que el valor de PIN2 sea accesible en otras partes del código.
Una vez que una variable ha sido asignada, se puede probar su valor para ver si cumple ciertas condiciones
(instrucciones if..), o puede utilizar directamente su valor. Como ejemplo ilustrativo veamos tres operaciones
útiles con variables: el siguiente código prueba si la variable “entradaVariable” es inferior a 100, si es cierto se
asigna el valor 100 a “entradaVariable” y, a continuación, establece un retardo (delay) utilizando como valor
“entradaVariable” que ahora será como mínimo de valor 100:
Nota: Las variables deben tomar nombres descriptivos, para hacer el código más legible. Nombres de variables
pueden ser “contactoSensor” o “pulsador”, para ayudar al programador y a cualquier otra persona a leer el
código y entender lo que representa la variable. Nombres de variables como “var” o “valor”, facilitan muy poco
que el código sea inteligible. Una variable puede ser cualquier nombre o palabra que no sea una palabra
reservada en el entorno de Arduino.
Declaración de variables:
Todas las variables tienen que declararse antes de que puedan ser utilizadas. Para declarar una variable se
comienza por definir su tipo como int (entero), long (largo), float (coma flotante), etc, asignándoles siempre un
nombre, y, opcionalmente, un valor inicial. Esto sólo debe hacerse una vez en un programa, pero al ser una
variable, el valor de la misma se puede cambiar en cualquier momento usando aritmética y reasignaciones
diversas.
El siguiente ejemplo declara la variable “entradaVariable” como una variable de tipo entero “int”, y
asignándole un valor inicial igual a cero. Esto se llama una asignación.
7/
intentradaVariable = 0;
Una variable puede ser declarada en una serie de lugares del programa y en función del lugar en donde se
lleve a cabo la definición esto determinará en que partes del programa se podrá hacer uso de ella. Pueden ser
globales o locales.
Una variable global es aquella que puede ser vista y utilizada por cualquier función y estamento de un
programa. Esta variable se declara al comienzo del programa, antes de setup().
Una variable local es aquella que se define dentro de una función o como parte de un bucle. Sólo es visible y
sólo puede utilizarse dentro de la función en la que se declaró.
Por lo tanto, es posible tener dos o más variables del mismo nombre en diferentes partes del mismo programa
que pueden contener valores diferentes. La garantía de que sólo una función tiene acceso a sus variables
dentro del programa simplifica y reduce el potencial de errores de programación.
El siguiente ejemplo muestra cómo declarar a unos tipos diferentes de variables y la visibilidad de cada
variable:
Tipos de variables:
En función del tipo de variable el compilador reservará memoria con el nombre de la variable para esa variable
voidfuncion()
byte Variable que almacena un valor numérico de tipo entero de 8 bits (1 byte) sin decimales y sin signo.
Tienen un rango entre 0 y 255 (va desde 0000 0000 al 1111 1111 en binario)
8/
bytevar = 180; // declara 'var' como tipo byte
bytevar = Bxxxxxxxx; // “B es el formateador binario (B00010100 = 20 decimal)
char (carácter) Ocupa 1 byte y permite almacenar caracteres, dígitos alfanuméricos, signos de puntuación,
etc, (al ser almacenado se convierte en número y usa la tabla ASCII para pasarlo a carácter)
char car = ‘b’; se declara “car” de tipo carácter y se inicializa con el carácter ‘b’ (código 97 den dec.)
char letra = 45; se declara “letra” de tipo carácter y se inicializa con el carácter ‘E’ (código 45 den dec.)
int Datos de tipos entero. Almacenan valores numéricos de 16 bits (2 bytes) sin decimales
comprendidos en el rango 32,767 (215 -1) a -32,768 (-215 ).
int var = 1500; // declara 'var' como una variable de tipo entero y la inicializa a 1500
Nota: Las variables de tipo entero “int” pueden sobrepasar (overflow) su valor máximo o mínimo como
consecuencia de una operación. Por ejemplo, si x = 32767 y una posterior declaración agrega 1 a x, x = x + 1
entonces el valor se x pasará a ser -32.768. (algo así como que el valor da la vuelta, se produce overflow)
long Entero largo. El formato de variable numérica de tipo extendido “long” se refiere a números
enteros (tipo 32 bits) sin decimales que se encuentran dentro del rango -2147483648 a 2147483647.
unsignedlong Entero largo sin signo. (entero 32bit sin signo, desde 0 a 4,294,967,295)
Existen también otros nombres para los anteriores tipos de datos. Consultar en el foro de
Arduinohttps://forum.arduino.cc/index.php?topic=41590.0 y https://oscarliang.com/arduino-difference-byte-
uint8-t-unsigned-cha/
float Ocupa 4 bytes (32 bits). El formato de dato del tipo “punto flotante” “float” se aplica a los números
con decimales. Los números de punto flotante tienen una mayor resolución que los de 32 bits con un rango
comprendido 3.4028235E +38 a +38-3.4028235E.
9/
floatunaVariable = 3.14; // declara 'unaVariable' como tipo flotante
Nota: Los números de punto flotante no son exactos, y pueden producir resultados extraños en las
comparaciones. Los cálculos matemáticos de punto flotante son también mucho más lentos que los del tipo de
números enteros, por lo que debe evitarse su uso si es posible.
double En el caso de Arduino, es lo mismo que float pero en C o C++, double ofrece doble precisión, es
decir, es un float con doble precisión.
String (cadena de caracteres) Es un conjunto de caracteres todos seguidos que termina con el carácter ‘\0’
llamado carácter Null o fin de cadena o ASCII(0).
La diferencia es que en caso de definirlas con arrays[] hay que incluír el ‘\0’ final de cadena.
Esto es hablando extrictamente del Ansi “C” o standard “C”. Este carácter no se visible y tampoco se
puede imprimir ya que se usa como fin de cadena. Las funciones print y println están compliladas en sus
librerías de manera buscan ese carácter para saber cuándo finaliza la impresión, o la unión de cadenas , las
funciones que manipulan cadenas en general. Cuando deben mandar algo al puerto Serie , previamente le
agregan en Null antes de llamar a la librería, en el sistema Arduino ( Ojo esto es solo en las funciones
print/println) ya que tratan al argumento como cadenas, no ocurre así con o tras funciones que
manipulan cadenas pues suponen que lo son.
Tenemos un arreglo de caracteres sin fin de cadena y datos que es una cadena
10/
array Un array o matriz (también llamado vector) de valores es un conjunto de variables ordenadas del
mismo tipo a las que se accede con un número índice. El tipo del array de variables se indica al principio, sigue
el nombre del array seguido de unos corchetes. Dentro de los corchetes puede haber un número 3 que indica el
número de elementos (variables) que contiene el array o bien estar vacío, en este último caso al array se le
inicializa con valores.
Cualquier valor puede ser recogido y referenciado haciendo uso del nombre de la matriz y el número del
índice. El primer valor de la matriz es el que está indicado con el índice 0, es decir el primer valor del conjunto
es el de la posición 0. Un array tiene que ser declarado y opcionalmente asignados valores a cada posición
antes de ser utilizado.
p.e. si queremos almacenar 5 datos de temperatura, al ser valores con parte entera y decimal el tipo del array
será float, y su queremos inicializarla, es decir, asignar desde el principio los valores que va a contener el array
sería:
Se han creado unas posiciones de memoria cuya denominación es el nombre del array con su subíndice y
contiene los datos de inicialización.
Lista_val_Temp[0] 18.60
Lista_val_Temp[1] 19.58
Lista_val_Temp[2] 20.14
Lista_val_Temp[3] 22.56
Lista_val_Temp[4] 24.57
Del mismo modo es posible declarar una matriz indicando el tipo de datos y el tamaño y posteriormente,
asignar valores a una posición especifica:
Cuando se trata de array de caracteres el procedimiento es idéntico. Lo que distingue simplemente un array
de caracteres y una cadena, es que la cadena es un array de caracteres + el último elemento Null o ‘\0’.
I nicialización de Arrays
Se pueden declarar arrays[] y asignar más tarde o directamente declarar y asignarle los elementos,
vemos los casos posibles:
Caso 1: Declaración solamente y posterior inicialización
int precios [4];
precios[0]=10; precios[1]=24; precios[2]=10045; precios[3]=0;
Caso 2: Declaración e inicialización
intprecios[4]={10,24,10045,0};
Caso 3: Declaración e inicialización ( sin dimensión)
int precios[]={10,24,10045,0};
Arduino – Strings
https://www.tutorialspoint.com/arduino/arduino_strings.htm
12/
Las matrices se utilizan a menudo para instrucciones de tipo bucle, en los que la variable de incremento del
contador del bucle se utiliza como índice o puntero del array.
El siguiente ejemplo básico se inicializa un array de números enteros con y se realizan operaciones entre ellos
para variar su contenido. Se visualiza por el puerto serie antes y después de las operaciones el contenido del
array.
void setup(){
Serial.begin(9600);
}
voidloop(){
// visualizamos primero los valores iniciales del array de enteros
Serial.print("Los valores iniciales del array son: ");
for(inti=0; i<=4; i++){
Serial.print('\t');
Serial.print(lista_enteros[i]);
}
// realizamos operaciones de modificación de los elementos:
lista_enteros[4] = -27;
lista_enteros[2] = lista_enteros[1]/4;
lista_enteros[3] -= 3;
Utilizando un bucle tipo for, el contador comienza en cero 0 y escribe el valor que figura en la posición de
índice 0 en la serie que hemos escrito dentro del arrayparpadeo[], en este caso 180, que se envía a la salida
analógica tipo PWM configurada en el PIN10, se hace una pausa de 200 ms y a continuación se pasa al
siguiente valor que asigna el índice “i”.
voidsetup() {
pinMode(ledPin, OUTPUT); //configura la salida PIN 10
13/
}
/* Prct_Ejemplo_Variables_01.ino
Código ejemplo que visualiza por el monitor serie los diferentes tipos de datos.
*/
intnum_ent = 32767.6; // es el límite superior y no devolverá decimal
unsignedintnum_entss = 0.3; // devuelve solo la parte entera
word palabra1 = 12.35; // solo vale la parte entera.
longnum_entlarg = 3344523451;
unsigned long num_entlargss = 2945544345;
floatnum_flotante = 4.35654689971;
doublenum_doble = -74.2645654689971;
char letra1 = 'H';
char letra2 = 73;
String saludo = "¡Hola Vaxka! !Qué tal estais coleguitas¡";
void setup(){
Serial.begin(9600);
14/
… con la siguiente salida:
Realizar los ejemplos de display 7 segmentos y sacar por serial cadenas de caracteres como arrays.
Consultas en:
- http://arduino.cc/es/Reference/ASCIIchart
- http://arduino.cc/es/
- Más ejemplos en
https://gist.github.com/fairchild/94327/2f51486f19d5eeb96dfc701c7f46821cdeac4e22
Ejercicios:
15/
Aritmética:
Los operadores aritméticos que se incluyen en el entorno de programación son suma, resta, multiplicación,
división y resto. Estos devuelven la suma, diferencia, producto, cociente y resto (respectivamente) de dos
operandos:
Elija el tamaño de las variables de tal manera que sea lo suficientemente grande como para que los resultados
sean lo precisos que usted desea. Para las operaciones que requieran decimales utilice variables tipo float,
pero sea consciente de que las operaciones con este tipo de variables son más lentas a la hora de realizarse el
cómputo.
Nota: Utilice el operador (int) myFloat para convertir un tipo de variable a otro sobre la marcha. Por ejemplo,
i = (int) 3,6 establecerá i igual a 3.
16/
Asignaciones compuestas:
Así se denominan porque combinan una operación aritmética con una variable asignada. Estas son
comúnmente utilizadas en los bucles tal como se describe más adelante. Estas asignaciones compuestas
pueden ser:
Nota: Por ejemplo, x * = 3 hace que x se convierta en el triple del antiguo valor x y por lo tanto x es reasignada
al nuevo valor.
Operadores de comparación:
Las comparaciones de una variable o constante con otra se utilizan con frecuencia en las estructuras
condicionales del tipo if..para testear si una condición es verdadera. En los ejemplos que siguen en las
próximas páginas se verá su utilización práctica usando los siguientes tipo de condicionales:
x == y // x es igual a y
x != y // x no es igual a y
x < y // x es menor que y
x > y // x es mayor que y
x <= y // x es menor o igual que y
x >= y // x es mayor o igual que y
Operadores lógicos
Los operadores lógicos son usualmente una forma de comparar dos expresiones y devolver un VERDADERO o
FALSO dependiendo del operador. Existen tres operadores lógicos, AND (&&), OR (||) y NOT (!), que a
menudo se utilizan en estamentos de tipo if..:
Logical AND:
if (x > 0 && x < 5) // cierto sólo si las dos expresiones son ciertas
Logical OR:
if (x > 0 || y > 0) // cierto si una cualquiera de las expresiones es cierta
Logical NOT:
if (!x > 0) // cierto solo si la expresión es falsa
17/
Constantes (palabras reservadas):
El lenguaje de programación de Arduino tiene unos valores predeterminados, que son llamados constantes
y palabras reservadas. Se utilizan para hacer los programas más fáciles de leer. En el anexo V hay una
relación de palabras y constantes reservadas en Arduino que también se pueden consultar en este enlace
Estas son constantes booleanas que definen los niveles HIGH (alto) y LOW (bajo) cuando estos se refieren al
estado de las salidas digitales. false se asocia con 0 (cero), mientras que true se asocia con 1, pero para ser
exactos, true también puede ser cualquier otra cosa excepto cero, es decir, todo lo que sea diferente de 0
es verdadero o cierto a nivel lógico o booleano. Por lo tanto, en sentido booleano o lógico, -1, 2 y -200 son
valores que también se define como true. (esto es importante tenerlo en cuanta).
if (b == true);
{
ejecutar las instrucciones;
}
Estas constantes definen los niveles de salida altos o bajos y se utilizan para la lectura o la escritura digital
para las patillas. HIGH o ALTO se define como en la lógica de nivel 1, ON, ó 5 voltios, mientras que LOW o
BAJO es lógica nivel 0, OFF, o 0 voltios.
Estas constantes son utilizadas para definir, al comienzo del programa, el modo de funcionamiento de los
pines mediante la instrucción-función pinMode() de tal manera que el pin puede ser una entrada INPUT o
una salida OUTPUT.
18/
Estructuras de control o condicionales:
Son unas instrucciones que modifican la dirección secuencial de ejecución del código. Las hay de
bifurcación, iteración, etc. Se denominan también condicionales porque normalmente van asociadas al
cumplimiento de una condición lógica.
if () si() https://www.arduino.cc/en/Reference/If
La instrucción “if” es una instrucción que se utiliza para comprobar si una determinada condición lógica
encerrada entre paréntesis se cumple. Es la instrucción típica de bifurcación. Se usa por ejemplo para
comprobar si una determinada variable es mayor, menor o igual –simbolos de comparación- que un
determinado valor, si la condición es cierta ejecuta una serie de declaraciones (operaciones) o instrucciones
que se escriben dentro de llaves. Si es falsa (la condición no se cumple) y el programa salta a la siguiente
instrucción y no ejecuta las operaciones que están dentro de las llaves, El formato para if es el siguiente:
if ( condición_lógica)
{
Instrucciones a ejecutar ….;
}
Ejemplo: Supongamos que queremos que se active una salida digital (en el pin 9) con un nivel alto si una
cierta variable x es mayor de 127. El código sería el siguiente:
if ( x > 127)
{
digitalWrite(9, HIGH);
}
Nota: Tenga en cuenta el uso especial del símbolo '=', poner dentro de if (x = 10), podría parecer que es
válido pero sin embargo no lo es ya que esa expresión asigna el valor 10 a la variable x, por eso dentro de la
estructura if se utilizaría X==10 que en este caso lo que hace el programa es comprobar si el valor de x es
10. Ambas cosas son distintas por lo tanto dentro de las estructuras if, cuando se pregunte por un valor se
debe poner un signo lógico de comparación; de igual “==”, mayor o igual que “>=”, etc.
if....esle...(si....sino.....) https://www.arduino.cc/en/Reference/Else
if... else viene a ser un estructura que se ejecuta en respuesta a la idea “si esto no se cumple haz esto otro”.
Por ejemplo, si se desea probar una entrada digital, y hacer una cosa si la entrada fue alto o hacer otra cosa
si la entrada es baja, usted escribiría que de esta manera:
else puede ir precedido de otra condición de manera que se pueden establecer varias estructuras
condicionales de tipo unas dentro de las otras (anidamiento) de forma que sean mutuamente excluyentes
pudiéndose ejecutar a la vez. Es incluso posible tener un número ilimitado de estos condicionales . Recuerde
sin embargo qué sólo un conjunto de declaraciones se llevará a cabo dependiendo de la condición probada.
19/
En el ejemplo que se muestra a continuación, se lee el valor de una señal de entrada analógica que puede
variar entre 0 y 1023 correspondiendo a un valor entre 0v y 5v respectivamente. Queremos que detecte los
valores de entrada por debajo de 2v (se encienda el led rojo) detectar nivel Bajo (“0” o LOW), entre 2v y 3v
(se encienda el led Azul) nivel indeterminado y mayor de 3v para detectar nivel alto (“1” o HIGH).
// Voltimetro_TTL_00
bytepinPot = A2;
intledV = 7;
intledA = 6;
intledR = 5;
intvalPot = 0;
voidsetup() {
Serial.begin(9600);
voidloop() {
20/
Modificar el programa de tal forma que se ajuste a los valores de salida normalizados en TTL para nivel alto
(entre 2,0v y 5.0v) y para nivel bajo (entre 0.0v y 0.8v).
Similar al if pero compara el valor de la variable con un valor especificado en la sentencias case. Cuando
coincida el valor con una de las sentencia case se ejecutará el código que contenga terminando éste en una
última sentencia break;. Si ninguna de los case coincide puede haber una última opción denominada default
con el conjunto de sentencias y finalizado por un break;.
switch (var) {
case 1: //hacer algo cuando var sea igual a 1
break;
case 2: //hacer algo cuando var sea igual a 2
break;
default: // si nada coincide, ejecuta el "default" // el "default" es opcional
}
La declaración for se usa para repetir un bloque de sentencias encerradas entre llaves un número
determinado de veces. Cada vez que se ejecutan las instrucciones del bucle se vuelve a testear la condición.
La declaración for tiene tres partes separadas
por (;)
for (int i=0; i<20; i++) // declara i, prueba que es menor que 20, incrementa i en 1
{
digitalWrite(13, HIGH); // envía un 1 al pin 13
delay(250); // espera 1⁄4 seg.
digitalWrite(13, LOW); // envía un 0 al pin 13
delay(250); // espera 1⁄4 de seg.
}
Nota: El bucle en el lenguaje C es mucho más flexible que otros bucles encontrados en algunos otros
lenguajes de programación, incluyendo BASIC. Cualquiera de los tres elementos de cabecera puede
omitirse, aunque el punto y coma es obligatorio. También las declaraciones de inicialización, condición y
expresión puede ser cualquier estamento válido en lenguaje C sin relación con las variables declaradas.
Estos tipos de estados son raros pero permiten disponer soluciones a algunos problemas de programación
raras.
21/
Ejercicio: realiza un sistema con Arduino que detecte visualmente y por el puerto serie los valores pares
entre 0 y 100.
Un bucle del tipo while es un bucle de ejecución continua mientras se cumpla la expresión colocada entre
paréntesis en la cabecera del bucle. La variable de prueba tendrá que cambiar para salir del bucle. La
situación podrá cambiar a expensas de una expresión dentro el código del bucle o también por el cambio de
un valor en una entrada de un sensor
El siguiente ejemplo testea si la variable "unaVariable” es inferior a 200 y, si es verdad, ejecuta las
declaraciones dentro de los corchetes y continuará ejecutando el bucle hasta que 'unaVariable' no sea
inferior a 200.
El bucle do …while funciona de la misma manera que el bucle while, con la salvedad de que la condición se
prueba al final del bucle, por lo que el bucle siempre se ejecutará al menos una vez.
do
{
Instrucciones;
} while (unaVariable ?? valor);
El siguiente ejemplo asigna el valor leído leeSensor() a la variable 'x', espera 50 milisegundos, y luego
continua mientras que el valor de la 'x' sea inferior a 100:
do
{
x = leeSensor
delay(50);
} while (x < 100);
22/
Instrucciones de funciones básicas.
Las funciones que se relacionan a continuación, son instrucciones-funciones básicas que proporciona el
entorno, muy utilizadas a la hora de configurar, leer y escribir en los pines de entrada/salida, retardos,
operar matemáticamente con datos, comunicar con el terminal serie, etc. Se agrupan con diferentes grupos
según su funcionalidad.
Esta instrucción es utilizada en la parte de configuración setup () y sirve para configurar el modo de
trabajo de un PIN pudiendo ser INPUT (entrada) u OUTPUT (salida).
Los terminales de Arduino, por defecto, están configurados como entradas, por lo tanto no es necesario
definirlos en el caso de que vayan a trabajar como entradas. Los pines configurados como entrada quedan,
bajo el punto de vista eléctrico, como entradas en estado de alta impedancia.
Estos pines tienen a nivel interno una resistencia de 20 KΩ a las que se puede acceder mediante software.
Estas resistencias se accede de la siguiente manera:
Las resistencias internas normalmente se utilizan para conectar las entradas a interruptores. En el ejemplo
anterior no se trata de convertir un pin en salida, es simplemente un método para activar las resistencias
interiores.
Los pins configurado como OUTPUT (salida) se dice que están en un estado de baja impedancia esta do y
pueden proporcionar 40 mA (miliamperios) de corriente a otros dispositivos y circuitos. Esta corriente es
suficiente para alimentar un diodo LED (no olvidando poner una resistencia en serie), pero no es lo
suficiente grande como para alimentar cargas de mayor consumo como relés, solenoides, o motores.
Un cortocircuito en las patillas Arduino provocará una corriente elevada que puede dañar o destruir el chip
Atmega. A menudo es una buena idea conectar en la OUTUPT (salida) una resistencia externa de 470 o de
1000 Ω.
Es muy importante saber el tipo de señal presente en las entradas y el tipo de señal que se quiere en las
salidas según sea su naturaleza analógica o digital.
digitalRead(pin)
Lee el valor de un pin (definido como digital) dando un resultado HIGH (alto) o LOW (bajo). El pin se puede
especificar ya sea como una variable o una constante (0-13).
valor = digitalRead(Pin); // hace que 'valor sea igual al estado leído en ́Pin ́
digitalWrite(pin, value)
Envía al p
́ in ́ definido previamente como OUTPUT el valor HIGH o LOW (poniendo en 1 o 0 la salida). El pin
se puede especificar ya sea como una variable o como una constante (0-13).
23/
El siguiente ejemplo lee el estado de un pulsador conectado a una entrada digital y lo escribe en el ́pin d
́ e
salida LED:
analogRead(pin)
Lee el valor de tensión en el pin analógico especificado. La placa Arduino posee 6 canales conectados a un
conversor analógico digital de 10 bits (resolución de 10 bits (2 10 =1024). Esto significa que convertirá
tensiones entre 0 y 5 voltios a un número entero entre 0 y 1023. Esto proporciona una resolución en la
lectura de: 5 voltios / 1024 unidades, es decir, 0.0049 voltios (4.9mV) por unidad. El rango de entrada
puede ser cambiado usando la función analogReference().
Nota: Los pins analógicos (0-5) a diferencia de los pines digitales, no necesitan ser declarados como INPUT u
OUPUT ya que son siempre INPUT ś .
analogWrite(pin, value)
Consulta cuantos y cuales pines tiene el Arduino Mega como salidas PWM.
Si enviamos el valor 0 genera una salida de 0 voltios en el pin especificado; un valor de 255 genera una
salida de 5 voltios de salida en el pin especificado. Para valores de entre 0 y 255, el pin saca tensiones entre
24/
0 y 5 voltios - el valor HIGH de salida equivale a 5v (5 voltios). Teniendo en cuenta el concepto de señal
PWM , por ejemplo, un valor de 64 (=1/4 de 256) equivaldrá a mantener 0 voltios de tres cuartas partes del
tiempo y 5 voltios a una cuarta parte del tiempo; un valor de 128 equivaldrá a mantener la salida en 0 la
mitad del tiempo y 5 voltios la otra mitad del tiempo, y un valor de 192 (=3/4 de 256) equivaldrá a
mantener en la salida 0 voltios una cuarta parte del tiempo y de 5 voltios de tres cuartas partes del tiempo
restante. Ver Anexo III.
Debido a que esta es una función de hardware, en el pin de salida analógica (PWN) se generará una onda
constante después de ejecutada la instrucción analogWrite hasta que se llegue a ejecutar otra instrucción
analogWrite (o una llamada a digitalRead o digitalWrite en el mismo pin).
Nota: Las salidas analógicas a diferencia de las digitales, no necesitan ser declaradas como INPUT u
OUTPUT..
El siguiente ejemplo lee un valor analógico de un pin de entrada analógica, convierte el valor dividiéndolo
por 4, y envía el nuevo valor convertido a una salida del tipo PWM o salida analógica:
Funciones-instrucciones de tiempo.
Aunque existe una librería específica de funciones de tiempo time.h, hay dos funciones que se usan mucho
inicialmente y no necesitan cargar esa librería.
delay(ms)
Detiene la ejecución del programa la cantidad de tiempo en milisegundos que se indica en la propia
instrucción. De tal manera que 1000 equivale a 1seg.
millis()
Devuelve el número de milisegundos transcurrido desde el inicio del programa en Arduino hasta el
momento actual. Normalmente será un valor grande (dependiendo del tiempo que esté en marcha la
aplicación después de cargada o después de la última vez que se pulsó el botón “reset” de la tarjeta), es por
ello que la variable donde se almacene ese valor se ha de declarar como unsignedlong
Nota: Este número se desbordará (si no se resetea de nuevo a cero), después de aproximadamente 9 horas.
25/
Funciones-instrucciones matemáticas.
Aunque existe una librería específica de funciones para operaciones matemáticas math.h, hay funciones
que se usan mucho inicialmente y no necesitan cargar esa librería.
map()
Es una de las funciones más útiles. Se utiliza cuando queremos situar un valor dentro de un rango dado, en
otro rango especificado de forma proporcional.
Dos rangos que vamos a usar mucho son: como rango de valores posibles en entradas analógicas desde 0 a
1023 y como rango de valores posibles en salidas pseudo-analógicas (salidas PWM) entre 0 y 255. Así pues,
si recogemos un valor de entrada y queremos “mapearlo” en un valor proporcional de salida según los
rangos anteriormente descritos tendríamos que escribir:
Ejercicio: escribe la expresión matemática si quisiera mapear el valor=980 del rango 0-1023 al valor
equivalente en el rango 0-255.
x=(980x255)/1023=244
Ejercicio: Reflexiona la expresión matemática que nos mapearía un valor dentro de un rango X a otro rango
Y.
min(x, y)
Calcula el mínimo de dos números para cualquier tipo de datos devolviendo el número más pequeño.
valor = min(valor, 100); // asigna a valor el más pequeños de los dos números especificados.
Si 'valor' es menor que 100 valor recogerá su propio valor si v́ alor ́ es mayor que 100 valor pasara a valer
100.
max(x, y)
Calcula el máximo de dos números para cualquier tipo de datos devolviendo el número mayor de los dos.
valor = max(valor, 100); // asigna a valor el mayor de los dos números 'valor' y 100.
De esta manera nos aseguramos de que valor será como mínimo 100.
randomSeed(seed)
Debido a que Arduino es incapaz de crear un verdadero número aleatorio, randomSeed le permite colocar
una variable, constante, u otra función de control dentro de la función random, lo que permite generar
números aleatorios "al azar". Hay una variedad de semillas, o funciones, que pueden ser utilizados en esta
función, incluido millis () o incluso analogRead () que permite leer ruido eléctrico a través de un pin
analógico.
El siguiente ejemplo genera un valor aleatorio entre 0-255 y lo envía a una salida analógica PWM :
intrandNumber;
intled = 10; // variable que almacena el valor aleatorio // define led como 10
voidsetup() {} // no es necesario configurar nada
voidloop()
{
randomSeed(millis()); // genera una semilla para aleatorio a partir de la función millis()
randNumber = random(255); // genera número aleatorio entre 0-255
analogWrite(led, randNumber); // envía a la salida led de tipo PWM el valor
delay(500); // espera 0,5 seg.
}
Otras instrucciones.
return:
Esta instrucción termina una f unción y retorna un valor desde una f unción a la f unción llamada,
si se desea.
Syntax:
return;
return value; // ambas son válidas
El ejemplo que incorpora es el de una función que compara la señal de entrada de un sensor con un umbral determinado
(400)
int checkSensor(){
if (analogRead(0) > 400) {
return 1;
else{
return 0;
}
}
27/
Funciones-instrucciones de comunicación con el puerto serie.
Se utiliza para la comunicación entre la placa Arduino y un ordenador u otros dispositivos. Todas las placas
Arduino tienen al menos un puerto serie Serial. Se comunica a través de los pines digitales 0 (RX) y 1 (TX),
así como con el ordenador mediante USB. Por lo tanto, si utilizas estas funciones, no puedes usar los pines 0
y 1 como entrada o salida digital.
Puedes utilizar el monitor del puerto serie incorporado en el entorno Arduino para comunicarte con la placa
Arduino. Hacer clic en el botón del monitor de puerto serie en la barra de herramientas y seleccionar la
misma velocidad en baudios utilizada en la llamada a begin().
Serial.begin(rate)
Abre el puerto serie y fija la velocidad en bits por segundo (baudios) para la transmisión de datos en serie.
El valor típico de velocidad para comunicarse con el ordenador es 9600, aunque otras velocidades pueden
ser soportadas tales como: 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600 o
115200.
voidsetup()
{
Serial.begin(9600); // abre el Puerto serie
} // configurando la velocidad en 9600 bps
Nota: Cuando se utiliza la comunicación serie los pins digital 0 (RX) y 1 (TX) no puede utilizarse al mismo
tiempo.
Serial.avaible()
intSerial.available()
Devuelve y por lo tanto se obtiene un número entero correspondiente al número de bytes (caracteres)
disponibles para leer o capturar desde el puerto serie. Equivaldría a la función serialAvailable().
Devuelve Un entero con el número de bytes disponibles para leer desde el buffer serie, o 0 si no hay
ninguno. Si hay algún dato disponible, SerialAvailable() será mayor que 0. El buffer serie puede almacenar
como máximo 64 bytes.
Ejemplo
28/
En otra fuente pone:
Esta función retorna 1 si existen bytes disponibles para ser leídos , caso contrario devuelve -1 y hay que
tener mucho cuidado cuando se la usa con While() debido a que la velocidad de ejecución del micro es muy
superior a la velocidad con que se reciben o transmiten los datos por el Serial Port. Supongamos el siguiente
programa:
Serial.available()
29/
Al ejecutar , abrimos el monitor y enviemos nuevamente el “1”.
49
Ciclo:0
13
Ciclo:1
10
Ciclo:2
No estaría realizando lo que pedíamos, ya que saldríamos de While si no hay más datos, como
vienen 49-13-10, esperaríamos que el ciclo 1 se ejecute después de recibir estos caracteres. Esto se
produce debido a las diferencias de velocidad con que ejecuta Arduino y la velocidad con que se
reciben los datos. El clock del Arduino=16Mhz, supongamos que 1 c i clo de i nstrucción como en la
mayoría de los micros sea de ¼ Fclok = 4Mhz, esto implica que un ciclo de inst rucción dura 0 . 2 5
microsegundos. De acuerdo al compilador una instrucción puede demorar varios ciclos de
instrucción. Supongamos que el While() demora 10 ciclos de instrucción = 2.5 us. U n dat o By t e 8N1 a
9600 demora en llegar (8+1)*1/9600=937 us. Ni bien se reciba el 49 , se imprime y el while() vuelve a
ejecutarse ,pero no habrá datos disponibles hasta 937us , en este caso el CR y, por lo tanto el flujo del
programa sale del While dado que el av ailable=-1, y así ejecuta el ciclo 1 del for, pero como los dat os
todavía no están disponibles quedan en el primer While esperando. Si sumamos un pequeño retardo
dentro del while , descomentando la línea delay(100) ( con un par de milisegundos bastaría); obligamos
a no seguir la ejecución para dar tiempo a que llegue el segundo carácter .Ejecutamos ahora veremos
lo que queremos ver
49
13
10
Ciclo:0
Serial.println(data)
Imprime los datos en el puerto serie, seguido por un retorno de carro automático y salto de línea. Este
comando toma la misma forma que Serial.print (), pero es más fácil para la lectura de los datos en el
Monitor Serie del software.
Nota: Para obtener más información sobre las distintas posibilidades de Serial.println () y Serial.print ()
puede consultarse el sitio web de Arduino.
El siguiente ejemplo toma de una lectura analógica pin0 y envía estos datos al ordenador cada 1 segundo.
voidsetup()
{
Serial.begin(9600); // configura el puerto serie a 9600bps
30/
}
voidloop()
{
Serial.println(analogRead(0)); // envía valor analógico
delay(1000); // espera 1 segundo
}
Vuelca o envía un número o una cadena de caracteres, al puerto serie. Dicho comando puede tomar
diferentes formas, dependiendo de los parámetros que utilicemos para definir el formato de volcado de los
números.
Parámetros
datatype: determina el formato de salida de los valores numéricos (decimal, octal, binario, etc...)
DEC, OCT, BIN, HEX, BYTE , si no se pone nada devuelve caracteres ASCII
Ejemplos:
Si desde el principio declaramos e inicializamos la variable int b = 79; los diferentes formatos de salida de b
por el monitor serie sería los siguientes:
Serial.print(b)
Vuelca o envía el valor de b como un número decimal en caracteres ASCII. Equivaldría a printInteger().
Serial.print(b); // imprime la cadena –string- "79".
Serial.print(b, DEC)
Vuelca o envía el valor de b como un número decimal en caracteres ASCII. Equivaldría a printInteger().
Serial.print(b, DEC); // imprime la cadena –string- "79".
Serial.print(b, HEX)
Vuelca o envía el valor de b como un número hexdecimal en caracteres ASCII. Equivaldría a printHex();
Serial.print(b, OCT)
Vuelca o envía el valor de b como un número Octal en caracteres ASCII. Equivaldría a printOctal();
Serial.print(b, OCT); // prints the string "117".
Serial.print(b, BIN)
Vuelca o envía el valor de b como un número binario en caracteres ASCII. Equivaldría a printBinary();
Serial.print(b, BIN); // prints the string "1001111".
Serial.print(b, BYTE)
Vuelca o envía el valor de b como un byte. Equivaldría a printByte();
Serial.print(b, BYTE); // Devuelve el caracter "O", el cual representa el carácter
//ASCII del valor 79. (Ver tabla ASCII ).
Serial.print(str)
Vuelca o envía la cadena de caracteres como una cadena ASCII. Equivaldría a printString().
31/
Serial.print("Hello World!"); // vuelca "Hello World!".
Vuelca o envía un número o una cadena de caracteres al puerto serie, seguido de un carácter de retorno de
carro "CR" (ASCII 13, o '\r')y un carácter de salto de línea "LF"(ASCII 10, o '\n'). Toma la misma forma que el
comando Serial.print()
Serial.Read()
intSerial.Read()
Lee o captura un byte (un caracter) desde el puerto serie. Equivaldría a la función serialRead().
Devuelve :El siguiente byte (carácter) desde el puerto serie, o -1 si no hay ninguno.
Ejemplo
voidsetup() {
Serial.begin(9600); // abre el puerto serie,y le asigna la velocidad de 9600 bps
}
voidloop() {
if (Serial.available() > 0) { // envía datos sólo si los recibe:
incomingByte = Serial.read(); // lee el byte de entrada y lo almacena en variable
Serial.print("I received: "); //imprime “He recibido: “
Serial.println(incomingByte, DEC); //lo vuelca a pantalla el dato almacenado
}
}
32/
Serial.read()
Para nuestro análisis carguemos el siguiente código donde Arduino lo que hace es
renviar como loop todo lo mismo que recibe
Loop
33/
Librerías
Arduino trabaja con librerías que están ya instaladas y otras que hay que instalar.
Para la instalación y conocimiento de las librerías de Arduino pordemos consultar:
Installing an Arduino Library: https://learn.sparkfun.com/tutorials/installing-an-arduino-library
Ayuda – Documentación:
Las librerías contienen código de funciones y programas ejemplos que ayudan en la generación de código
para Arduino.
Es muy importante saber cómo incluir librerías en el entorno de Arduino. Existen básicamente tres
procedimientos de incorporación de librerías al entorno de Arduino.
Tenga en cuenta: las bibliotecas Arduino se administran en tres lugares diferentes: dentro de la carpeta de
instalación IDE, dentro de la carpeta principal y en la carpeta de bibliotecas dentro de su sketchbook. La
forma en que se eligen las bibliotecas durante la compilación está diseñada para permitir la actualización de
las bibliotecas presentes en la distribución. Esto significa que al colocar una biblioteca en la carpeta
"libraries" de su sketchbook se anulan las otras versiones de las bibliotecas.
Lo mismo ocurre con las bibliotecas presentes en instalaciones de núcleos adicionales. También es
importante tener en cuenta que la versión de la biblioteca que coloque en su sketchbook puede ser inferior
a la de las carpetas de distribución o núcleo, sin embargo, será la utilizada durante la compilación. Cuando
selecciona un núcleo específico para su placa, se utilizan las bibliotecas presentes en la carpeta del núcleo
en lugar de las mismas bibliotecas presentes en la carpeta de distribución IDE.
Por último, pero no menos importante, es la forma en que el software Arduino (IDE) se actualiza a sí mismo:
todos los archivos en Programas / Arduino (o la carpeta donde instaló el IDE) se eliminan y se crea una
nueva carpeta con contenido nuevo.
Esta es la razón por la que recomendamos que solo instale bibliotecas en la carpeta de sketchbook para que
no se eliminen durante el proceso de actualización de Arduino IDE.
34/
APÉNDICES:
La tabla de caracteres ASCII (acrónimo inglés de American Standard Code for Information
Interchange —Código Estándar Estadounidense para el Intercambio de Inf ormación—), es una tabla
que recoge los caracteres llamados de control, alfanuméricos, signos de puntuación, etc. del alfabeto
occidental.
Más información en tabla de caracteres ASCII El código ASCII utiliza 7 bits para representar los
caracteres, aunque inicialmente empleaba un bit adicional (bit de paridad) que se usaba para detectar
errores en la transmisión. Esto da lugar a un total de 128 caracteres. En la actualidad define códigos para
32 caracteres no imprimibles, los primeros, de los cuales la mayoría son caracteres de control usado
originalmente para gestionar el texto en impresoras. Los más importantes para nosotros son el nº 0 o
carácter nulo, el nº 8 o tabulador ‘\n’, el nº 13 o retorno de carro ‘\r’, el nº 10 o cambio de línea ‘\0’ con los
que terminaremos los mensajes que enviemos. Los otros 95 caracteres imprimibles que les siguen en la
numeración (empezando por el nº 32 el carácter espacio).
Los caracteres ASCII imprimibles ( a partir del 33) se pueden visualizar en la pantalla de un computador PC
cualquiera pulsando el código numérico correspondiente en el teclado numérico (para ello la tecla NumLock
ha de estar activa) mientras se mantiene pulsada la tecla ALT-GR.
Casi todos los sistemas informáticos actuales utilizan el código ASCII o una extensión compatible para
representar textos y para el control de dispositivos que manejan texto como el teclado.
35/
Anexo II: Sistemas de comunicación Serie en Arduino.(Prácticas Comunicación Serial)
Los sistemas integrados en placa de que dispone Arduino son: Comunicación Serie, protocolo TWI
(TwoWire) o I2C e ISP. Todos son protocolos de comunicación serie. El más común y tradicional sistema de
comunicación de la placa Arduino con el exterior es la comunicación por el puerto serie RS-232 que está
implementado sobre un USB.
Así pues, La tarjeta Arduino puede establecer comunicación serie (recibir y enviar valores codificados en
ASCII) con un dispositivo externo, a través de una conexión por un cable/puerto USB (tarjeta USB) o
cable/puerto serie RS-232(tarjeta serie) (Enlace) Igual que para la descarga de los programas, sólo será
necesario indicar el número de puerto de comunicaciones que estamos utilizando y la velocidad de
transferencia en baudios (enlace).También hay que tener en cuenta las limitaciones de la transmisión en la
comunicación serie, que sólo se realiza a través de valores con una longitud de 8-bits (1 Byte)(Ver
Serial.write(c) o Serial.read() ). Dentro del IDE, disponemos de la opción Herramientas →"Monitor Serie"
(Ctrl+May+M), que posibilita la visualización y envío de datos con Arduino.
Hoy en día la manera más común de comunicación entre dispositivos electrónicos es la comunicación
serial básicamente porque la comunicación en paralelo conlleva el uso de muchos cables y, excepto
entornos muy determinados, está en desuso al menos entre dispositivos externos y con cable. Arduino
utiliza este tipo de comunicación usando varios protocolos.
Series de pulsos
En el modo más sencillo y común de comunicación serial (asincrónica, 8 bits, más un bit de parada) siempre
se está enviando un byte, es decir un tren de 8 pulsos de voltaje legible por la máquina como una serie de 8,
1s ó 0s:
O sea, que no importa cual modificador usemos siempre se están enviando bytes. La diferencia está en lo
que esos bytes van a representar y sólo hay dos opciones en el caso de Arduino: una serie de caracteres
ASCII o un número.
36/
Si Arduino lee en un sensor analógico un valor de 65, equivalente a la serie binaria 01000001 esta será
enviada, según el modificador, como:
Enlaces de consulta:
- https://es.wikipedia.org/wiki/RS-232
- https://aprendiendoarduino.wordpress.com/tag/serial/
- http://diymakers.es/usando-el-puerto-serie-del-arduino/
37/
Anexo III: Salidas (pseudo-) analógicas PWM (Modulación por Anchura de Pulso)
La modulación de ancho de pulso (PWM, por sus siglas en inglés Pulse-Width Modulation) de una
señal, es una técnica que logra producir el efecto de una señal analógica sobre una carga, a partir de
la variación de la frecuencia y ciclo de trabajo de una señal digital. El ciclo de trabajo describe la
cantidad de tiempo que la señal está en un estado lógico alto, como porcentaje del tiempo total dura
un ciclo completo. Otra forma de decirlo sería el ciclo de trabajo (Duty Cicle = DC) de una señal
periódica que es el ancho relativo de su parte positiva en relación con el período. Expre sado
matemáticamente:
𝜏
𝐷𝐶 (%) = · 100
𝑇
𝜏
𝑉𝑚𝑒𝑑 = 𝑉𝑐𝑐 = 𝑉𝐴𝑉 = 𝑉𝑚á𝑥 · = 𝑉𝑚á𝑥 · 𝐷𝐶
𝑇
Dónde:
Vmed = VAV (AV = Average = Media)también puede expresarse como Vcc, es el valor medio o el
valor de continua de la magnitud tensión.
D es el ciclo de trabajo (DutyCycle) determina el porcentaje de tiempo que el pulso (o
voltaje aplicado) está en estado activo (on) durante un ciclo.
τ es el tiempo en que la función es positiva (ancho del pulso positivo)
T es el período de la función o ciclo, es el tiempo total que dura la señal.
τ
T
t
Período
38/
PWM NO es una señal analógica pero pretende crear una señal de continua proporcional al un
número.
Es importante recordar en todo momento que en una salida PWM el valor de tensión realmente
es 5v que es el valor máximo de alimentación de la señal pulsante PWM y 0v valor mínimo.
Por ejemplo, si estamos alimentando un dispositivo que necesita 3V, y usamos una pulsada, en
realidad estaremos suministrando 5V durante un 60% del tiempo y 0V durante el 40%. Pero si el
dispositivo, por ejemplo, soporta como máximo 3V, podemos dañarlo si lo alimentamos
mediante una PWM.
Una señal pulsada es suficiente para emular una señal analógica en muchas aplicaciones sobre todo
en aplicaciones de regulación y control. Por ejemplo, podemos variar la intensidad luminosa en un
LED mediante un PWM. El LED realmente se enciende y apaga varias veces por segundo, pero este
parpadeo es tan rápido que el ojo no lo aprecia. El efecto global percibido es que el LED brilla con
menor intensidad.
Nota: Ciertos sistemas pueden requerir frecuencias superiores a las mostradas anteriormente y
dependerá del tipo de respuesta requerido.
Recomendaciones:
Por otro lado, debemos tener en cuenta los efectos que suponen la rápida conexión y
desconexión de la señal pulsada en el dispositivo alimentado. Por ejemplo, en el caso de cargas
inductivas (motores, relés, o electroimanes) la desconexión supondrá la generación de voltaje
inducido que puede dañar la salida digital o el propio dispositivo, por lo que será necesario disponer
de las protecciones oportunas.
En cuanto a transistores, en general, los de tipo BJT, MOSFET e IGBT resultan apropiados para
funcionar como amplificación de señales PWM.
4Al variar la velocidad de un motor DC con un PWM, en la mayoría de los casos la inercia del motor se encargará de
que el efecto del PWM sea despreciable. No obstante, en función de la frecuencia podemos notar vibraciones o ruidos,
en cuyo caso deberemos variar la frecuencia del PWM.
39/
Ejemplo 1:
Para crear una señal de 3V dada una fuente digital que puede ser alta (5V) o baja (0V), se podría
utilizar un PWM con un ciclo de trabajo del 60%. El cual generaría una señal de 5V el 60% del
tiempo. Si la señal es conmutada lo suficientemente rápido, el voltaje visto en los terminales del
dispositivo parecerá ser el valor promedio de la señal. Si el estado lógico bajo es 0V (que es el caso
más común) entonces el voltaje promedio puede ser calculado multiplicando el voltaje que
represente el estado lógico alto por el ciclo de trabajo, o 5V x 0.60 = 3V. Seleccionar un ciclo de
trabajo del 80% sería equivalente a 4V (=5V x 0.80), un 20% a 1V (=5V x 0.20), y así
sucesivamente.
Ejemplo 2:
Si tenemos un voltaje de 9v y lo modulamos con un dutycycle del 10%, obtenemos 0.9V de señal
analógica de salida.
Ejercicios:
1) ¿Qué valor tengo que mandar a una salida PWM para obtener. 3,8v?
(Sol.)Vmed = Vmáx * DC 3,8 = 5*ValorPWM/255 =>ValorPWM= 3,8*255/5 = 193.8
(194)
analogWrite(9, 90);
4) Escribe un código en Arduino para generar una señal que haga que un led (en el mismo pin
que en el ejercicio anterior) vaya aumentando la luminosidad linealmente desde cero hasta el
máximo durante un segundo, en el siguiente segundo haga lo contrario, desde el máximo
vaya descendiendo la luminosidad hasta estar totalmente apagada y vuelva a comenzar el
ciclo de forma indefinida.
Para una información más detallada, aquí hay un enlace que lo clarifica: Frecuencia de las salidas
PWM
Enlaces de consulta:
- https://www.arduino.cc/en/Tutorial/PWM
- Consulta el siguiente enlace y explica las incompatibilidades que existen con el uso de los timers.
https://www.luisllamas.es/salidas-analogicas-pwm-en-arduino/
- http://digital.ni.com/public.nsf/allkb/AA1BDEA4AA224E3E86257CE400707527
- http://www.tutoelectro.com/tutoriales/microcontroladores/guia-pic/pwm-modulacion-de-ancho-
de-pulso/
40/
Otra forma de generar señales PWM es utilizando la capacidad del microprocesador. La señal de
salida obtenida de un microprocesador es una señal digital de 0 voltios (LOW) y de 5 voltios
(HIGH). Lo que podemos hacer es generar la señal cuadrada “a pelo”, es decir, diciendo
expresamente el valor en tiempo del nivel alto y el del nivel bajo y sabiendo que ambos sumen el
mismo valor para mantener el período.
Con el siguiente código y con sólo realizar modificaciones en los intervalos de tiempo que el pin
seleccionado tenga valor HIGH o LOW, a través de la función digitalWrite(), generamos la señal
PWM con un DC de un 25% y un Vcc de 1.25v.
/* señal PWM */
intdigPin = 10; // pin digital 10
voidsetup() {
Preguntas:
41/
Anexo IV: Generación de Tonos musicales.
Se utiliza la función tone() y la noTone().
TUTORIALES
42/
Anexo V: Conversor Analógico-Digital (A/D)
El dispositivo establece una relación entre su entrada (señal analógica) y su salida (Digital) dependiendo de
su resolución. La resolución determina la precisión con la que se reproduce la señal original.
Esta resolución se pude saber, siempre y cuando conozcamos el valor máximo de la entrada a convertir y la
cantidad máxima de la salida en dígitos binarios.
Por ejemplo, un conversor A/D de 8-bits puede convertir valores que van desde 0V hasta el voltaje de
referencia (Vref) y su resolución será de:
Lo que quiere decir que mapeará los valores de voltaje de entrada, entre 0 y Vref voltios, a valores enteros
comprendidos entre 0 y 255 (2 n-1 ).
La tarjeta Arduino utiliza un conversor A/D de 10-bits, así que: Resolución = Vref/1024 (2 10 )
Mapeará los valores de voltaje de entrada, entre 0 y Vref voltios, a valores enteros comprendidos entre 0 y
1023 (2n-1 ). Con otras palabras, esto quiere decir que nuestros sensores analógicos están caracterizados
con un valor comprendido entre 0 y 1023. (Ver analogRead()).
Si Vref es igual a 5v, la resolución es aproximadamente de 5 milivoltios (=5/1023=4.887mV). Por lo tanto el
error en las medidas de voltaje será siempre de sólo 5 milivoltios.
Al enviar datos por el puerto serie, tenemos que tener en cuenta que la comunicación se realiza a través de
valores con una longitud de 8-bits (Ver serialWrite(c) o serialRead(c) ), mientras que como ya se hemos
indicado, el A/D (Convertidor) de Arduino tiene una resolución de 10-bits.
Por ejemplo, si capturamos los valores de un sensor analógico (e.j. potenciómetro) y los enviamos por el
puerto serie al PC, una solución podría ser transformarlos en un rango entre 0 y 9 y en modo de codificación
ASCII (carácter).
0 ASCII -->decimal = 48
1 ASCII -->decimal = 49
etc..
En forma de código podría quedar como:
Otra fórmula sería dividiendo por 4 ¿Esto es correcto? (1024/256) los valores capturados de los sensores
analógicos, para convertirlos en valor de byte válido (0 – 255).
value = analogRead(analogPin)/4;
serialWrite(value);
43/
Anexo VI: Palabras reservadas del IDE de Arduino
Estas palabras son constante, variables y funciones que se definen en el lenguaje de programación de
Arduino (No deben usarse en el IDE de Arduino). No se deben usar estas palabras clave para nombres de
variables.
45/
Anexo VI: CIRCUITOS DE INTERFACE CON ARDUINO
Conexión de un diodo Led a una salida de Arduino Entrada analógica mediante un potenciómetro
Conexión de un pulsador/interruptor
46/
Conexión de un sensor de tipo resistivo (LRD, NTC, PTC..) a una entrada
analógica
47/
Control de un motor de cc mediante el CI L293 Control de un motor paso a paso unipolar
48/
Control mediante transistor TIP120
VCC VCC
VCC VCC
12V 12V
5V 5V
R3
R3 50Ω
50Ω
R1
R1 4.7kΩ
4.7kΩ Q2
Q2 IRLI530N
IRLI530N Arduino 5v
Q1
Q1 IO1 R2
IO1 R2
10kΩ R4
1kΩ 2N2222A
100kΩ
2N2222A
49/