TODOPIC

FORO TÉCNICO => Foro Técnico => Mensaje iniciado por: DominusDRR en 01 de Mayo de 2023, 12:01:01

Título: Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 01 de Mayo de 2023, 12:01:01
Hola.

Tengo en la mente un proyecto, que se puede decir que es más por pasatiempo que algo profesional.

Debo medir el voltaje RMS de la red eléctrica, cuyo valor debe ser de 127VAC, sin embargo, ese valor varía en algunas ocasiones, así que es necesario visualizarlo constantemente.

Una solución práctica y efectiva sería comprar un voltímetro (digital o analógico) y eso sería todo el reto.

(https://m.media-amazon.com/images/I/71lKk9gu6rL._AC_UF1000,1000_QL80_.jpg)

Sin embargo como es algo que deseo hacer por divertirme y he decidido construir dicho voltímetro con elementos que poseo, como por ejemplo unas muestras de microcontroladores que alguna vez las adquirí, pero nunca les he dado un uso práctico.

La primera idea que se me vino a la mente, es usar un chip que ya es un voltímetro digital, en alguna ocasión, yo mismo lo sugerí, aquí en el foro a alguien que deseaba hacer, exactamente lo mismo.

(https://www.eleccircuit.com/wp-content/uploads/2013/01/digital-voltmeter-circuit-diagram-using-ICL7107.png)

Esta solución, también creo que no sería un reto grande. Obviamente el diseño del PCB y la colocación de los elementos sería algo divertido, pero prefiero también escribir algo de código.

Así que he decido darle un plus adicional al mismo. Aparte de simplemente medir y visualizar el voltaje RMS, voy a agregar dos funcionalidades más:

1. Mediante un pulsador, el hardware  dejará de mostrar el voltaje, a indicar la frecuencia de la red.
2. Si el voltaje es menor a un valor mínimo o mayor a un valor máximo, se activará una señal acústica para informar de dicho problema en la red.

A continuación muestro un diagrama de bloques bastante burdo e incompleto del hardware:

(https://pbs.twimg.com/media/FvDIOQaWcAEgBwz?format=png&name=medium)

La primera condición, que elegido, es que el máximo valor pico de la señal de voltaje AC que podría medir el voltímetro sería 300V (212.13 Vrms), este valor es debido a que el ADC del microcontrolador trabaje con un valor DC máximo de 3.0V, y de esa manera los cálculos de los componentes podrían ser en valores cerrados (sin muchos decimales).

Entonces, cuando la señal de voltaje sea 300V, a la entrada del ADC debería ser 3.0V, mientras cuando sea -300V, el voltaje en la entrada ADC debería ser 0V.

Esto plantea un sistema de 2 ecuaciones con dos incógnitas:

(https://pbs.twimg.com/media/FvDLkrxXoAEkQOf?format=png&name=small)

Al resolver las ecuaciones, se tiene que la señal de voltaje AC, debe darse una ganancia (o mejor dicho, atenuarla) y sumarle un desplazamiento (offset)

La ganancia (menor que uno, es de 1/200) y el desplazamiento es de 1.5V.

Para atenuar la señal, así como la sumar del desplazamiento, decidí usar un amplificador operacional en modo restador con offset:

(https://i.stack.imgur.com/GIv9u.jpg)

Donde R1 sería de un valor de 200k, Rf de 1k y Vref sería de 1.5V.

Como mencioné inicialmente, tengo varios elementos de muestras solicitada y sobrantes de otros proyectos, el amplificador operacional que dispongo es el MCP6L01, y procedí a realizar una simulación con MPLAB Mindi para determinar si funciona esta primera parte del circuito.

(https://pbs.twimg.com/media/FvDPBHPXgEQPK6r?format=png&name=large)

Algo que en este momento recuerdo, es que el microcontrolador funciona con 3.3V, pero el ADC deseo que funcione con un voltaje de referencia de 3.0V, la razón es que usar el mismo voltaje de alimentación, éste no es exacto, es decir se aproxima a 3,3V, pero suele variara ligeramente dependiendo de varias circunstancias.

Mientras que al tener una referencia fija de voltaje, creo que el error del ADC sería menor con respecto al voltaje del LDO.

Por último, el microcontrolador que poseo es el PIC32MX170F256B.

(https://www.microchip.com/content/dam/mchp/mrt-dam/ic-images/ssop/28-lead-n2x/PIC32MX170F256B-N2X-Regular.jpg)

Espero recibir comentarios, sobre todo negativos para darme cuenta de algún posible error o problema que tenga mi proyecto antes de embarcarme en eso.

Estaré actualizando constantemente este hilo indicando el avance del proyecto.



 

 






 
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 01 de Mayo de 2023, 14:20:27
Muy interesante, me suscribo al hilo. De momento ya he aprendido algo: no conocía el MPLAB Mindi, así que muchas gracias
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 01 de Mayo de 2023, 15:25:56
Muy interesante, me suscribo al hilo. De momento ya he aprendido algo: no conocía el MPLAB Mindi, así que muchas gracias

Sí, es útil para simular componentes analógicos de MCHP, incluyendo operacionales y comparadores que están dentro de algunos microcontroladores.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 01 de Mayo de 2023, 15:35:38
Fuente de voltaje del sistema.

Para energizar al microcontrolador, amplificadores operacionales y display, quiero usar una fuente sin transformador, también denominada Transformerless Power Supply

Recordaba que tenía por ahí unos LNK3206GQ sobrantes de un proyecto, y por un momento pensé que los había perdido y los encontré.

Con este circuito integrado, puedo tener una fuente de voltaje DC de hasta 300mA, que creo que es suficiente para todos los elementos.

(https://pbs.twimg.com/media/FvEChMoWAAAy4ci?format=jpg&name=medium)

Para el display de 7 segmentos, pienso que podría trabajar con 5V, mientras que el MCU y los amplificadores OP, trabajarían a 3.3V.

La idea de esta fuente, es que el voltímetro siga trabajando correctamente midiendo el valor rms y la frecuencia a pesar que el voltaje de la empresa eléctrica varíe.





Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 01 de Mayo de 2023, 16:19:22
Circuito de acondicionamiento explicado con más detalle.

El circuito de acondicionamiento se puede aproximar al siguiente esquemático:

(https://pbs.twimg.com/media/FvEH9MiWYAgE-dt?format=png&name=large)

A continuación explico que debería hacer cada parte.

1. Amplificador OA1. Este conforma el diferencial con desplazamiento u offset que se explicó al inicio del post

2. Amplificador OA2. Este es la fuente de referencia de 1.5V. Nótese que para crear dicha referencia, parto del circuito referencia de voltaje de 3.0V LM4040D30ILPR, y mediante un simple divisor con resistencias, obtengo los 1.5V.

(https://pbs.twimg.com/media/FvEKdBZWYCUvtAZ?format=png&name=900x900)

Ocupo este amplificador para un acople de impedancias, ya que una fuente o referencia de voltaje debe tener una impedancia baja respecto a la carga, pero el divisor de tensión con las resistencias R6 y R7, no cumplen dicha condición, así que con un seguidor de voltaje cumple la característica necesaria.

3. Amplificador OA3. Con este amplificador deseo crear un filtro activo para eliminar cualquier ruido de alta frecuencia, generalmente el ruido de alta frecuencia podría alterar al CPU del microcontrolador provocando un fallo o un reinicio. No es el diseño final y aún no he calculado los valores, está de referencia el filtro Butterworth  (¿O es Chebyshev? No recuerdo, lo he de determinar cuando sea necesario)

4. Amplificador OA4.

Necesito detectar el cruce por cero de la señal sinusoidal para empezar a adquirir datos y medir también su periodo (frecuencia).
Mediante el adicionamiento, la señal varia sobre un eje de 1.5V, así que usando la referencia de ese valor y la señal acondicionada para generar una onda cuadrada que llegará al microcontrolador y le permitirá detectar cuando empieza y finaliza un periodo de la señal.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Mayo de 2023, 11:56:27
Asignación de los terminales o pines del microcontrolador

La asignación de los pines del microcontrolador será de la siguiente manera:

(https://pbs.twimg.com/media/FvIUpoDWAAIg9ER?format=png&name=large)

A continuación lo explico con más detalle.

El terminal 1 es el reinicio, así que deberá conectarse a la red RC que recomienda el fabricante.

El terminal 2 será la referencia externa de 3.0V para el ADC.

El terminal 3 será la entrada al ADC.

(https://pbs.twimg.com/media/FvIV_TjXgAEY1Ct?format=jpg&name=medium)

Todo el puerto B será el bus de datos para el display de 7 segmentos.

(https://pbs.twimg.com/media/FvIWSuPXsAQechn?format=png&name=small)

Lo que no se aun es si utilizar el pin RB7 para controlar el punto decimal, es posible que decida que la lectura siempre sea con un decimal  y por lo tanto ese punto debería estar siempre activo sin necesidad de ser controlado por el MCU.

Al ser un display de 4 dígitos:

(https://content.instructables.com/FZI/CZGZ/IBTF5EDQ/FZICZGZIBTF5EDQ.png?auto=webp)

Necesito realizar un barrido de cada dígito, para lo cual los terminales RB8, RB9, RB12 y RB13 controlarán cada uno de los dígitos.

Los termines RA2 y RA3 serán para el cristal oscilador interno. Tenía la idea de usar el oscilador interno RC, pero al no ser preciso, no se que tan grande sea el error en las mediciones.

El terminal RA4 se conectará al terminal IC1 que corresponde al módulo de captura, que me servirá para medir el periodo de la señal e iniciar y detener la adquisición de datos del ADC.

(https://pbs.twimg.com/media/FvIYdasWIAUtoAl?format=jpg&name=medium)

Los terminales RB10 y RB11 me permitirán conectar el programador y depurador del microcontrolador.

El terminal RB14 servirá para el conmutador o pulsador que me permitirá pasar de leer el valor RMS a mostrar la frecuencia de la señal y viceversa. No se si usar una interrupción externa para ese evento o solamente mediante pulleo realizar ese proceso, sin embargo, escogí ese terminal porque se puede usar la interrupción externa 1 en caso que em anime a realizarlo de esa manera.

(https://pbs.twimg.com/media/FvIZhx5WAAIjtTp?format=jpg&name=medium)

Y eso es todo por el momento, empezaré a diseñar el PCB cuando tenga un poco más de tiempo. Y cuando termine otra placa de mi trabajo, pienso enviaren conjunto para fabricar ambas a la vez.





Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Mayo de 2023, 12:04:07
Estoy olvidando la señal acústica, para lo cual debo general una onda cuadra, justamente con el terminal sobrante RB15, puede ser la salida del modulo de comparación 1 para generar una señal PWM.

(https://pbs.twimg.com/media/FvIbugZWcAU5ilr?format=jpg&name=medium)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Mayo de 2023, 13:47:51
Tenía unas dudas si el seguidor de voltaje para producir 1.5 funcionaría correctamente y con el comparador para crear la señal de onda cuadrada sincronizada con el cruce por cero.

Primero verifiqué, la referencia de 1.5 V y esto obtuve (Salida de X2)

(https://pbs.twimg.com/media/FvIxtlCWABwI7u9?format=png&name=large)

Se puede apreciar que existe un ruido en la señal de 1.5V, reflejo de la señal AC de aproximadamente 70 uV pico a pico, tal vez debería usar un filtro RC para eliminarlo, con la consecuencia de aumentar la impedancia de la señal de referencia, o utilizar otro seguidor luego del filtro para evitar ese posible problema.

Luego verifiqué el X3 se comporta de manera apropiada como comparador y esto obtuve:

(https://pbs.twimg.com/media/FvIzC8wXwAMH18V?format=png&name=large)

Así que parece que el ruido en la referencia de 1.5V no es problema.

Nótese que aun no he colocado el filtro alta frecuencia del amplificador diferencial con desplazamiento, cuya salida es la que debería usar para ser comparada con 1.5V.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 04 de Mayo de 2023, 12:37:32
Estoy en la parte más complicada del proyecto.....  :shock:

Encontrar un caja plástica para el dispositivo.

Estoy buscando algo similar a esto:

(https://www.okwenclosures.com/en/Plug-Cases/PLUG-CASE-F-D_TitleImageSwap500x408.jpg)

Lo ideal sería que la disposición fuese horizontal y mucho mejor si fuera transparente.

Si encuentro uno horizontal (de cualquier color) puedo cortar el panel frontal para colocar una lámina de acrílico trasparente y visualizar el display.

Tal vez también podría comprar sólo el enchufe y ponerlo en cualquier caja.

¿Alguna sugerencia?





Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 04 de Mayo de 2023, 12:50:24
https://es.multi-box.com/es/productos/cajas/cajas-industriales/cajas-plastico/cajas-poliestireno/cajas-electronica-enchufables/mbpo-st
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 04 de Mayo de 2023, 12:52:01
https://www.altinkaya.eu/80-plug-in-enclosures
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 04 de Mayo de 2023, 13:16:12
https://www.altinkaya.eu/80-plug-in-enclosures

Gracias por la info.

Tal vez solo deba comprar un conector así:

(https://pbs.twimg.com/media/FvS_romWIAg-H2D?format=png&name=360x360)

Y colocarlo en cualquier caja.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 08 de Mayo de 2023, 11:39:26
Por el momento, empecé a realizar el esquemático de la fuente voltaje:

(https://pbs.twimg.com/media/FvnOveMXgAIuOfo?format=png&name=large)

La bobina, por un instante no comprendía como usarla, ya presenta cuatro terminales, y el esquemático ejemplo, lo muestra como que fuese una bobina de dos terminales, sin embargo, en el mismo documento del LNK3206GQ, hay un ejemplo de diseño del PCB.

(https://pbs.twimg.com/media/FvnPqVLXgAM8_ds?format=jpg&name=large)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 11 de Mayo de 2023, 11:16:27
He diseñado el filtro de segundo orden con el software FilterLab de MCHP, para una frecuencia de 1000 Hz

(https://pbs.twimg.com/media/Fv2lT8oacAIRsSk?format=png&name=large)

(https://pbs.twimg.com/media/Fv2lXHbaQAIC3HV?format=png&name=900x900)

Voy a utilizar resistencias de 9.3k y 13k respectivamente para R11 y R12, no creo que afecte mucho para la frecuencia diseñada.

La idea del filtro es eliminar cualquier ruido de alta frecuencia proveniente desde la red eléctrica.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: scrwld en 12 de Mayo de 2023, 04:42:54
hola dominusDRR, en estos enlaces hay información que te puede servir para tu proyecto:


https://docs.openenergymonitor.org

https://docs.openenergymonitor.org/electricity-monitoring/index.html

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 12 de Mayo de 2023, 12:05:24
hola dominusDRR, en estos enlaces hay información que te puede servir para tu proyecto:


https://docs.openenergymonitor.org

https://docs.openenergymonitor.org/electricity-monitoring/index.html

Muchas garcias por la infor, puede ser útil
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 13 de Mayo de 2023, 11:33:48
He adelantado un poco del PCB.

La fuente de voltaje (aún falta los reguladores de 5V y 3.3V)

(https://pbs.twimg.com/media/FwA9X64WwAATdy8?format=png&name=large)

El acondicionamiento de la señal:

(https://pbs.twimg.com/media/FwA9aj1WIAI1ZeI?format=png&name=large)

El microcontrolador con sus periféricos:

(https://pbs.twimg.com/media/FwA9c0QWwAAPMH3?format=png&name=4096x4096)

El PCB (aun sin rutear)

(https://pbs.twimg.com/media/FwA9jtPXgAI7qoN?format=png&name=small)

Antes de continuar, voy hacer pruebas reales del acondicionamiento de la señal con el amplificador operacional. Tengo unos pocos en PCBs para usarlos en una  protobard:

(https://pbs.twimg.com/media/FwA8PKLWYAUWCzy?format=png&name=small)

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 15 de Mayo de 2023, 13:50:16

He realizado las pruebas con el amplificador operacional para determinar si el acondicionamiento funciona como predijo la simulación.

Debo indicar que para tal prueba he utilizado resistencias comunes y corrientes (para el proyecto usaré superficiales de 1% de tolerancia), y aún no he utilizado el circuito referencia de voltaje, que es algo que no tenía y es una compra que está en camino. Por lo que usé un arreglo de resistores para conseguir los 1.5V


(https://pbs.twimg.com/media/FwLq5HwWIAIRHYD?format=jpg&name=large)

Tengo un osciloscopio con batería que era lo ideal para "observar" las formas de onda de la señal acondicionada, y de esa manera evitar un posible corto circuito entre la alimentación del osciloscopio y la red eléctrica que se conecta al amplificador diferencial, pero al verificar que dicha herramienta funcione solamente con la batería, descubrí que no era así, ni tampoco se cargaba, al revisarla, veo que está estropeada.

(https://pbs.twimg.com/media/FvecRQbWcAc9lZe?format=jpg&name=large)

Pero hasta conseguir dicha batería o buscar un transformador de aislamiento, para evitar el posible corto circuito, se me ocurrió que puedo usar dos transformadores de pequeña potencia de la siguiente manera.

(https://pbs.twimg.com/media/FwLtSBlXsAgLOpj?format=png&name=900x900)

De esa manera, la señal que se va acondicionar, estará aislada de la red eléctrica que alimenta al osciloscopio.

Cuando observé la señal acondicionada, obtuve esto, que por un momento pensé que era algún tipo de distorsión de la señal sinusoidal. Tenía la idea que el op, o el circuito acondicionaban correctamente la señal, pero distorsionaban la forma de onda


(https://pbs.twimg.com/media/FwLt9IOXsAYUPRy?format=jpg&name=large)

Así que decidí conectar directamente el osciloscopio a la salida del transformador para ver como era la señal de voltaje, y la distorsión provenía desde ahí y no era culpa del circuito con el operacional (Puse la punta de prueba x10)

(https://pbs.twimg.com/media/FwLvD1fXwAIzqzU?format=jpg&name=large)

Entonces, se puede afirmar hasta ahora que el acondicionamiento de la señal funciona, obviamente no es preciso por las resistencias utilizadas, y la referencia de voltaje que conseguí es de 1.4V.

Usé uno de los 4 operacionales disponibles para el comparador, para generar una onda cuadrada sincronizada con el cruce por cero de la sinusoidal y este es el resultado:

(https://pbs.twimg.com/media/FwLwK7xXsAU82Fw?format=jpg&name=large)

Me olvidé indicar que no he tenido resistencias de precisión de 200k, pero tengo de 2 Megas, así que para la atenuación del amplificador diferencial, use resistencias de 2M con resistencias de 10k.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 19 de Mayo de 2023, 14:01:12
He terminado el diseño del PCB, pero aun no voy a enviar a fabricar. Tengo que aprovechar el envío de otros PCBs en donde trabajo para tomar ventaja el envío, más o menos quedan así:

(https://pbs.twimg.com/media/FwgYnNoWYAA3_jC?format=png&name=medium)

(https://pbs.twimg.com/media/FwgYxCHXwBszRUn?format=png&name=medium)

(https://pbs.twimg.com/media/FwgY7thXoAAu3RD?format=png&name=medium)

Voy a utilizar un jumper para alimentar al circuito con 120VAC o una fuente externa de voltaje DC.

La fuente externa es para evitar un posible cortocircuito entre mi PC al conectar el programador/depurador al circuito cuando este creando el firmware del microcontrolador. Es decir que cuando ya finalice la creación del código, el hardware funcionará directamente con los 120VAC de la red eléctrica.

(https://pbs.twimg.com/media/FwgZrzUXwBADvs0?format=png&name=large)

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 19 de Mayo de 2023, 14:45:17
Buena pinta.

La tira de vías que tienes en la parte superior, junto a R26, ¿son para diagnósticos?, ¿o las has hecho así de grandes por otra razón?
En caso negativo, ¿no te interesaría dejar algunos puntos de diagnóstico a lo largo de la PCB donde chequear con el multímetro u osciloscopio fácilmente?
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 19 de Mayo de 2023, 15:29:39
Buena pinta.
La tira de vías que tienes en la parte superior, junto a R26, ¿son para diagnósticos?, ¿o las has hecho así de grandes por otra razón?

Creo que te refieres a los terminales del display. La librería de Eagle es de esa manera.

Buena pinta.

En caso negativo, ¿no te interesaría dejar algunos puntos de diagnóstico a lo largo de la PCB donde chequear con el multímetro u osciloscopio fácilmente?

Suelo utilizar las vías o un terminal de algún componente para poner la punta de prueba del osciloscopio.

Si no es fácil mantener la punta de prueba en un terminal de un componente, sueldo un cable temporal para sujetarlo apropiadamente.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 20 de Mayo de 2023, 01:55:14
Ok
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Junio de 2023, 12:02:40
Hola.

Hasta tener la oportunidad de enviar a fabricar los PCBs, estoy pensado en crear el código para calcular el valor RMS, pero antes de ese proceso, estaba analizando como usar el módulo de captura para "medir" el periodo de la señal, ya que nunca he usado este periférico.

En los ejemplos de Harmony 3, se tiene el ejemplo icap_capture_mode, donde se mide la duración de un pulso en la entrada de un terminal del microcontrolador:

https://microchip-mplab-harmony.github.io/csp_apps_pic32mz_ef/apps/icap/icap_capture_mode/readme.html (https://microchip-mplab-harmony.github.io/csp_apps_pic32mz_ef/apps/icap/icap_capture_mode/readme.html)

En mi caso, si mido el ancho de pulso, deberé multiplicar por 2 para obtener el periodo de la señal, o determinar si el módulo puede iniciar y detener la captura sólo con flanco.

Abrí el ejemplo para determinar como usa el módulo y el temporizador que ayuda a la medición.

(https://pbs.twimg.com/media/FxoEEtqXwAcUFXZ?format=png&name=small)

(https://pbs.twimg.com/media/FxoEJ4nXgAEt0SL?format=png&name=small)

Código: C
  1. ICAP1_Enable();
  2.    
  3.     OCMP3_Enable();
  4.    
  5.     TMR2_Start();
  6.    
  7.     while ( true )
  8.     {
  9.         /* Maintain state machines of all polled MPLAB Harmony modules. */
  10.         SYS_Tasks ( );
  11.        
  12.         while(!ICAP1_CaptureStatusGet());
  13.  
  14.         capturedValue[captureIndex++] = ICAP1_CaptureBufferRead();
  15.  
  16.         if ( captureIndex > 1){
  17.             printf("Pulse Width Count = %d\r\n",(capturedValue[1] - capturedValue[0]));
  18.             captureIndex = 0;
  19.         }
  20.     }

Lo que no estoy seguro, cual son las unidades de medición del ancho de pulso. La descripción del ejemplo, el periodo mide 2000.

(https://microchip-mplab-harmony.github.io/csp_apps_pic32mz_ef/apps/icap/icap_capture_mode/images/output_icap_capture_mode.png)

Según yo, esos 2000 son ciclos de reloj, ¿o puedo estar equivocado y que sean milisegundos?  :shock:

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 02 de Junio de 2023, 12:25:01
Yo creo que te está contando 2000 ticks del Timer2
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Junio de 2023, 12:29:27
Yo creo que te está contando 2000 ticks del Timer2

Si puede ser, tendría que esperar a tener el hardware para hacer pruebas o adaptar este ejemplo a una placa de desarrollo que tengo.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Junio de 2023, 13:01:19
Si, estuve revisando esta información de como configurar un temporizador periférico:

https://microchipdeveloper.com/harmony3:pic32mzef-getting-started-training-module-step2 (https://microchipdeveloper.com/harmony3:pic32mzef-getting-started-training-module-step2)

En el ejemplo qeu indiqué antes, con el pre escalamiento de 256 del temporizador 2, la frecuencia de los pulsos contados es 390,625 Hz, es decir que cada pulso contado es de 2.56 ms.

El registro de perdido de dicho temporizador está calibrado a 39,061, por lo tanto el temporizador se desbordará cada 39,061*2.56ms = 99.99 milisegundos segundos (o 100 segundos como indica el campo TIME, configurado en milisegundos).

Respecto a los 2000 contados, serían 2000*2.56ms = 5.12 segundos.



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 02 de Junio de 2023, 13:45:32
 ((:-))
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Junio de 2023, 18:29:48
Voy a intentar adelantar un poco de código.

El proyecto lo voy hacer con XC32, con MPLAB Harmony 3 y con MCC.

Dejo en imágenes los pasos si alguien, en algún momento desea crear un proyecto con las herramientas mencionadas.

Primero, en MPLAB X inicio un nuevo proyecto con H3 con MCC

(https://pbs.twimg.com/media/FxpLeMXXgAIhkbE?format=png&name=900x900)

Luego selecciono se abre otra ventana, donde debo seleccionar la ruta donde se descargó el repositorio de H3.

(https://pbs.twimg.com/media/FxpL3MfWcAEKvbK?format=png&name=900x900)

A continuación, indico donde deseo crear mi proyecto:

(https://pbs.twimg.com/media/FxpMNfgWwAAACE7?format=png&name=900x900)

Finalmente, selecciono el microcontrolador que deseo usar.

(https://pbs.twimg.com/media/FxpNpM4XoAImuoE?format=png&name=900x900)

Luego se abre el asistente del administrador de contenido, donde selecciono la opción para H3.

(https://pbs.twimg.com/media/FxpP5ScX0AAbbxJ?format=png&name=large)

(https://pbs.twimg.com/media/FxpQDfjXgAIVgdv?format=png&name=large)

Nuevamente, el MCC solicita la ruta del repositorio, creo que es algo redundante, pero así está la cosa.

(https://pbs.twimg.com/media/FxpQMBxXwAEVlRz?format=png&name=small)

Finalmente el MCC tiene este aspecto:

(https://pbs.twimg.com/media/FxpTFqIXsAAI8U4?format=png&name=large)

Con el módulo System, se puede calibrar los bits de configuración, también conocidos como fuses.

(https://pbs.twimg.com/media/FxpTc6EX0AALQcZ?format=png&name=900x900)

La primera palabra de configuración se denomina DEVCFG3 el cual posee tres partes.

USERID nos permite agregar un número de identificación que podría ser la versión del firmware o cualquier otra información.

Una característica de la familia de este MCU es que las salidas o entradas de varios periféricos pueden ser ‘colocados’ en diferentes terminales del MCU. Esto es una ventaja sobre otros microcontroladores debido a que muy a menudo comparten varios periféricos sobre los mismos terminales. Por ejemplo si se utiliza el módulo de comunicación serial asincrónica RS232, el módulo SPI ya no se podría utilizar y viceversa.

Con la familia de este microcontrolador ese problema se resuelve fácilmente asignado a otros terminales las entradas y salidas del otro periférico.

Los periféricos que no poseen esta ventaja son el módulo de comunicación I2C y el conversor ADC cuyos terminales son fijos.

Al poner PMDL1WAY en ON nos permite una sola vez bloquear al Módulo Periférico (Peripheral Module), el cual permite deshabilitar a un módulo periféricos una sola vez, hasta asignarle correctamente los terminales externos del MCU. Luego de la configuración correcta de todos los periféricos no hay manera de volver a modificar al PPS hasta un reinicio del MCU.

El IOL1WAY en ON nos permite una sola vez bloquear a los registros RPnR para la asignación correcta de los terminales al periférico.

(https://pbs.twimg.com/media/FxpU6S5XgAAt3Hz?format=png&name=small)

DEVCFG2 y DEVCFG1, están relacionados con el oscilador, así que prefiero usar la parte gráfica del oscilador para configurarlo.

(https://pbs.twimg.com/media/FxpVmW3XwAA-rao?format=png&name=small)

EL CPU del microcontrolador puede trabajar a 50MHZ, pero poseo un cristal de 8MHz, así que la frecuencia próxima sería 48 MHz.

(https://pbs.twimg.com/media/FxpWXmeWcAIZWrr?format=jpg&name=medium)

Si se regresa a la configuración de DEVCFG2 y DEVCFG1, se podrá observar que han cambiado algunos bits.

(https://pbs.twimg.com/media/FxpX3k-XsAAyDgc?format=png&name=small)

Nótese que el bit FNOSC, de DEVCFG1, está en FRCPLL, esto significa Fast RC PPL, que es oscilador interno RC de alta velocidad, y no deseo utilizar dicho oscilador, quiero usar el cristal.

Y lo que deso usar es XT más multiplicador de frecuencia (PLL)

(https://pbs.twimg.com/media/FxpYy2GXoAEMEQE?format=png&name=900x900)

(https://pbs.twimg.com/media/FxpZN8tWYAAegCg?format=png&name=small)

El bit IESO controla el arranque con dos velocidades, cuando se energiza el sistema, el cristal u oscilador necesitan un tiempo hasta estabilizarse correctamente, habilitado el modo de dos velocidades con el bit IESO, permite al CPU utilizar primero el oscilador interno para luego conmutar al oscilador principal. En nuestro caso no utilizaré dicha funcionalidad, pero debo utilizar el temporizador relacionado con el Power On Reset (POR) hasta que se estabilice el oscilador principal.

FPBDIV y permite definir la frecuencia a la cual los periféricos trabajarán y es un múltiplo de la frecuencia de oscilación del CPU. La dejaremos en un valor igual a 1, es decir sin división.


FCKSM y tiene 3 sub-opciones. El FSCM o Fail-Safe Clock Monitor vigila que el oscilador principal funcione correctamente, si existiera alguna falla, puede conmutar a un oscilador interno para que el CPU siga trabajando.  Creo que voy a dejar deshabilitado al FSCM y a la conmutación de oscilador. O tal vez debería optar por la opción de conmutación al oscilador interno.

Deseo usar el perro guardián, así que configuro para que su desborde sea en 1024 ms, y las opciones de ventana ese temporizador, no las utilizaré (en OFF)

(https://pbs.twimg.com/media/FxpbBmfWcAYwCFW?format=png&name=small)


Con respecto DEVCFG0,  tiene cinco opciones, la primera se denomina JTAGEN y permite la depuración mediante JTAG que es una norma de la IEEE de un puerto de acceso para probar o depurar aun dispositivo. Yo usaré un ICD3 o un SNAP;   por lo que dicha opción estará en OFF.

La segunda opción nos permite configurar que canal ICSP va ser utilizado y en este caso es el número 2.

Respecto a las protecciones de escritura en la memoria de programa y de bootlader, ya que es un proyecto casero y no pienso crear una actualización remota, no pienso activar esas casillas, sólo al de protección de lectura mediante un programador externo.

EL Background debugger, lo dejo en OFF, tampoco es algo no importante, ya que es un proyecto casero, y se pone de manera automática en ON, si utilizo el programador/depurador para depurar con el hardware.

(https://pbs.twimg.com/media/FxpdFYnXoAAk2ZY?format=png&name=small)

Hasta aquí dejo esta explicación que resultó muy extensa.

En otro momento continuo con la configuración del MCC antes de generar el código.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 03 de Junio de 2023, 12:31:43
Continúo con la configuración.

Ahora voy a configurar los pines o terminales del micro:

(https://pbs.twimg.com/media/FxtECYrWcAQsmXr?format=png&name=medium)

Configuro cada uno de los terminales de acuerdo al diseño deseado.


(https://pbs.twimg.com/media/FxtG-ntX0AEqjO_?format=png&name=900x900)

En recursos de dispositivo busco y agrego el módulo Core:

(https://pbs.twimg.com/media/FxtHXcMXoAAZu1C?format=png&name=small)

Siempre al agregar este módulo, me pregunta si deseo usar FreeRTOS, pero para este ejemplo simple, no creo que es necesario.

(https://pbs.twimg.com/media/FxtHpKVXsAY7Y-X?format=png&name=small)

Con el módulo Core, activo la casilla para generar archivos de aplicación, esto permite crear tareas o procesos de máquina de estados, y esa forma de escribir código me gusta.

(https://pbs.twimg.com/media/FxtIBQZWYAEmBTK?format=png&name=small)

Las tareas, según yo, las creo por cada periférico que se desea controlar o un proceso particular que se desea que sea independiente.

Por el momento creo dos, la primera que será para controlar el display, y la segunda, será aquella que realicé el proceso de calcular el valor rms.

(https://pbs.twimg.com/media/FxtImBWXsAA3a2o?format=png&name=small)

Más adelante determinaré si es necesario más tareas o no.

Lo que voy a adelantar en agregar son los módulo relacionados con la captura de pulsos.

Creo un nuevo grupo para tener más ordenado los módulos:

(https://pbs.twimg.com/media/FxtKIHIXoAA7cDD?format=png&name=360x360)

Por defecto, el grupo se llama Group 0, pero lo cambio de nombre:

(https://pbs.twimg.com/media/FxtKoe5XgAMOlLa?format=png&name=small)

Dentro del nuevo grupo, agrego el módulo ICAP1.

(https://pbs.twimg.com/media/FxtLOn9XgAE0THD?format=png&name=large)


Configuro el módulo ICAP1 para que capture por solamente por flanco de subida  (no se si esto deba cambiar) y asociado al temporizador 2, el cual funciona como 16 bits.

(https://pbs.twimg.com/media/FxtL1kGXsAAbWJh?format=png&name=900x900)

También agrego el temporizador 2.

(https://pbs.twimg.com/media/FxtMZyiXgAUxUTF?format=png&name=small)

Ya que el periodo a medir es aproximadamente 17 ms, (60Hz), pienso que el temporizador 2, debe incrementarse a paso mucho más pequeños, podría ser cada 100 microsegundos o menos.

Configurando TMR2 con un pre escalamiento de 64, la frecuencia de cada pulso sería de 750 kHz o 1.333 us, pienso que sería un valor bueno para calcular el periodo de una señal.

También con estos valores, TMR2 se desbordaría cada 50 ms, que es mucho mayor que 17 ms.

No son lo valores definitivos, debería hacer pruebas para determinar la exactitud de la medición del periodo.

(https://pbs.twimg.com/media/FxtTXuuXsAA3V3b?format=png&name=900x900)

Me olvidaba que sé utilizar el Core Timer para generar retardos asincrónicos, para cualquier delay en el código. Así que vuelvo al grupo raíz o Root y agrego dicho módulo par disponer de las librerías de ese periférico.

(https://pbs.twimg.com/media/FxtUB2qXsAIMxzp?format=png&name=small)

Creo que eso es todo, cualquier momento puedo volver abrir el MCC y modificar la configuración, por ahora voy a generar el código.

(https://pbs.twimg.com/media/FxtUbTFXgAchyOt?format=png&name=small)

Una vez generado el código, puedo cerrar el MCC y este es el aspecto que tiene:

(https://pbs.twimg.com/media/FxtU3c0XgAATD2f?format=jpg&name=medium)




Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 03 de Junio de 2023, 23:25:06
Para calcular el RMS debo cumplir con la siguiente condición de varias muestras adquiridas por el ADC según la siguiente ecuación:

(https://docs.openenergymonitor.org/_images/equation3.png)

El máximo valor que mide el ADC correspondería a 300V, mientras que el mínimo es -300V

Antes de aplicar la ecuación de arriba, creo, que debo cambiar los valores obtenidos del ADC a los niveles de voltaje, o tal vez haya otra manera

Esto analizando las cuatro opciones que posee el ADC para mostrar los resultados.

Cada uno de los valores, deben ser multiplicados por una pendiente o ganancia m y sumados un desplazamiento o constante c, para llegar a los valores de voltaje mínimo y máximo.

V instantáneo = (Valor del ADC)* m + c

El ADC puede mostrar su resultado de 4 formas diferentes

(https://pbs.twimg.com/media/FxvmEwzWcAAPHNb?format=png&name=medium)

Para la primera sería:

1023*m + c = 300
0*m + c = -300

De aquí m = 200/341 y c = -300.

Para la segunda opción sería:

511*m + c = 300
-512*m + c = -300, donde m = 200/341 y c = 0.293

Para la tercera opción sería:

0.999*m + c = 300
0*m + c = -300 , donde m = 600.6006 y c =-300

Y la última sería:

0.499*m + c = 300
-0.5*m + c = -300, donde m = 109.111 y c = 245.

Con estos resultados pienso que la primera opción, parece la mejor.

Es decir que cada valor obtenido del ADC, debo multiplicarlo por m y sumarlo c. El resultado debo elevarlo al cuadrado e ir sumando cada uno de esos valores.

La suma total debo dividirla para el número de muestras que se haya obtenido en el periodo de tiempo, y ese nuevo resultado, debo extraer la raíz cuadrada.

Ahora bien, me parece que esa constante m, podría salir del sumatorio, y la constante c sería otro sumatorio a parte, es decir, que creo que antes de multiplicar cada valor por m y sumarle c, se podría realizar el sumatorio sin alterar aún los valores adquiridos, y luego, con el resultado final, multiplicaría por una ganancia y sumarle.

De esa manera, podría aliviar la carga de calculo al CPU del microcontrolador.





Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 03 de Junio de 2023, 23:52:06
Creo que quedaría así:

(https://pbs.twimg.com/media/FxvxB1KXwAAN-Yu?format=png&name=900x900)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 04 de Junio de 2023, 12:09:26
Empecé a realizar algunas pruebas con el código y el simulador de MPLAB X, ya que aun no tengo el hardware listo.

Lo primero que hice fue imaginar que tenía 100 muestras de una señal sinusoidal perfecta, con RMS de 120V.

El circuito acondicionador cambia la señal de entrada 300V a 3.0V que sería 1023 en el ADC, con -300, la señal sería de 0.0V y el ADC también sería 0.

Si mi señal es de 120VAC, quiere decir que el valor pico sería 169.7056V.

El circuito acondicionador con el amplificador operacional, da una ganancia de 1/200 a la señal y suma una constante de 1.5.

Por lo tanto.

169.7056/200 + 1.5 = 2.3482V

-168.7056/200 + 1.5 = 0.65147V

Si el ADC, para 3.0V son 1023, realizando una simple regla de 3.

3.0V---- equivale a ---- > 1023

2.3482--- equivale a  800.84.81 (801 siendo entero sin signo)

0.65147-- equivale a  222.1519 (222 para un número sin signo)

Creo un vector o arreglo para almacenar dichas muestras, y lo hago en la estructura de datos de la tarea appRMS:

(https://pbs.twimg.com/media/FxyXHZZWIAMYyaY?format=png&name=small)

Ahora bien, con ayuda de excel, genero las 100 muestras de la señal, la fámula usada es:

=341*((169,7056/200)*SENO(2*PI()*A3/100)+1,5)


(https://pbs.twimg.com/media/FxyXmctWYAM9AR5?format=png&name=small)

Copio y pego todas esos valores para el arreglo en el archivo c, de la tarea.

(https://pbs.twimg.com/media/FxyX-YlXoAAoDe9?format=png&name=small)

El proceso para obtener el valor rms es el siguiente:

Código: C
  1. unsigned char i;
  2.             float sumatorio1 = 0.0;
  3.             float sumatorio2 = 0.0;
  4.             for (i = 0; i< 100; i++)
  5.             {
  6.                 sumatorio1 +=(float)(apprmsData.arreglo[i]*apprmsData.arreglo[i]); // sumatorio(x^2)
  7.             }
  8.             sumatorio1 = 0.34399*sumatorio1; // m^2* sumatorio1
  9.            
  10.              for (i = 0; i< 100; i++)
  11.              {
  12.                  sumatorio2 +=(float)(apprmsData.arreglo[i]);
  13.              }
  14.             sumatorio2 = -351.9062*sumatorio2; //2mc* sumatorio2(x)
  15.            
  16.             sumatorio1 = sumatorio1 + sumatorio2 + 8910000; //8910000 = (N-1)*C^2
  17.             sumatorio1 = sumatorio1/100;
  18.             sumatorio1 =  sqrtf(sumatorio1); //raiz cuadrada de todo

Y al simular, obtengo un valor cercano, no se donde se hay error.

(https://pbs.twimg.com/media/FxyYk56WAAEnIGY?format=png&name=medium)

He visto que el núcleo MIPS, tal vez me sea útil para acelerar el procesamiento de datos y tal vez reducir el error.

(https://pbs.twimg.com/media/FxyZEYJWIAALKC5?format=png&name=900x900)

Debo indicar que para la simulación con MPLAB X. escogí el nivel de optimización de XC32 en 0 o sin optimización de código, ya que cuando se compila con optimización, muchas veces se reducen procesos y no es posible "ver" algunas partes de la simulación.



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 04 de Junio de 2023, 15:32:32
Hice una prueba, donde no separé al sumatorio en varias partes y obtuve el valor correcto.

(https://pbs.twimg.com/media/FxzGCmvXwAAPgcB?format=png&name=large)

Pienso que cualquiera de los dos formas, están bien, lo que creo que está mal en el primer intento, es que no convertí a float cada elemento del arreglo antes de realizar cualquier operación matemática.

Independiente de la precisión de ambos métodos, aparentemente esté último es el "mejor", ya que tiene pocas líneas de código.

El problema sería determinar, cuántas ciclos de máquina consume y este, no me agrada mucho, ya que me gusta que el código que hago sea multitarea.

Si consume muchos ciclos de máquina, podría decirse que posiblemente ingrese una latencia al sistema, latencia que podría ser despreciable.

Es por esa razón que pienso dividir al proceso para obtener al RMS, en un máquina de estados donde haga poco a poco cada operación matemática sin apropiarse completamente del CPU permitiendo a otras tareas realizar sus procesos.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 05 de Junio de 2023, 14:01:36
Ahora voy a analizar el funcionamiento del ADC del microcontrolador.

EL ADC tiene un buffer de 16 palabras que pensaba que me serían útiles para adquirir 16 muestras de manera automática.

(https://pbs.twimg.com/media/Fx33TKqX0AECtuF?format=jpg&name=medium)

Ahora bien, la señal se se desea muestrear con el ADC es aproximadamente de 60 Hz o de un periodo de 16.667 ms.

El muestreo debe ser mucho menos que ese tiempo, por ejemplo si fuera 100 veces más pequeño, sería 166,667 us, así que podría escoger un muestreo a 100 us o 10 ksps.

Aquí se debe considerar el tiempo de adquisición y el tiempo de conversión.
(https://pbs.twimg.com/media/Fx34c8VWABYoVNj?format=jpg&name=medium)

Según el manual de la sección del conversor ADC, el tiempo de adquisición de la señal está dado por los bits ADCS del registro ADCON3
(https://pbs.twimg.com/media/Fx35F46WAA0dmWg?format=png&name=small)

El tiempo mínimo debe ser superior a 83.33 ns.

(https://pbs.twimg.com/media/Fx35dIjWAAgdjUi?format=png&name=900x900)

Y en mi caso TpB es 1/48MHz.

(https://pbs.twimg.com/media/Fx35q0HWABEqYiG?format=png&name=small)

Buscando un valor correcto para el bits ADCS, puedo afirmar que se puede conseguir 1 us de tiempo de adquisición:

(https://pbs.twimg.com/media/Fx36IG1WAAc0Qha?format=png&name=small)

Según el manual, el tiempo de conversión es 12 veces TAD, más 1 o 2 TADs adicionales, por lo tanto, el tiempo de conversión sería aproximadamente 14 us

(https://pbs.twimg.com/media/Fx3824bXoAMG3G7?format=jpg&name=large)

Es decir que el muestreo sería a una razón de 15 us o 66.67 ksps.

Esto permitiría obtener más muestras, es decir ser más preciso el cálculo, o tal vez utilizar un retardo para esperar los 100 us.

Si utilizo el retardo, no necesitaría usar todo el buffer del ADC, me bastaría solo adquirir la información de una palabra de dicho arreglo, similar al ejemplo con dicho conversor con harmony 3:

Código: C
  1. while (1)
  2.     {
  3.         /* Maintain state machines of all polled MPLAB Harmony modules. */
  4.         SYS_Tasks ( );
  5.  
  6.         /* Auto sampling mode is used, so no code is needed to start sampling */
  7.                
  8.         /* Start ADC conversion in software */
  9.         ADC_ConversionStart();
  10.  
  11.         /* Wait till ADC conversion result is available */
  12.         while(!ADC_ResultIsReady())
  13.         {
  14.  
  15.         };
  16.  
  17.         /* Read the ADC result */
  18.         adc_count = ADC_ResultGet(ADC_RESULT_BUFFER_0); //<=== Sólo obtiene el resultado de la primera palabra del buufer
  19.         input_voltage = (float)adc_count * ADC_VREF / ADC_MAX_COUNT;
  20.  
  21.         printf("ADC Count = 0x%03x, ADC Input Voltage = %d.%02d V \r", adc_count, (int)input_voltage, (int)((input_voltage - (int)input_voltage)*100.0));
  22.     }
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 06 de Junio de 2023, 16:48:49
Ahora voy adelantar la tarea que estará dedicada a mostrar cualquier información en el display.

Primero creo un arreglo de tipo unsigned char de longitud 4, para cada dígito del display de 7 segmentos.

Este arreglo necesita una variable como índice o puntero, y al ser sólo 4 dígitos, puede ser también char sin signo.

También necesito una variable de tipo int si signo que utilizaré para crear retardos asincrónicos en esta tarea.

Código: C
  1. typedef struct
  2. {
  3.     /* The application's current state */
  4.     APPDISPLAY_STATES state;
  5.     /* TODO: Define any additional data used by the application. */
  6.     unsigned char arregloDisplay[0x04];
  7.     unsigned char punteroDisplay;
  8.     unsigned int retardo;
  9. } APPDISPLAY_DATA;

Al ser un display de ánodo común, los valores a representar cada dígito serían los siguientes:

(https://pbs.twimg.com/media/Fx8507QWcAEQraX?format=png&name=900x900)

Puedo hacer una función con retorne cada valor en función de una variable en una instrucción, pero prefiero usar un arreglo en la memoria flash. Este arreglo estará en el archivo c de la tarea.

(https://pbs.twimg.com/media/Fx87YUyXsAYDGFK?format=png&name=900x900)

El puerto B, no es de 8 bits, es decir que se debe enmascarar lo que se va a escribir en él, para no alterar el bit8, bit 9, etc de ese puertos.

Sería algo así con un or a nivel de bytes:

Código: C
  1. LATB = 0xFFFFFF00 | valor obtenido del arreglo

Puedo usar l'abstracción  de Harmony para manipular el puerto:

Código: C
  1. void GPIO_PortWrite(GPIO_PORT port, uint32_t mask, uint32_t value);


Donde port, es el puerto, mask, indica que bits se desea alterar y value, es el valor que se desea escribir.

La máscara debe ser 1 para los bits que se desea que sean alterados, y caso contrario 0,

En mi caso sería así:

Código: C
  1. GPIO_PortWrite(GPIO_PORT_B, 0x0000FF,  valor obtenido del arreglo);

Al inicializar la tarea, el puntero de display y el valor para cada dígito los pongo en cero:

Código: C
  1. void APPDISPLAY_Initialize ( void )
  2. {
  3.     /* Place the App state machine in its initial state. */
  4.     appdisplayData.state = APPDISPLAY_STATE_INIT;
  5.  
  6.     /* TODO: Initialize your application's state machine and other
  7.      * parameters.
  8.      */
  9.     appdisplayData.punteroDisplay = 0x00; //apunto al primer display
  10.     appdisplayData.arregloDisplay[0x00] = 0x00; //valor inicial en cero
  11.     appdisplayData.arregloDisplay[0x01] = 0x00; //valor inicial en cero
  12.     appdisplayData.arregloDisplay[0x02] = 0x00; //valor inicial en cero
  13.     appdisplayData.arregloDisplay[0x03] = 0x00; //valor inicial en cero
  14. }

De manera empírica de otros proyectos he determinando que la frecuencia de activación de cada display puede ser de 1 ms, obviamente sería de probarlo con el hardware, pero lo dejo por ahora.

En el primer estado de la tarea que renombré ESTADO_INICIAL, capturo el valor que tenga el Core Timer, para pasar al siguiente estado que he denominado MOSTRANDO_DATOS.

Código: C
  1. void APPDISPLAY_Tasks ( void )
  2. {
  3.  
  4.     /* Check the application's current state. */
  5.     switch ( appdisplayData.state )
  6.     {
  7.         /* Application's initial state. */
  8.         case APPDISPLAY_ESTADO_INICIAL:
  9.         {
  10.            
  11.             appdisplayData.retardo = CORETIMER_CounterGet();
  12.             appdisplayData.state = APPDISPLAY_ESTADO_MOSTRANDO_DATOS;
  13.             break;
  14.         }
  15.  
  16.         case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
  17.         {
  18.  
  19.             break;
  20.         }
  21.  
  22.         /* TODO: implement your application state machine.*/
  23.         /* The default state should never be executed. */
  24.         default: break;  /* TODO: Handle error in application's state machine. */
  25.     }
  26. }

En el segundo estado de la tarea, debería esperar 1 ms para cambiar la información a cada dígito del display:

Código: C
  1. case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
  2. {
  3.        if ((CORETIMER_CounterGet() - appdisplayData.retardo) > _1ms)
  4.        {
  5.                
  6.        }
  7.        break;
  8. }

La constante _1ms se calcula en función de los ciclos de reloj contados por el temporizador central o CORE TIMER.

Este temporizador funciona a la mitad de la frecuencia del sistema, es decir 24 MHz, es decir que cada ciclo es de 41.666 ns, por lo tanto para conseguir 1 ms, sería 1ms/41.666ns = 24000 ó 0x5DC0

Código: C
  1. #define _1ms 0x5DC0

Para acceder al valor que se desea mostrar, se debe recurrir al arreglo que contiene el valor mediante la variable puntero display, así:

Código: C
  1. appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]

Pero este valor no es el adecuado para mostrarlo en el display, así que se recurre al arreglo creado en la memoria flash, es decir:

Código: C
  1. digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]

Para colocar este valor en el puerto B, mediante la función para escribir un número en puerto de H3 sería de la siguiente manera:

Código: C
  1. GPIO_PortWrite(GPIO_PORT_B, 0x0000FF, (uint32_t) digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]);

Y también se debe activar la base de cada transistor PNP que controla dígito del display y es algo que hasta ahora no considero.

Por defecto, en el MCC los pines RB8, RB9, RB12 y RB13 están configurados por defecto en 1 lógico (cada dígito del display apagado), pero podría ponerlos en 1 lógico al inicio de la tarea:

Código: C
  1. void APPDISPLAY_Initialize ( void )
  2. {
  3.     /* Place the App state machine in its initial state. */
  4.     appdisplayData.state = APPDISPLAY_ESTADO_INICIAL;
  5.  
  6.     /* TODO: Initialize your application's state machine and other
  7.      * parameters.
  8.      */
  9.     /*** Apago cada uno de los dígitos del display***/
  10.     DISPLAY1_Set();
  11.     DISPLAY2_Set()
  12.     DISPLAY3_Set();
  13.     DISPLAY4_Set();
  14.     /***********************************************/
  15.     appdisplayData.punteroDisplay = 0x00; //apunto al primer display
  16.     appdisplayData.arregloDisplay[0x00] = 0x00; //valor inicial en cero
  17.     appdisplayData.arregloDisplay[0x01] = 0x00; //valor inicial en cero
  18.     appdisplayData.arregloDisplay[0x02] = 0x00; //valor inicial en cero
  19.     appdisplayData.arregloDisplay[0x03] = 0x00; //valor inicial en cero
  20. }

Lo que necesito, es con el mismo puntero del arreglo de display, ir seleccionando los terminales RB8, RB9, RB12 y RB13.

Con la función para activar

Código: C
  1. GPIO_PortClear(GPIO_PORT_B,bit del puerto);

Entonces nuevamente escribo un arreglo en la memoria flash de 4 bytes para manipular los 4 bits.

Código: C
  1. //                                             bit8   bit9  bi12    bit13
  2. const unsigned short bitsDigitoDisplay[0x04] = {1<<8, 1<<9, 1<<12, 1<<13};

Entonces sería de la siguiente manera, pero aun está incompelto:
Código: C
  1. case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
  2. {
  3.       if ((CORETIMER_CounterGet() - appdisplayData.retardo) > _1ms)
  4.       {
  5.           GPIO_PortWrite(GPIO_PORT_B, 0x0000FF, (uint32_t) digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]);
  6.           GPIO_PortClear(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay]);
  7.           appdisplayData.punteroDisplay++;
  8.       }
  9.       break;
  10. }

Necesito apagar el display previo al que se va activar:

Código: C
  1. GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay - 0x01]);

pero eso no es factible si punteroDisplay es igual a cero, por lo tanto sería así:

Código: C
  1. if (appdisplayData.punteroDisplay > 0x00)
  2.  {
  3.      GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay - 0x01]);
  4.  }
  5.  else // si appdisplayData.punteroDisplay  es cero, se debe apagar el 4to dígito
  6.  {
  7.       GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[0x03]);
  8.   }

También es necesario verificar que al incrementar el puntero, no debe sobrepasar 3:

Código: C
  1. if (appdisplayData.punteroDisplay > 0x03)
  2. {
  3.    appdisplayData.punteroDisplay = 0x00;
  4. }

Luego de todo esto, la tarea debe volver a capturar un valor del CORE TIMER, para generar otro retardo.

Entonces el segundo estado de la tarea sería así:
Código: C
  1. case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
  2. {
  3.     if ((CORETIMER_CounterGet() - appdisplayData.retardo) > _1ms)
  4.     {
  5.         if (appdisplayData.punteroDisplay > 0x00)
  6.         {
  7.             GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay - 0x01]);
  8.         }
  9.         else // si appdisplayData.punteroDisplay  es cero, se debe apagar el 4to dígito
  10.         {
  11.             GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[0x03]);
  12.         }
  13.         GPIO_PortWrite(GPIO_PORT_B, 0x0000FF, (uint32_t) digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]);
  14.         GPIO_PortClear(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay]);
  15.         appdisplayData.punteroDisplay++;
  16.         if (appdisplayData.punteroDisplay > 0x03)
  17.         {
  18.             appdisplayData.punteroDisplay = 0x00;
  19.         }
  20.         appdisplayData.retardo = CORETIMER_CounterGet(); // vuelvo a capturar otro valor del Core Timer para otro retardo
  21.     }
  22.     break;
  23. }

Esta tarea estaría funcionando de manera independiente, cualquier valor que se desease mostrar en el display, deberá hacerse desde otra tarea o proceso modificando los valores del arreglo appdisplayData.arregloDisplay
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 06 de Junio de 2023, 17:28:19
¡Vaya hilazo te está quedando!  ((:-)) ((:-)) ((:-))
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 07 de Junio de 2023, 12:50:14
He conseguido unas cajas plásticas de un amigo que tenía un negocio de fabricación de taxímetros:

(https://pbs.twimg.com/media/FyB_J9NWYAEfVDZ?format=jpg&name=large)

Pero no consideré que hay dos agujeros laterales para los tornillos:

(https://pbs.twimg.com/media/FyB_QUxWAAMfWan?format=png&name=large)

Así tengo que realizar una corrección al PCB antes de su fabricación.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 06 de Julio de 2023, 09:47:34
Hola, ya envíe a fabricar el PCB.

Tuve que modificar el anterior diseño, porque necesitaba colocar unos agujeros a los extremos para los postes que contienen los tornillos de sujeción de la caja plástica.

También, escogí el color lila para el PCB, nunca he realizado placas en ese color:

(https://pbs.twimg.com/media/F0WpPV6XoAEkADr?format=jpg&name=small)

(https://pbs.twimg.com/media/F0WpZTCXgAAwVoQ?format=jpg&name=small)

(https://pbs.twimg.com/media/F0WrNo9WAAEv7Q_?format=png&name=900x900)

Respecto a la fuente, coloqué un diodo rectificador antes del regulador de 5V (D4) para evitar una polarización inversa cuando use una fuente externa la cual usaré cuando desee depurar el firmware del microcontrolador:

Adicionalmente, la carga de 1mA (15k) que necesita la fuente de 15V, la sustituí por un diodo led con su resistencia limitadora. (LED1 y R5)

(https://pbs.twimg.com/media/F0WryKrWIAA9Eqh?format=png&name=medium)



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 16 de Agosto de 2023, 16:25:11
Al fin llegaron los PCBs:

(https://pbs.twimg.com/media/F3rPv6uWkAArJNO?format=jpg&name=large)

Lo primero que voy hacer, es colocar los elementos de la fuente para ver si funciona.... :shock:
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: tsu_electronica en 16 de Agosto de 2023, 22:13:50
jeje como que si funciona claro que va a funcionar  ((:-))
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 19 de Agosto de 2023, 12:07:29
Ayer coloqué todos los componentes con respecto a la fuente y quedó así:

(https://pbs.twimg.com/media/F35wCGoWgAA1NZV?format=jpg&name=large)

Con un poco de temor y esperando que no explote algo, conecte el circuito a la red de 120VAC, y el led rojo que puse como carga, y funcionó correctamente:

(https://pbs.twimg.com/media/F35wU5BXsAAEoDs?format=jpg&name=large)

Pero aquí viene algo que me preocupa, al medir el voltaje, obtengo aproximadamente 3.3V cuando supuestamente, la fuente se diseñó para 15V:

(https://pbs.twimg.com/media/F35wbhXXAAAuw3H?format=jpg&name=large)

Talvez sería buena idea trabajar con este voltaje, sin recurrir a un LDO para bajar a5V y 3,3V respectivamente, pero no se si esos 3.3V vayan a ser constantes, y no deberían estar ahí.

Revisando un poco creo que posiblemente encontré la falla.

He colocado 2 resistencias de 2.49k:

(https://pbs.twimg.com/media/F35xuJ5WgAAGxx3?format=png&name=medium)

Cuando lo correcto es que una es de 16.5k:

(https://pbs.twimg.com/media/F35x__EW8AAgkaf?format=png&name=small)

Voy a  corregir ese error y veo que sucede.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 19 de Agosto de 2023, 14:05:16
Remplacé la resistencia R3 por el valor correcto y parece que el voltaje ahora es el adecuado:

(https://pbs.twimg.com/media/F36MEWVWAAAnJOL?format=jpg&name=large)


Esta es la forma de onda del voltaje con el osciloscopio:

(https://pbs.twimg.com/media/F36McVSW8AAQpO1?format=jpg&name=large)

Está es la componente sólo de AC de la señal de voltaje:

(https://pbs.twimg.com/media/F36MwPQXcAE1Urm?format=jpg&name=large)

Ahora, el siguiente paso, es colocar todos los componentes relacionados con el acondicionamiento de la señal (amplificador diferencial) para determinar su correcto funcionamiento.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 20 de Agosto de 2023, 01:33:57
Pues muy bien, menos mal que te diste cuenta del cambio de la resistencia.

Lo que no entiendo es lo de la forma de onda AC. ¿No debería salirte una curva de 50/60Hz?
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 20 de Agosto de 2023, 10:13:42
Pues muy bien, menos mal que te diste cuenta del cambio de la resistencia.

Lo que no entiendo es lo de la forma de onda AC. ¿No debería salirte una curva de 50/60Hz?

Lo que se ha probado hasta ahora, es la fuente DC del sistema, es decir el conversor AC/DC, que cambia los 120VAC de la red eléctrica a 15 VDC.

Esos 15 voltios servirán para alimentar al microcontrolador (Reduciéndolo a 3.3V) y al amplificador diferencial.

La primera forma de onda son los 15V (en realidad 14VDC) con el rizado o ruido que toda fuente de voltaje posee.

La segunda forma de onda es sólo el rizado de la anterior, es decir el osciloscopio elimina la componente DC y se ve sólo el valor AC.


(https://i.ytimg.com/vi/bN73ZL9ewCQ/maxresdefault.jpg)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 20 de Agosto de 2023, 11:57:01
Ah, vale, entendido.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 22 de Agosto de 2023, 23:09:02
Me acabo de llevar un chasco, estaba colocando los componentes que conforman el amplificador diferencial, cuando me acabo de dar cuenta que diseñe el PCB con el footprint del OP, pensando que tenía unas muestras de un tamaño determinado, cuando en realidad eran más grandes:

(https://pbs.twimg.com/media/F4LlNMTXUAE8ofZ?format=jpg&name=large)

Ahora lo que tengo que hacer, es comprar del tamaño correcto y esperar a que lleguen.

Tal vez me anime adelantar, la parte del microcontrolador con el display.



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 23 de Agosto de 2023, 01:34:57
Bueno, pues toca esperar. No te imaginas la de veces que me ha pasado a mí algo parecido.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 23 de Agosto de 2023, 12:04:52
Bueno, pues toca esperar. No te imaginas la de veces que me ha pasado a mí algo parecido.

Eso me pasa por confianzudo, tenía que a ver revisado todo lo que tengo antes de enviar a fabricar el PCB.

Lo que suele pasar es que diseñas primero el PCB y cuando vas a comprar los elementos, no hay en existencias en los tamaños/disposición deseada.

Por eso es mejor tener primero todos los elementos primero antes de crear la placa, pero en este caso teniendo con anticipación los elementos he cometido un error de novato.
 :(

Lo bueno es que el proyecto es sólo un pasatiempo, así que no hay prisas.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 31 de Agosto de 2023, 14:32:17
Así quedó con el microcontrolador y los transistores:

(https://pbs.twimg.com/media/F44F8O5W0AAZsx6?format=jpg&name=large)

Y la tarea que administra al display, funciona correctamente:

(https://pbs.twimg.com/media/F4zANDaXQAA5Ord?format=jpg&name=medium)

Aproveché el hardware para hacer un video tutorial del manejo del display con el compilador XC32 y Harmony 3:

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Leon Pic en 04 de Septiembre de 2023, 07:42:15
 <3 <3 <3 <3
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 05 de Septiembre de 2023, 12:09:38
 :-/ :-/
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Wasbfire en 10 de Septiembre de 2023, 19:38:11
He leido tu proyecto y me parecio increible la verdad, felicidades. Pero tengo una duda, este proyecto funciona solamente para frecuencias de la red electrica o tambien sirve para niveles de frecuencia mas altos, como por ejemplo 20kHz.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 10 de Septiembre de 2023, 19:42:20
He leido tu proyecto y me parecio increible la verdad, felicidades. Pero tengo una duda, este proyecto funciona solamente para frecuencias de la red electrica o tambien sirve para niveles de frecuencia mas altos, como por ejemplo 20kHz.

En teoría si, ya que el cálculo matemático del RMS no depende de la frecuencia.

Dependería de la velocidad de muestreo del conversor ADC.  Si puede tomar muestras mayores que 20 kHz, digamos 200 kSPS o más, el cálculo sería mucho más aproximado a la realidad.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 10 de Septiembre de 2023, 19:45:29
He leido tu proyecto y me parecio increible la verdad, felicidades. Pero tengo una duda, este proyecto funciona solamente para frecuencias de la red electrica o tambien sirve para niveles de frecuencia mas altos, como por ejemplo 20kHz.

En teoría si, ya que el cálculo matemático del RMS no depende de la frecuencia.

Dependería de la velocidad de muestreo del conversor ADC.  Si puede tomar muestras mayores que 20 kHz, digamos 200 kSPS o más, el cálculo sería mucho más aproximado a la realidad.

Me olvidaba, también dependería del ancho de banda del amplificador operacional ocupado como acondicionador de la señal. (También debería ser mucho mayor que 20 kHz)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 18 de Septiembre de 2023, 13:53:23
Hola.

Hasta comprar los elementos faltantes (debido a que importar poco, me sale muy caro, y esperar algunas semanas para comprarlos junto con otros que la empresa necesita), voy a crear la tarea que controla al buzzer, la cual servirá para advertir de un sobre o bajo voltaje.

También he decido, con el buzzer, realizar una tonada o música, cuando el dispositivo es energizado.

Ya he trabajado antes con el módulo comparador de salida, exactamente haciendo lo que he descrito, y funciona con un temporizador de 16 o 32 bits para realizar la comparación:

(https://pbs.twimg.com/media/F6UfL8PWwAAB371?format=jpg&name=medium)

En la zona gráfica del MCC, hice un nuevo grupo denominado buzzer:

(https://pbs.twimg.com/media/F6UfdJXWoAAeC1i?format=png&name=900x900)

Dentro del cual he colocado el módulo OCMP1, que corresponde a la salida OC1:

(https://pbs.twimg.com/media/F6Uf5wEWYAEM8Mk?format=png&name=medium)

Las características del buzzer son las siguientes:

(https://pbs.twimg.com/media/F6UgyDrWUAAqdls?format=png&name=900x900)

Internet hay varios ejemplos de como generar música con una señal PWM

La frecuencia de las notas musicales, está en el rango aproximado desde 200 Hz a 3000 Hz.

Por lo tanto, para modificar, la frecuencia del PWM, se necesita modificar el registro del PRy del temporizador asociado:


(https://pbs.twimg.com/media/F6UiOxmWIAQ-9UZ?format=png&name=900x900)

Entonces, el valor a comparar, no es importante, pero como fuente de reloj, selecciono el temporizador 3, para no interferir con aquel que se va a usar con el módulo de captura de la señal cuadrada sincronizada con la sinusoidal:

(https://pbs.twimg.com/media/F6UkCKNXwAATzwS?format=png&name=900x900)

Y creo una tarea con el nombre appBuzzer que se dedicará a generar la música inicial, y tonos de advertencia:

(https://pbs.twimg.com/media/F6UkPu8WQAIQ_Gp?format=png&name=small)

Tengo de un proyecto, con un microcontrolador PIC32MZ, estas definiciones para cada nota musical, donde cada una de ellas tiene como comentario, la frecuencia necesaria. Por ejemplo la nota musical c_ corresponde a 261Hz, y el valor a cargar en el PRy es 191570 para generar esa frecuencia.

Obviamente, para este microcontrolador, que trabaja a otra frecuencia, debo recalcular esos valores

Código: C
  1. #define mute 0
  2. #define c_      191570 //       261 Hz se puso guión bajo _ debido a que había confilctos con definiciones de aws o con freertos
  3. #define d_      170067 //       294
  4. #define e_      151974 //       329
  5. #define f   143265 //   349
  6. #define g   127876 //   391
  7. #define gS      120481 //       415
  8. #define a       113635 //       440
  9. #define aS      112359 //       445
  10. #define b       107295 //       466
  11. #define cH      95601  //       523
  12. #define cSH 90252  //   554
  13. #define dH      85178  //   587
  14. #define dSH 80385  //   622
  15. #define eH      75872  //       659
  16. #define fH      71632  //       698
  17. #define fSH 67567  //   740
  18. #define gH      63775  //       784
  19. #define gSH     60240  //       830
  20. #define aH      56817  //       880
  21.                
  22. #define cHH     23888   //      2093
  23. #define AB      26823   //      1864
  24. #define F6      35816   //      1396
  25. #define d7      21285   //      2349
  26. #define DE      20087   //      2489
  27. #define f7      17901   //      2793
  28. #define FG      16890   //      2960
  29. #define GA      15050   //      3322
  30. #define ABx 13407       //      3729
  31. #define CD      22551   //      2217
  32. #define E7      18960   //      2637
  33. #define g7      15943   //      3136

Mas tarde continúo con la explicación para generar la melodía inicial.



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 18 de Septiembre de 2023, 19:21:23
Continúo con respecto del PWM.

Según las definiciones anteriores, la frecuencia mínima es 261 Hz y la máxima es 3136 Hz, esto implicaría un periodo máximo de la señal PWM de 3.831 ms y mínimo de 318.88 microsegundos respectivamente.

Por lo tanto, el periodo del PWM debería ser mayor a esos 3.8 ms, por ejemplo el periodo podría ser 7ms.

Jugando con los parámetros del temporizador 3, con un escalamiento de 8, es decir con 6 Mhz, y con PR3 igual a 42000, conseguiría 7ms.

(42000/6MHz = 7 ms)

(https://pbs.twimg.com/media/F6VNXx-X0AEAqPA?format=png&name=900x900)

Ahora bien, si deseamos un periodo de 318.88 us, PR3 = f* T = 6MHz * 318.88 us = 1913.26, el cual es un valor que el PR3 puede poseer.

La ecuación para calcular el periodo de la señal PWM es:

(https://pbs.twimg.com/media/F6VPfBHXYAEj5ns?format=png&name=900x900)

Donde TPB es el periodo de la frecuencia del reloj del bus de periféricos, es decir 1/48MHz.

TMR Prescaler Value, es el valor del pre escalamiento que es 8, es decir que TPB * TMR Prescaler Value = 1/6MHz.

Con esto hice una tabla en Excel para conseguir los valores de PR2 para cada frecuencia auditiva:

(https://pbs.twimg.com/media/F6VTtUUWgAEwv8v?format=png&name=900x900)

Y lo pego en el archivo cabecera de la tarea appbuzzer: (obviamente sin decimales)

(https://pbs.twimg.com/media/F6VbVSeXAAA9bYI?format=png&name=900x900)

Una canción esta definida como una serie de notas musicales, y cada nota tiene un tiempo de duración.

Por lo que creo una estructura de datos de la siguiente manera:

Código: C
  1. typedef struct
  2. {
  3.     unsigned int FrecuenciaNota;
  4.     unsigned int Tiempo;
  5. }NotasMusicales;

Donde FrecuenciaNota es el valor del PR del temporizador, y Tiempo es la duración de la nota musical, por lo tanto creo un arreglo con 12 notas musicales así:

Código: C
  1. NotasMusicales      Musica[0x0C];

Esto lo creo en el archivo en C de la tarea del buzzer.

(https://pbs.twimg.com/media/F6VZATnWsAAHvIm?format=png&name=900x900)

En el estado inicial de la tarea, lo que hago, es inicializar el arreglo 'musica' con los valores de PR3 y retardos para generar la música inicial

(https://pbs.twimg.com/media/F6VbupbWMAAJcRr?format=png&name=small)

Recuerde que 1 ms está dado por:

Código: C
  1. #define _1ms 0x5DC0

También, en el estado inicial de la tarea (que la renombré) deshabilito todo lo relacionado con la configuración del PWM, de lo contrario, es psoible que el buzzer haga sonidos antes de empezar a ejecutarse la tarea, e inicio o arranco al temporizador 3:

(https://pbs.twimg.com/media/F6VdxIJW8AElk-5?format=png&name=900x900)

Necesito un puntero, para ir obteneindo cada valor del arreglo denominado Musica, el cual será parte de la esctructura de datos de la tarea:

(https://pbs.twimg.com/media/F6VewvSXEAEhtWs?format=png&name=360x360)

Y lo inicializo en la el código en C de la tarea:

(https://pbs.twimg.com/media/F6VfUGFWkAEIyZy?format=png&name=900x900)

También, necesito una variable para generar retardos asincrónicos, y la escribo en la estructura de datos:

(https://pbs.twimg.com/media/F6VrpvRWwAAT760?format=webp&name=small)

Para cambiar el valor del PR3, creo una función así:

Código: C
  1. void actualizarFrecuenciaPWM(unsigned int frecuencia)
  2. {
  3.     TMR3_PeriodSet(frecuencia); //es similar a PR3 = frecuencia;
  4.     OCMP1_CompareSecondaryValueSet(frecuencia >> 1); // ancho de pulso en 50%
  5. }

Donde también intento que la relación de trabajo del PWM sea del % al escribir en el registro OC1RS, la mitad del valor de PR3.

En la inicialización de la tarea, capturo un valor del temporizador central o Core Timer, y genero la primera nota con el PWM mediante la función  actualizarFrecuenciaPWM

(https://pbs.twimg.com/media/F6Vs00cW8AAQnTX?format=png&name=medium)

En el estado inicial, espero el tiempo que dura cada nota mediante un retardo asincrónico así:

(https://pbs.twimg.com/media/F6Vt_u2XoAAgZ9K?format=jpg&name=medium)

Cuando el retardo ha finalizado, se hace lo siguiente:

Se captura un nuevo valor de temporizador central para el próximo retardo.

Incremento en 1, el puntero del arreglo denominado Musica.

Si el puntero está aún dentro del tamaño del arreglo musica, verifico que la siguiente sea mute o silencio, si es así, apago el PWM para generar un silencio.

Si no es mute actualizo el valor del PR3 con el valor de la siguiente nota.

Si el puntero es mayor que el tamaño del arreglo, la melodía ha finalizado , apago el PWM y salto a un estado denominado reposo, donde esperará la tarea hasta cuando se desee generar una señal acústica.

Esa señal acústica, será generada en un nuevo estado, pero eso será más adelante, por ahora sólo deseo crear esta parte del código.

Mañana, voy a probar con el hardware si este código funciona.

(https://pbs.twimg.com/media/F6VzQ28WgAA2cRf?format=png&name=medium)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 19 de Septiembre de 2023, 02:18:44
Jeje, lo que hace el aburrimiento mientras te llegan los componentes.
Por cierto, ¿por qué ocultas las notas de la canción?
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 19 de Septiembre de 2023, 10:07:41
Por cierto, ¿por qué ocultas las notas de la canción?

Por copyright   :)

En realidad es el principio de una canción de una película muy famosa, similar a esta otra:



 Alguna vez quise convertir cualquier música a tonos con su frecuencia y duración, pero nunca supe como hacerlo.

En internet encuentras muchas melodías de canciones famosas para ser generadas con un PWM.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 19 de Septiembre de 2023, 11:20:02
Descargue el nuevo código al hardware y este es el resultado:


Se puede apreciar que hay un tono no deseado antes de empezar la melodía.

Estaba asumiendo que se ejecuta algo de código antes de inicializar la tarea donde deshabilito el PWM, intenté varias cosas, por ejemplo poner en 1, el valor a comparar para que el ancho de pulso inicial sea pequeño, para que no genere ese ruido, así:

(https://pbs.twimg.com/media/F6ZNqNZWQAA63Fa?format=png&name=medium)

También intenté con un valor igual a cero, pero el resultado era el mismo.

Busqué donde se inicializa o activa el PWM, pensado que el código generado lo activaba antes de hora, pero no es así. Donde se activa el PWM es en donde yo escribí OCMP1_Enable

(https://pbs.twimg.com/media/F6ZOJXYXgAA-O3X?format=png&name=360x360)

Así que se me ocurrió escribir una nota de silencio, en el código inicial, esto implica que el arreglo Musica, es ahora de 13 elementos:

(https://pbs.twimg.com/media/F6ZPL-BXwAACETz?format=png&name=large)

Al hacer esto, la melodía sonó como debe ser.


Lo que sospecho es que la(s) función(es) que inicializan la(s) tarea(s) toman algo de tiempo, es decir, la primera vez si estaba colocando el primer tono correcto, pero hasta configurar todas las tareas y procesos, toma su tiempo, generando un sonido no deseado.

Agregando un silencio inicial, se evita el problema.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 21 de Septiembre de 2023, 13:06:09
Estoy pensando en el diseño para calcular el valor RMS.

La primera idea básica conceptual, es que mediante la señal cuadrada que se generaría sincronizada con la red de 60Hz, sería útil para empezar y detener la adquisición de datos o muestras del ADC.

El inicio y detención, sería por el flanco de subida o positivo de dicha señal, así:

(https://pbs.twimg.com/media/F6j0fO4WQAAcjYk?format=jpg&name=large)


El problema es que no se cuantos ciclos de máquina tome el cálculo del valor RMS (se podría medir), como se puede apreciar en la imagen de arriba, finalizada la adquisición de datos, el CPU se concentraría en realizar ese cálculo.

No creo que tome mucho tiempo, pero sin embargo, tendría que esperar el otro ciclo de la señal senoidal para realizar una nueva adquisición de datos, tampoco pienso que afecte la precisión del cálculo, pero no me gusta la idea que pierda tiempo realizando ese proceso.

La segunda opción es que siempre este adquiriendo los datos del ADC.

Esto implicaría usar dos buffers o arreglos para almacenar la información.

En el primer ciclo, guardaría en el primer arreglo, luego la tarea que calcula el RMS, realizaría sus cálculos con ese array, pero en ese mismo ciclo, la información del ADC, se guardaría en el segundo array.

Luego al finalizar el segundo ciclo, el RMS se calculara con el segundo arreglo, y en el primero se almacenaría la información, algo así como esta imagen:

(https://pbs.twimg.com/media/F6j3kcUX0AE5k8X?format=jpg&name=large)


Hasta qui parece que funcionaría la idea de que siempre se esta adquiriendo información de la señal sinusoidal, sin embargo, es posible que las operaciones de cálculo del RMS, sean instrucciones atómicas, es decir no se pueden dividir en más subfunciones, y ejecutarlas toman algo de tiempo de tal manera, que por ejemplo si se está esperando el tiempo de adquisición de datos, ese tiempo sea más grande, debido a que no termina de ejecutarse alguna parte del cálculo RMS.

El tiempo de adquisición es de 1 us, el tiempo de conversión es aproximadamente de 14 us, y entre cada muestra, debe esperarse 100 us:

(https://pbs.twimg.com/media/F6j5bybXMAAJGiV?format=png&name=large)

Anteriormente, propuse la utilización de modo polled es decir que espero a que una bandera finalice, para conocer si la conversión ADC está lista. Pero como menciono, el CPU podría estar ejecutando un proceso de cálculo RMS, y hasta que finalice y regrese a verificar esa bandera del ADC, el tiempo será mayor, y posiblemente, genere algún error de precisión.

También, yo ocupo retardos asincrónicos, los cuales no son precisos, y se ocupan en tareas no tan críticas, por ejemplo, en los displays, cada uno muestra información a una tasa de 1000 us  (1ms), pero si por algún momento fuera 1015 us, por decir algo, el usuario no va a notar eso.

Así que me veo obligado a usar interrupciones, tanto, para la finalización del la conversión del ADC y para la generación de 100 us.

De esa manera, pienso que se mejoraría la latencia producida del proceso de cálculo RMS



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 21 de Septiembre de 2023, 14:17:31
¿Pero necesitas estar calculando en tiempo real?.
Yo en mi Dimmer con medición de consumo tomo 10 ondas completas y luego hago todos los cálculos y espero al siguiente cruce por cero para arrancar el proceso de nuevo.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 21 de Septiembre de 2023, 14:21:42
¿Pero necesitas estar calculando en tiempo real?.
Yo en mi Dimmer con medición de consumo tomo 10 ondas completas y luego hago todos los cálculos y espero al siguiente cruce por cero para arrancar el proceso de nuevo.

Claro, podría ser como dices, pero creo que no sería lo que se denomina "True RMS", y si se puede y no es complicado, hay que intentarlo.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 23 de Septiembre de 2023, 13:52:21
Estos son los ejemplos que voy a tomar de referencia.

1. Interrupción del conversor ADC

El ejemplo se denomina adc_interrupt_pic32mx470_curiosity

Y el ejemplo es el siguiente:

Código: C
  1. void ADC_ResultHandler(uintptr_t context)
  2. {
  3.     /* Read the ADC result */
  4.     adc_count = ADC_ResultGet(ADC_RESULT_BUFFER_0);
  5.     result_ready = true;
  6. }
  7.  
  8.  
  9. int main ( void )
  10. {
  11.     /* Initialize all modules */
  12.     SYS_Initialize ( NULL );
  13.     ADC_CallbackRegister(ADC_ResultHandler, (uintptr_t)NULL);
  14.  
  15.     printf("\n\r---------------------------------------------------------");
  16.     printf("\n\r                    ADC Demo                 ");
  17.     printf("\n\r---------------------------------------------------------\n\r");
  18.  
  19.     /* Start ADC conversion */
  20.     ADC_ConversionStart();
  21.  
  22.  
  23.     while (1)
  24.     {
  25.         /* Maintain state machines of all polled MPLAB Harmony modules. */
  26.         SYS_Tasks ( );
  27.  
  28.         /* Auto sampling mode is used, so no code is needed to start sampling */
  29.  
  30.         /* Wait till ADC conversion result is available */
  31.         if(result_ready == true)
  32.         {
  33.             result_ready = false;
  34.             input_voltage = (float)adc_count * ADC_VREF / ADC_MAX_COUNT;
  35.             printf("ADC Count = 0x%03x, ADC Input Voltage = %d.%02d V \r", adc_count, (int)input_voltage, (int)((input_voltage - (int)input_voltage)*100.0));
  36.  
  37.             /* Start ADC conversion */
  38.             ADC_ConversionStart();
  39.         }
  40.     }
  41.  
  42.     /* Execution should not come here during normal operation */
  43.  
  44.     return ( EXIT_FAILURE );
  45. }

Se puede observar que en la línea 13, se asigna o registra con la función ADC_CallbackRegister, la función que manejará la interrupción al finalizar la conversión del ADC.

Esta función se denomina ADC_ResultHandler y está en la línea 1, donde obtiene el valor de la conversión y la guarda en la variable adc_count

La configuración de dicho periférico, con la zona gráfica del MCC es como se muestra:

(https://pbs.twimg.com/media/F6uQJTSWoAAk-qI?format=png&name=large)

2. Interrupción por un temporizador

El ejemplo que voy a tomar de referencia, se llama tmr_timer_mode_pic32mx_12_sk

Código: C
  1. /* This function is called after period matches in Timer 3 (32-bit timer) */
  2. void TIMER2_InterruptSvcRoutine(uint32_t status, uintptr_t context)
  3. {
  4.     /* Toggle LED */
  5.     LED1_Toggle();
  6. }
  7. // *****************************************************************************
  8. // *****************************************************************************
  9. // Section: Main Entry Point
  10. // *****************************************************************************
  11. // *****************************************************************************
  12.  
  13. int main ( void )
  14. {
  15.     /* Initialize all modules */
  16.     SYS_Initialize ( NULL );
  17.    
  18.     TMR2_CallbackRegister(TIMER2_InterruptSvcRoutine, (uintptr_t) NULL);
  19.     TMR2_Start();
  20.  
  21.     while ( true )
  22.     {
  23.         /* Maintain state machines of all polled MPLAB Harmony modules. */
  24.         SYS_Tasks ( );
  25.     }
  26.  
  27.     /* Execution should not come here during normal operation */
  28.  
  29.     return ( EXIT_FAILURE );
  30. }

La función que registra a aquella que se llama cuando la interrupción se produce se denomina TMR2_CallbackRegister y está en la línea 18.

Y la función  TIMER2_InterruptSvcRoutine, lo único que hace es conmutar el estado lógico de un led.

Este ejemplo usa al temporizador 2, en modo de 32 bits, esto implica que el temporizador 3, trabaja en conjunto para conseguir ese ancho en bits.

(https://pbs.twimg.com/media/F6uTFG7XsAAGTGU?format=png&name=900x900)

En el módulo del TMR2, está configurado a 32 bits, y se indica que la habilitación de la interrupción, debe hacerse en el temporizador secundario o esclavo, en este caso es el TMR3, y su configuración es:

(https://pbs.twimg.com/media/F6uTwTRXsAALP56?format=png&name=medium)

En mi caso, pienso usar el temporizador 4, pero no creo que sea necesario trabajar a 32 bits (TMR5) para alcanzar los 100 us.

3. Interrupción por flanco positivo

Aquí viene lo interesante.

Estaba pensando, para detectar el flanco positivo de la onda cuadrada, solamente esperar su transición, de 0 a 1 lógico, pero esto de esperar en una tarea de estados de máquina (que también es un proceso asincrónico), implica que su precisión puede alterarse, debido a los cálculos del RMS anteriormente mencionados.

Busqué ejemplos de Harmony, con respecto a esto, y hay varios ejemplos los cuales corresponden a un ejemplo común denominado GPIO interrupt

Pensé que se utilizaba la interrupción externa, pero, lo que en realidad, se utiliza es el cambio de estado de un terminal o un pin.

No logro encontrar un ejemplo que explícitamente posea módulos, como los anteriores periféricos, donde pueda configurar las características de la interrupción externa.

Abrí un hilo en el foro de MCHP:

https://forum.microchip.com/s/topic/a5C3l000000Br5vEAC/t392257 (https://forum.microchip.com/s/topic/a5C3l000000Br5vEAC/t392257)

Y también estoy esperando al soporte técnico:

El peor de los casos, sería escribir mi propia configuración, como se hacía en los viejos tiempos.


 




Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 24 de Septiembre de 2023, 12:50:16
Hola.

Hasta esperar una respuesta del foro (o más seguro, del soporte técnico) de MCHP, voy a intentar lo siguiente.

El terminal que va ser utilizado para el módulo de captura para medir la frecuencia de la señal AC, también dispone de una interrupción externa:

(https://pbs.twimg.com/media/F6zSRRFWoAA0Ox0?format=png&name=small)

En teoría, sólo se podría usar una de las dos opciones, pero mediante el modulo System, podría habiliar a esa interrupción:

(https://pbs.twimg.com/media/F6zSxJaWIAA6Cow?format=png&name=small)

Luego, creo un nuevo grupo, denominado adquisición:

(https://pbs.twimg.com/media/F6zTIQDW8AEW8zQ?format=png&name=small)

Dentro de este nuevo grupo, agrego el módulo ADC, el cual tiene las siguientes configuraciones.

- La interrupción está habilitada
- La fuente de reloj es del bus de periféricos de 48 MHz.
- El divisor de reloj es 23, para conseguir 1000 ns (1 us) de tiempo de adquisición, como al inicio mencioné.
- La referencia de voltaje es VREF+ y AVSS (GND) donde VERF + será 3.0V
- El canal 0 del ADC, se conectará a la entrada analógica AN1.
- El resultado de lo conversión será un número de 32 bits de tipo entero

(https://pbs.twimg.com/media/F6zTXZLXgAANRCM?format=png&name=medium)

También agrego el temporizador 4, en modo de 16 bits para generar 100 us:

(https://pbs.twimg.com/media/F6zUilKXIAAKRqj?format=png&name=900x900)

Con el módulo Core, creo una nueva tarea denominada appSampling, que será la encargada de inicializar la habilitación de la interrupción externa, y esta a su vez, habilitará las interrupciones del ADC y del TMR4 al mismo tiempo:

(https://pbs.twimg.com/media/F6zUyWHXUAAxsYy?format=png&name=medium)

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 24 de Septiembre de 2023, 14:15:36
Estaba buscando información sobre la interrupción externa con Harmony 3, y encontré este hilo en el foro de MCHP:

https://forum.microchip.com/s/topic/a5C3l000000BqqMEAS/t391969 (https://forum.microchip.com/s/topic/a5C3l000000BqqMEAS/t391969)

En base a eso y buscando más información de la función EVIC_ExternalInterruptCallbackRegister:

https://onlinedocs.microchip.com/oxy/GUID-450989FA-38E4-4D68-AB61-15ADB29AD718-en-US-2/GUID-FF33409B-66B4-4FEA-B3BE-8085BC5ACA81_6.html (https://onlinedocs.microchip.com/oxy/GUID-450989FA-38E4-4D68-AB61-15ADB29AD718-en-US-2/GUID-FF33409B-66B4-4FEA-B3BE-8085BC5ACA81_6.html)

El estado de la tarea appSampling sería así:

Código: C
  1. void APPSAMPLING_Tasks ( void )
  2. {
  3.     /* Check the application's current state. */
  4.     switch ( appsamplingData.state )
  5.     {
  6.         /* Application's initial state. */
  7.         case APPSAMPLING_ESTADO_INICIAL:
  8.         {
  9.             ICAP1_Disable(); //Deshabilito el módulo de captura
  10.             TMR4_CallbackRegister(ManejarInterrupcionTMR4, (uintptr_t) NULL);// registro función de interrupción por TMR4
  11.             ADC_CallbackRegister(ManejarInterrupcionADC, (uintptr_t)NULL); // registro función de interrupción por ADC
  12.             EVIC_ExternalInterruptCallbackRegister(EXTERNAL_INT_2, &ManejarInterrupcionExterna, (uintptr_t)NULL); //Registro la función que se llama por la interrupción externa
  13.             appsamplingData.state = APPSAMPLING_ESTADO_REPOSO;
  14.             break;
  15.         }
  16.  
  17.         case APPSAMPLING_ESTADO_REPOSO: break;
  18.         /* TODO: implement your application state machine.*/
  19.         /* The default state should never be executed. */
  20.         default: break; /* TODO: Handle error in application's state machine. */
  21.     }
  22. }

Donde en el estado inicial se hace lo siguiente:

1. Deshabilitar el módulo de captura, por el momento, aun no voy a medir la frecuencia de la seña AC.
2. Registrar la función que se invoca cuando la interrupción del TMR4 sucede (100 us)
3. Registrar la función que se invoca cuando la interrupción del ADC sucede.
4. Registrar la función que se invoca cuando la interrupción externa 2 sucede.
5. Ir a un estado de reposo, ya que todos esos tres procesos funcionan en base a interrupciones y no tiene sentido crear más estados de máquina.



Las funciones mencionadas quedarían así:

Código: C
  1. / *****************************************************************************
  2. // *****************************************************************************
  3. // Section: Application Local Functions
  4. // *****************************************************************************
  5. // *****************************************************************************
  6. void ManejarInterrupcionTMR4(uint32_t status, uintptr_t context);
  7. void ManejarInterrupcionADC(uintptr_t context);
  8. void ManejarInterrupcionExterna (EXTERNAL_INT_PIN pin, uintptr_t context);
  9.  
  10. /* TODO:  Add any necessary local functions.
  11. */
  12.  
  13. void ManejarInterrupcionTMR4(uint32_t status, uintptr_t context)
  14. {
  15.  
  16. }
  17. void ManejarInterrupcionADC(uintptr_t context)
  18. {
  19.     //adc_count = ADC_ResultGet(ADC_RESULT_BUFFER_0);
  20. }
  21. void ManejarInterrupcionExterna (EXTERNAL_INT_PIN pin, uintptr_t context)
  22. {
  23.    
  24. }

Estaba pensando que si este voltímetro, no se alimentara con voltaje AC, digamos uno 100 V DC, no aparecería una señal cuadrada, y por lo tanto el proceso para capturar datos con el ADC no funcionaría.

Tenía la idea que, debería existir un retardo asincrónico en el estado de reposo de la tarea appSampling, de tal manera que si sobrepasaba cierto límite, y no ocurría la interrupción externa, debía emitirse una alarma y informar algo en el display de que no se detecta una señal de AC.

Pero luego, pensado, que si se realiza el cálculo RMS de una señal de DC, sería exactamente su valor medio o DC, y serviría también como voltímetro DC.

Entonces, lo que pienso ahora, es que si el temporizador asincrónico sobre pasa cierto límite, en lugar de informar el error, debería iniciar la conversión (similar  a lo que haría la interrupción externa) y de esa manera obtendría el valor DC de la señal.

Es una idea que luego podría implementar.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 25 de Septiembre de 2023, 11:08:45

Recordé que el ADC, es de 10 bits, entonces no tiene sentido que el formato del resultado sea de 32 bits, así que lo modifiqué a 16 bits:

(https://pbs.twimg.com/media/F64BIsmXkAAC0X_?format=png&name=900x900)

También me faltaba habilitar la interrupción externa 2, para lo cual modifiqué el estado inicial como se indica en la siguiente figura:

(https://pbs.twimg.com/media/F64A8L0XYAEVBVy?format=jpg&name=medium)

Para almacenar las muestras, cree una estructura de datos así:

Código: C
  1. typedef struct
  2. {
  3.     unsigned short  bufferADC[256]; // almacena cada muestra adquirida por el ADC
  4.     unsigned char   muestra;        // apunta a cada uno de los elementos de bufferADC
  5. }EstructuraADC;

Donde bufferADC, va a almacenar cada muestra del ADC.

La razón que escogí un tamaño de 256 bytes, es debido a que si va tomar una muestra cada 100 us, y el periodo de la señal es de 16.667 ms (60 Hz), entonces 16.667 ms / 100 us = 166.67 muestras.

Obviamente la frecuencia no va ser contante, pero no creo que sobrepase o disminuya en gran medida, así que creo que 256 bytes es suficiente.

Mientras que muestra es el puntero a cada elemento del arreglo, también sería el periodo discreto para el cálculo del RMS.

Con esta estructura, creo un arreglo de dos elementos, en la estructura de datos de la tarea así:

Código: C
  1. typedef struct
  2. {
  3.     /* The application's current state */
  4.     APPSAMPLING_STATES state;
  5.     /* TODO: Define any additional data used by the application. */
  6.     EstructuraADC   estructuraADC[0x02];
  7.     unsigned char   punteroABuffer; // De 0 a 1
  8. } APPSAMPLING_DATA;

Mediante punteroABuffer, escojo el primer o segundo buffer.

En el estado inicial de la tarea, las variables muestras las inicializo en cero. pero la variable punteroABuffer, la pongo en 1, ya que cuando suceda la interrupción externa, apuntará al siguiente buffer, que será el 0, y de esa manera se inicializa correctamente:

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 (Primer buffer)
  9.     appsamplingData.estructuraADC[0x00].muestra = 0x00; // Muestra de buffer 0 inicializado
  10.     appsamplingData.estructuraADC[0x01].muestra = 0x00; // Muestra de buffer 1 inicializado
  11. }

Cuando ocurre la interrupción externa, se debe inicializar la adquisición de datos del ADC e iniciar el funcionamiento del temporizador.

Esta interrupción, me sirve para conmutar al buffer de almacenamiento de datos, así que la variable punteroABuffer, es incrementada (o inicializada en cero si es mayor que uno) :

(https://pbs.twimg.com/media/F64FOFBWQAAYSWr?format=jpg&name=medium)

Cuando sucede la interrupción del ADC, se debe tomar la muestra, y guardarla en el buffer correspondiente, e incrementar la variable muestra:

(https://pbs.twimg.com/media/F64FyppXcAAKqW7?format=png&name=large)

Y cuando sucede, la interrupción del temporizador (100 us), se debe realizar una nueva adquisición conversión del ADC:

(https://pbs.twimg.com/media/F64GTKLWoAAaf-e?format=png&name=large)

Hasta aquí, en teoría se estaría siempre muestreando la señal sinusoidal, cada ciclo se almacenaría en dos buffers independientes. Debería probar su funcionamiento, es posible que haya un error que no note u algún otro problema.

Suponiendo que funciona, el siguiente paso, es que la tarea dedicada a calcular el RMS, lo haga con el buffer diferente al que se está usando para almacenar datos.




Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 26 de Septiembre de 2023, 18:52:29
Estaba analizando en mi mente esto de las tres interrupciones, y creo que si puede existir un problema.

Hice unos diagramas en un cuaderno, ya que no tengo mucho tiempo para hacerlas en un software, me resulta más rápido.

Para entender el proceso, tenemos lo siguiente:

(https://pbs.twimg.com/media/F6-3jcmXQAAluH8?format=jpg&name=large)

La interrupción 2 (Detección de flanco positivo) es quien desencadena todo, es decir, activa al temporizador 4 y al conversor ADC. De ahí en adelante solo estas dos interrupciones, funcionan de manera sincrónica.

El ADC termina la adquisición y conversión, genera una interrupción para guardar la muestra, y mucho más luego, la interrupción del TMR4, inicia de nuevo el funcionamiento del ADC, repitiéndose este proceso varias veces.

El problema, es cuando sucede de nuevo la interrupción externa INT2, la cual no está en sincronía con las otras dos

Tenemos dos casos.

El primero, cuando la interrupción externa ocurre luego de haber finalizado una adquisición conversión del ADC y antes de los 100 us.

(https://pbs.twimg.com/media/F6-5WYrWcAEpbfG?format=jpg&name=large)

Este caso no es muy problemático, lo que si debe hacerse, es detener y reiniciar el temporizador 4 e iniciar otro proceso del ADC.

El segundo caso, es cuando la interrupción externa, ocurre antes que el proceso del ADC haya finalizado:

(https://pbs.twimg.com/media/F6-6SuRW0AAk2jJ?format=jpg&name=large)

En este caso, también debe detenerse y reiniciar el temporizador, pero no debe arrancar o funcionar, hasta que finalice el proceso del ADC.

Tan pronto como el ADC finalice su proceso, se debe iniciar nuevamente una adquisicón y conversión ADC y arrancar nuevamente el TMR4.

En estos días, voy a pensar como implementar este proceso.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 28 de Septiembre de 2023, 22:59:02
Hoy día tengo un poco más de tiempo para continuar.

Respecto a que la interrupción externa INT2, debe reiniciar al temporizador TMR4, creo que puedo hacer esto:

Código: C
  1. void ManejarInterrupcionExterna (EXTERNAL_INT_PIN pin, uintptr_t context)
  2. {
  3.     TMR4_Stop();                        // Detengo a TMR4:
  4.     TMR4 = 0x0000;                      // Limpio/reinicio el conteo  
  5.     ADC_ConversionStart();              // inicia la conversión
  6.     TMR4_Start();                       // inicia a funcionar el temporizador 4
  7.     /** Cambio de buffer **/
  8.     appsamplingData.punteroABuffer++;   // apunto al siguiente Buffer
  9.     if (appsamplingData.punteroABuffer > 0x01)
  10.     {
  11.         appsamplingData.punteroABuffer = 0x00;
  12.     }
  13.     appsamplingData.estructuraADC[appsamplingData.punteroABuffer].muestra = 0x00; //limpio puntero (muestra) del buffer
  14. }

En cuanto al evento de la interrupción externa sucede cuando aun el ADC está adquiriendo/convirtiendo, aun no sé, es como determinar si el ADC está en cualquiera de esos estados.

El bit SAMP del registro AD1CON1, cuando está cero puede significar dos cosas, no está adquiriendo datos, o el ADC está en modo conversión.

Mientras que en el mismo registro, el bit DONE, sólo se pone a uno para informar que la conversión ADC a finalizado.

Podría recurrir a una bandera para conocer que el ADC está en cualquiera de los dos modos, algo así:

Código: C
  1. TMR4_Stop();                        // Detengo a TMR4:
  2.     TMR4 = 0x0000;                      // Limpio/reinicio el conteo  
  3.     ADC_ConversionStart();              // inicia la conversión
  4.     bandera = true;                     // ADC inicia proceso
  5.     TMR4_Start();                       // inicia a funcionar el temporizador 4

Código: C
  1. void ManejarInterrupcionADC(uintptr_t context)
  2. {
  3.    bandera = false; // ADC finaliza proceso
  4.  
  5. appsamplingData.estructuraADC[appsamplingData.punteroABuffer].bufferADC[appsamplingData.estructuraADC[appsamplingData.punteroABuffer].muestra] = ADC_ResultGet(ADC_RESULT_BUFFER_0);
  6.     appsamplingData.estructuraADC[appsamplingData.punteroABuffer].muestra++;
  7. }


Si no encuentro alguna otra opción, deberé hacerlo de esa manera.

Otra duda que tengo, es que el ejemplo que estoy tomando como referencia, tiene el muestreado en modo automático.

Según las hoja de datos, en ese modo, cuando finaliza una conversión, de manera automática, entra en modo de muestreo:

(https://pbs.twimg.com/media/F7J-Fp3XQAAhXQj?format=jpg&name=medium)

Pero en mi caso yo debo esperar hasta que el temporizador produzca una interrupción, entonces, lo que entiendo, es que cuando hayan pasado los 100 us, y ejecute la línea ADC_ConversionStart, lo que voy a obtener es la muestra de 100 us atrás, no la de ese momento. Obviamente en una señal de muy baja frecuencia, o DC, no tendría mucha importancia.

O tal vez no sea tan crítico, que mi señal muestreada, sea de hace 100 us en el pasado.

Tal vez deba utilizar el modo manual de activar el muestreado, y también creo que debería manualmente, activar la conversión.

Otra duda que tenía, era con el nivel de prioridad de las interrupciones, y que sucede cuando dos ocurren al mismo tiempo.

La interrupción externa es la que tiene la prioridad más alta, 7, las otras dos tienen prioridad de 1.

Pienso que la interrupción del ADC, debe ser la de más alta que INT2, y la del TMR4, debe ser la más baja.

ADC > INT2 > TMR4.

Hay dos escenarios

1. Sucede la interrupción externa y la del TMR4 al mismo tiempo

En este caso, la interrupción de INT2, bloquea a la interrupción del TMR4, y INT2, lo que hace es inicializar al temporizador, conmuta de buffer y arranca al ADC, luego la interrupción del temporizador no tendría que ser, ya que el ADC ya está funcionando, la bandera antes mencionada sería útil para tal caso.

2.  Sucede la interrupción externa y la del ADC al mismo tiempo

La muestra ADC se guarda en el buffer actual y cuando se reanuda la interrupción externa, se reinicia al temporizador y se cambia de buffer.



La interrupción del TMR4 y del ADC al mismo tiempo, no es posible, ya que el temporizador, es quien inicializa al ADC, y su interrupción sucede luego.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 29 de Septiembre de 2023, 11:14:41
Estaba leyendo el manual del conversor ADC, y creo, si no comprendí mal que el proceso donde la adquisición es automática, sería como se muestra en esta imagen:

(https://pbs.twimg.com/media/F7MteCtWgAA8OkR?format=png&name=4096x4096)

Cuando enciendo el ADC, la adquisición funciona casi inmediatamente.

Luego transcurre un tiempo indeterminado hasta que se configuren otros periféricos, se inicien las tareas y procesos.

Sucede la interrupción externa INT2, y con  ADC_ConversionStart();  se inicia la conversión, y la muestra obtenida, es aquella que se tomó poco después de encender el ADC, y se podría decir que no es tan útil.

También la adquisición se inicia automáticamente.

Cuando sucede la interrupción del TMR4, nuevamente se ejecuta el ADC_ConversionStart(), pero la muestra obtenida es aquella que se muestreo anteriormente.

En pocas, la información contenida en cada buffer, tendría un retrazo de 100 us, pero no creo que sea algo crítico dicho  "atraso".


Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 21 de Noviembre de 2023, 18:57:25
Al fin llegó el OP con el tamaño correcto y lo he colocado en el PCB.

(https://pbs.twimg.com/media/F_fVCMkXwAAP-fQ?format=jpg&name=large)

En los siguientes días voy a continuar con el proyecto.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 22 de Noviembre de 2023, 13:59:46
He conectado a la red AC de la empresa eléctrica y está es la forma de onda a la entrada del ADC.

(https://pbs.twimg.com/media/F_jU7JzWAAAySGr?format=jpg&name=medium)


El voltaje de la red eléctrica es de aproximadamente 125 VAC, es decir que el voltaje pico es +- 176.78V.

El acondicionamiento de la señal se basa en la ecuación:

Vout = Vin/200 +1.5V, por lo tanto el Voltaje máximo sería:

Vout max = 176.78/200 +1.5 = 2.38V

Y el voltaje mínimo sería:

Vout min = -176.78/200 + 1.5 = 0.6161.

Según la imagen de arriba, el voltaje pico es 2.36V y el mínimo aproximadamente 0.6, así que parece que el acondicionamiento funciona correctamente.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 22 de Noviembre de 2023, 14:13:35
Muy bien, DominusDRR, muy interesante.

Veo en la onda cierta distorsión justo después de cada cresta. ¿Es así o será cosa de la foto?
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 22 de Noviembre de 2023, 14:20:38
Muy bien, DominusDRR, muy interesante.

Veo en la onda cierta distorsión justo después de cada cresta. ¿Es así o será cosa de la foto?

La misma red eléctrica no es de buena calidad, me parece que el parámetro de calidad se denomina THD o TDH, no recuerdo, me imagino que es bajo.

(https://pbs.twimg.com/media/FwLvD1fXwAIzqzU?format=jpg&name=large)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 22 de Noviembre de 2023, 14:22:29
Pues si esa es la onda de la red eléctrica realmente es mala
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 24 de Noviembre de 2023, 10:59:46
Hola.

Me olvidé comentar que la respuesta del soporte de MCHP sobre el funcionamiento del ADC es como se describe.

Durante el tiempo de conversión, que dura por lo menos 132 ns, el condensador se va cargando hasta alcanzar el voltaje de la señal de entrada.

(https://pbs.twimg.com/media/F_tBOzVWcAA9Ujo?format=png&name=medium)

Luego el capacitor sigue el voltaje durante los 100 us.

Cuando inicia la conversión, el capacitor se desconecta de la señal de entrada y empieza la conversión del valor que tenga en ese instante.

El capacitor se descarga para nuevamente alcanzar en 132 ns al voltaje de la señal analizada, el siguiente gráfico demuestra lo que ocurre.

(https://pbs.twimg.com/media/F_tCPj7XoAAaRqV?format=png&name=large)

Conecte como voltaje de entrada AC, la salida de un transformador reductor de 120VAC a 24VAC y también iba a usa una fuente externa de 9VDC, para energizar al microcontrolador, y de esa manera depurar el código, pero para mi sorpresa, con 24VAC, la fuente transformerless que tiene el PCB funciona correctamente.

Coloqué un punto de ruptura cuando se produzca el segundo flanco de subida en la interrupción externa. Mi idea es ver cuantas muestras adquirió en un periodo de la señal:

(https://pbs.twimg.com/media/F_tDd99XQAAqpEX?format=png&name=large)

Y se puede apreciar que el un periodo de la señal AC, existen 200 muestras.

Si el periodo de la señal AC es de 1/60 ó 16.667 ms y estoy tomando una muestra cada 100 us, por lo tanto el número de muestras sería:

16.667ms / 100us = 166.667, que está cerca al valor de 200, parecería que está bien, por ahora.

El siguiente paso es calcular el RMS con las muestras adquiridas.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Picuino en 24 de Noviembre de 2023, 14:51:39
Para conseguir un valor más exacto deberías calcular el valor RMS de un número par de periodos exactos.
Por ejemplo comenzando la primera conversión con el cruce por cero y terminando la última conversión lo más cerca del siguiente cruce por cero que sea par.

Puedes simular en una hoja excel o con un programa el resultado de hacer los cálculos con una onda sinusoidal perfecta.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Picuino en 24 de Noviembre de 2023, 15:18:20
Adjunto hoja excel de ejemplo con cálculo de RMS en 4 semiciclos y un error del 0.1% en los cálculos debido al error de muestreo, que no está sincronizado perfectamente con la frecuencia de la onda sinusoidal.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Picuino en 24 de Noviembre de 2023, 15:29:53
Lo de medir un número par de semiciclos es importante, porque la onda no suele ser simétrica. En una ocasión estuve midiendo la frecuencia de red para observar las desviaciones y era imperativo tomar un número par de semiciclos para que la medida no tuviese error.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 24 de Noviembre de 2023, 16:10:10
Para conseguir un valor más exacto deberías calcular el valor RMS de un número par de periodos exactos.
Por ejemplo comenzando la primera conversión con el cruce por cero y terminando la última conversión lo más cerca del siguiente cruce por cero que sea par.

Hola, si esa es la idea, anteriormente expliqué como se va hacer. Tengo dos buffers o arreglos, en un periodo dado, el buffer 1 se utiliza para almacenar la información, mientras que el otro es utilizado por la tarea RMS para realizar el cálculo.

Luego en el siguiente periodo, se intercambian los buffers, es decir el número 2 se utiliza para almacenar las muestras y el 1 para calcular el RMS.

Puedes simular en una hoja excel o con un programa el resultado de hacer los cálculos con una onda sinusoidal perfecta.

eh... si, gracias, puedes ver en anteriores publicaciones que hice eso.

Aqui:

http://www.todopic.com.ar/foros/index.php?topic=51537.30 (http://www.todopic.com.ar/foros/index.php?topic=51537.30)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 28 de Noviembre de 2023, 18:09:17
Hola.

He escrito la tarea que realiza el cálculo del RMS según las siguientes ecuaciones que se dedujeron tiempo atrás, está dividida en varias partes, de tal manera que se intenta que no sea un proceso apropiativo del CPU, o por lo menos reducir esa desventaja de alguna manera.

(https://pbs.twimg.com/media/FxvxB1KXwAAN-Yu?format=png&name=900x900)

En la tarea que se realiza el muestreo, pongo en verdadero una bandera booleana para indicar el fin de un periodo de muestreo:

(https://pbs.twimg.com/media/GADG_06XoAAt8X0?format=png&name=medium).

En la tarea que calcula el RMS, en el primer estado, espero que dicha bandera pase a verdadero, para realizar los cálculos.

Código: C
  1. case APPRMS_ESTADO_INICIAL:
  2. {
  3.     if (appsamplingData.periodoCompleto)
  4.     {
  5.           apprmsData.indice = 0x00;
  6.           apprmsData.sumatorio1 = 0.0;
  7.           apprmsData.sumatorio2 = 0.0;
  8.           apprmsData.puntero = (appsamplingData.punteroABuffer == 0x01)? 0 : 1;
  9.           appsamplingData.periodoCompleto = false;
  10.           apprmsData.state = APPRMS_ESTADO_SUMATORIO_1;
  11.     }
  12.     break;
  13. }

Nótese que en esta tarea tengo una variable denominada puntero, la cual es inicializada en 0, si el buffer 1 está siendo usado para almacenar muestras, o es inicializado en 1, si el buffer 0 está siendo usado para almacenar muestras.

Código: C
  1. apprmsData.puntero = (appsamplingData.punteroABuffer == 0x01)? 0 : 1;

En el segundo estado se realiza el primer sumatorio, que es elevar al cuadrado cada elemento de la muestra.

Código: C
  1. case APPRMS_ESTADO_SUMATORIO_1: // sumatorio(x^2)
  2.         {
  3.             if (apprmsData.indice < appsamplingData.estructuraADC[apprmsData.puntero].muestra)
  4.             {
  5.                 apprmsData.sumatorio1 += (float)(appsamplingData.estructuraADC[apprmsData.puntero].bufferADC[apprmsData.indice])*(float)(appsamplingData.estructuraADC[apprmsData.puntero].bufferADC[apprmsData.indice]);
  6.                 apprmsData.indice++;
  7.             }
  8.             else
  9.             {
  10.                 apprmsData.indice = 0x00;
  11.                 apprmsData.sumatorio1 = 0.34399*apprmsData.sumatorio1; // m^2* sumatorio1
  12.                 apprmsData.state = APPRMS_ESTADO_SUMATORIO_2;
  13.             }
  14.             break;
  15.         }

Nótese que cada elemento del arreglo es convertido a float, antes de multiplicarse con sigo mismo, esto no lo noté antes, cuando hice pruebas, era la causa del error en la imprecisión de la prueba que se realizó hace tiempo atrás.

Código: C
  1. for (i = 0; i< 100; i++)
  2. {
  3.    // el error consiste en primero multiplicar cada elemento del arreglo y luego convertirlo en float
  4.    sumatorio1 +=(float)(apprmsData.arreglo[i]*apprmsData.arreglo[i]); // sumatorio(x^2)
  5.  }

El valor en appsamplingData.estructuraADC[apprmsData.puntero].muestra, tiene el número de muestras.

Recuerde que el valor del ADC varía de 0 a 1023.

Estos cálculos ya se hicieron anteriormente, pero los pondré aquí para recordarlo.

Si el valor del ADC es 1023, significa que el valor medido es 300 V.

Si el valor del ADC es 0, significa que el valor medido es -300V

Por lo tanto,

1023*m + c = 300
0*m + c = -300

Donde m sería igual a m = 200/341 y c = -300.

m al cuadrado sería 0.34399 y por eso se hace esto:

Código: C
  1. apprmsData.sumatorio1 = 0.34399*apprmsData.sumatorio1;

En otro post, voy a continuar explicando que se hace en el estado APPRMS_ESTADO_SUMATORIO_2
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 28 de Noviembre de 2023, 19:01:03
En el estado APPRMS_ESTADO_SUMATORIO_2 se realiza el siguiente sumatorio, pero esta vez cada muestra ya no se debe elevar al cuadrado y al final se debe multiplicar por 2mc, es decir 2* (200/341)*(-300) = -351.9062.
Código: C
  1. case APPRMS_ESTADO_SUMATORIO_2:
  2. {
  3.     if (apprmsData.indice < appsamplingData.estructuraADC[apprmsData.puntero].muestra)
  4.     {
  5.             apprmsData.sumatorio2 += (float)(appsamplingData.estructuraADC[apprmsData.puntero].bufferADC[apprmsData.indice]);
  6.             apprmsData.indice++;
  7.     }
  8.     else
  9.     {
  10.             apprmsData.sumatorio2 = -351.9062*apprmsData.sumatorio2; //2mc* sumatorio2(x)
  11.             apprmsData.sumatorio1 = apprmsData.sumatorio1 + apprmsData.sumatorio2 + 90000*(float)(appsamplingData.estructuraADC[apprmsData.puntero].muestra) - 90000;  // (N-1)*C^2
  12.             apprmsData.sumatorio1 = apprmsData.sumatorio1/(appsamplingData.estructuraADC[apprmsData.puntero].muestra - 1);
  13.             apprmsData.state = APPRMS_ESTADO_EXTRAER_RAIZ_CUADRADA;
  14.     }
  15.     break;
  16. }

Luego de realizar, este sumatorio, se debe sumar la constante (N-1)*c^2, es decir 90000*(N-1), de ahí el porqué se hace esto:

Código: C
  1. + 90000*(float)(appsamplingData.estructuraADC[apprmsData.puntero].muestra) - 90000;

Finalmente, hay que dividir la suma total, para el periodo, que es el número de muestras:

Código: C
  1. apprmsData.sumatorio1 = apprmsData.sumatorio1/(appsamplingData.estructuraADC[apprmsData.puntero].muestra - 1);

En el último estado, se obtiene la raíz cuadrada del sumatorio total y en teoría debería obtener 24VAC,

Código: C
  1. case APPRMS_ESTADO_EXTRAER_RAIZ_CUADRADA:
  2. {
  3.       apprmsData.sumatorio1 =  sqrtf(apprmsData.sumatorio1); //raiz cuadrada del sumatorio
  4.       apprmsData.state = APPRMS_ESTADO_INICIAL;
  5.       break;
  6. }

En los próximos días verificaré si esto funciona.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 30 de Noviembre de 2023, 12:07:09
Hola, ya realicé algunas pruebas, a continuación explico algunos detalles.

En primer lugar, como se analizó hace mucho, la interrupción por conversión ADC, era la que debía tener mayor prioridad, luego la interrupción externa y finalmente la interrupción del temporizador 4, así es lo que hice:


(https://pbs.twimg.com/media/GAMJN6aWQAEsHV2?format=png&name=small)

Estaba haciendo algunas pruebas, y de repente, el sumatorio total dividido para el número de muestras era negativo, y al obtener la raíz cuadrada, obviamente se generaba un error.

(https://pbs.twimg.com/media/GAMJs5_XsAAmT0l?format=png&name=large)

Lamentablemente, detuve la depuración con el hardware, pero repetí el proceso hasta nuevamente conseguir un valor negativo.

En ese momento, exporté a un archivo CVS todo lo que contenía el arreglo, para con ayuda de excel realizar los cálculos y determinar en que parte de mi código estaba mal.

(https://pbs.twimg.com/media/GAMKgn2XYAAa1N-?format=png&name=900x900)

Y efectivamente, la suma total puede dar un número negativo.

Por un momento, pensé que estaba mal algo en la ecuación de los sumatorios, la razón del valor negativo, es que la contante c es -300 y también existe un - 300 x C^2.

Luego de pensarlo un poco me doy cuenta que el sumatorio debe ser un valor absoluto, ya que de donde se parte, está elevado al cuadrado, así que esa suma nunca debe ser negativa:

(https://pbs.twimg.com/media/GAMLkUXWYAAuOLF?format=png&name=900x900)

Entonces, coloqué la función que extrae el valor absoluto de un flotante en el sumatorio total.

Código: C
  1. case APPRMS_ESTADO_SUMATORIO_2:
  2.         {
  3.             if (apprmsData.indice < appsamplingData.estructuraADC[apprmsData.puntero].muestra)
  4.             {
  5.                 apprmsData.sumatorio2 += (float)(appsamplingData.estructuraADC[apprmsData.puntero].bufferADC[apprmsData.indice]);
  6.                 apprmsData.indice++;
  7.             }
  8.             else
  9.             {
  10.                 apprmsData.sumatorio2 = -351.9062*apprmsData.sumatorio2; //2mc* sumatorio2(x)
  11.                 apprmsData.sumatorio1 = apprmsData.sumatorio1 + apprmsData.sumatorio2 + 90000*(float)(appsamplingData.estructuraADC[apprmsData.puntero].muestra) - 90000;  // (N-1)*C^2
  12.                 apprmsData.sumatorio1 = fabs(apprmsData.sumatorio1/(appsamplingData.estructuraADC[apprmsData.puntero].muestra)); //valor absoluto
  13.                 apprmsData.state = APPRMS_ESTADO_EXTRAER_RAIZ_CUADRADA;
  14.             }
  15.             break;
  16.         }

Al hacer esto, parece que realiza un cálculo bastante aproximado del RMS, me faltaría hacer pruebas con un multímetro al mismo tiempo.

(https://pbs.twimg.com/media/GAMMY69WwAE8EKG?format=png&name=large)

También utilicé la función powf para elevar al cuadrado cada elemento del arreglo, en el segundo estado de la tarea:

Código: C
  1. case APPRMS_ESTADO_SUMATORIO_1: // sumatorio(x^2)
  2.         {
  3.             if (apprmsData.indice < appsamplingData.estructuraADC[apprmsData.puntero].muestra)
  4.             {
  5.                 apprmsData.sumatorio1 += powf((float)(appsamplingData.estructuraADC[apprmsData.puntero].bufferADC[apprmsData.indice]),2);
  6.                 apprmsData.indice++;
  7.             }
  8.             else
  9.             {
  10.                 apprmsData.indice = 0x00;
  11.                 apprmsData.sumatorio1 = 0.34399*apprmsData.sumatorio1; // m^2* sumatorio1
  12.                 apprmsData.state = APPRMS_ESTADO_SUMATORIO_2;
  13.             }
  14.             break;
  15.         }

Ahora debo pensar como tomar ese resultado (el rms) y descomponerlo para colocarlo en el display




Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Diciembre de 2023, 15:09:28
Hola, la función que descompone al valor RMS para mostrarlo en el display, la voy a colocar en la tarea que administra al display y será de la siguiente manera.
Código: C
  1. void rmsDisplay(float valorRMS)
  2. {
  3.  
  4. }

En esta función, lo primero que hago es separar la parte entera y la parte decimal de la siguiente manera:
Código: C
  1. int parteEntera = (int)floorf(valorRMS);
  2. float parteDecimal = (float)(valorRMS - parteEntera);

Supuestamente, la función floorf retorna la parte entera como flotante,

Si por ejemplo el valor rms es 123.4567, floorf sería 123.000, parteEntera será igual a 123 y parteDecimal será igual a 0.4567

Luego tengo que verificar si la parte entera es de 3, 2 o 1 dígito, es decir, si es mayor a 99 (de 100 en adelante) hago lo siguiente:

Código: C
  1. if (parteEntera > 99)
  2. {
  3.      appdisplayData.arregloDisplay[0x00] = (unsigned char)floorf(parteDecimal *10); // obtengo el primer decimal
  4.      appdisplayData.arregloDisplay[0x01] = (unsigned char)(parteEntera%10); // obtengo unidad
  5.      appdisplayData.arregloDisplay[0x02] = (unsigned char)((parteEntera/10)%10); //obtengo unidadDeDecena
  6.      appdisplayData.arregloDisplay[0x03] = (unsigned char)(parteEntera/100);
  7. }

Para el dígito 0, la parteDecinal se multiplica por 10, es decir para el ejemplo, sería 4.567, al aplicar floorf, sería 4.000, y al pasarlo al display tendría 4.
Para el dígito 1, la parte entera al realizar el módulo con diez, obtengo 7.
Para el dígito 2, la parte entera al realizar la división para diez, tendría 12, y ese resultado al obtener el módulo con diez, tendría 2.
Para el dígito 3, la parte entera al realizar la división para cien, obtengo 1.

Lo que me acabo de dar cuenta, en este momento, es que para esta opción, el dígito 0 también debe activar su punto decimal.

Debo pensar como hacer esto.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 02 de Diciembre de 2023, 16:38:50
Se me ha ocurrido una idea de como añadir el punto decimal a cualquier número.

Actualmente tengo un arreglo que cambia el numero de cada dígito al valor adecuado para activar el número correcto en el display:

Código: C
  1. //                                          0     1    2    3    4    5   6    7     8   9
  2. const unsigned char digitoDisplay[0x0A] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x98};

Por ejemplo, si un display tiene el número cero, el arreglo retorna 0xC0, que es el valor que visualiza  cero en el display.

El bit más alto de este número corresponde al segmento PD del display, si deseara que el número cero tenga su punto decimal activo, el valor a retornar sería 0x40.

Para el número 1, es 0xF9, para 1 con punto decimal, sería 0x79, es decir el bit 7 de cualquiera de los valores del arreglo, deben estar en cero.

Estos 10 nuevos valores, los añadiría al arreglo así:

Código: C
  1. //                                          0     1    2    3    4    5   6    7    8   9    0.   1.   2.    3.   4.   5.   6.   7.   8.   9.
  2. const unsigned char digitoDisplay[0x14] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x98,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x38,0x00,0x18};


Es decir, por ejemplo, que si deseo que un display active su punto decimal, simplemente debo sumar 10.

Por ejemplo, si el display tiene un valor de 7, al sumarle 10, será 17, que corresponde a 0x38, que es el número 7 con punto decimal, por lo tanto mi código donde el valor RMS es mayor a 99 sería ahora así:

Código: C
  1. if (parteEntera > 99)
  2.     {
  3.         appdisplayData.arregloDisplay[0x00] = (unsigned char)floorf(parteDecimal *10);
  4.         appdisplayData.arregloDisplay[0x01] = 10 + (unsigned char)(parteEntera%10); // sumo diez para activar el punto decimal
  5.         appdisplayData.arregloDisplay[0x02] = (unsigned char)((parteEntera/10)%10);
  6.         appdisplayData.arregloDisplay[0x03] = (unsigned char)(parteEntera/100);
  7.     }

Luego tendría un else if, para valores mayores que 10, así:

Código: C
  1. else if (parteEntera > 9)
  2.     {
  3.         int decimalDosDigitos = (int)floorf(parteDecimal *100);
  4.        
  5.         appdisplayData.arregloDisplay[0x00] = (unsigned char)(decimalDosDigitos%10);
  6.         appdisplayData.arregloDisplay[0x01] = (unsigned char)(decimalDosDigitos/10);
  7.        
  8.         appdisplayData.arregloDisplay[0x02] = 10 + (unsigned char)(parteEntera%10); //sumo diez para el punto decimal
  9.         appdisplayData.arregloDisplay[0x03] = (unsigned char)(parteEntera/10);
  10.     }

En este caso, supongamos que el valor RMS es 78.953.

En la variable auxiliar decimalDigitos al multiplicar la parte decimal por 100, se tendría 95.3, por lo tanto tendría 95.

En el display 0, se tendría el módulo de 95 para 10, que sería 5.
En el display 1, se tendría el residuo de 95 para 10, que sería 9.

En el display 2, se tendría el módulo de 78 para 10, que sería 8, y más 10, para que el 8 tenga punto decimal
En el display 3, se tendría el residuo de 78 para 10, que sería  7.

Por lo tanto en el display se vería 78.95

Y finalmente tendrá un caso else, que sería para valores enteros del RMS de 0 a 9, y sería así:

Código: C
  1. else
  2.     {
  3.         int decimalTresDigitos = (int)floorf(parteDecimal *1000);
  4.        
  5.         appdisplayData.arregloDisplay[0x00] = (unsigned char)(decimalTresDigitos%10);
  6.         appdisplayData.arregloDisplay[0x01] = (unsigned char)((decimalTresDigitos/10)%10);
  7.         appdisplayData.arregloDisplay[0x02] = (unsigned char)(decimalTresDigitos/100); // obtengo centena
  8.        
  9.         appdisplayData.arregloDisplay[0x03] = 10 + (unsigned char)(parteEntera);
  10.     }

Supongamos que el valor rms es 5.347.

La parte decimal al multiplicarse por 1000 sería 347, que sería el valor de la variable auxiliar decimalTresDigitos.

El display 0 tendría el residuo del 347 para 10, es decir 7.
El display 1 tendría el residuo de la división de 347/10, con 10, es decir 4.
El display 2 tendría el residuo de la división de 347 para 100, es decir 3.

El display 3, tendría la parte entera, que sería 5, que al sumarle 10, sería 5 con punto decimal.

Eso creo que sería todo, falta probarlo con el hardware.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 03 de Diciembre de 2023, 12:46:49
Hola.

He realizado las pruebas, para determinar el valor medido.

Primero quería conocer cuanto duraba la tarea en realizar el cálculo del RMS de un periodo.

Utilizo una variable tipo entero, que utilizo para capturar el valor del Core Timer cuando inicia ese proceso:

Código: C
  1. case APPRMS_ESTADO_INICIAL:
  2.         {
  3.             if (appsamplingData.periodoCompleto)
  4.             {
  5.                 apprmsData.retardo = CORETIMER_CounterGet(); // capturo el valor instantáneo del Core Timer
  6.                 apprmsData.indice = 0x00;
  7.                 apprmsData.sumatorio1 = 0.0;
  8.                 apprmsData.sumatorio2 = 0.0;
  9.                 apprmsData.puntero = (appsamplingData.punteroABuffer == 0x01)? 0 : 1;
  10.                 appsamplingData.periodoCompleto = false;
  11.                 apprmsData.state = APPRMS_ESTADO_SUMATORIO_1;
  12.             }
  13.             break;
  14.         }

Luego, al finalizar el cálculo,  hago una diferencia o resta entre el valor del Core Timer y el valor inicial capturado, de esa manera mido cuanto tiempo duró ese proceso:

Código: C
  1. case APPRMS_ESTADO_EXTRAER_RAIZ_CUADRADA:
  2.         {
  3.             rmsDisplay(sqrtf(apprmsData.sumatorio1)); //la raiz cuadrada de todo lo envío a la función rmsDisplay
  4.             apprmsData.retardo = CORETIMER_CounterGet() - apprmsData.retardo;
  5.             apprmsData.state = APPRMS_ESTADO_INICIAL;
  6.             Nop(); //aquí pondo un punto de ruptura.
  7.             break;
  8.         }

Con esto, el valor de retardo es 37329.

(https://pbs.twimg.com/media/GAbwDx5XYAAgGX1?format=png&name=large)

Si la frecuencia de ese reloj o temporizador es de 24MHz, el tiempo medido sería:

37329/24MHz = 1.555 ms, que es menor que el periodo de la señal medida (16.667 ms)

También se debe considerar que no esta el código, con el nivel de optimización máximo, está con el nivel gratuito, creo que mejoraría ese tiempo en algo en ese modo.

A continuación, tengo un video del RMS medido con los 24VAC:



Se puede ver que el valor medido, no es exacto, hay un error de 2 voltios aproximadamente, también se puede apreciar que por un instante, parece que se muestra un valor mayor a 99 voltios, pero es muy rápido.

También la transición de los valores decimales, es muy rápida, debo colocar algún tipo de retardo, para evitar eso.

Tenía la esperanza que al utilizar 24VAC, el acondicionamiento de la señal de un voltaje pequeño, generaba ese error, así que lo conecté a 120VAC, he igual manera, hay un error:

.

Pero en un instante dado, se puede ver 122 VAC:

(https://pbs.twimg.com/media/GAbzOYnW0AAsY2v?format=jpg&name=medium)

Debo determinar si es un error del código, o el acondicionamiento de la señal, está introduciendo un error.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 03 de Diciembre de 2023, 14:49:31
Hola, estaba realizando unas pruebas, y he descubierto que a veces, el número de muestras es menor al que debería ser por el periodo.

Como dije antes, si el periodo es de aproximadamente 16.667 ms, al tomar muestras en intervalos de 100 us, debería tener unas 167 muestras aproximadamente, pero a veces, tengo entre 40 a 80 muestras.

Es como si la interrupción externa, ocurriera antes de completar un periodo.

Investigando, un poco, hay un problema al utilizar un amplificador operacional como comparador, en lugar de un comparador de voltaje en si.

Esto es, cuando las dos señales a comparar tienen un nivel de voltaje casi iguales, la salida del operacional oscila, ya que no puede definir cual es alta respecto a la otra.


(https://pbs.twimg.com/media/GAcJ3TWWIAExyfo?format=png&name=small)


Está oscilación se la ha sabido conocer como  "ruido de ida y vuelta" o "chattering".

(https://file.elecfans.com//web2/M00/6C/E6/pYYBAGMvzk-AZrdtAAFOhJDC2SA664.png)

Lo que podría ser la causa del posible problema inicialmente explicado.

Es algo similar al rebote de un pulsador al ser presionado.

Posiblemente la solución es un retardo (obviamente asincrónico) y/o un capacitor.

En estos días voy a analizar con el osciloscopio esa señal para determinar si existe tal ruido.



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Picuino en 04 de Diciembre de 2023, 06:59:14
Otra solución mejor que el retardo es añadir histéresis con realimentación positiva.
https://es.wikipedia.org/wiki/Disparador_Schmitt
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 04 de Diciembre de 2023, 10:04:43
Otra solución mejor que el retardo es añadir histéresis con realimentación positiva.
https://es.wikipedia.org/wiki/Disparador_Schmitt

Si, es una buena idea, pero el PCB ya está construido, sería tal vez para una nueva versión del hardware.

Sin embargo debo determinar si dicho ruido se está produciendo (en las simulaciones de MPLAB Mindi no sucede), y si es así, realizar una solución engorrosa tratando de colocar un capacitor y/o una solución a nivel de software.

Por cierto, la simulación (la línea roja es la salida del OP)

(https://pbs.twimg.com/media/GAgYDOWWcAAdyjW?format=png&name=large)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 04 de Diciembre de 2023, 11:00:22
Pues no parece algún ruido en la salida del operacional utilizado como comparador:

(https://pbs.twimg.com/media/GAgkVYeXYAEFLkM?format=png&name=900x900)

Estuve verificado por algún tiempo, pero parece funcionar bien.

Sospecho acerca de la configuración del ADC, voy a intentar analizar eso cuando tengo un poco de tiempo libre.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: AnitaMalhereux en 05 de Diciembre de 2023, 09:27:17
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.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.

(https://pbs.twimg.com/media/GAlkALoW0AA845T?format=png&name=medium)

(https://pbs.twimg.com/media/GAlknEXWQAAtR0K?format=png&name=360x360)

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.

(https://pbs.twimg.com/media/GAllC2wWgAAyweS?format=png&name=small)

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
(https://pbs.twimg.com/media/GAllR98XgAAJfpL?format=png&name=small)

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:
(https://pbs.twimg.com/media/GAlssMpWUAAezJk?format=png&name=medium)


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.

(https://pbs.twimg.com/media/GAltYDyWIAAz-Yf?format=png&name=medium)

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:
(https://pbs.twimg.com/media/GAluL_UW8AIFth0?format=png&name=small)

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.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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:

(https://pbs.twimg.com/media/GAoIRqnXMAAsWOf?format=png&name=900x900)

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

(https://pbs.twimg.com/media/GAoJ848W0AAJaz5?format=png&name=medium)

(https://pbs.twimg.com/media/GAoKQ4uXEAABDp-?format=png&name=medium)

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.

(https://pbs.twimg.com/media/GAoL1ByW0AA6X8A?format=png&name=medium)

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.



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno 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.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.

(https://pbs.twimg.com/media/GAq15tgW4AAEecz?format=jpg&name=large)

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

(https://pbs.twimg.com/media/GAq5JEYWgAARLiS?format=png&name=small)

Que sería un valor correcto del número de muestras.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.

(https://pbs.twimg.com/media/GAwrD7hXsAA37Ou?format=png&name=small)

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

(https://pbs.twimg.com/media/GAwrYZNXUAARow1?format=jpg&name=large)

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.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Nocturno en 07 de Diciembre de 2023, 18:04:10
¡Muy bien!
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.

(https://pbs.twimg.com/media/GBGE-uuXYAABFHI?format=png&name=900x900)

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

(https://pbs.twimg.com/media/GBGFUxwWsAA9YmY?format=png&name=small)

Espero en esta semana escribir el código y compartirlo aquí.

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.

(https://pbs.twimg.com/media/GBGE-uuXYAABFHI?format=png&name=900x900)

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

(https://pbs.twimg.com/media/GBGFUxwWsAA9YmY?format=png&name=small)

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:

(https://pbs.twimg.com/media/GBPBXhmXsAAU__I?format=png&name=900x900)

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

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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



 
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: AnitaMalhereux 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
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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,
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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.

(https://pbs.twimg.com/media/GBzgxUsWoAg-ATs?format=png&name=900x900)

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.




Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR 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:

(https://pbs.twimg.com/media/GCh0jX_W4AAwKQr?format=png&name=900x900)

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

(https://pbs.twimg.com/media/GCh1AOSWsAAeKan?format=png&name=small)

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

(https://pbs.twimg.com/media/GCh1dAhWQAAL5H7?format=png&name=medium)

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:

(https://pbs.twimg.com/media/GCh5DIMXsAAeUZ8?format=png&name=900x900)

Al realizar esto, el registro IC1R es igual a 2

(https://pbs.twimg.com/media/GCh5W5KWUAAgz2D?format=png&name=small)

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

(https://pbs.twimg.com/media/GCh5tPaWkAAnyab?format=png&name=900x900)

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:

(https://pbs.twimg.com/media/GCh66hZXIAAKYPf?format=png&name=medium)

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.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 30 de Diciembre de 2023, 18:52:34
Hola.

Sí se pueden conectar dos periféricos a un mismo pin, no se si mediante el MCC se puede hacer esto, yo lo hice manualmente:

(https://pbs.twimg.com/media/GCoDnaUWsAEKKFS?format=png&name=small)

También me di cuenta que no debía hacer la deshabilitación de los periféricos en la función cambiarProceso, esta sólo debe inicializar la tarea de muestro y el del cálculo del RMS

Código: C
  1. void cambiarProceso(void)
  2. {
  3.     APPSAMPLING_Initialize();   // Reinicio la tarea de muestreo
  4.     APPRMS_Initialize();        // Reinicio la tarea que calcula el valor RMS
  5. }

En cambio, en el primer estado de la tarea de muestro (APPSAMPLING), debo en función de la bandera medirFrecuencia, deshabilitar un periférico y habilitar el otro.

Código: C
  1. case APPSAMPLING_ESTADO_INICIAL:
  2.         {
  3.             if (apppulsadorData.medirFrecuencia)
  4.             {
  5.                 /** Deshabilito todo lo relacionado con el cálculo del valor RMS**/
  6.                 EVIC_ExternalInterruptDisable(EXTERNAL_INT_2);  //detengo la interrupción por interrupción externa
  7.                 EVIC_SourceStatusClear(INT_SOURCE_EXTERNAL_2);  //limpio la bandera por interrupción externa
  8.                 TMR4_Stop();                                    //detengo al temporizador 4
  9.                 TMR4_InterruptDisable();                        //deshabilito la interrupción del temporizador 4
  10.                 EVIC_SourceStatusClear(INT_SOURCE_TIMER_4);     //limpio la bandera por interrupción de tmr4
  11.                 ADC_Disable();                                  //deshabilito al módulo ADC
  12.                 EVIC_SourceStatusClear(INT_SOURCE_ADC);         //limpio la bandera por interrupción del ADC
  13.                 /*************************************************/
  14.                 ICAP1_Enable();
  15.                 TMR2_Start();
  16.                 ICAP1_CallbackRegister(ManejarInterrupcionModuloCaptura, (uintptr_t)NULL);
  17.                 appsamplingData.captura = 0x0000;
  18.             }
  19.             else
  20.             {
  21.                 /** Deshabilito todo lo relacionado con el cálculo del periodo de la señal**/
  22.                 ICAP1_Disable(); //Deshabilito el módulo de captura
  23.                 TMR2_Stop();
  24.                 EVIC_SourceStatusClear(INT_SOURCE_INPUT_CAPTURE_1); // limpio bandera del módulo de captura.
  25.                 /*************************************************/
  26.                 TMR4_Stop();
  27.                 TMR4_CallbackRegister(ManejarInterrupcionTMR4, (uintptr_t) NULL);// registro función de interrupción por TMR4
  28.                 ADC_CallbackRegister(ManejarInterrupcionADC, (uintptr_t)NULL); // registro función de interrupción por ADC
  29.                 EVIC_ExternalInterruptCallbackRegister(EXTERNAL_INT_2, &ManejarInterrupcionExterna, (uintptr_t)NULL); //Registro la función que se llama por la interrupción externa
  30.                 EVIC_ExternalInterruptEnable(EXTERNAL_INT_2); // Habilito la interrupción externa 2
  31.                
  32.                 TMR4_InterruptEnable();
  33.                 ADC_Enable();
  34.             }
  35.             appsamplingData.state = APPSAMPLING_ESTADO_REPOSO;
  36.             break;
  37.         }

El error que mencioné antes que cuando presionaba el pulsante para regresar a medir la frecuencia, era debido a que TMR4 y el ADC eran deshabilitados, y eran necesario volver a activarlos. (Línea 32 y 32 del código de arriba)

El código inicial que usé para visualizar la frecuencia fue así:

Código: C
  1. void ManejarInterrupcionModuloCaptura(uintptr_t context)
  2. {
  3.     appsamplingData.captura = ICAP1_CaptureBufferRead() - appsamplingData.captura;
  4.     rmsDisplay(750000.000/((float)(diferencia)));
  5.     }
  6. }

Pero en el display salía cualquier cosa, menos un valor cercano, sólo la primera vez que sucedía la interrupción del comparador, se obtiene un valor que corresponde a 60Hz.

Luego de darle vueltas a lo que estaba pensando y analizando el código de ejemplo de Microchip que mide tiempo con el comparador que es este:
Código: C
  1. while ( true )
  2.     {
  3.         /* Maintain state machines of all polled MPLAB Harmony modules. */
  4.         SYS_Tasks ( );
  5.        
  6.         while(!ICAP1_CaptureStatusGet());
  7.  
  8.         capturedValue[captureIndex++] = ICAP1_CaptureBufferRead();
  9.  
  10.         if ( captureIndex > 1){
  11.             printf("Pulse Width Count = %d\r\n",(capturedValue[1] - capturedValue[0]));
  12.             captureIndex = 0;
  13.         }
  14.     }

Me di cuenta que deben tomarse dos muestras, y realizar la diferencia entre las dos para obtener el valor medido, así que cambié la variable captura a un arreglo de 2 palabras con su índice.

(https://pbs.twimg.com/media/GCoGpjbWUAARzeO?format=png&name=small)

Y realicé un código similar al ejemplo de Microchip:

Código: C
  1. void ManejarInterrupcionModuloCaptura(uintptr_t context)
  2. {
  3.     appsamplingData.captura[appsamplingData.indiceCaptura++] = ICAP1_CaptureBufferRead();
  4.     if (appsamplingData.indiceCaptura > 0x01)
  5.     {
  6.         uint32_t diferencia = appsamplingData.captura[0x01] -  appsamplingData.captura[0x00];
  7.         if (diferencia)
  8.         {
  9.             rmsDisplay(750000.000/((float)(diferencia)));
  10.         }
  11.         appsamplingData.indiceCaptura = 0x00;
  12.     }
  13. }

Nótese que hay un  if (diferencia), ya que a veces, cuando presiono el pulsador para cambiar a medir frecuencia, el microcontrolador, reinicia. Pensaba que podía estar realizándose un división para cero, pero sigue pasando, es algo que debo revisar.

Y este es el resultado, obviamente, el cambio de la información el el display es mucho más rápido, me imagino que se debe a que al medir la frecuencia, no demora al CPU ya que no hace cálculos como en el caso del RMS.


El cambio en el display es muy rápido, es algo que debo corregir, pero se puede ver al poner pausa que el valor medido es de 60 Hz:

(https://pbs.twimg.com/media/GCoI08SXgAAT1HU?format=png&name=900x900)

Pero también se visualizar un valor igual a cero, y a pesar que está controlado que si la diferencia tiene ese valor, no se muestre en el display, es algo que debo investigarlo

(https://pbs.twimg.com/media/GCoJFeNXwAABwrN?format=png&name=900x900)

También aparece la alarma de "bajo voltaje", ya que dicho proceso toma el valor de 60 como voltaje y esa es la razón.

Debería también crear otros límites cuando se está midiendo la frecuencia. Según busqué, el error es de 5Hz, es decir la frecuencia no debe ser mayor a 60.5Hz o menor a 59.5 Hz.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 31 de Diciembre de 2023, 11:20:38
Hola.

He modificado las muestras a tipo flotante así:

Código: C
  1. void ManejarInterrupcionModuloCaptura(uintptr_t context)
  2. {
  3.     appsamplingData.captura[appsamplingData.indiceCaptura++] = ICAP1_CaptureBufferRead();
  4.     if (appsamplingData.indiceCaptura > 0x01)
  5.     {
  6.         float diferencia = (float)(appsamplingData.captura[0x01]) -  (float)(appsamplingData.captura[0x00]);
  7.         if (diferencia > 0.00)
  8.         {
  9.             rmsDisplay(750000.000/diferencia);
  10.         }
  11.         appsamplingData.indiceCaptura = 0x00;
  12.     }
  13. }

Y este es el resultado:


También he modificado la parte que alerta al usuario de un sobre(Voltaje/Frecuencia) o sub (Voltaje/Frecuencia) así:

Código: C
  1. #define maximoVoltaje       127.00
  2. #define minimoVoltaje       110.00
  3. #define maximaFrecuencia    60.50
  4. #define minimaFrecuencia    59.50

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

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 07 de Enero de 2024, 16:24:11
Hola.

Estaba cambiando las baterías a unos UPS que poseo, y recordé que cuando entran en modo de respaldo, no generan una onda sinuosidad, así que pensé que sería una buena idea determinar que tan correcto es el Vrms generado por el UPS.

Primero determine cual es el voltaje del UPS cuando no está en modo de respaldo, el voltaje RMS como se puede ver es de 105V.

Pensé que el voltaje de la red, había caído a ese valor, pero no era así, el UPS atenuaba la señal, ya que de la empresa eléctrica estaba en 126Vrms

Las puntas de prueba del osciloscopio están x10, mi voltímetro mide 103.1 Vrms

(https://pbs.twimg.com/media/GDQxmyPXUAAuFSp?format=jpg&name=large)

Cuando entra en modo de respaldo, se puede apreciar que la forma de voltaje, no es cuadrada, es rectangular, y los picos que aparecen cuando el voltaje cae, me imagino que es debido a que los SCRs, ya que recuerdo que había forma de hacer un conversor DC/AC  con 2 SCRs y transformador con toma central. No recuerdo porque aparecían esos picos.


(https://pbs.twimg.com/media/GDQyu5bW8AAMY9R?format=jpg&name=large)

El multímetro indica 79.1Vrms, mientras que el voltímetro que hice, mide 112.2 Vrms, así que tal vez si mide el valor RMS de manera un poco más precisa.

(tendría que calcular el VRMS con integrales de la gráfica mostrada por el osciloscopio)

Actualización

Ya recordé, es por un capacitor, que sirve para apagar al SCR, al aplicarte momentáneamente un voltaje negativo.


(https://www.daenotes.com/sites/default/files/article-images/Single-Phase-inverter.png)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Eduardo2 en 07 de Enero de 2024, 20:44:57
...Primero determine cual es el voltaje del UPS cuando no está en modo de respaldo, el voltaje RMS como se puede ver es de 105V.

Pensé que el voltaje de la red, había caído a ese valor, pero no era así, el UPS atenuaba la señal, ya que de la empresa eléctrica estaba en 126Vrms

Las puntas de prueba del osciloscopio están x10, mi voltímetro mide 103.1 Vrms
Ese tester no es TrueRMS,  pero como la señal de entrada es "bastante" senoidal el valor es confiable.
En el que fabricaste no se si a las constantes m y c  les diste los valores teóricos o hiciste alguna calibración, de todas formas, la fórmula en http://www.todopic.com.ar/foros/index.php?topic=51537.msg424985#msg424985  tiene un error ; el último término no es (N-1)c^2 sino Nc^2 pues es el resultado se sumar una constante de 0 a N-1 , o sea N términos.
Eso hace que el resultado final sea menor de lo que debiera pudiendo hasta ser negativo.

Citar
Cuando entra en modo de respaldo, se puede apreciar que la forma de voltaje, no es cuadrada, es rectangular, y los picos que aparecen cuando el voltaje cae, me imagino que es debido a que los SCRs, ya que recuerdo que había forma de hacer un conversor DC/AC  con 2 SCRs y transformador con toma central. No recuerdo porque aparecían esos picos.
Las UPS "normales" no son con SCRs sino MOSFETs.  Su forma es rectangular porque debe tener el mismo valor RMS y de pico que la línea.  Debe ser así para poder conectarle tanto cargas resistivas como equipos electrónicos.

Ese pico inverso es propio de una configuración puente cada vez que un transistor va al corte,  te conviene colocar alguna carga resistiva (las difíciles de encontrar lámparas incandescentes) porque debería desaparecer o al menos disminuir.

Citar
El multímetro indica 79.1Vrms, mientras que el voltímetro que hice, mide 112.2 Vrms, así que tal vez si mide el valor RMS de manera un poco más precisa.

Por lo que se alcanza a ver en el osciloscopio el tiempo de conducción incluyendo el pico son aprox 2.6ms y el máximo 206V
Entonces el valor RMS es:  206V*sqrt(2.6ms/8.333ms) =  115Vrms

Con estas condiciones el tester debería indicar:   1.11*206V*2.6ms/8.333ms = 71.3V  (cerca   :) ) 
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 07 de Enero de 2024, 21:03:00
Ese tester no es TrueRMS,  pero como la señal de entrada es "bastante" senoidal el valor es confiable.

Hola, gracias por escribir, recuerdo que mencioné que no es true RMS el voltímetro de mi multímetro.

(https://pbs.twimg.com/media/GDR0-DuWAAAt_pT?format=png&name=large)
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 07 de Enero de 2024, 21:06:37

En el que fabricaste no se si a las constantes m y c  les diste los valores teóricos o hiciste alguna calibración, de todas formas, la fórmula en http://www.todopic.com.ar/foros/index.php?topic=51537.msg424985#msg424985  tiene un error ; el último término no es (N-1)c^2 sino Nc^2 pues es el resultado se sumar una constante de 0 a N-1 , o sea N términos.
Eso hace que el resultado final sea menor de lo que debiera pudiendo hasta ser negativo.


Puede ser, voy a revisarlo para ver si se debe corregir eso.

Pero negativo no puede ser, ya si se parte de un sumatorio, donde su contenido está al cuadrado, por lo tanto su resultado siempre será positivo (valor absoluto:

(https://pbs.twimg.com/media/GAMLkUXWYAAuOLF?format=png&name=900x900)

Respuesta #81 en:

http://www.todopic.com.ar/foros/index.php?topic=51537.75 (http://www.todopic.com.ar/foros/index.php?topic=51537.75)

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 07 de Enero de 2024, 21:09:35

Las UPS "normales" no son con SCRs sino MOSFETs.  Su forma es rectangular porque debe tener el mismo valor RMS y de pico que la línea.  Debe ser así para poder conectarle tanto cargas resistivas como equipos electrónicos.

Ese pico inverso es propio de una configuración puente cada vez que un transistor va al corte,  te conviene colocar alguna carga resistiva (las difíciles de encontrar lámparas incandescentes) porque debería desaparecer o al menos disminuir.

Citar
El multímetro indica 79.1Vrms, mientras que el voltímetro que hice, mide 112.2 Vrms, así que tal vez si mide el valor RMS de manera un poco más precisa.

Por lo que se alcanza a ver en el osciloscopio el tiempo de conducción incluyendo el pico son aprox 2.6ms y el máximo 206V
Entonces el valor RMS es:  206V*sqrt(2.6ms/8.333ms) =  115Vrms

Con estas condiciones el tester debería indicar:   1.11*206V*2.6ms/8.333ms = 71.3V  (cerca   :) )

Si, puede ser, en la universidad, recuerdo que se hizo muchos laboratorios de electrónica de potencia, y ya son muchos años.

Laboralmente sólo he estado relacionado con microcontroladores y realmente he olvidado mucho de ese campo.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Eduardo2 en 07 de Enero de 2024, 21:27:46
Pero negativo no puede ser, ya si se parte de un sumatorio, donde su contenido está al cuadrado, por lo tanto su resultado siempre será positivo (valor absoluto:
Mas bien, lo que puede dar negativo es la expresión final porque está mal (la de "por lo tanto, todo esto debe ser positivo"), debe terminar en Nc2

Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 07 de Enero de 2024, 21:35:04
http://www.todopic.com.ar/foros/index.php?topic=51537.msg424985#msg424985  tiene un error ; el último término no es (N-1)c^2 sino Nc^2 pues es el resultado se sumar una constante de 0 a N-1 , o sea N términos.


Si busco en Wikipedia, se tiene que:

(https://pbs.twimg.com/media/GDR6wLDXgAAT6pb?format=png&name=small)

Siguiendo la imagen de arriba, m es cero, n es N - 1, por lo tanto (n - m + 1) = (N - 1 - 0  + 1)  = N

Mi error fue tomar esto de referencia:

(https://pbs.twimg.com/media/GDR79AhXUAEgIL8?format=png&name=small)

Donde tiene validez, si se empieza con i = 1, pero en mi caso empieza en cero



Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 07 de Enero de 2024, 21:44:17
Pero negativo no puede ser, ya si se parte de un sumatorio, donde su contenido está al cuadrado, por lo tanto su resultado siempre será positivo (valor absoluto:
Mas bien, lo que puede dar negativo es la expresión final porque está mal (la de "por lo tanto, todo esto debe ser positivo"), debe terminar en Nc2

Sería en esta parte, donde debo corregirlo:

(https://pbs.twimg.com/media/GDR-MTNWkAAKJHy?format=png&name=large)

En esta semana que viene, hago el cambio y veo que pasa.

Gracias
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 08 de Enero de 2024, 12:07:55
Hola, he realizado el cambio sugerido por Eduardo 2.0 así:

Código: C
  1. apprmsData.sumatorio2 = -351.9062*apprmsData.sumatorio2; //2mc* sumatorio2(x)
  2.  apprmsData.sumatorio1 = apprmsData.sumatorio1 + apprmsData.sumatorio2 + 90000*(float)(appsamplingData.estructuraADC[apprmsData.puntero].muestra)/* - 90000*/;  // (N-1)*C^2
  3. apprmsData.sumatorio1 = /*fabs(*/apprmsData.sumatorio1/((float)appsamplingData.estructuraADC[apprmsData.puntero].muestra/*)*/);
  4. apprmsData.state = APPRMS_ESTADO_EXTRAER_RAIZ_CUADRADA;

Y parece que ha mejorado, ya que antes ente el voltímetro del multímetro que tengo y el que hice, había siempre una diferencia aproxiamdamente de 2 voltios, ahora es de un poco más de 1 voltio.

(https://pbs.twimg.com/media/GDVDVQJXEAAta6N?format=jpg&name=large)

Obvaimente, debo intentar conseguirme unos que sea TRUE rms para determinar que tan impreciso es el que he realizado.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Picuino en 29 de Enero de 2024, 14:08:24
Puedes meterle una onda cuadrada desde un microcontrolador, que tiene un valor RMS conocido, y comprobar que mide lo esperado.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 29 de Enero de 2024, 14:22:17
Puedes meterle una onda cuadrada desde un microcontrolador, que tiene un valor RMS conocido, y comprobar que mide lo esperado.

Si, gracias, esa era la idea de usar el UPS en modo de respaldo. Y parece que está bastante bien.

Luego veo eso, estoy un poco ocupado en el trabajo, y estaba en lo de la caja plástica.

Cuando me desocupe, regreso a este proyectillo.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: Eduardo2 en 29 de Enero de 2024, 14:44:40
Hay controles que los podés hacer en CC.
- El offset invirtiendo la polaridad.
- El factor de escala con un voltaje alto.
- La linealidad del ADC y los errores por truncamiento con mediciones a diferentes voltajes.
Esos tres aspectos es preferible en CC que en CA por la independencia respecto a otras fuentes de error y porque es mas preciso que en CA.
Título: Re:Proyecto para medir el valor eficaz verdadero (True RMS)
Publicado por: DominusDRR en 29 de Enero de 2024, 14:50:18
Hay controles que los podés hacer en CC.
- El offset invirtiendo la polaridad.
- El factor de escala con un voltaje alto.
- La linealidad del ADC y los errores por truncamiento con mediciones a diferentes voltajes.
Esos tres aspectos es preferible en CC que en CA por la independencia respecto a otras fuentes de error y porque es mas preciso que en CA.

Si puede ser, gracias, pero no es un proyecto profesional.

La idea principal, como dije, era que donde vivo, que es una zona rural, a veces el voltaje varía y mi idea era que me avise de un sobre voltaje o subvoltaje.

Lo de calcular el RMS y el procesamiento en tiempo real, sólo era por divertirme, como dijo alguien por ahí, sólo tomabas el máximo pico y dividías para 1.41 y listo.