viernes, 20 de junio de 2025

Ascensor simplificado de tres pisos

Este modelo de ascensor se ha diseñado intentando simplificar al máximo su construcción. 


Necesita de cinco piezas en 3D para el mecanismo, una base sobre la que se sujeta el motor, un soporte superior que sujeta una polea, el cuadro deslizante sobre el que se sujetará la caja del ascensor y las dos poleas. Entre la base y el soporte superior se sitúan un par de varillas de aluminio de 4 milímetros de diámetro y 29 centímetros de largo, que sirven como guías de la caja del ascensor. La estructura de soporte está formada por una base de madera, sobre la que se atornilla la pieza de la base imprimida en 3D, la placa de Arduino y el driver de motores, y un listón de 30 centímetros de largo y una sección de 10 x 25 milímetros, aunque puede tener cualquier sección mayor que esta. Sobre este listón van atornilladas las dos piezas imprimidas en 3D de la base y el soporte superior, los tres finales de carrera y los tres soportes de los pulsadores. 


Piezas de plástico

Los archivos para imprimir las piezas en 3D se pueden descargar en Thingiverse. La pieza base.stl pesa 14 gramos y se tarda en imprimir 1 hora y 15 minutos, soporte-superior.stl pesa 9 gramos y se tarda en imprimir 52 minutos, caja.stl pesa 7 gramos y se tarda en imprimir 42 minutos, polea-inferior.stl pesa 11 gramos y se tarda en imprimir 1 hora y 8 minutos, polea-superior.stl pesa 4 gramos y se tarda en imprimir 25 minutos, las tres piezas soporte-interruptor.stl pesan 18 gramos y se tardan en imprimir 1 hora y 40 minutos. En total 63 gramos y 6 horas y dos minutos de impresión.

Motorreductor GM12-N20

Para mover al ascensor utilizamos un motorreductor GM12-N20 comprado en Aliexpress a un precio de 2,2 euros.  Este mismo modelo de motor en Bricogeek se vende a un precio de 4,5 euros. Uno de estos motores pesa 10 gramos. 



Si conectamos el motor a una fuente de alimentación a un voltaje de un voltio en vacío consume entre 0,026 y 0,03 amperios y con 5 voltios 0,052 amperios. Para mover el ascensor con un voltio el motor necesita entre 0,034 y 0,05 amperios y con 5 voltios 0,07 amperios.

Conexiones de los pines de Arduino

Los finales de carrera que detectan la llegada de la cabina a los distintos pisos están conectados a los pines 7 (Planta baja), 8 (Primer piso) y 9 (Segundo piso). Los pulsadores utilizados para solicitar el ascensor en los distintos pisos están conectados a los pines 2 (Planta baja), 4 (Primer piso) y 6 (Segundo piso). 

En el driver del motor L298N el pin 3 de Arduino va a la entrada N1 y el pin 5 a la entrada N2 del driver, que corresponden al motor A. Para modificar la velocidad del motor se puede utilizar el pin ENA del driver, retirando el puente jumper correspondiente y haciendo llegar una señal PWM (analogWrite) desde un pin libre de Arduino. Un valor analógico 255 dejará el voltaje de salida a los motores a 5 voltios, que es el que le proporcionamos al driver, y un valor 0 sin tensión. para conseguir voltajes intermedios de salida hemos de variar el valor del analogWrite.


Los pulsadores van conectados por uno de sus puntos de conexión a 5 voltios y por el otro hacia el pin digital que le corresponda de la placa Arduino. En ese mismo punto se ha de conectar la tierra a través de una resistencia de 10K. En este caso como que no disponía de resistencias de 10 K le he puesto de 20 K y funciona perfectamente. Esta conexión hacia tierra hace que se descargue rápidamente este pin de Arduino pasando de HIGH a LOW en el momento que dejamos de apretar el pulsador. Este mismo montaje también se ha de hacer con los finales de carrera. En este caso los 5 voltios los llevamos al terminal COM y la salida hacia el pin digital de Arduino la conectamos al terminal NO, con su conexión a tierra a través de la resistencia, en este caso, de 20K.





