As per the given task, we need to generate a triangular waveform using DAC
In this task, we will be using the ESP32’s built-in DAC to generate the analog triangular waveform.
Additionally, we need to control the amplitude and frequency of the waveform using two potentiometers.
To achieve this, the potentiometers will be connected to two different ADC channels (GPIO pins) of the ESP32.
Based on their values, the waveform will change amplitude and frequency changes in real time
We are generating a smooth triangle waveform using the ESP32's built-in DAC. And the shape and speed of the wave adjust in real-time using two potentiometers:
The waveform is output as an analog voltage signal on GPIO25 (DAC1).
#define DAC_PIN 25 // GPIO25 = DAC1
#define AMP_POT_PIN 34 // Pot 1 for amplitude
#define FREQ_POT_PIN 35 // Pot 2 for frequency
// Global variables
int amplitude = 128; // Default amplitude (mid-range)
float frequency = 250; // Default frequency (mid-range)
unsigned long lastPotReadTime = 0;
const unsigned long POT_READ_INTERVAL = 100000; // Read pots every 100ms
// Wave generation variables
int currentValue = 0;
bool rising = true;
unsigned long lastStepTime = 0;
long delaySteps = 0;
int readAvg(int pin, int samples = 5) { // Reduced samples for speed
int sum = 0;
for (int i = 0; i < samples; i++) sum += analogRead(pin);
return sum/samples;
}
void setup() {
Serial.begin(115200);
analogReadResolution(12);
}
void loop() {
unsigned long currentTime = micros();
// 1. Read pots every 100ms (non-blocking)
if (currentTime - lastPotReadTime >= POT_READ_INTERVAL) {
lastPotReadTime = currentTime;
int ampRaw = readAvg(AMP_POT_PIN);
int freqRaw = readAvg(FREQ_POT_PIN);
amplitude = map(ampRaw, 0, 4095, 1, 255); // Ensure amplitude ≥ 1
frequency = map(freqRaw, 0, 4095, 1, 500); // Target: 1Hz–500Hz
// Calculate the delay between each DAC step in microseconds.
// Formula: delaySteps = 1000000L (1 second in µs) / total number of DAC steps per waveform.
// A full triangle wave has 2 * amplitude steps (rising + falling).
// So, for a given frequency and amplitude, the total time per waveform is 1/frequency,
// and each DAC step must occur at:
// delaySteps = 1,000,000 µs / (2 * amplitude * frequency)
delaySteps = 1000000L / (2 * amplitude * frequency);
}
// 2. Generate a triangle wave (non-blocking)
if (currentTime - lastStepTime >= delaySteps) {
lastStepTime = currentTime;
dacWrite(DAC_PIN, currentValue);
if (rising) {
currentValue++;
if (currentValue >= amplitude) rising = false;
} else {
currentValue--;
if (currentValue <= 0) rising = true;
}
}
}
readAvg()
: This function reads the ADC value 5 times & returns the average of the ADC values.
analogReadResolution(12)
: Set ADC resolution to 12-bit.
loop()
:
if (currentTime - lastPotReadTime >= POT_READ_INTERVAL) :
This checks if 100,000 microseconds have passed. delaySteps
using:delaySteps = 1000000 / (2 * amplitude * frequency);
Generating the Triangle Wave
delaySteps
microseconds, we either:currentValue
by 1 if we’re going up, oramplitude
) or bottom (0), we flip the direction using the rising
flag.currentValue
is sent to the DAC via dacWrite()
.Video