Está en la página 1de 8

#include <Servo.

h>
/*
====================================================================================================
=====================================
CONSTANTES

====================================================================================================
===================================== */

// Constantes de configuración de pines y nombres para su testeo

const int PLANTAS = 3; // Ascensor con tres plantas

// Parámetros de ángulo de giro del servo


const int ANGULOMAXIMO = 180;
const int ANGULOMINIMO = 0;
const int PASO = 30;

const int outServo = 3; // Salida del servo. Pendiente de ubicar. Utilizar para el control
los pines asociados al PWM

// Pines de salida del BCD 7 segementos. Muestra la planta actual


const int outPinA = 10;
const int outPinB = 11;
const int outPinC = 12;
const int outPinD = 13;
// Led's que simulan el sentido de giro del motor del ascensor
const int subidaMotor = 0;
const int bajadaMotor = 1;

// Led´s que indican el estado en que nos encontramos


const int ledReposo = 2;
const int ledEntreplanta = A0;
const int ledPuerta = A2;

const int fCarrera = A4; // Sensor de final de carrera del motor subida bajada. Lectura de
pin analógico
const int sensorPuerta = A5; // Sensor de seguridad de la puerta. Lectura de pin analógico

// Pines de entrada de la botonera del ascensor y botón de cada planta


const int botAscensor[PLANTAS] = {4,5,6}; // Dentro se indica el número del pin utilizado
const int botPlanta[PLANTAS] = {7,8,9};

//int fCarreraPlanta[PLANTAS -1]; // Sensor de final de carrera que avisa de llegada


a la planta --> parar el ascensor
//int sensorPuerta[PLANTAS -1]; // Sensor de seguridad de cierre de puertas --> uno
por cada planta

/*
====================================================================================================
=====================================
VARIABLES

====================================================================================================
===================================== */

// Configuración del servomotor


Servo puertaServo; // Crear un objeto servo
int posicionServo = 0; // posición de servo

// Registros utilizados para el funcionamiento del Ascensor. De la planta [1


a PLANTAS -1]
int botonesAscensor[PLANTAS]; // Array de pulsadores del teclado del ascensor
int pulsadoresPlanta[PLANTAS]; // Array de pulsadores de cada planta
//int finalCarrPlanta[PLANTAS]; // Array de finales de carrera para cada planta

// Variables para conocer el estado y ubicación del ascensor


int planta = 0; // Indica la planta actual donde se encuentra el
ascensor. Se actualiza al llegar a una nueva planta
int estadoAscensor = 0; // '0' --> reposo, '1' --> subir, '2' --> bajar
boolean estadoReposo = false; // Variable semáforo para no re-escribir en los
puertos de salida. Reposo planta
boolean estadoPuerta = false; // Variable semáforo para no re-escribir en los
puertos de salida. Puerta
int estado = 0; // Para la máquina de estados del ascensor

// Variables de ayuda a la secuencias de funcionamiento


boolean encendidoMotor = false;
boolean abriendoPuerta = false;
int parpadeo = LOW;

// Variables para el parpadeo de led


long milisegundosAnteriores = 0; // Almacena la última vez que el LED se ha actualizado. Se
utilizan variables long ya que el tiempo se mide en milisegundos
// Rápidamente se convertirá en un número más grande que se
puede almacenar en un int
long periodo = 500; // Intervalo de parpadeo del LED (milisegundos)

// Variables de filtrado de ruido en la lectura de sensores ópticos


long miliSegAntLectura = 0; // Variable que almacena la última lectura de 'millis()'
para comparar el tiempo transcurrido
long intervalo = 350; // Tiempo de espera para eliminar ruido
boolean lecturaOptico = false; // Variable para leer la primera activación y rechazar el
resto durante un tiempo determinado 'intervalo'

// Variables de lectura pulsadores


int anteriorLeido = LOW; // Lectura anterior del pulsador de entrada

/*
====================================================================================================
=====================================
FUNCIONES
====================================================================================================
===================================== */

// Lectura de la entrada indicada en 'pin'


boolean antiRebote(int pin){

boolean pulsado = false;


int leido = digitalRead(pin); // Lee el estado del pin y la almacena en una
variable local

if (leido == HIGH && anteriorLeido == LOW) // Si el pulsador cambia de 0 a 1


pulsado = true;

anteriorLeido = leido;
return pulsado;
}

// Retardo de tiempo indicado en tiempo para filtrar ruido en las lecturas