El hilo está atado al ala central del tambor, pasándolo por un agujero de unos 2 milímetros que hay que hacer en el mismo. este nudo conviene fijarlo con algún tipo de pegamento. De este nudo parten dos trozos de hilo. Uno de ellos se enrolla en la porción interior del tambor y el otro en la porción exterior. Si uno se enrolla en un sentido el otro se ha de enrollar en sentido contario, de forma que al girar el tambor movido por el motor eléctrico de un lado se recoge hilo y del otro se suelta. Se han de enrollar suficientes vueltas para que la cabina del ascensor pueda hacer todo su recorrido. El extremo del hilo que se ha enrollado en la parte interior del tambor se pasa por la polea superior y se lleva al punto de sujeción de la caja del ascensor en donde se unirá con el otro extremo del hilo que viene directamente del tambor. Una vez puesto en funcionamiento el ascensor varias veces arriba y abajo el hilo se afloja y hace falta volver a tensarlo.




Programas con IDE de Arduino

Programa de prueba

Un primer programa para probar los pulsadores del primer y segundo piso es el que se muestra a continuación. Apretando el del primer piso sube y apretando el del segundo piso baja. Son importantes los retardos de 100 milisegundos, si no se ponen el driver no tiene tiempo de reaccionar.

Para que el ascensor haga lo que aquí esta descrito el motor ha de girar en la dirección correcta y no en la inversa. Hay dos factores físicos que influyen en este sentido de giro, o más bien el hecho de si el ascensor sube o baja, uno de ellos es como esté conectado el motor con el driver de motores, ya que los dos cables que unen estos dos elementos pueden estar de dos formas posibles, el otro factor es el sentido en el que está enrollado el hilo sobre el tambor que lo mueve para estirar la caja del ascensor hacia arriba o hacia abajo. Variando uno solo de estos dos factores se invertirá el sentido de subida o bajada respecto de un mismo programa. Por supuesto, también se puede invertir este sentido de subida o bajada invirtiendo los dos cables de entrada de señal en el driver de motores N1 y N2.

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(3,OUTPUT);
pinMode(3,OUTPUT);
}

void loop()
{
digitalWrite(5,LOW);
digitalWrite(3,LOW);

if(digitalRead(4)==HIGH){
    digitalWrite(3,HIGH);
    delay(100);
}

if(digitalRead(2)==HIGH){
  digitalWrite(5,HIGH);
  delay(100);
} 
 
}

Programa para dos pisos

Este programa mueve el ascensor entre el piso uno (planta baja) y el dos. No es demasiado seguro, porque si una vez en el dos volvemos a pulsar el botón del segundo piso volverá a subir hacia el tercero y una vez allí no habrá quien lo pare y se encallará al final del recorrido. Lo mismo ocurre si pulsamos el botón del primer piso cuando ya está en él.

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(3,OUTPUT);
pinMode(3,OUTPUT);
}

void loop()
{

if(digitalRead(4)==HIGH){
    digitalWrite(5,HIGH);
    delay(100);
}

if(digitalRead(2)==HIGH){
  digitalWrite(3,HIGH);
  delay(100);
}

if(digitalRead(8)==HIGH){
  digitalWrite(5,LOW);
  delay(100);
}
if(digitalRead(7)==HIGH){
  digitalWrite(3,LOW);
  delay(100);
}

}

Programa mejorado para dos pisos

Para hacer subir el ascensor del primero al segundo se ha de cumplir una doble condición, por una parte que el botón del segundo piso esté apretado y por otra que el final de carrera del primer piso también lo esté, es decir que el ascensor se encuentre en el primer piso. Lo mismo se ha de cumplir cuando se desea bajar el ascensor.

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(3,OUTPUT);
pinMode(3,OUTPUT);
}

void loop()
{

if((digitalRead(4)==HIGH)&&(digitalRead(7)==HIGH)){
    digitalWrite(5,HIGH);
    delay(100);
}

if((digitalRead(2)==HIGH)&&(digitalRead(8)==HIGH)){
  digitalWrite(3,HIGH);
  delay(100);
}

if(digitalRead(8)==HIGH){
  digitalWrite(5,LOW);
  delay(100);
}
if(digitalRead(7)==HIGH){
  digitalWrite(3,LOW);
  delay(100);
}

}

Programa para tres pisos

Para resolver este programa utilizaremos variables, una nos indica cual es el botón que se ha pulsado y la otra en que piso se encuentra la caja del ascensor, es decir que final de carrera se encuentra presionado. Aunque se deje de pulsar el botón, o de pisar el final de carrera, estos valores se mantienen hasta que de nuevo se pulse otro botón  o se presione otro final de carrera.

