Generador de señales con esp32

Generador de Señales — ESP32 + OLED
ESP32 DAC 8-bit SSD1306 128×64 4 formas de onda
Una señal senoidal continua varía suavemente en todo instante de tiempo. Sin embargo, el ESP32 solo puede generar valores en instantes discretos separados por un período de muestreo Ts. El DAC interno de 8 bits produce 256 niveles de tensión entre 0 V y 3.3 V.
y[n] = A · sin(2π · n / N)    n = 0, 1, 2, ..., N−1
— Línea azul = señal continua ideal  ·  ● Puntos naranjas = muestras del DAC
Simulación 1:1 · SSD1306 128×64 px · Fósforo verde
🔲
ESP32 DevKit v1
DAC integrado 8-bit
Canales GPIO25 / GPIO26
📺
OLED 0.96" SSD1306
128×64 px, I²C
Alimentación 3.3 V
🎚
Potenciómetro 10 kΩ ×2
WH148 multivuelta lineal
Frecuencia + Amplitud
Pulsador táctil ×1
6×6 mm, 4 pines
Cambio de forma de onda
🔌
Protoboard 400 pts
+ cables Dupont
M-M y M-H
Resistencias 10 kΩ ×2
Pull-down pulsador
y divisor de tensión
🔋
Cable USB micro
Programación y
alimentación 5 V
🛠
Condensador 100 nF
Desacoplo salida DAC
(opcional, mejora la señal)
⚠ El ESP32 incluye dos canales DAC de 8 bits (0–3.3 V en GPIO25 y GPIO26). Para mayor resolución se puede agregar un DAC externo MCP4725 (I²C, 12-bit, ~$1 USD en Mercado Libre).
Arduino IDE · Librerías requeridas: Adafruit SSD1306 · Adafruit GFX
// ─── Generador de Señales ESP32 + OLED ───────────────────
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_W     128
#define OLED_H      64
#define POT_FREQ    34   // ADC1 canal 6 — solo entrada
#define POT_AMP     35   // ADC1 canal 7 — solo entrada
#define BTN_PIN     32   // Pulsador con INPUT_PULLUP
#define DAC_PIN     25   // DAC Canal 1 (0–3.3 V)
#define N_SAMPLES   64   // Muestras por ciclo

Adafruit_SSD1306 display(OLED_W, OLED_H, &Wire, -1);

const char* sigNames[] = {"Seno", "Cuadrada", "Triangular", "Sierra"};
uint8_t  sigType  = 0;
uint8_t  tabla[N_SAMPLES];
bool     btnPrev  = false;

// ── Precalcula tabla de N muestras ──────────────────────
void buildTable(uint8_t type) {
  for (int i = 0; i < N_SAMPLES; i++) {
    float t = (float)i / N_SAMPLES;
    float v = 0;
    switch (type) {
      case 0: v = sinf(2*M_PI*t); break;                       // Seno
      case 1: v = (t < 0.5f) ? 1.0f : -1.0f; break;            // Cuadrada
      case 2: v = (t < 0.5f) ? (4*t-1) : (3-4*t); break;      // Triangular
      case 3: v = 2*t - 1; break;                               // Sierra
    }
    tabla[i] = (uint8_t)((v + 1.0f) * 127.5f);
  }
}

// ── Dibuja forma de onda en la OLED ─────────────────────
void drawOLED(float freqHz, int amp) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print(sigNames[sigType]);
  display.print("  ");
  display.print(freqHz, 1);
  display.print("Hz  A:");
  display.print(amp);
  display.print("%");

  // Línea divisoria
  display.drawFastHLine(0, 10, OLED_W, SSD1306_WHITE);

  // Forma de onda (píxeles individuales)
  for (int x = 0; x < OLED_W; x++) {
    int idx = (x * N_SAMPLES) / OLED_W;
    int rawY = (int)(tabla[idx] * amp / 100);
    int y = 12 + (50 - rawY * 50 / 255);
    display.drawPixel(x, constrain(y, 12, 62), SSD1306_WHITE);
  }
  display.display();
}

void setup() {
  pinMode(BTN_PIN, INPUT_PULLUP);
  dacWrite(DAC_PIN, 128);  // Nivel medio al inicio
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.display();
  buildTable(sigType);
}

void loop() {
  int   rawFreq = analogRead(POT_FREQ);
  int   rawAmp  = analogRead(POT_AMP);
  float freqHz  = map(rawFreq, 0, 4095, 1, 2000);
  int   amp     = map(rawAmp,  0, 4095, 0, 100);
  long  stepUs  = (long)(1000000.0f / (freqHz * N_SAMPLES));

  // Botón: cicla entre señales
  bool btnNow = !digitalRead(BTN_PIN);
  if (btnNow && !btnPrev) {
    sigType = (sigType + 1) % 4;
    buildTable(sigType);
  }
  btnPrev = btnNow;

  // Emite un ciclo completo por el DAC
  for (int i = 0; i < N_SAMPLES; i++) {
    dacWrite(DAC_PIN, (tabla[i] * amp) / 100);
    delayMicroseconds(stepUs);
  }
  drawOLED(freqHz, amp);
}
Componente Pin ESP32 Nota
OLED SSD1306SDAGPIO 21I²C Data
OLED SSD1306SCLGPIO 22I²C Clock
OLED SSD1306VCC / GND3.3 V / GNDNo superar 3.3 V
Pot. FrecuenciaPin centralGPIO 34ADC1_CH6, solo entrada
Pot. AmplitudPin centralGPIO 35ADC1_CH7, solo entrada
Ambos potenciómetrosExtremos3.3 V / GNDDivisor de tensión
PulsadorPin AGPIO 32INPUT_PULLUP interno
PulsadorPin BGND
Salida de señalGPIO 25DAC Canal 1 (0–3.3 V)
GPIO34 y GPIO35 son de entrada únicamente (sin pull-up interno). Los potenciómetros de 10 kΩ entre 3.3 V y GND mantienen el consumo dentro del límite de 12 mA por pin del ESP32.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *