Voy a hacer ahora una introducción general a la programación en Arduino, pues veo que el tema ha suscitado cierto interés.
Como ya hemos dicho, lo habitual es programar el Arduino desde la plataforma libre y gratuita asociada al mismo: el IDE. Se puede descargar en el siguiente enlace:
https://www.arduino.cc/en/Main/SoftwareComo puede verse hay versiones para todas las plataformas, elegimos la adecuada a nuestro sistema y la descargamos. Si sois linuxeros, conviene además de la instalación ejecutar un complemento denominado arduino-linux-setup.sh para que las cosas funcionen correctamente con vuestra instalación.
Al arrancar el IDE nos presenta un programa en blanco que tiene un aspecto similar a éste:

Por cierto, comentar que el código se escribe técnicamente en texto plano que se guarda con la extensión .ino, la plataforma se encarga de generar una carpeta para cada proyecto con el mismo nombre que le demos. Este es un programa en blanco, pero vamos a estudiar la estructura general de un programa sencillo que ya hemos citado aquí: tecladoyreles.ino
#include <Keypad.h> //llama a la librería Keypad.h que va a hacernos la gestión del teclado
char codigo[2]; //Cadena donde se guardaran los caracteres de las teclas presionadas
int cont=0; //variable que se incrementara al presionar las teclas
char modoa[]="A*"; //aquí escribimos el código de dos digitos Modo A
char modob[]="B*"; //aquí escribimos el código de dos digitos Modo B
char modoc[]="C*"; //aquí escribimos el código de dos digitos Modo C
char modod[]="D*"; //aquí escribimos el código de dos digitos Modo D
char modo0[]="0*"; //aquí escribimos el código de dos digitos Modo 0
char modo1[]="1*"; //aquí escribimos el código de dos digitos Modo 1
const byte ROWS = 4; //Numero de filas del teclado que se está usando
const byte COLS = 4; //Numero de columnas del teclado que se está usando
char hexaKeys[ROWS][COLS] = //Aquí pondremos la disposición de los caracteres tal cual están en nuestro teclado
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {39, 41, 43, 45}; //Seleccionamos los pines en el arduino donde irán conectadas las filas
byte colPins[COLS] = {47, 49, 51, 53}; //Seleccionamos los pines en el arduino donde irán conectadas las columnas
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); //inicializa el teclado,
// así no nos tenemos que encargar de definir entradas ni salidas
#define DOS 2
#define TRES 3
#define CUATRO 4
#define CINCO 5
#define SEIS 6
#define SIETE 7
#define OCHO 8
#define NUEVE 9
int reposo = 0;
void setup()
{
pinMode(13, OUTPUT); //Pin 13 como salida
Serial.begin(9600); //inicializar puerto serie
pinMode(DOS,OUTPUT);// Estas son las salidas a los relés (placa de 8 relés) se establecen como salida
pinMode(TRES,OUTPUT);
pinMode(CUATRO,OUTPUT);
pinMode(CINCO,OUTPUT);
pinMode(SEIS,OUTPUT);
pinMode(SIETE,OUTPUT);
pinMode(OCHO,OUTPUT);
pinMode(NUEVE,OUTPUT);
digitalWrite(DOS,HIGH);
digitalWrite(TRES,HIGH);
digitalWrite(CUATRO,HIGH);
digitalWrite(CINCO,HIGH);
digitalWrite(SEIS,HIGH);
digitalWrite(SIETE,HIGH);
digitalWrite(OCHO,HIGH);
digitalWrite(NUEVE,HIGH);
char codigo[]="0*";
}
void loop()
{
char customKey = customKeypad.getKey(); //se guarda en la variable customKey el caracter de la tecla presionada
if (customKey != NO_KEY || cont>=5) //se evalúa si se presionó una tecla
{
codigo[cont]=customKey; //se guarda caracter por caracter en la matriz codigo[]
cont=cont+1; //incrementamos la variable cont
if(cont==2) //si ya fueron presionadas 2 teclas se evalúa el código introducido
{
Serial.println(codigo); //se imprime en el puerto serie el código introducido
Serial.println(cont);
if(codigo[0]==modoa[0]&&codigo[1]==modoa[1])
{
digitalWrite(DOS,HIGH);
digitalWrite(CUATRO,HIGH);
delay(150); // Espera 150 milésimas de segundo
digitalWrite(DOS,LOW);
digitalWrite(CUATRO,LOW);
digitalWrite(13,!digitalRead(13)); //si la contraseña fue correcta se enciende o se apaga el led del pin13
}
if(codigo[0]==modob[0]&&codigo[1]==modob[1])
{
digitalWrite(DOS,HIGH);
digitalWrite(TRES,HIGH);
digitalWrite(CUATRO,HIGH);
digitalWrite(CINCO,HIGH);
digitalWrite(SEIS,LOW);
digitalWrite(SIETE,LOW);
digitalWrite(OCHO,LOW);
digitalWrite(NUEVE,LOW);
delay(150);
reposo = ReposoReles();
digitalWrite(13,!digitalRead(13)); //si la contraseña fue correcta se enciende o se apaga el led del pin13
}
if(codigo[0]==modoc[0]&&codigo[1]==modoc[1])
{
digitalWrite(DOS,HIGH);
digitalWrite(TRES,LOW);
digitalWrite(CUATRO,HIGH);
digitalWrite(CINCO,LOW);
digitalWrite(SEIS,HIGH);
digitalWrite(SIETE,LOW);
digitalWrite(OCHO,HIGH);
digitalWrite(NUEVE,LOW);
delay(150);
reposo = ReposoReles();
digitalWrite(13,!digitalRead(13)); //si la contraseña fue correcta se enciende o se apaga el led del pin13
}
if(codigo[0]==modod[0]&&codigo[1]==modod[1])
{
digitalWrite(DOS,LOW);
digitalWrite(TRES,HIGH);
digitalWrite(CUATRO,LOW);
digitalWrite(CINCO,HIGH);
digitalWrite(SEIS,LOW);
digitalWrite(SIETE,HIGH);
digitalWrite(OCHO,LOW);
digitalWrite(NUEVE,HIGH);
delay(150);
reposo = ReposoReles();
digitalWrite(13,!digitalRead(13)); //si la contraseña fue correcta se enciende o se apaga el led del pin13
}
if(codigo[0]==modo0[0]&&codigo[1]==modo0[1])
{
digitalWrite(DOS,HIGH);
digitalWrite(TRES,HIGH);
digitalWrite(CUATRO,HIGH);
digitalWrite(CINCO,HIGH);
digitalWrite(SEIS,HIGH);
digitalWrite(SIETE,HIGH);
digitalWrite(OCHO,HIGH);
digitalWrite(NUEVE,HIGH);
delay(150);
reposo = ReposoReles();
digitalWrite(13,!digitalRead(13)); //si la contraseña fue correcta se enciende o se apaga el led del pin13
}
if(codigo[0]==modo1[0]&&codigo[1]==modo1[1])
{
digitalWrite(DOS,LOW);
digitalWrite(TRES,LOW);
digitalWrite(CUATRO,LOW);
digitalWrite(CINCO,LOW);
digitalWrite(SEIS,LOW);
digitalWrite(SIETE,LOW);
digitalWrite(OCHO,LOW);
digitalWrite(NUEVE,LOW);
delay(150);
reposo = ReposoReles();
digitalWrite(13,!digitalRead(13)); //si la contraseña fue correcta se enciende o se apaga el led del pin13
}
cont=0; //resetear a 0 la variable cont
}
}
}
int ReposoReles() {
digitalWrite(DOS,HIGH);
digitalWrite(TRES,HIGH);
digitalWrite(CUATRO,HIGH);
digitalWrite(CINCO,HIGH);
digitalWrite(SEIS,HIGH);
digitalWrite(SIETE,HIGH);
digitalWrite(OCHO,HIGH);
digitalWrite(NUEVE,HIGH);
}
Un programa de Arduino tiene seis partes fundamentales: la primera es la inclusión de las librerías necesarias para que algunos complementos de Arduino funcionen correctamente. Podríamos ponernos a programarlos directamente, pero ya hay mucha gente que lo ha hecho por nosotros, y ¿para qué hacer un trabajo que ya está hecho y a nuestra disposición? En el caso del programa que veis sólo hay una librería implicada, la que maneja el teclado: Keypad.h
En Internet vamos a encontrar mucha información de las posibilidades de las librerías, sus funciones y sus aplicaciones (eso sí, casi siempre en inglés).
En total de mi programación he usado seis librerías, tres en el programa del primer Arduino y otras tres en el segundo. Son pocas, pero relevantes. Siempre van detrás de la etiqueta #include.
A continuación va la parte dedicada a la definición de variables. Aunque se pueden definir variables en medio del código, la etiqueta de programación recomienda que se declaren al principio. Hay muchos tipos de variables en Arduino, pero la más utilizada es del tipo int (entero), aunque en el ejemplo aparecen char (matriz de caracteres) y byte (octeto o byte). Aquí tienen una guía completa:
https://www.arduino.cc/reference/en/#variablesEn este grupo también se incluyen las definiciones de constantes para nombrar los pines: ej. "#define SEIS 6" a partir de ahora nos referiremos al pin 6 como SEIS (es sensible a las mayúsculas).
El siguiente bloque de código viene el setup comienza con el código "void setup() {" y termina cuando se cierra esta llave. Este bloque sólo se ejecutará una vez, al principio, por lo que pondremos allí todas las tareas iniciales que necesitemos para dejar nuestro sistema preparado para el trabajo, es decir, para la siguiente parte que se ejecutará indefinidamente (el loop). En este bloque de setup se suele aprovechar a declarar el pin 13 como salida, pues este pin está ligado a un led del Arduino, por lo que es la primera realidad que podemos cambiar sin conectar nada a la placa, si conseguimos encender ese led, lo demás vendrá rodado!!
También se abre el puerto serie que servirá para monitorizar cuando lo necesitemos el comportamiento del Arduino desde la pantalla del ordenador. Esas son las dos primeras líneas de nuestro ejemplo.
El cuarto bloque es el loop, la parte del programa que se repite indefinidamente empiza en el código "void loop() {" y termina con la llave de cierre. Esa es la parte mollar del programa, lo que realmente queremos que haga, de lo que nos ocuparemos más adelante en otro capítulo.
El bloque que sigue es el de las funciones, trozos de código que en lugar de repetirlo en distintos puntos, se coloca al final, y se llama cuando es necesario, en nuestro caso ReposoReles() es una función que pone todos los relés en inactivos (recordemos que se desactivan por alto-> HIGH). para llamar una función hay que poner una orden muy rara: hay que definir una variable del mismo tipo que la función (int) y mandar a Arduino la siguiente orden:
reposo = ReposoReles();
Con esto se llama a la función, que se ejecuta y tras esto el programa retorna a la siguiente línea de código.
El bloque sexto y último es el de las interrupciones. Se denomina interrupción en informática a un evento habitualmente externo que determina que el sistema ejecute algún tipo de rutina, se usa por ejemplo para recibir las órdenes del teclado y los movimientos del ratón. En este caso no se usa para el teclado, que se detecta de otro modo, y en este programa no hay ningún uso, pero en el programa completo utilizo las interrupciones para detectar el paso de los trenes por los sensores:
void inte4() { //Pin 19 Puerta 1b Superior trasera
contp1b = contp1b + 1;
contp1a = 0;
contp2a = 0;
contp2b = 0;
contp3a = 0;
contp3b = 0;
if (millis() > tiempo1b + param1 && contp1b >= param2) {
est_puerta1b = LOW;
contp1b = 0;
tiempo1b = millis();
//Serial.println("Puerta 1B");
}
}
Las interrupciones están directamente asociadas a unos determinados pines, no todos los pines del Arduino están preparados para establecer interrupciones, en el caso de la Mega 2560 sólo tiene seis y son los pines 2, 3, 18, 19, 20 y 21. Depende del modelo que se use, vamos a tener distintas posibilidades. Para mayor información ver la tabla siguiente:

Y estas son las seis partes que podemos distinguir en un programa de Arduino. Os dejo como ejercicio (¿se me nota la vena docente?) que encontréis cinco de los seis bloques citados en el siguiente programa:
#include <IRLremote.h>
#define LEDPIN 13
#define emisor1 30
#define puerta1a 18
#define puerta1b 19
int intpuerta1a = 5;
int intpuerta1b = 4;
volatile boolean est_puerta1a = HIGH, est_puerta1b = HIGH;
int estado = 0, lastStatea=0, lastStateb=0;
volatile long tiempo1a = 0, tiempo1b = 0;
int estadotren = 0;
int estadoanterior = 0;
int vueltastrenarriba = 0;
void setup() {
// initialize the LED pin as an output:
pinMode(LEDPIN, OUTPUT);
pinMode(emisor1, OUTPUT);
// initialize the gate sensors pins as an interruption input:
pinMode(puerta1a, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(puerta1a), inte5, HIGH);
pinMode(puerta1b, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(puerta1b), inte4, HIGH);
digitalWrite(puerta1a, LOW);
digitalWrite(puerta1b, LOW); // turn on the pullup
digitalWrite(emisor1, HIGH);
Serial.begin(9600);
}
void loop(){
if (est_puerta1a == LOW && est_puerta1b == LOW) {
if (tiempo1a + 50 < tiempo1b && tiempo1a != 0) {
estadotren = 2;
Serial.println("SENTIDO ANTI-HORARIO");
digitalWrite(LEDPIN, HIGH);
}
if (tiempo1b + 50 < tiempo1a && tiempo1b != 0) {
estadotren = 3;
Serial.println("SENTIDO HORARIO");
digitalWrite(LEDPIN, LOW);
}
est_puerta1a = HIGH;
est_puerta1b = HIGH;
tiempo1b = 0;
tiempo1a = 0;
vueltastrenarriba = vueltastrenarriba + 1;
Serial.println(vueltastrenarriba);
delay(4000);
estadoanterior = estadotren;
}
delay(5);
}
void inte5() {
if (millis() > tiempo1a + 500){
est_puerta1a = LOW;
tiempo1a = millis();
Serial.println("Puerta A");
}
}
void inte4() {
if (millis() > tiempo1b + 500) {
est_puerta1b = LOW;
tiempo1b = millis();
Serial.println("Puerta B");
}
}
Espero haber contribuido a que vayáis comprendiendo mejor el Arduino y sus muchas posibilidades. Otro día, más.
Saludos