Se necesitan tantas estructuras condicionales como pulsadores y finales de carrera hay.

Para mover hacia arriba, hacia abajo o detener el ascensor se utilizan tres estructuras condicionales más. Si las variables pisoorigen y pisodestino son iguales se para el ascensor, si pisoorigen es menor que piso destino el ascensor sube y si pisoorigen es mayor que pisodestino el ascensor baja.

Este programa reinicia el ascensor aunque al comenzar el programa la caja del ascensor se encuentre entre dos pisos, e incluso aunque se encuentre por debajo del piso 1. La única situación que no puede salvar es si se encuentra al inicio por encima del piso 3. Su defecto es que cualquiera nos puede secuestrar el ascensor antes de que llegue al punto deseado, pulsando un nuevo botón.

int pisoorigen = 0;
int pisodestino = 1; //Este valor hace que al iniciar el programa el ascensor baje al primer piso

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(3,OUTPUT);
pinMode(3,OUTPUT);
}

void loop()
{

if(digitalRead(2)==HIGH){
    pisodestino = 1;
}  

if(digitalRead(4)==HIGH){
    pisodestino = 2;
}

if(digitalRead(6)==HIGH){
    pisodestino = 3;
}

if(digitalRead(7)==HIGH){
    pisoorigen = 1;
}  

if(digitalRead(8)==HIGH){
    pisoorigen = 2;
}

if(digitalRead(9)==HIGH){
    pisoorigen = 3;
}

if(pisoorigen==pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,LOW);
  delay(100);
}

if(pisoorigen<pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,HIGH);
  delay(100);
}

if(pisoorigen>pisodestino){
  digitalWrite(3,HIGH);
  digitalWrite(5,LOW);
  delay(100);
}

}

Programas con STEAMakersBlocks

Programa de prueba

Un primer programa para probar los pulsadores del primer y segundo piso es el que se muestra a continuación. Apretando el del primer piso sube y apretando el del segundo piso baja. Son importantes los retardos de 100 milisegundos, si no se ponen el driver no tiene tiempo de reaccionar.

Para que el ascensor haga lo que aquí esta descrito el motor ha de girar en la dirección correcta y no en la inversa. Hay dos factores físicos que influyen en este sentido de giro, o más bien el hecho de si el ascensor sube o baja, uno de ellos es como esté conectado el motor con el driver de motores, ya que los dos cables que unen estos dos elementos pueden estar de dos formas posibles, el otro factor es el sentido en el que está enrollado el hilo sobre el tambor que lo mueve para estirar la caja del ascensor hacia arriba o hacia abajo. Variando uno solo de estos dos factores se invertirá el sentido de subida o bajada respecto de un mismo programa. Por supuesto, también se puede invertir este sentido de subida o bajada invirtiendo los dos cables de entrada de señal en el driver de motores N1 y N2.


Programa para dos pisos


Este programa mueve el ascensor entre el piso uno (planta baja) y el dos. No es demasiado seguro, porque si una vez en el dos volvemos a pulsar el botón del segundo piso volverá a subir hacia el tercero y una vez allí no habrá quien lo pare y se encallará al final del recorrido. Lo mismo ocurre si pulsamos el botón del primer piso cuando ya está en él.

Programa mejorado para dos pisos

Para hacer subir el ascensor del primero al segundo se ha de cumplir una doble condición, por una parte que el botón del segundo piso esté apretado y por otra que el final de carrera del primer piso también lo esté, es decir que el ascensor se encuentre en el primer piso. Lo mismo se ha de cumplir cuando se desea bajar el ascensor.

Programa para tres pisos

Para resolver este programa utilizaremos variables, una nos indica cual es el botón que se ha pulsado y la otra en que piso se encuentra la caja del ascensor, es decir que final de carrera se encuentra presionado. Aunque se deje de pulsar el botón, o de pisar el final de carrera, estos valores se mantienen hasta que de nuevo se pulse otro botón  o se presione otro final de carrera.

Se necesitan tantas estructuras condicionales como pulsadores y finales de carrera hay.

Para mover hacia arriba, hacia abajo o detener el ascensor se utilizan tres estructuras condicionales más. Si las variables pisoorigen y pisodestino son iguales se para el ascensor, si pisoorigen es menor que piso destino el ascensor sube y si pisoorigen es mayor que pisodestino el ascensor baja.

