Si desea hacer cosas con un bucle, entonces necesita cambiar las cosas para que la repetición del bucle se rija por el ciclo de red síncrono que se repite. Esta no es la forma más limpia de hacer las cosas, pero debería ser posible para que funcione.
Tenga en cuenta que solo hay una cosa lenta de controlar, el control de velocidad de cambio de fase del ventilador. Puede acomodar muchas otras cosas 'rápidas', leer un interruptor, configurar un relé, dentro del tiempo que demora esperar el siguiente cruce por cero.
while running:
{
wait_for_zero_crossing();
read_fan_speed_control();
compute_speed_to_delay_for_fan();
delay_for_fan_speed_control_time();
pulse_fan_triac();
set_fan_relay();
read_light_control();
set_light_relay();
...
read_other_control();
set_other_relay();
}
Un método bastante mejor es usar interrupciones. Cuando tiene una tarea sincrónica como esperar los ciclos de la red, y una tarea asíncrona como leer los interruptores, es bueno usar interrupciones para manejar la parte crítica del trabajo, como esta. En general, usted desea que la rutina de servicio de interrupción (ISR) se ejecute lo más rápido posible, es decir, realice el menor trabajo posible. Mientras se gasten unos pocos ciclos fuera del ISR, se ejecutará su código asíncrono.
volatile int fan_control; # needed so main and ISR communicate correctly
setup_ISR_to_run_every_100uS; # for instance, 10kHz
while running:
{
read_fan_speed_control();
fan_control = compute_speed_to_delay_for_fan();
read_light_control();
set_light_relay();
...
read_other_control();
set_other_relay();
}
ISR:
{
if zero_crossing_just_happened():
count = 0;
else:
count += 1;
if count == fan_control:
pulse_fan_triac();
...
if count == other_control:
pulse_other_triac();
}
Como puede ver, es fácil ampliar esta sección de ISR para acomodar fácilmente otros canales de control de cambio de fase. Dejaré como implementar zero_crossing_just_happened()
como un ejercicio para el lector.
Estos fragmentos son bocetos, obviamente mucho se ha omitido. He mostrado la declaración volatile
ya que a menudo se olvida en estas situaciones. Obliga al compilador a volver a leer el valor de la memoria en cada lectura y no a intentar optimizarlo utilizando una copia basada en registros.
Una vez que haya aprendido a usar interrupciones, puede usarlas para escanear un dispositivo multiplexado, capturar datos de ADC en segundo plano, todo tipo de cosas que no puede hacer bien con un solo bucle asíncrono.