Hola.
Estoy esperando el soporte técnico de MCHP con respecto al ADC, quiero sacarme esa duda del porqué de las 2 muestras consecutivas.
Hasta mientras, voy a realizar las alarmas audibles con el buzzer respecto a un posible sobre y sub voltaje.
Para un sobre voltaje, deseo hacer tres pulsos de audio de duración de 100 ms. Entre cada pulso habrá 200 ms, y antes de volver a generar los tres pulso, se espera unos 700 ms, algo similar a esta imagen que no es a escala.

Para un subvoltaje, creo que será un pulso de 100 ms, y entre el siguiente, pasará unos 700 ms.

Espero en esta semana escribir el código y compartirlo aquí.
Así queda el código de las alarmas, aun debo probar su funcionamiento.
La tarea del buzzer, sólo tenía dos estados, el primero es el que toca la melodía inicial, y el segundo no hace nada, es decir la tarea está en reposo:
typedef enum
{
/* Application's state machine's initial state. */
APPBUZZER_ESTADO_INICIAL=0,
APPBUZZER_ESTADO_REPOSO,
/* TODO: Define states used by the application state machine. */
} APPBUZZER_STATES;
He creado tres estado más, uno que espera el tono en alto, otro que espera el tono en bajo y el tercero que espera los 700 ms para nuevamente repetir el proceso:
typedef enum
{
/* Application's state machine's initial state. */
APPBUZZER_ESTADO_INICIAL=0,
APPBUZZER_ESTADO_REPOSO,
/* TODO: Define states used by the application state machine. */
APPBUZZER_ESTADO_PULSO_EN_ALTO,
APPBUZZER_ESTADO_PULSO_EN_BAJO,
APPBUZZER_ESTADO_PULSO_EN_SILENCIO
} APPBUZZER_STATES;
La tarea debe ser forzada a cambiar al estado APPBUZZER_ESTADO_PULSO_EN_ALTO, previamente, el buzzer debe ser activado y capturado el valor instantáneo del
Core Timer para generar un retardo de 100ms.
Este estado sería así:
case APPBUZZER_ESTADO_REPOSO: break;
/* TODO: implement your application state machine.*/
/* The default state should never be executed. */
case APPBUZZER_ESTADO_PULSO_EN_ALTO:
{
if ((CORETIMER_CounterGet() - appbuzzerData.retardo) > _100ms)
{
OCMP1_Disable();
appbuzzerData.retardo = CORETIMER_CounterGet();
appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_BAJO;
}
break;
}
Una vez que transcurra los 100ms, el buzzer es desactivado, se captura otra vez un valor instantáneo del temporizador central para el siguiente reatrdo y se cambia el estado de la tarea a APPBUZZER_ESTADO_PULSO_EN_BAJO.
La estructura de datos de la tarea, debe tener 3 datos adicionales, una variable de tipo entera sin signo para capturar el valor instantáneo del temporizador central, una variable donde se escriba el número de pulsos de audio deseados que se genere, y otra que realice un conteo de los mismos,
typedef struct
{
/* The application's current state */
APPBUZZER_STATES state;
/* TODO: Define any additional data used by the application. */
unsigned char PunteroMusica;
unsigned int retardo;
unsigned char numeroPulsos;
unsigned char contadorPulsos;
} APPBUZZER_DATA;
El estado APPBUZZER_ESTADO_PULSO_EN_BAJO, será de la siguiente manera, donde se espera los 200ms:
case APPBUZZER_ESTADO_PULSO_EN_BAJO:
{
if ((CORETIMER_CounterGet() - appbuzzerData.retardo) > _200ms)
{
appbuzzerData.contadorPulsos--;
if (appbuzzerData.contadorPulsos)
{
OCMP1_Enable();
appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_ALTO;
}
else
{
appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_SILENCIO;
}
appbuzzerData.retardo = CORETIMER_CounterGet();
}
break;
}
Cuando haya pasado los 200 ms, se decrementa la variable contadorPulsos, si aun es mayor que cero ( if (appbuzzerData.contadorPulsos)), se vuelve activar el buzzer y cambia la tarea nuevamente al estado APPBUZZER_ESTADO_PULSO_EN_ALTO.
Si es cero (else), se cambia al estado APPBUZZER_ESTADO_PULSO_EN_SILENCIO.
Este caso no finaliza sin antes nuevamente capturar el valor que tenga el
Core Timer en ese momento.
En el estado APPBUZZER_ESTADO_PULSO_EN_SILENCIO, se espera 500ms, que sumados a los 200 anteriores, darían los 700 ms
case APPBUZZER_ESTADO_PULSO_EN_SILENCIO:
{
if ((CORETIMER_CounterGet() - appbuzzerData.retardo) > _500ms)
{
appbuzzerData.contadorPulsos = appbuzzerData.numeroPulsos;
appbuzzerData.retardo = CORETIMER_CounterGet();
OCMP1_Enable();
appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_ALTO;
}
break;
}
Pasado el retardo, se restaura el valor de la variable contadorPulsos mediante numeroPulsos, nuevamente se captura el valor del
Core Timer, se activa el buzzer y se regresa al estado APPBUZZER_ESTADO_PULSO_EN_ALTO.
La función que cambia el reposo de la tarea del buzzer sería así:
void analizarNivelVoltaje(float voltajeRMS)
{
if (appbuzzerData.state > APPBUZZER_ESTADO_INICIAL)
{
if (voltajeRMS > maximoVoltaje)
{
appbuzzerData.numeroPulsos = 0x03;
}
else if (voltajeRMS < minimoVoltaje)
{
appbuzzerData.numeroPulsos = 0x01;
}
else
{
OCMP1_Disable();//apago el PWM
appbuzzerData.state = APPBUZZER_ESTADO_REPOSO;
return;
}
appbuzzerData.contadorPulsos = appbuzzerData.numeroPulsos;
appbuzzerData.retardo = CORETIMER_CounterGet();
actualizarFrecuenciaPWM(cHH);
OCMP1_Enable();
appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_ALTO;
}
}
Esta función tiene de parámetro el voltaje rems medido.
Si el voltaje es mayor al máximo, numeroPulsos se inicia con 3, si es menor al voltaje mínimo, numeroPulsos se inicia con 1.
Para estos dos casos, se inicia la variable contadorPulsos, se captura el valor de temporizador central, se actualiza la frecuencia del PWM, ya que cuando estaba en el estado de reposo, estaba en
mute o en cero; se habilita el buzzer y se cambia el estado de la tarea a APPBUZZER_ESTADO_PULSO_EN_ALTO
Para el caso else, que es un nivel de voltaje normal, se apaga el buzzer, la tarea se cambia a modo de reposo, y para evitar todo el proceso cuando el voltaje es anómalo, uso un return para salir rápidamente de la función.
Los valores de maximo y mínimo voltaje son los siguientes, no se si son los adecuados:
#define maximoVoltaje 127.00
#define minimoVoltaje 110.00
Esta función debería llamarse cuando se tenga el valor RMS calculado, y la he puesto cuando se va a modificar el valor que hay en los displays:

Cuando tenga tiempo, hago unas pruebillas, modificando maximoVoltaje y minimoVoltaje, lo ideal sería tener un transformador o autotransformador variable.