Este programa reinicia el ascensor aunque al comenzar el programa la caja del ascensor se encuentre entre dos pisos, e incluso aunque se encuentre por debajo del piso 1. La única situación que no puede salvar es si se encuentra al inicio por encima del piso 3. Su defecto es que cualquiera nos puede secuestrar el ascensor antes de que llegue al punto deseado, pulsando un nuevo botón.


Evitando que no nos dejen llegar al destino

Para impedir que nos quiten el ascensor desde otra planta vamos a hacer que las estructuras condicionales asociadas a los pulsadores se encuentren dentro de otra estructura condicional cuya condición es que pisoorigen y pisodestino tengan el mismo valor.


Esta es la parte modificada respecto del programa anterior.


El mismo programa realizado con funciones

Para poner un poco de orden en todo esto creamos cuatro funciones en las que colocamos el código correspondiente y llamamos a estas funciones desde el bucle en el momento adecuado.


Programa con memoria

Mientras la caja del ascensor está subiendo o bajando, es decir el momento en que pisoorigen y pisodestino no tienen el mismo valor, si pulsamos un botón su valor se acumula en la variable pisodestino1. Al parar el ascensor, momento en que las variables pisoorigen y pisodestino tienen el mismo valor, lo primero que se hace es sustituir el valor de la variable pisodestino por el de pisodestino1 y pasar esta última a valor 0. De esta manera mientras el ascensor está subiendo o bajando podemos introducir, mediante los botones, un valor para el piso de destino siguiente, le hemos introducido un nivel de memoria, aunque este valor se puede modificar mientras el ascensor está en marcha.

El programa se puede descargar de SteamakersBlocks.


Variando la velocidad del motor

Para variar la velocidad de giro del motor primero se ha de colocar el cable entre el pin ENA del driver  y el pin 10 de Arduino. También se han de modificar las funciones subir y bajar tal como se muestra a continuación.


Incorporando sonido

Para poder incorporar las conexiones de un altavoz de 8 Ω y 2 watios (Comprado en Aliexpress por 3,6 euros) y un zócalo para tarjetas de memoria MicroSD se han de modificar algunas de las conexiones en el modelo de ascensor original. Los finales de carrera que detectan la llegada de la cabina a los distintos pisos están conectados a los pines analógicos A0 (Planta baja), A1 (Primer piso) y A2 (Segundo piso). Los pulsadores utilizados para solicitar el ascensor en los distintos pisos siguen estando conectados a los pines 2 (Planta baja), 4 (Primer piso) y 6 (Segundo piso). 

En el driver del motor L298N se conectan de la misma forma el pin 3 de Arduino a la entrada N1 y el pin 5 a la entrada N2 del driver, que corresponden al motor A. 

El positivo del altavoz está conectado al pin digital 9 y el negativo a GND.

El tarjetero para la MicroSD tiene 6 conexiones, dos para la alimentación a 5 voltios y 4 de señal, CS (El pin de Arduino al que está conectado es el que se debe definir en el programa), SCK, MOSI y MISO. Si se utiliza la librería SD.h el pin 11 está conectado a MOSI, el 12 a MISO y el 13 a SCK. En este caso CS está conectado al pin 10.


El altavoz va montado en una carcasa impresa en 3D que lo protege mediante una rejilla. El archivo para imprimir este elemento se puede descargar de Thingiverse.


A continuación se pueden ver las conexiones del tarjetero.



Este era el aspecto del altavoz antes de protegerlo con su rejilla.


El programa para el ascensor con sonido se puede encontrar en SteamakersBlocks.

Este programa utiliza el Intérprete de código ASCII que también se puede descargar en SteamakersBlocks.

Salvo la función ASCII que tiene un conjunto de bloques muy grande, ya que tiene una estructura condicional para cada código ASCII, todas las demás funciones se muestran a continuación.


En el bloque Inicializar se configura la velocidad del puerto serie, y el pin al que está conectado el tarjetero de la tarjeta SD. Se establecen los valores de las diferentes variables y se leen dos archivos .txt que se utilizarán para producir las melodías RTTTL en el altavoz. He intentado leer tres archivos con la misma estructura de bloques pero no lo ha hecho e ignoro la razón. Para hacer esta lectura se utiliza la función Leer archivo y previamente se asigna a la variable de texto Nombre de archivo el nombre del archivo que se desea leer. Para comprobar que la lectura es correcta se envía la lectura por el puerto serie a la Consola y se reproduce el sonido en el altavoz.