// Anchura del tiempo de antirrebote --> ( miliSegActuales - miliSegAntLectura > X mseg )
boolean retardo(){
unsigned long miliSegActuales = millis();

if(miliSegActuales - miliSegAntLectura > intervalo){


miliSegAntLectura = miliSegActuales; // Guarda la última vez que se ha cumplido el tiempo de
filtro y actualiza la variable 'miliSegAntLectura'
if (lecturaOptico) // Si ya se ha cumplido el tiempo del filtro y se ha
leído el primer cambio en el sensor, se cambia
lecturaOptico = false; // 'lecturaOptico = false' para iniciar una nueva captura
del senor
}
return lecturaOptico;
}
// Lee el sensor óptico del pin analógico correspondiente. Con filtro antirrebote
int lecturaSensorOptico(int sensor){
int lectura = LOW;
unsigned long miliSegActuales = millis();

if (analogRead(sensor) <= 100 && !retardo()){ // Se recoge el primer dato y cuando pasa un
tiempo mínimo 'intervalo' (filtro ruido) --> se puede volver a capturar un nuevo dato
lectura = HIGH; // Hay activación del sensor
lecturaOptico = HIGH;
}
return lectura;
}

// Lectura de los pulsadores de la botonera del ascensor y de cada planta


void lecturaPulsadores(){
for (int i = 0; i < PLANTAS; i++){
if (antiRebote(botAscensor[i])){
botonesAscensor[i] = HIGH;
}
if (antiRebote(botPlanta[i])){
pulsadoresPlanta[i] = HIGH;
}
}
}

// Indica el número de planta en que se encuentra


void numeroPlanta(int num){
// Convierte un número decimal a binario y lo saca por los pines de salida 0-3
digitalWrite(outPinD, HIGH && (num & B00001000));
digitalWrite(outPinC, HIGH && (num & B00000100));
digitalWrite(outPinB, HIGH && (num & B00000010));
digitalWrite(outPinA, HIGH && (num & B00000001));
}

// Indica si se ha pulsado algún botón de la planta indicada


boolean botonPulsado(int planta){
return (botonesAscensor[planta]== HIGH) || (pulsadoresPlanta[planta]== HIGH);
}

// Indica que se ha pulsado algún botón distinto al de la planta donde está el ascensor
boolean llamadaAscensor(int planta){
boolean llamada = false;
for (int i = 0; i < PLANTAS; i++){
if (i != planta){
if (botonesAscensor[i] == HIGH || pulsadoresPlanta[i] == HIGH)
llamada = true;
}
}
return llamada;
}

/*
----------------------------------------------------------------------------------------------------
---------------------------- */

// Sensor de llegada a planta. Llama a la función de lectura del sensor, escribe en la posición
correspondiente y luego lo verifica
boolean sensorFinalCarrera(int sensor, int planta){
// finalCarrPlanta[planta] = lecturaSensorOptico(sensor); // Para cuando se dispone de un
sensor por planta
return lecturaSensorOptico(sensor) == HIGH; // Verifico si se ha activado el
sensor de final de carrera
}

/* ······························· Funciones para control del motor de subida/bajada del ascensor


························ */

// Para el motor del ascensor


void pararMotor(){
// apagar el led correspondiente de simulado de funcionamiento
digitalWrite(subidaMotor, LOW);
digitalWrite(bajadaMotor, LOW);
encendidoMotor = false;
}

// Arranque en sentido de subida. Simulado con un led


boolean arranqueMotorSubida(){
digitalWrite(subidaMotor, HIGH);
return true;
}

// Arranque en sentido de bajada. Simulado con un led


boolean arranqueMotorBajada(){
digitalWrite(bajadaMotor, HIGH);
return true;
}

/*
····································································································
···················· */

// Encendido con parpadeo de led de estado


void parpadeoLedEstado(int pin){

unsigned long milisegundosActuales = millis();

if(milisegundosActuales - milisegundosAnteriores > periodo) {


milisegundosAnteriores = milisegundosActuales; // Guarda la última vez que parpadeaba el LED
parpadeo = !parpadeo; // Conmuta el valor escrito en el pin
digitalWrite(pin, parpadeo);
}
}

// Encendido de led de estado


boolean ledEstadoEncendido(int pin){
digitalWrite(pin, HIGH);
return true;
}

// Apagado de led de estado


boolean ledEstadoApagado(int pin){
digitalWrite(pin, LOW);
return false;
}

