Aquí tienes la "adaptación rápida" del código convertido en la clase Aguja. Esto nos permite definir más agujas rápidamente. Como ejemplo, he puesto que controle dos agujas.
//Desvío simple con millis() 4/5/2020
//Servo con dos botones y LEDs. Resistencias Pull Up.
#include <Servo.h>
const uint8_t PIN_SERVO_UNO = 3; // motor en PIN ~3
const uint8_t PIN_SERVO_DOS = 10; // motor en PIN ~10
//Botones
const uint8_t PIN_DESVIO_UNO = 4; // Botón para desvío, mueve a izquierda
const uint8_t PIN_RECTA_UNO = 5; // Botón para vía recta, mueve a derecha (0°)
const uint8_t PIN_DESVIO_DOS = 8; // Botón para desvío, mueve a izquierda
const uint8_t PIN_RECTA_DOS = 9; // Botón para vía recta, mueve a derecha (0°)
const uint8_t VALOR_BOTON_DETECTADO = LOW; //Valor que deberá tener el pin cuando se detecta el botón
//LEDs
const uint8_t VERDE_RECTA_UNO = 6; // Led de vía recta
const uint8_t AZUL_DESVIO_UNO = 7; // LED de desvío
const uint8_t VERDE_RECTA_DOS = 11; // Led de vía recta
const uint8_t AZUL_DESVIO_DOS = 12; // LED de desvío
const unsigned long TIEMPO_DURACION_CAMBIO = 1500UL; // Este es el tiempo total que queremos que tarde la aguja en cambiar de posición
// Prototipado de la clase Aguja
class Aguja {
public: // Las variables y funciones declaradas como públicas son accesibles por todos
// Constructor
Aguja(Servo &servo, unsigned long duracionCambio, uint8_t pinRecta, uint8_t pinDesvio, uint8_t pinLuzVerde, uint8_t pinLuzAzul);
void loop(); // Lo que normalmente pondríamos en el loop() principal. Se ha de ejecutar contínuamente
private: // Las variables y funciones declaradas como privada no son accesibles fuera de la clase
Servo &servo; // Referencia al servo
unsigned long duracionCambio; // Este es el tiempo total que queremos que tarde la aguja en cambiar de posición
uint8_t pinRecta; // Botón para vía recta, mueve a derecha (0°)
uint8_t pinDesvio; // Botón para desvío, mueve a izquierda
uint8_t pinLuzVerde;
uint8_t pinLuzAzul;
int anguloActual; // Ángulo en que se encuentra actualmente la aguja. Inicialmente lo pondremos a cero
int anguloDestino; // Ángulo en que queremoa que se posicione la aguja. Inicialmente lo pondremos a cero
unsigned long instanteAnterior; // En principio lo inicializamos a cero, sólo se usa cuando se está moviendo la aguja
unsigned long tiempoUnGrado; // Tiempo que ha de pasar entre grado y grado de movimiento de la aguja
enum estado_t { // Estos son los estados de cualquier aguja, no importa qué aguja (no hace falta el _UNO)
ESTADO_INICIAL, // Para cuando se encienda el Arduino se posicione recta
ESTADO_DESVIANDO, // Cuando está cambiando de recta a desvío
ESTADO_DESVIO, // Cuando está en modo desvío
ESTADO_RECTIFICANDO, // Cuando está cambiando de desvío a recta
ESTADO_RECTA, // Cuando está en recta
} estado; // Inicialmente tenemos que posicionarla recta, sí o sí
};
// Implementación de las funciones de la clase Aguja
Aguja::Aguja(Servo &servo, unsigned long duracionCambio, uint8_t pinRecta, uint8_t pinDesvio, uint8_t pinLuzVerde, uint8_t pinLuzAzul)
: servo(servo),
duracionCambio(duracionCambio),
pinRecta(pinRecta),
pinDesvio(pinDesvio),
pinLuzVerde(pinLuzVerde),
pinLuzAzul(pinLuzAzul),
anguloActual(0),
anguloDestino(0),
instanteAnterior(0),
tiempoUnGrado(0),
estado(ESTADO_INICIAL)
{
pinMode(pinRecta, INPUT_PULLUP); // resistencia PULL UP
pinMode(pinDesvio, INPUT_PULLUP);
pinMode(pinLuzVerde, OUTPUT); //Configura pines de salida para LEDs
pinMode(pinLuzAzul, OUTPUT);
}
void Aguja::loop() {
unsigned long instanteActual = millis();
// La variable estado nos indica en qué estado se encuentra la máquina de estados.
// Tenemos que controlar qué ha de hacerse mientras se está en ese "estado".
// Según el estado y las "condiciones" se mantiene en el estado en que está o cambia de estado.
switch (estado) {
case ESTADO_INICIAL: // Encendido Arduino, posicionamos la vía recta 0°
servo.write(0); // Mueve a 0°
// Indicamos vía recta
digitalWrite (pinLuzAzul, LOW); // Apagar el LED de desvío
digitalWrite(pinLuzVerde, HIGH); // Enciende LED verde, vía recta
estado = ESTADO_RECTA; // Cambiamos de estado
break; // Si no ponemos este break, el programa continúa ejecutando las siguientes líneas
case ESTADO_RECTA: // La vía está recta y permanecerá en este estado hasta que se pulse el botón de desvío
if (digitalRead(pinDesvio) == VALOR_BOTON_DETECTADO) { // Si se pulsa el botón de desvío
// Indicamos desvío
digitalWrite (pinLuzVerde, LOW);
digitalWrite (pinLuzAzul, HIGH);
anguloDestino = 45; // Ángulo en que queremoa que se posicione la aguja
tiempoUnGrado = duracionCambio / abs(anguloDestino - anguloActual); // Tiempo de "salto" entre grado y grado de movimento
anguloActual++; // Incrementamos un grado el ángulo actual
servo.write(anguloActual); // Posisionamos el servo en el nuevo ángulo
instanteAnterior = instanteActual; // Guardamos el instante en que se ha movido el servo
estado = ESTADO_DESVIANDO; // Cambiamos de estado
}
break;
case ESTADO_DESVIANDO: // Se está moviendo la aguja para desvío
if ((instanteActual - instanteAnterior) >= tiempoUnGrado) { // Si ya ha pasado el tiempo que hay que esperar entre cada moviento de un grado
anguloActual++; // Incrementamos un grado el ángulo actual
servo.write(anguloActual); // Posisionamos el servo en el nuevo ángulo
instanteAnterior = instanteActual; // Guardamos el instante en que se ha movido el servo
if (anguloActual == anguloDestino) { // Si ya la aguja está en su "destino", cambiamos de estado
estado = ESTADO_DESVIO; // Cambiamos de estado
}
}
break;
case ESTADO_DESVIO: // La vía está desvíada y permanecerá en este estado hasta que se pulse el botón de recta
if (digitalRead(pinRecta) == VALOR_BOTON_DETECTADO) { // Si se pulsa el botón de reta
// Indicamos vía recta
digitalWrite (pinLuzVerde, HIGH);
digitalWrite (pinLuzAzul, LOW);
anguloDestino = 0; // Ángulo en que queremoa que se posicione la aguja
tiempoUnGrado = duracionCambio / abs(anguloDestino - anguloActual); // Tiempo de "salto" entre grado y grado de movimento
anguloActual--; // Decrementamos un grado el ángulo actual
servo.write(anguloActual); // Posisionamos el servo en el nuevo ángulo
instanteAnterior = instanteActual; // Guardamos el instante en que se ha movido el servo
estado = ESTADO_RECTIFICANDO; // Cambiamos de estado
}
break;
case ESTADO_RECTIFICANDO: // Se está moviendo la aguja para vía recta
if ((instanteActual - instanteAnterior) >= tiempoUnGrado) { // Si ya ha pasado el tiempo que hay que esperar entre cada moviento de un grado
anguloActual--; // Decrementamos un grado el ángulo actual
servo.write(anguloActual); // Posisionamos el servo en el nuevo ángulo
instanteAnterior = instanteActual; // Guardamos el instante en que se ha movido el servo
if (anguloActual == anguloDestino) { // Si ya la aguja está en su "destino", cambiamos de estado
estado = ESTADO_RECTA; // Cambiamos de estado
}
}
break;
}
}
Servo servoUno;
Servo servoDos;
Aguja agujaUno(servoUno, TIEMPO_DURACION_CAMBIO, PIN_RECTA_UNO, PIN_DESVIO_UNO, VERDE_RECTA_UNO, AZUL_DESVIO_UNO);
Aguja agujaDos(servoDos, TIEMPO_DURACION_CAMBIO, PIN_RECTA_DOS, PIN_DESVIO_DOS, VERDE_RECTA_DOS, AZUL_DESVIO_DOS);
void setup() {
servoUno.attach(PIN_SERVO_UNO, 750, 1800); //Configura el Servo, 750 ms = 0° y 1800 ms = 180°
servoDos.attach(PIN_SERVO_DOS, 750, 1800); //Configura el Servo, 750 ms = 0° y 1800 ms = 180°
}
void loop() {
agujaUno.loop(); // Llamamos al loop() de Aguja
agujaDos.loop(); // Llamamos al loop() de Aguja
}