En el bloque Bucle se leen los pines analógicos A0, A1 y A2 conectados a los finales de carrera para asignar valor a la variable numérica pisoorigen

Después se sigue con cuatro estructuras condicionales que comparan las variables pisoorigen y pisodestino

Si las dos variables tienen el mismo valor para la caja del ascensor dirigiéndose a la función Parar, También emite una sintonía con el valor de la variable de texto Piso. Para que esta sintonía solamente se reproduzca una vez se introduce dentro de una estructura condicional controlada por la variable Control1. También se llama a las funciones leer memoria y leer botones que permiten que el ascensor tenga un grado de memoria.

En otra estructura condicional se llama a la función memoria si pisoorigen y pisodestino son diferentes, es decir si el ascensor está subiendo o bajando. De esta forma mientras el ascensor está en movimiento podemos solicitar el ascensor para su siguiente desplazamiento.

Las otras dos estructuras condicionales hacen que la caja del ascensor suba o baje.


Las tres funciones subir, bajar y parar son las que controlan el motor de corriente continua.


La función leer botones asigna valor a la variable pisodestino cuando la caja del ascensor está parada.


La función memoria asigna un valor a la variable pisodestino1 cuando se pulsa alguno de los botones de los diferentes pisos. Esta función se ejecuta mientras la caja del ascensor se está moviendo arriba o abajo. El bloque del zumbador metido dentro de una estructura condicional permite que se ejecute una melodía en el momento de presionar uno de los pulsadores.


La función leer memoria se ejecuta cuando la caja del ascenso r ha llegado a su destino. y hace que el valor de la variable pisodestino sea el de la variable pisodestino1, es decir el que corresponde a alguno de los pulsadores presionados mientras se está moviendo la caja del ascensor.


La función Leer archivo introduce en la variable numérica Medida el valor de la cantidad de bytes del archivo a leer. Esta variable nos permite repetir ese número de veces la operación de leer el valor de todos los bytes del archivo. Una vez leído cada byte se llama a la función ASCII para que devuelva el signo alfanumérico correspondiente. Con esos signos se va haciendo crecer la variable de texto Texto.


Programas con sonido y el IDE de Arduino

Subir y bajar para hacer pruebas

Este programa permite subir la caja del ascensor mientras se aprieta el pulsador del segundo piso y bajarla mientras se aprieta el pulsador de la Planta Baja.

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(6,INPUT);
pinMode(3,OUTPUT);
pinMode(5,OUTPUT);
}

void loop(){

if(digitalRead(6)==HIGH){
  digitalWrite(3,LOW);
  digitalWrite(5,HIGH);
  delay(100);
}
else{
  digitalWrite(3,LOW);
  digitalWrite(5,LOW);
}

if(digitalRead(2)==HIGH){
  digitalWrite(3,HIGH);
  digitalWrite(5,LOW);
  delay(100);
}
else{
  digitalWrite(3,LOW);
  digitalWrite(5,LOW);
}

}

Programa básico de movimiento

El programa básico de subida y bajada para los tres pisos es el siguiente:

int pisoorigen = 0;
int pisodestino = 1; //Este valor hace que al iniciar el programa el ascensor baje al primer piso

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(6,INPUT);
pinMode(3,OUTPUT);
pinMode(5,OUTPUT);
}

void loop()
{

if(digitalRead(2)==HIGH){
    pisodestino = 1;
}  

if(digitalRead(4)==HIGH){
    pisodestino = 2;
}

if(digitalRead(6)==HIGH){
    pisodestino = 3;
}

if(analogRead(A0)>150){
    pisoorigen = 1;
}  

if(analogRead(A1)>150){
    pisoorigen = 2;
}

if(analogRead(A2)>150){
    pisoorigen = 3;
}

if(pisoorigen==pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,LOW);
  delay(100);
}

if(pisoorigen<pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,HIGH);
  delay(100);
}

if(pisoorigen>pisodestino){
  digitalWrite(3,HIGH);
  digitalWrite(5,LOW);
  delay(100);
}

}

Programa con movimiento y sonido 

El programa siguiente integra movimiento y sonido. Al poner en marcha el programa en el setup se ejecuta la función sonido3() que pone en marcha una melodía de inicio. Cuando se presiona un pulsador emite la sintonía correspondiente a la función sonido1() y cuando la caja del ascensor llega a presionar el final de carrera correspondiente emite otra sintonía correspondiente a la función sonido2().