// Incrementa o disminuye una posición el valor de planta


void actualizarPlanta(){
if (estadoAscensor == 1) // Ascensor subiendo
planta++;
else if (estadoAscensor == 2) // Ascensor bajando
planta--;
}

// se comprueba que el sentido es de subida


boolean subidaAscensor(){
return (estadoAscensor == 1);
}

// Se comprueba que el sentido es de bajada


boolean bajadaAscensor(){
return (estadoAscensor == 2);
}

// Determina el sentido de subida/bajada indicándolo en la variable


// 'estadoAscensor' : '0' --> reposo, '1' --> subir, '2' --> bajar
int sentidoAscensor(int planta){

// Si el ascensor está subiendo


int i = planta;
while (i < PLANTAS){
if (botonesAscensor[i] == 1 || pulsadoresPlanta[i] == 1){
return 1; // Hay que ascender
}
i++;
}
// Si el ascensor está bajando
i = planta;
while (i > -1){
if (botonesAscensor[i] == 1 || pulsadoresPlanta[i] == 1){
return 2; // Hay que descender
}
i--;
}
return 0; // Estado de reposo
}

/*
----------------------------------------------------------------------------------------------------
---------------------------- */

// Se borra en la planta correspondiente los botones que ahí se hayan pulsado


void borradoRegistroPlanta(int planta){
botonesAscensor[planta] = 0;
pulsadoresPlanta[planta] = 0;
}

// Sensor de seguridad de cierre de la puerta ante obstáculos


boolean sensorSeguridadPuerta(int sensor){
// sensorPuerta[planta] = lecturaSensorOptico(sensor); // Para cuando se dispone de un sensor
por planta para cada puerta
return lecturaSensorOptico(sensor) == HIGH; // Verifico que se ha activado el sensor
}

/* ······························· Funciones para control del motor paso a paso de la puerta del
ascensor ························ */

// Indica que la puerta está completamente abierta


boolean puertaAbierta(){
return posicionServo == ANGULOMAXIMO; // Se ha abierto completamente
}

// Indica que la puerta está completamente cerrada


boolean puertaCerrada(){
return posicionServo == ANGULOMINIMO; // Se ha cerrado completamente
}

// Detiene el cierre de la puerta --> por algún obstáculo


void paradaPuerta(){
delay(2000); // Detiene el funcionamiento del motor paso a paso
}

// Detiene la puerta en la última posición conocida


void detenerPuerta(){
puertaServo.write(posicionServo);
delay(500);
}

// Abre completamente la puerta desde la posición en la que se encontraba en ese momento


boolean aperturaEmergenciaPuerta(){

while (posicionServo < ANGULOMAXIMO){


posicionServo = posicionServo + PASO; // Valores en puerto serie (0-180)
puertaServo.write(posicionServo);
delay(50);
}
return true;
}
// Se abre la puerta del ascensor, durante un tiempo determinado
// OJO --> hay que tener en cuenta que no se debe activar o tener en cuenta el sensor de seguridad
de la puerta
boolean aperturaPuerta(){

if (posicionServo < ANGULOMAXIMO){


posicionServo = posicionServo + PASO; // Valores en puerto serie (0-180)
puertaServo.write(posicionServo);
delay(50);
}
return true;
}

// Indica cuando se ha terminado de cerrar la puerta, tras un tiempo, de entrada del ascensor
boolean cierrePuerta(){

if (posicionServo > ANGULOMINIMO){


posicionServo = posicionServo - PASO; // Valores en puerto serie (0-180)
puertaServo.write(posicionServo);
delay(100);
}
return true;
}

/*
····································································································
··························· */

/*
====================================================================================================
=====================================
INICIALIZACIÓN Y CONFIGURACIÓN

====================================================================================================
===================================== */

void setup() {

// Configuración de los pines digitales como entrada

pinMode(fCarrera, INPUT);

for (int i = 0; i < PLANTAS; i++){


pinMode(botAscensor[i], INPUT); // Dentro se indica el número del pin utilizado
pinMode(botPlanta[i] , INPUT);
botonesAscensor[i] = LOW;
pulsadoresPlanta[i] = LOW;
// finalCarrPlanta[i]= LOW; // Cuando se tiene un sensor de final carrera por planta
}

// Configuración de los pines digitales como salida. BCD 7 Segmentos


pinMode(outPinD, OUTPUT);
pinMode(outPinC, OUTPUT);
pinMode(outPinB, OUTPUT);
pinMode(outPinA, OUTPUT);

// Configuración de led's de estado


pinMode(ledEntreplanta, OUTPUT);
pinMode(ledReposo, OUTPUT);
pinMode(ledPuerta, OUTPUT);

// Led's de simulación del motor


pinMode(subidaMotor, OUTPUT);
pinMode(bajadaMotor, OUTPUT);

// Configuración del servo de apertura/cierre de puerta


puertaServo.attach(outServo); // Asocia el servo al pin 3
puertaServo.write(ANGULOMINIMO); // Inicializa la posición del servo
}

