aboutsummaryrefslogtreecommitdiff
path: root/textil.ino
blob: 846cb4162e88163e3a8b44aab814b5cb01181222 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
enum Reles {
  Rele1,
  Rele2,
  Rele3,
  MAX_RELE,
};

/* Configuracion */

// Tiempos de espera antes de emitir senyales de salida de rele.
// Unidades en milisegundos (1s = 1000ms).
const unsigned long TIEMPO_ESPERA_SALIDA_MS[MAX_RELE] = {
  5000,  // Rele 1.
  2000,  // Rele 2.
  3000,  // Rele 3.
};

// Pines reles.
//
// Pines 0 y 1 en Arduino UNO son para comunicacion serie, no usar.
const int Rele_Pin[MAX_RELE] = {
  2,  // Rele 1.
  3,  // Rele 2.
  4,  // Rele 3.
};

// Pin pulsador.
const int Pulsador_Pin = 5;

enum Estado {
  Estado_Inicial,
  Espera_Rele1,
  Salida_Rele1,
  Espera_Rele2,
  Salida_Rele2,
  Espera_Rele3,
  Salida_Rele3,
  Estado_Final,
  MAX_ESTADO,
};

enum Transicion {
  Automatica,  // Transicion automatica.
  Retardada,   // Transicion automatica retardada.
  Manual,      // Transicion al pulsar boton.
};

const Transicion transiciones[MAX_ESTADO] = {
  Manual,      // Estado_Inicial -> Espera_Rele1
  Retardada,   //                -> Salida_Rele1
  Manual,      //                -> Espera_Rele2
  Retardada,   //                -> Salida_Rele2
  Manual,      //                -> Espera_Rele3
  Retardada,   //                -> Salida_Rele3
  Manual,      //                -> Estado_Final
  Automatica,  //                -> Estado_Inicial
};


/* Entrada digital con debounce. */

// Tiempo en el que la senyal debe permanecer con un valor constante para
// que se ejecute la lectura logica de la senyal.
const unsigned long DEBOUNCE_DELAY_MS = 50;

struct EntradaDigital {
  int pin;                         // Pin de entrada.
  int estado;                      // Estado logico actual, LOW o HIGH.
  int ultima_senyal;               // Ultima senyal de entrada, LOW o HIGH.
  unsigned long debounce_time_ms;  // Tiempo del ultimo cambio de estado en la entrada.
};

// Lee un cambio de estado de la entrada digital.
// Devuelve cierto si se ejecuta un cambio de estado logico, falso en caso contrario.
bool leer_cambio_de_estado(EntradaDigital& entrada, unsigned long tiempo) {
  const int senyal_actual = digitalRead(entrada.pin);

  bool estado_cambiado = false;
  
  if (senyal_actual != entrada.ultima_senyal) {
    entrada.debounce_time_ms = tiempo;
  }
  else if (
    ((tiempo - entrada.debounce_time_ms) >= DEBOUNCE_DELAY_MS) &&
    (senyal_actual != entrada.estado) ){
      entrada.estado = senyal_actual;
      estado_cambiado = true;
  }

  entrada.ultima_senyal = senyal_actual;
  return estado_cambiado;
}


/* Programa principal. */

Estado estado_actual;
EntradaDigital pulsador;
unsigned long tiempo_ultima_transicion;

// Ejecuta una transicion de estado y devuelve el nuevo estado.
Estado ejecutar_transicion(Estado estado, unsigned long tiempo) {
  tiempo_ultima_transicion = tiempo;
  return Estado((estado + 1) % MAX_ESTADO);
}

// Actualiza la salida despues de un cambio de estado.
void actualizar_salida(Estado estado_actual) {
  switch (estado_actual) {
    case Estado_Inicial:
      break;
    case Salida_Rele1:
      digitalWrite(Rele_Pin[Rele1], HIGH);
      break;
    case Espera_Rele2:
      digitalWrite(Rele_Pin[Rele1], LOW);
      break;
    case Salida_Rele2:
      digitalWrite(Rele_Pin[Rele2], HIGH);
      break;
    case Espera_Rele3:
      digitalWrite(Rele_Pin[Rele2], LOW);
      break;
    case Salida_Rele3:
      digitalWrite(Rele_Pin[Rele3], HIGH);
      break;
    case Estado_Final:
      digitalWrite(Rele_Pin[Rele3], LOW);
      break;
    default:
      break;
  }
}

// Devuelve el tiempo de espera para el estado dado.
unsigned long get_tiempo_espera(Estado estado) {
  switch (estado) {
    case Espera_Rele1:
      return TIEMPO_ESPERA_SALIDA_MS[Rele1];
    case Espera_Rele2:
      return TIEMPO_ESPERA_SALIDA_MS[Rele2];
    case Espera_Rele3:
      return TIEMPO_ESPERA_SALIDA_MS[Rele3];
    default:
      return 0;
  }
}

// Inicializacion.
void setup() {
  const unsigned long tiempo = millis();
  
  for (int i = 0; i < MAX_RELE; ++i) {
    pinMode(Rele_Pin[i], OUTPUT);
    digitalWrite(Rele_Pin[i], LOW);
  }
  pinMode(Pulsador_Pin, INPUT);
  
  estado_actual = Estado_Inicial;

  pulsador = (EntradaDigital) {
    .pin = Pulsador_Pin,
    .estado = LOW,
    .ultima_senyal = LOW,
    .debounce_time_ms = tiempo,
  };

  tiempo_ultima_transicion = tiempo;
}

// Bucle principal.
void loop() {
  const unsigned long tiempo = millis();
  const Estado estado_original = estado_actual;

  switch (transiciones[estado_actual]) {
    case Automatica:
      estado_actual = ejecutar_transicion(estado_actual, tiempo);
      break;

    case Retardada: {
      const unsigned long tiempo_espera = get_tiempo_espera(estado_actual);
      if ( (tiempo - tiempo_ultima_transicion) >= tiempo_espera ) {
        estado_actual = ejecutar_transicion(estado_actual, tiempo);
      }
      break;
    }

    case Manual: {
      const bool pulsador_estado_cambiado = leer_cambio_de_estado(pulsador, tiempo);
      if (pulsador_estado_cambiado && pulsador.estado == HIGH) {
        estado_actual = ejecutar_transicion(estado_actual, tiempo);
      }
      break;
    }
  }

  if (estado_actual != estado_original) {
    actualizar_salida(estado_actual);
  }
}