#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// === Configuración ===
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define PUNTOS 100 // Número de puntos para generar la onda
#define TIEMPO_PANTALLA 0.1 // Tiempo de visualización en segundos
// Pines
#define POT_AMPLITUD 34 // Potenciómetro de amplitud
#define POT_FRECUENCIA 35 // Potenciómetro de frecuencia
#define BOTON 15 // Botón selector de onda
#define DAC_PIN 25 // Pin DAC
// === Variables globales ===
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int tipoOnda = 1; // 1=Senoidal, 2=Cuadrada, 3=Triangular
float formaOnda[PUNTOS]; // Array para almacenar la forma de onda
int indice = 0; // Índice actual en la forma de onda
int estadoAnteriorBoton = HIGH;
int lecturaAnteriorAmplitud = 0;
int lecturaAnteriorFrecuencia = 0;
unsigned long tiempoAnterior = 0;
unsigned long tiempoAntirrebote = 200;
int contadorActualizacion = 0;
float amplitud = 1.65; // Amplitud en voltios
float frecuencia = 1.0; // Frecuencia en Hz
const char* nombresOndas[] = {"SEN", "CUA", "TRI"};
// === Declaración de funciones ===
void generarSenoidal();
void generarTriangular();
void generarCuadrada();
void cambiarFormaOnda();
void aumentarFrecuencia();
void aumentarAmplitud();
void generarOnda(int tipo);
float mapearFrecuencia(int valorCrudo);
float mapearAmplitud(int valorCrudo);
int voltajeAY(float voltaje);
void actualizarPantalla();
// === Setup ===
void setup() {
Serial.begin(115200);
// Inicializar OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Error al inicializar OLED"));
for(;;);
}
// Pantalla de inicio
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println("Generador ON");
display.display();
delay(1000);
// Configurar pines
pinMode(BOTON, INPUT_PULLUP);
pinMode(POT_AMPLITUD, INPUT);
pinMode(POT_FRECUENCIA, INPUT);
// Generar forma de onda inicial
generarOnda(tipoOnda);
lecturaAnteriorAmplitud = analogRead(POT_AMPLITUD);
lecturaAnteriorFrecuencia = analogRead(POT_FRECUENCIA);
}
// === Loop principal ===
void loop() {
// Detectar cambio de forma de onda
cambiarFormaOnda();
// Actualizar amplitud y frecuencia
aumentarAmplitud();
aumentarFrecuencia();
// Generar señal según el tipo de onda
switch(tipoOnda) {
case 1:
generarSenoidal();
break;
case 2:
generarCuadrada();
break;
case 3:
generarTriangular();
break;
}
// Actualizar pantalla periódicamente
actualizarPantalla();
// Avanzar al siguiente punto
indice = (indice + 1) % PUNTOS;
// Calcular retardo para mantener la frecuencia
float tiempoRetardo = 1000000.0 / (PUNTOS * frecuencia); // en microsegundos
delayMicroseconds((int)tiempoRetardo);
}
// === Funciones de generación de señales ===
void generarSenoidal() {
// Generar voltaje desde la forma de onda precomputada
float voltaje = 1.65 + formaOnda[indice] * amplitud / 2;
int valorDAC = (int)((voltaje / 3.3) * 255);
valorDAC = constrain(valorDAC, 0, 255);
dacWrite(DAC_PIN, valorDAC);
}
void generarTriangular() {
// Generar voltaje desde la forma de onda precomputada
float voltaje = 1.65 + formaOnda[indice] * amplitud / 2;
int valorDAC = (int)((voltaje / 3.3) * 255);
valorDAC = constrain(valorDAC, 0, 255);
dacWrite(DAC_PIN, valorDAC);
}
void generarCuadrada() {
// Generar voltaje desde la forma de onda precomputada
float voltaje = 1.65 + formaOnda[indice] * amplitud / 2;
int valorDAC = (int)((voltaje / 3.3) * 255);
valorDAC = constrain(valorDAC, 0, 255);
dacWrite(DAC_PIN, valorDAC);
}
// === Función para cambiar forma de onda ===
void cambiarFormaOnda() {
unsigned long tiempoActual = millis();
int estadoBoton = digitalRead(BOTON);
if (estadoBoton == LOW &&
estadoAnteriorBoton == HIGH &&
(tiempoActual - tiempoAnterior) > tiempoAntirrebote) {
// Cambiar tipo de onda (1→2→3→1...)
tipoOnda = (tipoOnda % 3) + 1;
generarOnda(tipoOnda);
tiempoAnterior = tiempoActual;
}
estadoAnteriorBoton = estadoBoton;
}
// === Función para aumentar/ajustar frecuencia ===
void aumentarFrecuencia() {
int lecturaFrecuencia = analogRead(POT_FRECUENCIA);
frecuencia = mapearFrecuencia(lecturaFrecuencia);
lecturaAnteriorFrecuencia = lecturaFrecuencia;
}
// === Función para aumentar/ajustar amplitud ===
void aumentarAmplitud() {
int lecturaAmplitud = analogRead(POT_AMPLITUD);
amplitud = mapearAmplitud(lecturaAmplitud);
lecturaAnteriorAmplitud = lecturaAmplitud;
}
// === Funciones auxiliares ===
void generarOnda(int tipo) {
for (int i = 0; i < PUNTOS; i++) {
float x = (float)i / PUNTOS;
if (tipo == 1) { // Senoidal
formaOnda[i] = sin(2 * PI * x);
}
else if (tipo == 2) { // Cuadrada
formaOnda[i] = (x < 0.5) ? 1.0 : -1.0;
}
else if (tipo == 3) { // Triangular
formaOnda[i] = (x < 0.5) ? (4 * x - 1) : (-4 * x + 3);
}
}
}
float mapearFrecuencia(int valorCrudo) {
// Mapea 0-4095 a 0.5-50 Hz
return 0.5 + (valorCrudo / 4095.0) * (50.0 - 0.5);
}
float mapearAmplitud(int valorCrudo) {
// Mapea 0-4095 a 0-3.3V
return (valorCrudo / 4095.0) * 3.3;
}
int voltajeAY(float voltaje) {
// Convierte voltaje (0.4-2.9V) a coordenada Y (8-62)
voltaje = constrain(voltaje, 0.4, 2.9);
return (int)(62 - ((voltaje - 0.4) / (2.9 - 0.4)) * 54);
}
void actualizarPantalla() {
static int lecturaAmplitud = 0;
static int lecturaFrecuencia = 0;
lecturaAmplitud = analogRead(POT_AMPLITUD);
lecturaFrecuencia = analogRead(POT_FRECUENCIA);
contadorActualizacion++;
if (contadorActualizacion >= 10 ||
abs(lecturaAmplitud - lecturaAnteriorAmplitud) > 5 ||
abs(lecturaFrecuencia - lecturaAnteriorFrecuencia) > 5) {
// Limpiar área de gráfico
display.fillRect(0, 8, 128, 56, BLACK);
// Calcular cuántos puntos mostrar
float muestras = frecuencia * TIEMPO_PANTALLA * PUNTOS;
// Dibujar forma de onda
for (int x = 0; x < 127; x++) {
float fase1 = (x / 128.0) * muestras;
float fase2 = ((x + 1) / 128.0) * muestras;
int i1 = (int)fase1 % PUNTOS;
int i2 = ((int)fase1 + 1) % PUNTOS;
int j1 = (int)fase2 % PUNTOS;
int j2 = ((int)fase2 + 1) % PUNTOS;
float fraccion1 = fase1 - (int)fase1;
float fraccion2 = fase2 - (int)fase2;
// Interpolación lineal
float valor1 = formaOnda[i1] * (1 - fraccion1) + formaOnda[i2] * fraccion1;
float valor2 = formaOnda[j1] * (1 - fraccion2) + formaOnda[j2] * fraccion2;
float voltaje1 = 1.65 + valor1 * amplitud / 2;
float voltaje2 = 1.65 + valor2 * amplitud / 2;
int y1 = voltajeAY(voltaje1);
int y2 = voltajeAY(voltaje2);
display.drawLine(x, y1, x + 1, y2, WHITE);
}
// Dibujar ejes
display.drawFastVLine(0, 8, 56, WHITE);
display.drawFastHLine(0, voltajeAY(1.65), 128, WHITE);
// Limpiar barra de estado
display.fillRect(0, 0, 128, 8, BLACK);
// Mostrar información
display.setCursor(0, 0);
display.print("A=");
display.print(amplitud, 2);
display.print(" F=");
display.print(frecuencia, 1);
display.print("Hz");
// Tipo de onda
display.setCursor(90, 55);
display.print(nombresOndas[tipoOnda - 1]);
display.display();
lecturaAnteriorAmplitud = lecturaAmplitud;
lecturaAnteriorFrecuencia = lecturaFrecuencia;
contadorActualizacion = 0;
}
}