/*
====================================================================================================
=========================================
EJECUCIÓN DE LA APLICACIÓN

====================================================================================================
========================================== */

void loop(){

lecturaPulsadores(); // Lectura de todos los pulsadores del


Ascensor

switch(estado){
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ESTADO DE REPOSO EN PLANTA n
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */

case 0:
if (botonPulsado(planta)){ // En reposo, si se pulsa para abrir la puerta
y se está en la misma planta.
// Ya sea planta de destino o para seguir
subiendo o bajando
estado = 2;
estadoReposo = ledEstadoApagado(ledReposo);
}
else if (llamadaAscensor(planta)){ // Si se pulsa un boton para subir o bajar

estado = 1;
estadoReposo = ledEstadoApagado(ledReposo);
}
else if (!estadoReposo){ // Condición de reposo en una planta. Solo
entra una vez para no sobre-escribir los puertos

estadoReposo = ledEstadoEncendido(ledReposo);
numeroPlanta(planta);
}
break;

/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ESTADO DE ENTREPLANTA


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
/* xxxxx Activa el motor para subir/bajar el ascensor, y espera la activación del final
de carrera de la siguiente planta xxxxxxxx */

case 1:
parpadeoLedEstado(ledEntreplanta); // Indicador de entreplanta con parpadeo

if (sensorFinalCarrera(fCarrera, planta)){ // Espera a pasar por la siguiente


planta. Ascendiendo o descendiendo

actualizarPlanta(); // Se actualiza la planta de llegada


numeroPlanta(planta); // Planta a la que llegamos

if (botonPulsado(planta)){ // Llegada a planta deseada


pararMotor();
ledEstadoApagado(ledEntreplanta);
estado = 0;
}
}
else if (!encendidoMotor){ // Condición inicial. Aún no se ha
arrancado el motor

estadoAscensor = sentidoAscensor(planta); // Devuelve si se va a subir, bajar o


se está en reposo. La ascensión es preferente
if (subidaAscensor()){ // Se está subiendo.
encendidoMotor = arranqueMotorSubida();
}
else if (bajadaAscensor()){ // Se está bajando
encendidoMotor = arranqueMotorBajada();
}
}
break;

/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ESTADO DE APERTURA/CIERRE DE PUERTA


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */

case 2:
// Si se activa el sensor de seguridad de la puerta --> Algún obstáculo
if (sensorSeguridadPuerta(sensorPuerta) && !abriendoPuerta){ // Si se activa el sensor de
seguridad y se está cerrando la puerta
detenerPuerta(); // Detiene el cierre de la puerta
aperturaEmergenciaPuerta(); // Apertura de emergencia
paradaPuerta(); // Mantiene la puerta abierta durante
3 segundos
abriendoPuerta = true;
}
// Proceso normal: apertura + espera + cierre de puerta
else { // No se activa el sensor de
seguridad
if (botonPulsado(planta)){ // Apertura de puerta // Cada
pasada, se desplaza una distancia determinada por PASO del servo

if(!estadoPuerta){ // Inicio estado de apertura/cierre


de puerta. Solo entra una vez para no sobre-escribir los puertos
estadoPuerta = ledEstadoEncendido(ledPuerta);
}
aperturaPuerta();
abriendoPuerta = true;

if (puertaAbierta()){
borradoRegistroPlanta(planta); // Por si alguien vuelve a pulsar el
botón de planta, se abren las puertas
paradaPuerta();
}
}
else if (puertaCerrada()){ // La puerta ya está cerrada
estadoPuerta = ledEstadoApagado(ledPuerta);
estado = 0; // Vuelve a reposo en la planta donde
se encuentra el ascensor
}
else if(!botonPulsado(planta)){ // Proceso de cierre de puerta
abriendoPuerta = false;
cierrePuerta();
}
}
break;
}

También podría gustarte