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

0 Usuarios y 7 Visitantes están viendo este tema.

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #30 en: 03 de Junio de 2023, 23:52:06 »
Creo que quedaría así:

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

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #31 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:



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)




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



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.



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



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.



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

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #32 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.



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.

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

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #33 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.



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.


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


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



Y en mi caso TpB es 1/48MHz.



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



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



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.     }
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #34 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:



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.



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
« Última modificación: 06 de Junio de 2023, 16:54:28 por DominusDRR »
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #35 en: 06 de Junio de 2023, 17:28:19 »
¡Vaya hilazo te está quedando!  ((:-)) ((:-)) ((:-))

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #36 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:



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



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

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

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #37 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:







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)





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

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #38 en: 16 de Agosto de 2023, 16:25:11 »
Al fin llegaron los PCBs:



Lo primero que voy hacer, es colocar los elementos de la fuente para ver si funciona.... :shock:
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado tsu_electronica

  • PIC18
  • ****
  • Mensajes: 274
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #39 en: 16 de Agosto de 2023, 22:13:50 »
jeje como que si funciona claro que va a funcionar  ((:-))

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #40 en: 19 de Agosto de 2023, 12:07:29 »
Ayer coloqué todos los componentes con respecto a la fuente y quedó así:



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:



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



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:



Cuando lo correcto es que una es de 16.5k:



Voy a  corregir ese error y veo que sucede.

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

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #41 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:




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



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



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

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

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #42 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?

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:Proyecto para medir el valor eficaz verdadero (True RMS)
« Respuesta #43 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.



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