El contenido del archivo inicio.txt es: Ericcson:d=4,o=5,b=355:16b4,16d,16b4,16d,16b4,16d,16b4,16d,16d,16f,16d,16f,16d,16f,16d,16f,16f,16a,16f,16a,16f,16a,16f,16a,1p

El contenido del archivo piso.txt es: Sos:d=16,o=6,b=160:g,p,g,p,g,4p,8g.,p,8g.,p,8g.,4p,g,p,g,p,g,1p,g,p,g,p,g,4p,8g.,p,8g.,p,8g.,4p,g,p,g,p,g

El contenido del archivo llegada.txt es: :d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g,8p,8p

#include <SPI.h>
#include <SD.h>
#include <PlayRtttl.hpp>

const int pinCS = 10;  // Pin CS de la tarjeta SD
int longitud;
int pisoorigen = 0;
int pisodestino = 1; //Este valor hace que al iniciar el programa el ascensor baje al primer piso
boolean Control = false;
File archivo;

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(6,INPUT);
pinMode(3,OUTPUT);
pinMode(5,OUTPUT);

Serial.begin(9600);

  Serial.println("Inicializando tarjeta SD...");
  if (!SD.begin(pinCS)) {
    Serial.println("Error: No se pudo inicializar la tarjeta SD");
    while (true); // Detener ejecución
  }
  Serial.println("Tarjeta SD inicializada correctamente");

sonido3();

}


void sonido1(){

  archivo = SD.open("inicio.txt");
  if (archivo) {
    Serial.println("Leyendo archivo...");

  longitud = archivo.size();
  char contenido[longitud]; // Variable para guardar el contenido

    int i = 0;
    while (archivo.available() && i < longitud) {
      contenido[i] = archivo.read(); // Guardar cada carácter
      i++;
    }
    contenido[i] = '\0'; // Final de cadena

    archivo.close();
   
    Serial.println(contenido); // Imprimir todo el contenido guardado en la variable
    playRtttlBlocking(9, contenido);
   
  } else {
    Serial.println("Error: No se pudo abrir datos.txt");
  }

}

void sonido2(){

  archivo = SD.open("piso.txt");
  if (archivo) {
    Serial.println("Leyendo archivo...");

  longitud = archivo.size();
  char contenido1[longitud]; // Variable para guardar el contenido

    int i = 0;
    while (archivo.available() && i < longitud) {
      contenido1[i] = archivo.read(); // Guardar cada carácter
      i++;
    }
    contenido1[i] = '\0'; // Final de cadena

    archivo.close();
   
    Serial.println(contenido1); // Imprimir todo el contenido guardado en la variable
    playRtttlBlocking(9, contenido1);
   
  } else {
    Serial.println("Error: No se pudo abrir datos.txt");
  }

}

void sonido3(){

  archivo = SD.open("llegada.txt");
  if (archivo) {
    Serial.println("Leyendo archivo...");

  longitud = archivo.size();
  char contenido2[longitud]; // Variable para guardar el contenido

    int i = 0;
    while (archivo.available() && i < longitud) {
      contenido2[i] = archivo.read(); // Guardar cada carácter
      i++;
    }
    contenido2[i] = '\0'; // Final de cadena

    archivo.close();
   
    Serial.println(contenido2); // Imprimir todo el contenido guardado en la variable
    playRtttlBlocking(9, contenido2);
   
  } else {
    Serial.println("Error: No se pudo abrir datos.txt");
  }

}

void loop()
{

if(digitalRead(2)==HIGH){
    pisodestino = 1;
    sonido1();
}  

if(digitalRead(4)==HIGH){
    pisodestino = 2;
    sonido1();
}

if(digitalRead(6)==HIGH){
    pisodestino = 3;
    sonido1();
}

if(analogRead(A0)>150){
    pisoorigen = 1;
}  

if(analogRead(A1)>150){
    pisoorigen = 2;
}

if(analogRead(A2)>150){
    pisoorigen = 3;
}

if(pisoorigen==pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,LOW);
  if(Control==true){
    sonido2();
    Control = false;
  }
 
  delay(100);
}

if(pisoorigen<pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,HIGH);
  Control = true;
  delay(100);
}

