Sawtooth/ramp wave generator using arduino uno

Hello everyone,

I am struggling to create a sawtooth wave using arduino UNO R3.

I would like to end up having sawtooth waves with a certain delay from each others (have a look at the sketch). I have tried so many time to change the code, like using analogWrite instead of digitalWrite, using analogic ports, and many other attempts with no success.

//This section defines the pins on the Arduino. We specify the intigers (int) TTL1 through TTL4.
//If you expanding this to require 6 channels, uncomment the last two lines here and add additional code below where needed.
int TTL1 =5; // for optogenetic and openephys

//int TTL5 = 12;
//int TTL6 = 13; //Though, not recommend, as there are slight differences in this pin. If you must use pin 13 as a digital input, set its pinMode() to INPUT and use an external pull down resistor.

//This tells the Arduino to treat the pins as output. In this example, all channels are output. For an example with input (closed loop), see the Arduino-Simple_Closed_Loop.ino file section.
void setup() {
    pinMode(TTL1, OUTPUT);
}

//Draw out the desired waves for each channel on paper, on the same timeline, such that channel 1 appears over channel 2, etc. The condition (or state) of the Arduino changes any time any of the channels change. See the write up for more information.
//Define the number of conditions. Define the length of time (in ms) for each condition. 
int con1 = 2000;
int con2 = 10;
int con3 = 200;
int con4 = 7000;


//This is the code that the Arduino loops through. It will start on condition 1 and then move through the rest of the conditions and then auto restart back at condition 1.
//It writes each pin as High/ON or Low/Off for each condition, and the waits for the duration of condition (set above). 
void loop() {
    //Condition 1
    int i;
        for(int i = 1;  i <256;  i = i +1)
        {
        digitalWrite(TTL1,i);
        delay(con1);

digitalWrite(TTL1,LOW);
delay(con4);
}
}

![Mighty Jaagub-Gogo|690x202](upload://97dnhI8gnqJ0F2PBlhTwEwthycZ.png)

The best I can get out of this code is a square wave.

please help me, is very frustrating

You can try PWM instead:

int PWM_PIN = 5;      // Pin for generating the sawtooth wave

void setup() {
  pinMode(PWM_PIN, OUTPUT);
}

void loop() {
  for (int i = 0; i <= 255; i++) {
    analogWrite(PWM_PIN, i);    // Generate the sawtooth wave by varying the PWM duty cycle
    delay(10);                  // Delay between each step of the wave
  }
}

It's not possible to generate complicated analog waveforms directly from UNO outputs.
A DAC will work

You can generate triangles, sawtooths, sinewaves, anything.

1 Like

Hi @barshatriplee unfortunately it does not solve the problem. Any other suggestion?

barshatriplee's sketch gives out a rectangular waveform, but if you feed it in to a low pass filter, then you can get a sawtooth waveform at the output.

1st_Order_Lowpass_Filter_RC.svg

In the following oscilloscope traces, I've used barshatriplee's sketch and a low pass filter with R = 10kΩ and C = 1µF.

The yellow trace is Vin and the blue trace is Vout.


Low duty cycle, low output voltage.


Higher duty cycle , higher output voltage.


On a slower timebase the output is a sawtooth. (yellow trace turned off as the waveform is not distinguishable at this timebase).

You can't draw any current from the circuit above as loading the circuit makes the capacitor discharge more rapidly.

But you could us a buffer amplifier to give a useful output.

220px-Op-Amp_Unity-Gain_Buffer.svg

Something like this:
low pass filter and buffer

2 Likes

Hi, @zonedro

What is your application?

Can you please tell us your electronics, programming, arduino, hardware experience?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

1 Like

This link is for the Due... maybe you can reference it? It uses "lookup tables"

Wrong, this is what I created from a Uno, just by using a PWM output and an RC restoration filter.

A full cycle of a sin wave followed by one and two halves of a saw tooth. Complex enough for you?

2 Likes

Why don't you do something useful, like suppling the code and a schematic.

1 Like

Well once I have corrected you I can do it the OP is interested, awaiting his/her interest.

Or are you itching to Poo Poo it, you often are. Well here is the complex restoration filter.

The software is to be found here from the code from my book:-

You need chapter 12, listing 12-1 for the saw tooth example.

1 Like

consider using a ESP32 (or Due) which has two DACs
e.g. generate sawtooth waveform and a pulse

// ESP32 DAQ using  timer interrupts 100000times/second to 
// generate sawtooth wave and pulse using 100 sample lookup table

// adapted from ESP32 Sine Wave Example https://deepbluembedded.com/esp32-dac-audio-arduino-examples/

#include <driver/dac.h>

// Timer0 Configuration Pointer (Handle)
hw_timer_t *Timer0_Cfg = NULL;

// Sine LookUpTable & Index Variable
uint8_t SampleIdx = 0;
uint8_t lookupTable1[100], lookupTable2[100];

volatile int counter = 0;

// The Timer0 ISR Function (Executes Every Timer0 Interrupt Interval)
void IRAM_ATTR Timer0_ISR() {
  // Send SineTable Values To DAC One By One
  dac_output_voltage(DAC_CHANNEL_1, lookupTable1[SampleIdx++]);
  dac_output_voltage(DAC_CHANNEL_2, lookupTable2[SampleIdx++]);
  if (SampleIdx == 100) {
    SampleIdx = 0;
  }
  counter++;
}

void setup() {
  Serial.begin(115200);
  Serial.println("\nESP32 DAC sine wave");
  // Configure Timer0 Interrupt
  Timer0_Cfg = timerBegin(0, 80, true);
  timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
  timerAlarmWrite(Timer0_Cfg, 10, true);
  timerAlarmEnable(Timer0_Cfg);
  for (int i = 0; i < 50; i++)
    lookupTable1[i] = i * 4;
      for (int i = 20; i < 30; i++)
      lookupTable2[i]=200;

  // Enable DAC1 Channel's Output
  dac_output_enable(DAC_CHANNEL_1);
  dac_output_enable(DAC_CHANNEL_2);
}

void loop() {
  static long timer = millis();
  if (millis() - timer > 1000) {
    Serial.println(counter);
    counter = 0;
    timer = millis();
  }
}

result
image

Nice job and the OP doesn't need to buy a book

to be fair to both parties here maybe you could say @Grumpy_Mike has partially corrected @jim-p . While you can generate complicated waveforms it's always going to be at a much lower frequency than a true DAC. So if the definition of complicated involves high frequency (with high resolution) then @jim-p I would say is still partially correct. @Grumpy_Mike is also quite right to note that complex waveforms that can be generated at low frequencies. My guess is that the OP is probably looking in the frequency range where PWM would be just fine but I can't quite work that out from the code posted. @zonedro could you say what is the ramp time of your sawtooths?

How diplomatic!

Thank you

With delays of 2000ms and 7000ms in zonedro's original (flawed) sketch, the frequency can't be very high.

Unfortunately it looks as though we have scared zonedro off.

1 Like

Hello @JohnLincoln . Not so scared, just busy. Could you please explain why flawed code? What's wrong?

Tomorrow I will have my arduino due and tey out this code. Thanks for your reply

Hi @Grumpy_Mike . Could you please revise my original code and see what's going on and why does it not produce an output like in the pics?

Hello @JohnLincoln .could you please revise my code and adding the low pass filter in order to have the final output as in the pics in the attachments?