Autor Tema: Proyecto para medir el valor eficaz verdadero (True RMS)  (Leído 26613 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #90 en: 05 de Diciembre de 2023, 09:53:05 »
Hola, estoy siguiendo tu proyecto.

Creo que para descartar un problema de la interrupción externa, deberías realizar la parte que mencionaste que también medirías la frecuencia.

Al hacer eso, ya no dependes del temporizador 4 que genera interrupciones cada 100 us, ni del ADC.

Es decir, tal vez no necesitas el modulo de captura que estás pensando usar para medir la frecuencia, me refiero a que mediante el flanco positivo de la interrupción externa, hagas algo similar que utilizaste para medir cuanto tiempo te tomaba en realizar el cálculo del RMS de un periodo.

Es decir cuando sucede dicha int externa, capturas el valor del temporizador central o Core Timer, y en la siguiente interrupción, nuevamente capturas ese valor para realizar la diferencia y tienes el valor del periodo de la señal,

Luego con un poco de matemáticas obtienes el valor de la frecuencia y usas la misma función para mostrar ese valor en el display.

Con ese valor y visualizando si pasa algo similar como en los videos que has compartido, podrías afirmar que es un problema de la interrupción.

Si parece una buena idea, determinar si el mismo fenómeno sucede al medir la frecuencia.

También estaba pensando eso de no usar el módulo de captura, pero no se que tan preciso sea, ya que cuando sucede la interrupción, el CPU debe guardar el contexto, y ese proceso puede tomar algo de tiempo, mientras que con el módulo de captura, me parece que sería casi inmediato. Voy a analizarlo.

Lo que si tengo que hacer, es una tarea para eliminar el rebote mecánico del pulsante, a pesar que si tengo un capacitor de 0,1 uF.
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #91 en: 05 de Diciembre de 2023, 11:02:24 »
Hola, así queda la tarea del pulsante.

Primero en el MCC añado una nueva tarea mediante el módulo denominado CORE.





En la tarea, a parte de la variable que determina su estado, añadí dos más, una para determinar el estado del proceso, medir voltaje o medir frecuencia que es un booleano y otra para generar retardos asincrónicos.



En la inicialización de la tarea, la variable booleana, estará en falso, que significa que la medición del voltaje es aquello por defecto al funcionar el dispositivo


En el primer estado de la tarea, se espera a que el terminal donde está el pulsador pase a cero lógico.
Tan pronto como sucede esto, se conmuta el estado de la variable booleana, se captura el valor instantáneo del Core Timer y se cambia el estado de la tarea al siguiente:



En el siguiente estado, espero 200 ms para eliminar el rebote, y cuando transcurre ese retardo, debo verificar si el pulsante ha dejado de ser presionado (está en 1 lógico) o si el usuario lo sigue presionando.

Para la primera opción, simplemente debe regresar al estado inicial a esperar una nueva pulsación, caso contrario, debe ir a otro estado de la tarea, donde se espera a que el usuario deje de presionarlo.



En este tercer estado, ahora se espera que el pulsante regrese a 1 lógico, y cuando lo hace, nuevamente captura  el valor del Core Timer para generar el retardo asincrónico y la tarea es direccionado al estado que se espera a que el rebote desaparezca:


Y eso creo que es todo con respecto a ese tema, ahora pienso si usar o no el método de captura para medir la frecuencia.
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #92 en: 05 de Diciembre de 2023, 22:30:33 »
Creo que he descubierto un problema con el ADC.

Mientras depuraba el código tratando de determinar si los cálculos del RMS eran correctos, como mencioné anteriormente, en un periodo se tomaba entre 40 a 70 muestras, que es muy bajo para el periodo de 60 Hz.

También parecía que toma más muestras de lo que debería.

Así que se me ocurrió, no activar al temporizador 4, que genera cada 100 us una interrupción que activa una nueva adquisición/conversión del ADC:



Al realizar esto, y como no se genera una interrupción cada 100 us, al finalizar el periodo, debería tener una sola muestra, ya que sólo una vez se activo el inicio de la conversión ADC, pero para mi sorpresa, tengo dos muestras adquiridas en un solo periodo





Alguien puede pensar (y obviamente, yo también lo pensé) es que la línea 89 de arriba (ADC_ConversionStart()) es llamada dos veces y esa es la razón de las dos muestras.

La primera vez es en el inicio del periodo de la señal y la segunda vez cuando finaliza el periodo (que es cuando se alcanza el NOP de la línea 99).

Pero no tiene sentido, ya que la segunda vez que se llama a la función ADC_ConversionStart(), la conversión inicia y no pudo haberse producido la interrupción del ADC desde la línea 89 a la 99, pero para descartar esa posibilidad, puse al inicio la parte que verifica el valor de la variable punteroABuffer y el inicio del TMR4 (comentado) y del ADC al final, e igual, obtengo dos muestras, cuando debería ser una.



Como se puede ver en la imagen de arriba, la función ADC_ConversionStart, ahora en la línea 101, aun no es ejecutada, ya que se produjo el fin de periodo (Nop en la línea 95) y de igual manera, hay dos muestras del ADC obtenidas, cuando debe ser 1.

Tengo que revisar detenidamente, esto del ADC.



Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #93 en: 06 de Diciembre de 2023, 02:47:09 »
Es raro.

Quizás para poder rastrear mejor en qué momento se te generan ambas muestras, en la misma función donde lees el ADC e incrementas la muestra, podrías almacenar en otro array el valor de TMR4.
A ver si de esa manera encuentras alguna explicación.

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #94 en: 06 de Diciembre de 2023, 10:35:07 »
Es raro.

Quizás para poder rastrear mejor en qué momento se te generan ambas muestras, en la misma función donde lees el ADC e incrementas la muestra, podrías almacenar en otro array el valor de TMR4.
A ver si de esa manera encuentras alguna explicación.

Si, es como que se produjeran dos interrupciones del ADC, cuando sólo debe ser una.

Voy a abrir un ticket en el soporte técnico de MCHP para explicar el problema y ojalá puedan ayudarme, en el foro no se si pedir ayuda, ya no es como antes.

Lo que se me ha ocurrido a modo solo de prueba, es enviar el número de muestras al display por cada periodo, en lugar del valor RMS, de esa manera, voy a conocer cuantas muestras se toman por cada ciclo de la señal.
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #95 en: 06 de Diciembre de 2023, 11:06:33 »
Ya hice la prueba.

Para enviar el número de muestras hice lo siguiente:

Código: C
  1. case APPRMS_ESTADO_EXTRAER_RAIZ_CUADRADA:
  2. {
  3.         rmsDisplay((float)(appsamplingData.estructuraADC[apprmsData.puntero].muestra));
  4.         //rmsDisplay(sqrtf(apprmsData.sumatorio1)); //raiz cuadrada de todo
  5.         apprmsData.state = APPRMS_ESTADO_INICIAL;
  6.         break;
  7. }
Y el número de muestras es casi siempre 78.



Y también tiene esos parpadeos ocasionales, y cuando sucede, el número de muestras es alrededor de 168.



Que sería un valor correcto del número de muestras.
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #96 en: 07 de Diciembre de 2023, 14:04:57 »
Hola, parece que lo eh conseguido, pero con una solución engorrosa.

Buscando información el el foro de MCHP, encontré con alguien, con un problema similar, y alguien le sugería que en la interrupción del ADC, lea todos sus registros, ya que es un buffer de 16 bytes, o la otra opción es apagar el módulo ADC, limpiar la bandera de interrupción y volver a activarlo.

Hice la segunda opción de la siguiente manera:

Código: C
  1. void ManejarInterrupcionADC(uintptr_t context)
  2. {
  3.     appsamplingData.estructuraADC[appsamplingData.punteroABuffer].bufferADC[appsamplingData.estructuraADC[appsamplingData.punteroABuffer].muestra] = ADC_ResultGet(ADC_RESULT_BUFFER_0);
  4.     AD1CON1bits.ADON = 0;  // apago el ADC
  5.     IFS0bits.AD1IF = 0;    // limpio la bandera de interrupción
  6.     appsamplingData.estructuraADC[appsamplingData.punteroABuffer].muestra++;
  7.     AD1CON1bits.ADON =1;   // activo nuevamente el ADC
  8. }

Y al hacer esto, el número de muestras es de 167.



Cambié el código para que envíe el valor RMS al display, en lugar del número de muestras y este es el resultado



Es engorrosa la solución, ya que me parece que debería haber una forma que solamente un byte del buffer sea usado para el resultado del ADC, no estoy seguro porque toma 2 muestras consecutivas.

Tampoco ese parpadeo esporádico que a veces sucede, sigue ocurriendo, pensé que estaba relacionado, pero creo que es otra causa.
« Última modificación: 07 de Diciembre de 2023, 16:17:05 por DominusDRR »
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32


Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #98 en: 11 de Diciembre de 2023, 17:48:13 »
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í.

Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #99 en: 13 de Diciembre de 2023, 11:30:49 »
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:

Código: C
  1. typedef enum
  2. {
  3.     /* Application's state machine's initial state. */
  4.     APPBUZZER_ESTADO_INICIAL=0,
  5.     APPBUZZER_ESTADO_REPOSO,
  6.     /* TODO: Define states used by the application state machine. */
  7. } 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:

Código: C
  1. typedef enum
  2. {
  3.     /* Application's state machine's initial state. */
  4.     APPBUZZER_ESTADO_INICIAL=0,
  5.     APPBUZZER_ESTADO_REPOSO,
  6.     /* TODO: Define states used by the application state machine. */
  7.     APPBUZZER_ESTADO_PULSO_EN_ALTO,
  8.     APPBUZZER_ESTADO_PULSO_EN_BAJO,
  9.     APPBUZZER_ESTADO_PULSO_EN_SILENCIO
  10. } 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í:
Código: C
  1. case APPBUZZER_ESTADO_REPOSO: break;
  2.  /* TODO: implement your application state machine.*/
  3.  /* The default state should never be executed. */
  4.  case APPBUZZER_ESTADO_PULSO_EN_ALTO:
  5.  {
  6.       if ((CORETIMER_CounterGet() - appbuzzerData.retardo) > _100ms)
  7.       {
  8.           OCMP1_Disable();
  9.           appbuzzerData.retardo = CORETIMER_CounterGet();
  10.           appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_BAJO;
  11.       }
  12.       break;
  13. }

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,

Código: C
  1. typedef struct
  2. {
  3.     /* The application's current state */
  4.     APPBUZZER_STATES state;
  5.     /* TODO: Define any additional data used by the application. */
  6.     unsigned char PunteroMusica;
  7.     unsigned int retardo;
  8.     unsigned char numeroPulsos;
  9.     unsigned char contadorPulsos;
  10. } APPBUZZER_DATA;

El estado APPBUZZER_ESTADO_PULSO_EN_BAJO, será de la siguiente manera, donde se espera los 200ms:

Código: C
  1. case APPBUZZER_ESTADO_PULSO_EN_BAJO:
  2. {
  3.      if ((CORETIMER_CounterGet() - appbuzzerData.retardo) > _200ms)
  4.      {
  5.          appbuzzerData.contadorPulsos--;
  6.          if (appbuzzerData.contadorPulsos)
  7.          {
  8.              OCMP1_Enable();
  9.              appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_ALTO;
  10.          }
  11.          else
  12.          {
  13.              appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_SILENCIO;
  14.          }
  15.          appbuzzerData.retardo = CORETIMER_CounterGet();
  16.     }
  17.     break;
  18. }

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


Código: C
  1. case APPBUZZER_ESTADO_PULSO_EN_SILENCIO:
  2.  {
  3.      if ((CORETIMER_CounterGet() - appbuzzerData.retardo) > _500ms)
  4.      {
  5.            appbuzzerData.contadorPulsos = appbuzzerData.numeroPulsos;
  6.            appbuzzerData.retardo = CORETIMER_CounterGet();
  7.            OCMP1_Enable();
  8.            appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_ALTO;
  9.      }
  10.      break;
  11. }

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í:

Código: C
  1. void analizarNivelVoltaje(float voltajeRMS)
  2. {
  3.     if (appbuzzerData.state > APPBUZZER_ESTADO_INICIAL)
  4.     {
  5.         if (voltajeRMS > maximoVoltaje)
  6.         {
  7.             appbuzzerData.numeroPulsos = 0x03;
  8.         }
  9.         else if (voltajeRMS < minimoVoltaje)
  10.         {
  11.             appbuzzerData.numeroPulsos = 0x01;
  12.         }
  13.         else
  14.         {
  15.             OCMP1_Disable();//apago el PWM
  16.             appbuzzerData.state = APPBUZZER_ESTADO_REPOSO;
  17.             return;
  18.         }
  19.         appbuzzerData.contadorPulsos = appbuzzerData.numeroPulsos;
  20.         appbuzzerData.retardo = CORETIMER_CounterGet();
  21.         actualizarFrecuenciaPWM(cHH);
  22.         OCMP1_Enable();
  23.         appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_ALTO;
  24.     }
  25. }

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:

Código: C
  1. #define maximoVoltaje 127.00
  2. #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.

Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #100 en: 16 de Diciembre de 2023, 12:43:29 »
He realizado las pruebas de alarma.

Como mencioné antes, no tengo algo para variar el voltaje que mide el voltímetro, así que decidí modificar los límites del voltaje máximo y mínimo.

Primero lo hice para simular un sobre voltaje, así:

Código: C
  1. #define maximoVoltaje 120.00//127.00
  2. #define minimoVoltaje 90.00//110.00

Al realizar esto, me di cuenta, que el tono o la alarma, emitía un sonido continúo, nada relacionado con lo que deseaba.

Luego de analizar un poco el código, me di cuenta que la función analizarNivelVoltaje, es llamada siempre, cada vez que finaliza un periodo de la señal senoidal. Está función modifica el estado de la tarea del buzzer, y por lo tanto nunca la deja ni terminar la generación de un solo pulso de sonido.

La solución es que si la alarma de sobrevoltaje (o subvoltaje) ha sido ejecutado, la próxima vez, ya no se altere nada de la tarea.

Para conocer si una alarma está activa o no, usé la variable numeroPulsos, la cual es 3, 1 ó 0 si hay un sobrevoltaje, un subvoltaje o un voltaje normal respectivamente.

Cuando está alguna de estas alarmas activas, no se modificada nada de la tarea, y se abandona la función con una instrucción return

Código: C
  1. void analizarNivelVoltaje(float voltajeRMS)
  2. {
  3.     if (appbuzzerData.state > APPBUZZER_ESTADO_INICIAL)
  4.     {
  5.         if (voltajeRMS > maximoVoltaje)
  6.         {
  7.             if (0x03 == appbuzzerData.numeroPulsos) // ya está presente la alarma de sobrevoltaje
  8.             {
  9.                 return;
  10.             }
  11.             appbuzzerData.numeroPulsos = 0x03;
  12.         }
  13.         else if (voltajeRMS < minimoVoltaje)
  14.         {
  15.             if (0x01 == appbuzzerData.numeroPulsos) // ya está presente la alarma de subvoltaje
  16.             {
  17.                 return;
  18.             }
  19.             appbuzzerData.numeroPulsos = 0x01;
  20.         }
  21.         else
  22.         {
  23.             appbuzzerData.numeroPulsos = 0x00;
  24.             OCMP1_Disable();//apago el PWM
  25.             appbuzzerData.state = APPBUZZER_ESTADO_REPOSO;
  26.             return;
  27.         }
  28.         appbuzzerData.contadorPulsos = appbuzzerData.numeroPulsos;
  29.         appbuzzerData.retardo = CORETIMER_CounterGet();
  30.         actualizarFrecuenciaPWM(cHH);
  31.         OCMP1_Enable();
  32.         appbuzzerData.state = APPBUZZER_ESTADO_PULSO_EN_ALTO;
  33.     }
  34. }

La alarma de sobrevoltaje suena así:


Para la alarma de subvoltaje, modifiqué los límites así:

Código: C
  1. #define maximoVoltaje 140.00//127.00
  2. #define minimoVoltaje 127.00//110.00

Y suena así:


No me gusta mucho ese sonido, parece un paciente en un hospital en estado grave.

La próxima vez voy a aumentar el tiempo de silencio de 700 ms a 2 segundos



 
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado AnitaMalhereux

  • PIC10
  • *
  • Mensajes: 42
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #101 en: 16 de Diciembre de 2023, 15:09:40 »
Lo de las alarmas, tal vez deberías usar límites con histéresis.

Ya que si alguna vez el voltaje está en alguno de los límites, va estar que se activa la alarma y se corta.

No creo que es algo crítico, pero podría ser algo molestoso.

Tal vez deberías usar esos antiguos reguladores de brillo para lámpara incandescente, creo que sería más barato que conseguir un transformador variable. De paso pruebas que tan preciso es el calculo del valor rms de una señal AC recortada por SCRs

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #102 en: 16 de Diciembre de 2023, 15:17:58 »
Lo de las alarmas, tal vez deberías usar límites con histéresis.

Ya que si alguna vez el voltaje está en alguno de los límites, va estar que se activa la alarma y se corta.

No creo que es algo crítico, pero podría ser algo molestoso.

Tal vez deberías usar esos antiguos reguladores de brillo para lámpara incandescente, creo que sería más barato que conseguir un transformador variable. De paso pruebas que tan preciso es el calculo del valor rms de una señal AC recortada por SCRs

Buena observación.

Lo que no sé, es que tan "TRUE rms" es el multímetro que tengo, con uno que tenga esa característica, podría determinar que tan errada es la medición de mi hardware,
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #103 en: 20 de Diciembre de 2023, 13:34:13 »
Hola.

Voy a realizar la parte que captura el tiempo de la señal periódica de 60Hz.

Estaba pensando como hacerlo, y se me ocurrió, en la tarea que realiza el cambio de la bandera medirFrecuencia, crear una función denominada cambiar proceso, que configuraría todo lo necesario para conmutar a cualquiera de los procesos.

Código: C
  1. case APPPULSADOR_ESTADO_INICIAL:
  2.         {
  3.             if (false == PULSANTE_Get()) // espero a que el pulsante sea presionado
  4.             {
  5.                 apppulsadorData.medirFrecuencia = !apppulsadorData.medirFrecuencia; // cambio el estado de la variable booleana
  6.                 cambiarProceso(); //Conmuta entre voltímetro o frecuencímetro
  7.                 apppulsadorData.retardo = CORETIMER_CounterGet();
  8.                 apppulsadorData.state = APPPULSADOR_ESTADO_ELIMINAR_REBOTE;
  9.             }
  10.             break;
  11.         }

En la función cambiarProceso, tengo lo siguiente:

Código: C
  1. void cambiarProceso(void)
  2. {
  3.     if (apppulsadorData.medirFrecuencia)
  4.     {
  5.         EVIC_ExternalInterruptDisable(EXTERNAL_INT_2);  //detengo la interrupción por interrupción externa
  6.         EVIC_SourceStatusClear(INT_SOURCE_EXTERNAL_2);  //limpio la bandera por interrupción externa
  7.         TMR4_Stop();                                    //detengo al temporizador 4
  8.         TMR4_InterruptDisable();                        //deshabilito la interrupción del temporizador 4
  9.         EVIC_SourceStatusClear(INT_SOURCE_TIMER_4);     //limpio la bandera por interrupción de tmr4
  10.         ADC_Disable();                                  //deshabilito al módulo ADC
  11.         EVIC_SourceStatusClear(INT_SOURCE_ADC);         //limpio la bandera por interrupción del ADC
  12.     }
  13.     else
  14.     {
  15.         ICAP1_Disable(); //Deshabilito el módulo de captura
  16.         TMR2_Stop();
  17.         EVIC_SourceStatusClear(INT_SOURCE_INPUT_CAPTURE_1); // limpio bandera del módulo de captura.
  18.     }
  19.     APPSAMPLING_Initialize(); //reinicio la tarea de muestreo
  20. }

Si la bandera medirFrecuencia está en true, realizó todos los pasos necesarios para detener el proceso de medir el voltaje rms, caso contrario activo al módulo de captura y limpio una posible bandera de interrupción del modulo.

En cualquier caso, la tarea denominada appSampling, es reiniciada.

Código: C
  1. case APPSAMPLING_ESTADO_INICIAL:
  2.         {
  3.             if (apppulsadorData.medirFrecuencia)
  4.             {
  5.                 ICAP1_Enable();
  6.                 TMR2_Start();
  7.                 ICAP1_CallbackRegister(&ManejarInterrupcionModuloCaptura, (uintptr_t)NULL);
  8.             }
  9.             else
  10.             {
  11.                 ICAP1_Disable(); //Deshabilito el módulo de captura
  12.                 TMR4_Stop();
  13.                 TMR2_Stop();
  14.                 TMR4_CallbackRegister(ManejarInterrupcionTMR4, (uintptr_t) NULL);// registro función de interrupción por TMR4
  15.                 ADC_CallbackRegister(ManejarInterrupcionADC, (uintptr_t)NULL); // registro función de interrupción por ADC
  16.                 EVIC_ExternalInterruptCallbackRegister(EXTERNAL_INT_2, &ManejarInterrupcionExterna, (uintptr_t)NULL); //Registro la función que se llama por la interrupción externa
  17.                 EVIC_ExternalInterruptEnable(EXTERNAL_INT_2); // Habilito la interrupción externa 2
  18.             }
  19.             appsamplingData.state = APPSAMPLING_ESTADO_REPOSO;
  20.             break;
  21.         }

En esta tarea, en su primer estado, en función de medirFrecuencia, se configura el proceso de medir el voltaje RMS o el de capturar el tiempo.

El de capturar el tiempo, consiste en habilitar el módulo, inicializar el temporizador 2 y registrar una función que es aquella que maneja la interrupción de módulo de captura.

Para poder utilizar la función ICAP1_CallbackRegister, tenía que habilitar la interrupción del módulo, y era algo que me faltaba.



En la función ManejarInterrupcionModuloCaptura, mediante ICAP1_CaptureBufferRead, obtengo el valor medido del periodo de la señal.
He agregado un Nop, para poner un punto de ruptura, para depurar con el hardware y determinar si el módulo funciona y está midiendo el periodo de la señal.

Código: C
  1. void ManejarInterrupcionModuloCaptura(uintptr_t context)
  2. {
  3.     appsamplingData.captura = ICAP1_CaptureBufferRead();
  4.     Nop();
  5. }
Cuando tenga un poco de tiempo hago pruebas, si está bien, el siguiente paso sería convertir ese tiempo a Hz, y mostrarlo en el display.




Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1982
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #104 en: 29 de Diciembre de 2023, 13:52:29 »
Hola.

He realizado las pruebas y parece estar correcto la medición del periodo de la señal.

Hice unos cambios y tengo unas dudas que debo resolver.

Primero explico los cambios.

La tarea que se encarga del cálculo del valor RMS, está siempre funcionando y cada vez que finaliza dicho cálculo matemático, envía ese dato al display. Cuando el usuario conmute el proceso del dispositivo a mostrar la frecuencia, esta tarea debe entrar a un estado de pausa, así que cree un nuevo estado denominado IDLE:



La entrada a estado (o evitar dicho estado), se lo hace al inicializar la tarea en función de la bandera medirFrecuencia:



Esto implica llamar esta función cuando se realiza el cambio entre medir el voltaje RMS y medir la frecuencia de la señal:



El segundo cambio fue, en donde se obtiene la medición del periodo, en este caso, debe realizarse una resta entre el valor medido anteriormente y el actual, así:

Código: C
  1. void ManejarInterrupcionModuloCaptura(uintptr_t context)
  2. {
  3.     appsamplingData.captura = ICAP1_CaptureBufferRead() - appsamplingData.captura;
  4.     Nop();
  5. }

En este punto, hice las pruebas y noté que la interrupción del módulo de captura no funcionaba, es decir la función ManejarInterrupcionModuloCaptura nunca era invocada.

Revisé cada uno de los registros relacionados del modulo de captura al momento de depurar (modulo, temporizador 2, registros relacionados con la interrupción) y todo parecía estar correcto.

También noté que cuando volvía a presionar el pulsante, no volvía a ocurrir las interrupciones del ADC y todo lo relacionado con el cálculo del valor RMS


Parece que de alguna manera, la suspensión de las primeras interrupciones y configuraciones, y la habilitación de las relacionadas con la medición del periodo, algo quedaba mal habilitado o deshabilitado.

Antes de solucionar ese problema, decidí, sólo para probar que por defecto el dispositivo entre a modo de medir la frecuencia, esto es que la bandera  medirFrecuencia esté en verdadero inicialmente.

Código: C
  1. void APPSAMPLING_Initialize ( void )
  2. {
  3.     /* Place the App state machine in its initial state. */
  4.     appsamplingData.state = APPSAMPLING_ESTADO_INICIAL;
  5.     /* TODO: Initialize your application's state machine and other
  6.      * parameters.
  7.      */
  8.     appsamplingData.punteroABuffer  = 0x01; //apunto al segundo buffer, para que con INT2, se inicie 0 (Priemr buffer
  9.     appsamplingData.estructuraADC[0x00].muestra = 0x00; // Muestra de buffer 0 inicializado
  10.     appsamplingData.estructuraADC[0x01].muestra = 0x00; // Muestra de buffer 1 inicializado
  11.    
  12.     appsamplingData.periodoCompleto = true;//false; Solamente a manera de prueba, medir el periodo es por defecto
  13. }

De igual manera, seguía sin funcionar, hasta que recordé que este microcontrolador tiene la posibilidad de poner los terminales de un periférico en diferentes pines, en mi caso, el pin que es para la interrupción externa 2 que se usa como detector de cruce por cero, también debe ser la entrada del módulo de captura

Así que mediante el MCC, cambié por interrupción externa a entrada del módulo de captura:



Al realizar esto, el registro IC1R es igual a 2



Con el valor en 2, la entrada del modulo de captura IC1 se "conecta" a RPA4 que es el terminal denominado CRUCE_X_CERO.



Pero esto ha borrado la configuración de la interrupción 2.

Lo que debo hacer, es cuando se conmute de un proceso, también conectar y/o desconectar los periféricos relacionados, o determinar si ambos periféricos pueden compartir un mismo terminal o pin del microcontrolador.


Hecho este cambio, la interrupción por el módulo de captura ocurre:



El valor medido es 12499 ciclos del temporizador 2.

Si el temporizador funciona con el reloj principal que es de 48MHz y tiene un post escalamiento de 64, quiere decir que la frecuencia con la que funciona es 750kHz.

Entonces la frecuencia media es 750kHz/12499 = 60.005 Hz.

Lo cual parece estar correcto.

El siguiente paso, es determinar como conmutar o usar ambos periféricos en el mismo terminar.

Solucionar el problema que no vuelven a funcionar las interrupciones del proceso de calcular el valor RMS luego de abandonar el proceso de captura de tiempo.
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32