if(pisoorigen>pisodestino){
  digitalWrite(3,HIGH);
  digitalWrite(5,LOW);
  Control = true;
  delay(100);
}

}

Añadiendo una pantalla OLED

Para añadir la pantalla OLED usaré la librería SSD1306Ascii.h, ya que parece que la librería Adafruit_SSD1306.h resulta incompatible con las librerías que gestionan la tarjeta MicroSD. De todas formas con los dos elementos el programa se vuelve muy lento y la pantalla solamente trabaja al principio del programa.

#include <SPI.h>
#include <SD.h>
#include <PlayRtttl.hpp>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"


// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C

// Define proper RST_PIN if required.
#define RST_PIN -1

SSD1306AsciiAvrI2c oled;

const int pinCS = 10;  // Pin CS de la tarjeta SD
int longitud;
int pisoorigen = 0;
int pisodestino = 1; //Este valor hace que al iniciar el programa el ascensor baje al primer piso
boolean Control = false;
boolean Control1 = false;
File archivo;

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(6,INPUT);
pinMode(3,OUTPUT);
pinMode(5,OUTPUT);

Serial.begin(9600);





  Serial.println("Inicializando tarjeta SD...");
  if (!SD.begin(pinCS)) {
    Serial.println("Error: No se pudo inicializar la tarjeta SD");
    while (true); // Detener ejecución
  }
  Serial.println("Tarjeta SD inicializada correctamente");

sonido3();

 #if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0

  oled.setFont(Callibri15);
// oled.setFont(Arial14);
// oled.setFont(Callibri11_bold);
// oled.setFont(TimesNewRoman13);

  // Increase space between letters.
  oled.setLetterSpacing(2);
 
  oled.clear();
  oled.setStartLine(2);
  oled.println("ASCENSOR");
  oled.setStartLine(1);
  oled.println("Suba con nosotros");
  oled.println("Bienvenido");
}


void sonido1(){

  archivo = SD.open("inicio.txt");
  if (archivo) {
    Serial.println("Leyendo archivo...");

  longitud = archivo.size();
  char contenido[longitud]; // Variable para guardar el contenido

    int i = 0;
    while (archivo.available() && i < longitud) {
      contenido[i] = archivo.read(); // Guardar cada carácter
      i++;
    }
    contenido[i] = '\0'; // Final de cadena

    archivo.close();
   
    Serial.println(contenido); // Imprimir todo el contenido guardado en la variable
    playRtttlBlocking(9, contenido);
   
  } else {
    Serial.println("Error: No se pudo abrir datos.txt");
  }

}

void sonido2(){

  archivo = SD.open("piso.txt");
  if (archivo) {
    Serial.println("Leyendo archivo...");

  longitud = archivo.size();
  char contenido1[longitud]; // Variable para guardar el contenido

    int i = 0;
    while (archivo.available() && i < longitud) {
      contenido1[i] = archivo.read(); // Guardar cada carácter
      i++;
    }
    contenido1[i] = '\0'; // Final de cadena

    archivo.close();
   
    Serial.println(contenido1); // Imprimir todo el contenido guardado en la variable
    playRtttlBlocking(9, contenido1);
   
  } else {
    Serial.println("Error: No se pudo abrir datos.txt");
  }

}

void sonido3(){

  archivo = SD.open("llegada.txt");
  if (archivo) {
    Serial.println("Leyendo archivo...");

  longitud = archivo.size();
  char contenido2[longitud]; // Variable para guardar el contenido

    int i = 0;
    while (archivo.available() && i < longitud) {
      contenido2[i] = archivo.read(); // Guardar cada carácter
      i++;
    }
    contenido2[i] = '\0'; // Final de cadena

    archivo.close();
   
    Serial.println(contenido2); // Imprimir todo el contenido guardado en la variable
    playRtttlBlocking(9, contenido2);
   
  } else {
    Serial.println("Error: No se pudo abrir datos.txt");
  }

}

void loop()
{

if(digitalRead(2)==HIGH){
    pisodestino = 1;
    oled.clear();
    oled.setStartLine(2);
    oled.println("PLANTA BAJA");
    sonido1();
}  

if(digitalRead(4)==HIGH){
    pisodestino = 2;
    oled.clear();    
    oled.setStartLine(2);
    oled.println("PRIMERO");    
    sonido1();
}

if(digitalRead(6)==HIGH){
    pisodestino = 3;
    oled.clear();
    oled.setStartLine(2);
    oled.println("SEGUNDO");    
    sonido1();
}

if(analogRead(A0)>150){
    pisoorigen = 1;
}  

if(analogRead(A1)>150){
    pisoorigen = 2;
}

if(analogRead(A2)>150){
    pisoorigen = 3;
}

if(pisoorigen==pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,LOW);
  if(Control==true){
    sonido2();
    Control = false;
  }
 
  delay(100);
}

