Cómo hacer un osciloscopio con Arduino

Autor: José Olin
Publicado: 2022-05-31

En algún momento del camino Jedi, un circuito falla más allá de lo que un Serial.print() puede permitirnos debuguear: es el momento del osciloscopio. Los precios "oscilan" (XD broma no intencionada) entre unos pocos miles, y varias decenas. Sin embargo, si quieres analizar una señal de hasta 5V los pines analógicos de tu fiel Arduino pueden ser suficientes.

NOTA: Si necesitas algo sencillo, Arduino incluye la herramienta Serial Plotter.

Serial Plotter

Si buscas algo que después puedas integrar en una interfaz gráfica más completa, esta es tu guía ;)

Arremángate, que empezamos.

Motivación

Hace unas semanas el microcontrolador del Isiukak, un ST Nucleo F401RE, dejó de comunicarse con los drivers de Pololu.

¿Y si los drivers de Pololu son de 5V y quemaron el puerto del ST, que sólo soporta 3.3V? La hoja de datos decía que eran de 3.3V, "tolerantes a 5V", y si su tolerancia es violenta?

Nos preguntamos. Para desahogar toda duda decidimos construir un osciloscopio hecho en casa con un Arduino UNO.

No buscábamos algo de mucha precisión simplemente que nos permitiera graficar la señal de voltaje del puerto serial y darnos una idea de cómo se estaba comportando.

El sistema se divide en dos programas. Un script en Arduino y un programa en C++ que corre en el computador, con el que leemos el puerto serial y graficamos la señal de los pines analógicos del Arduino UNO.

Así es, un osciloscopio de 6 canales; nada mal...

Código en Arduino

Esta es la parte sencilla, sólo leemos los pines A0 al A5 y los transmitimos al computador con la mayor frecuencia posible.

En teoría el UNO puede transmitir hasta a 2 millones de bits por segundo, sin embargo sólo logramos comunicación hasta 500,000 bps. Si conoces una forma de superar este umbral usando QSerialPlot, puedes compartirlo en los comentarios.

#include <Arduino.h>

int inputs[6];
int inputsReaded = 6;
int inputs_pins[6] = {A0, A1, A2, A3, A4, A5 };
char* inputs_headers[6] = {"A0", "A1", "A2", "A3", "A4", "A5"};


void setup()
{
    //Serial.begin(115200); <- Funciona
    //Serial.begin(250000); <- Funciona
    //Serial.begin(300000); <- Funciona
    //Serial.begin(400000); <- Funciona
    Serial.begin(500000); // <- Funciona!
    //Serial.begin(600000); // Wowowow, tranquilo, viejo...
}

void loop()
{
    for(int index = 0; index < inputsReaded; index++)
    {
          // Leer cada canal
        inputs[index] = analogRead(inputs_pins[index]);

        // Desplegarlo en formato A0: 20, A1: 18, ...
        Serial.print(inputs_headers[index]); Serial.print(": ");
        Serial.print(inputs[index]);

        if(index < inputsReaded-1)
            Serial.print(", "); // Sólo los primeros 5 elementos llevan coma al final.
        else
            Serial.println(" "); // El último lleva un salto de línea.
    }
    delayMicroseconds(10);
}

NOTA: Si usas el IDE de Arduino no es necesario el #include <Arduino.h>. Sólo es necesario si usas PlatformIO.

Las partes importantes del código son

int inputsReaded: Número de canales a leer (En nuestras pruebas inputsReaaded = 2).

inputs_pins[6]: Un arreglo de 6 elementos con el nombre de los pines a leer. La idea es que el programa sea los más general posible en caso de que sólo ocupes medir 1 ó 2 canales, o incluso agregar fácilmente más canales si usaras otro microcontrolador.

inputs_headers[6]: Un arreglo de 6 elementos con el nombre de cada canal, en el mismo orden que inputs_pins.

En el loop se leen los canales y se envian por Serial.

Código en C++ (QtCreator)

Este código tiene un poco más de gracia; se encarga de leer los valores que recibe por serial con QSerialPort; separarlo en renglones (en ocasiones una lectura incluye más de 1 renglón); separar el valor de cada canal usando usando QRegularExpression y graficarlo usando QCustomPlot

Puedes descargar el código completo, tanto de Arduino como de la Interfaz gráfica del respositorio en Github

La mayoría de la magia está en el constructor de la ventana principal MainWindow::MainWindow(QWidget *parent)

serialCom = new SerialCommunication();
parser = new DataParser();
osciloscope = new Osciloscope();

La clase SerialCommunication lee el puerto serial del Arduino, DataParser separa los valores de cada canal y Osciloscope los grafica.

Otra sección importante es la conexión de la señal readyRead de QSerialPort con la función displayReadedData(), donde los datos se separan, se grafican y se colocan en la interfaz.

connect(serialCom->serial,  SIGNAL(readyRead()),
        this,               SLOT(displayReadedData())   );

La interfaz luce así

Con el dial puedes controlar el zoom horizontal de la amplitud de la señal.

Y aquí puedes verlo en funcionamiento en una de las primeras pruebas.

Si te interesan más detalles del código, deja un mensaje.

¡Hasta la autonomía, siempre!



.
Esta publicación es posible gracias a nuestros Patreons.