if(pisoorigen<pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,HIGH);
  Control = true;
  delay(100);
}

if(pisoorigen>pisodestino){
  digitalWrite(3,HIGH);
  digitalWrite(5,LOW);
  Control = true;
  delay(100);
}

}

 





Prescindiendo de la MicroSD para que sea operativo

Para hacer más ágil el funcionamiento del ascensor paso a prescindir del uso de la tarjeta MicroSD.

#include <PlayRtttl.hpp>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"


// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C

// Define proper RST_PIN if required.
#define RST_PIN -1

SSD1306AsciiAvrI2c oled;

int pisoorigen = 0;
int pisodestino = 1; //Este valor hace que al iniciar el programa el ascensor baje al primer piso
boolean Control = false;
char sonido11[] = "Ericcson:d=4,o=5,b=355:16b4,16d,16b4,16d,16b4,16d,16b4,16d,16d,16f,16d,16f,16d,16f,16d,16f,16f,16a,16f,16a,16f,16a,16f,16a,1p";
char sonido12[] = "C:d=4,o=5,b=140:8e6,8d#6,8e6,8d#6,8e6,8b,8d6,8c6,a,8p,8c,8e,8a,b,8p,8e,8g#,8b,c6";
char sonido13[] = "Sos:d=16,o=6,b=160:g,p,g,p,g,4p,8g.,p,8g.,p,8g.,4p,g,p,g,p,g,1p,g,p,g,p,g,4p,8g.,p,8g.,p,8g.,4p,g,p,g,p,g";

void setup()
{
pinMode(2,INPUT);
pinMode(4,INPUT);
pinMode(6,INPUT);
pinMode(3,OUTPUT);
pinMode(5,OUTPUT);

Serial.begin(9600);

sonido3();

 #if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0
  oled.clear();
  oled.setFont(Callibri15);
// oled.setFont(Arial14);
// oled.setFont(Callibri11_bold);
// oled.setFont(TimesNewRoman13);

  // Increase space between letters.
  oled.setLetterSpacing(2);
 
  oled.clear();
  oled.setStartLine(2);
  oled.println("ASCENSOR");
  oled.setStartLine(1);
  oled.println("Suba con nosotros");
  oled.println("Bienvenido");
}


void sonido1(){

  playRtttlBlocking(9, sonido11);  

}

void sonido2(){

  playRtttlBlocking(9, sonido12);

}

void sonido3(){

   playRtttlBlocking(9, sonido13);

}

void loop()
{

if(digitalRead(2)==HIGH){
    pisodestino = 1;
    oled.clear();
    oled.setStartLine(3);
    oled.println("");
    oled.println("PLANTA BAJA");
    sonido1();
}  

if(digitalRead(4)==HIGH){
    pisodestino = 2;
    oled.clear();    
    oled.setStartLine(3);
    oled.println("");
    oled.println("PRIMERO");    
    sonido1();
}

if(digitalRead(6)==HIGH){
    pisodestino = 3;
    oled.clear();
    oled.setStartLine(3);
    oled.println("");
    oled.println("SEGUNDO");    
    sonido1();
}

if(analogRead(A0)>150){
    pisoorigen = 1;
}  

if(analogRead(A1)>150){
    pisoorigen = 2;
}

if(analogRead(A2)>150){
    pisoorigen = 3;
}

if(pisoorigen==pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,LOW);
  if(Control==true){
    sonido2();
    Control = false;
  }
 
  delay(100);
}

if(pisoorigen<pisodestino){
  digitalWrite(3,LOW);
  digitalWrite(5,HIGH);
  Control = true;
  delay(100);
}

if(pisoorigen>pisodestino){
  digitalWrite(3,HIGH);
  digitalWrite(5,LOW);
  Control = true;
  delay(100);
}

}

 

Programando con SteamakersBlocks sonido y OLED

Con SteamakersBlocks he hecho un programa similar al anterior.














No hay comentarios:

Publicar un comentario