Simple Waveform Generator with Arduino Due
Generate waveforms by using the Arduino Due and its DAC features
Introduction
This tutorial shows how to make a simple waveform generator by using the DAC features of the Arduino Due board.
With push buttons, you will be able to choose a waveform shape (sine, triangular, sawtooth, or square) that we will send to to send to the DAC0 and DAC1 channels and change the frequency of the generated signal with a potentiometer.
Goals
- Create a simple waveform generator.
- Learn about DAC features on the DUE board.
Hardware & Software Needed
- Arduino Due
- 10K Ω potentiometer
- 2x push buttons
- 2x 10K Ω resistors
- Jumper wires
- Breadboard
- Arduino IDE (online or offline).
- Waveforms library
- Oscilloscope (optional)
Circuit
Connect power and ground on your breadboard to the Arduino. In the image below, the red (power) and black (ground) wires connect to the two long vertical rows on the breadboard, providing access to 3.3V and ground.
Connect a wire from digital pin 2 to one leg of a pushbutton. That same leg of the button connects through a pull-down resistor (10-kilohm) to ground. The other leg of the button connects to the 3.3V power.
Wire up another button in the same fashion, but to digital pin 3.
Hook up the potentiometer by connecting one side to power and the other side to ground. The pin in the middle of the potentiometer goes to analog input 0.
Pins DAC0 and DAC1 will generate the waveform. You can use an oscilloscope to visualize the generated waveforms.
Programming the Board
The waveforms are stored inside a two-dimensional array where each row represent a different waveform shape. The waveform samples are contained inside the columns, so you can access the waveform table using two indexes:
1waveformsTable[waveformIndex][samplesIndex]
With the waveformIndex array, you choose which samples to read. By incrementing the sampleIndex array from 0 to the maximum in a fixed time, you will create the waveform shape. Repeating this procedure continuously and sending the samples values on the DAC output will give you a constant signal.
In order to choose the waveform shape with a push button, match the button press to the waveformIndex increment. You can use the interrupts, triggering the the press event using the RISING option for easy access. So, when the Arduino Due sees a rising edge on the button pin, it will execute the function linked to the interrupt matched with the button:
void waveCh0_select()
and void waveCh1_select()
The potentiometer connected to analog pin 0 is used to choose the sample rate and the period of the signal is given by the sample rate multiplied for the number of the samples.
Taking into account the time for the instructions to execute, and adding the time for the analog input (around 40 µS to read the pot), maximum frequency for the signal with this sketch is around 170 Hz.
The sketch is composed of two files. One has the two-dimensional arrays, with the table of the samples for all the waveforms for legibility. Download the attached file from GitHub, or if you want to start from scratch you have to create a new folder inside your sketchbook folder and place the two files inside. The sketch file must have the same name of the folder, and the file with the sample table must be named
"Waveforms.h"
.Code
FunctionGenerator.ino
1/*2 Simple Waveform generator with Arduino Due3
4 * connect two push buttons to the digital pins 2 and 35 with a 10 kilohm pulldown resistor to choose the waveform6 to send to the DAC0 and DAC1 channels7 * connect a 10 kilohm potentiometer to A0 to control the8 signal frequency9
10 */11
12#include "Waveforms.h"13
14#define oneHzSample 1000000/maxSamplesNum // sample for the 1Hz signal expressed in microseconds15
16const int button0 = 2, button1 = 3;17volatile int wave0 = 0, wave1 = 0;18
19int i = 0;20int sample;21
22
23void setup() {24 analogWriteResolution(12); // set the analog output resolution to 12 bit (4096 levels)25 analogReadResolution(12); // set the analog input resolution to 12 bit26
27 attachInterrupt(button0, wave0Select, RISING); // Interrupt attached to the button connected to pin 228 attachInterrupt(button1, wave1Select, RISING); // Interrupt attached to the button connected to pin 329}30
31void loop() {32 // Read the the potentiometer and map the value between the maximum and the minimum sample available33 // 1 Hz is the minimum freq for the complete wave34 // 170 Hz is the maximum freq for the complete wave. Measured considering the loop and the analogRead() time35 sample = map(analogRead(A0), 0, 4095, 0, oneHzSample);36 sample = constrain(sample, 0, oneHzSample);37
38 analogWrite(DAC0, waveformsTable[wave0][i]); // write the selected waveform on DAC039 analogWrite(DAC1, waveformsTable[wave1][i]); // write the selected waveform on DAC140
41 i++;42 if(i == maxSamplesNum) // Reset the counter to repeat the wave43 i = 0;44
45 delayMicroseconds(sample); // Hold the sample value for the sample time46}47
48// function hooked to the interrupt on digital pin 249void wave0Select() {50 wave0++;51 if(wave0 == 4)52 wave0 = 0;53}54
55// function hooked to the interrupt on digital pin 356void wave1Select() {57 wave1++;58 if(wave1 == 4)59 wave1 = 0;60}
Waveforms.h
1#ifndef _Waveforms_h_2#define _Waveforms_h_3
4#define maxWaveform 45#define maxSamplesNum 1206
7static int waveformsTable[maxWaveform][maxSamplesNum] = {8 // Sin wave9 {10 0x7ff, 0x86a, 0x8d5, 0x93f, 0x9a9, 0xa11, 0xa78, 0xadd, 0xb40, 0xba1,11 0xbff, 0xc5a, 0xcb2, 0xd08, 0xd59, 0xda7, 0xdf1, 0xe36, 0xe77, 0xeb4,12 0xeec, 0xf1f, 0xf4d, 0xf77, 0xf9a, 0xfb9, 0xfd2, 0xfe5, 0xff3, 0xffc,13 0xfff, 0xffc, 0xff3, 0xfe5, 0xfd2, 0xfb9, 0xf9a, 0xf77, 0xf4d, 0xf1f,14 0xeec, 0xeb4, 0xe77, 0xe36, 0xdf1, 0xda7, 0xd59, 0xd08, 0xcb2, 0xc5a,15 0xbff, 0xba1, 0xb40, 0xadd, 0xa78, 0xa11, 0x9a9, 0x93f, 0x8d5, 0x86a,16 0x7ff, 0x794, 0x729, 0x6bf, 0x655, 0x5ed, 0x586, 0x521, 0x4be, 0x45d,17 0x3ff, 0x3a4, 0x34c, 0x2f6, 0x2a5, 0x257, 0x20d, 0x1c8, 0x187, 0x14a,18 0x112, 0xdf, 0xb1, 0x87, 0x64, 0x45, 0x2c, 0x19, 0xb, 0x2,19 0x0, 0x2, 0xb, 0x19, 0x2c, 0x45, 0x64, 0x87, 0xb1, 0xdf,20 0x112, 0x14a, 0x187, 0x1c8, 0x20d, 0x257, 0x2a5, 0x2f6, 0x34c, 0x3a4,21 0x3ff, 0x45d, 0x4be, 0x521, 0x586, 0x5ed, 0x655, 0x6bf, 0x729, 0x79422 }23 ,24
25 // Triangular wave26 {27 0x44, 0x88, 0xcc, 0x110, 0x154, 0x198, 0x1dc, 0x220, 0x264, 0x2a8,28 0x2ec, 0x330, 0x374, 0x3b8, 0x3fc, 0x440, 0x484, 0x4c8, 0x50c, 0x550,29 0x594, 0x5d8, 0x61c, 0x660, 0x6a4, 0x6e8, 0x72c, 0x770, 0x7b4, 0x7f8,30 0x83c, 0x880, 0x8c4, 0x908, 0x94c, 0x990, 0x9d4, 0xa18, 0xa5c, 0xaa0,31 0xae4, 0xb28, 0xb6c, 0xbb0, 0xbf4, 0xc38, 0xc7c, 0xcc0, 0xd04, 0xd48,32 0xd8c, 0xdd0, 0xe14, 0xe58, 0xe9c, 0xee0, 0xf24, 0xf68, 0xfac, 0xff0,33 0xfac, 0xf68, 0xf24, 0xee0, 0xe9c, 0xe58, 0xe14, 0xdd0, 0xd8c, 0xd48,34 0xd04, 0xcc0, 0xc7c, 0xc38, 0xbf4, 0xbb0, 0xb6c, 0xb28, 0xae4, 0xaa0,35 0xa5c, 0xa18, 0x9d4, 0x990, 0x94c, 0x908, 0x8c4, 0x880, 0x83c, 0x7f8,36 0x7b4, 0x770, 0x72c, 0x6e8, 0x6a4, 0x660, 0x61c, 0x5d8, 0x594, 0x550,37 0x50c, 0x4c8, 0x484, 0x440, 0x3fc, 0x3b8, 0x374, 0x330, 0x2ec, 0x2a8,38 0x264, 0x220, 0x1dc, 0x198, 0x154, 0x110, 0xcc, 0x88, 0x44, 0x039 }40 ,41
42 // Sawtooth wave43 {44 0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee, 0x110, 0x132, 0x154,45 0x176, 0x198, 0x1ba, 0x1dc, 0x1fe, 0x220, 0x242, 0x264, 0x286, 0x2a8,46 0x2ca, 0x2ec, 0x30e, 0x330, 0x352, 0x374, 0x396, 0x3b8, 0x3da, 0x3fc,47 0x41e, 0x440, 0x462, 0x484, 0x4a6, 0x4c8, 0x4ea, 0x50c, 0x52e, 0x550,48 0x572, 0x594, 0x5b6, 0x5d8, 0x5fa, 0x61c, 0x63e, 0x660, 0x682, 0x6a4,49 0x6c6, 0x6e8, 0x70a, 0x72c, 0x74e, 0x770, 0x792, 0x7b4, 0x7d6, 0x7f8,50 0x81a, 0x83c, 0x85e, 0x880, 0x8a2, 0x8c4, 0x8e6, 0x908, 0x92a, 0x94c,51 0x96e, 0x990, 0x9b2, 0x9d4, 0x9f6, 0xa18, 0xa3a, 0xa5c, 0xa7e, 0xaa0,52 0xac2, 0xae4, 0xb06, 0xb28, 0xb4a, 0xb6c, 0xb8e, 0xbb0, 0xbd2, 0xbf4,53 0xc16, 0xc38, 0xc5a, 0xc7c, 0xc9e, 0xcc0, 0xce2, 0xd04, 0xd26, 0xd48,54 0xd6a, 0xd8c, 0xdae, 0xdd0, 0xdf2, 0xe14, 0xe36, 0xe58, 0xe7a, 0xe9c,55 0xebe, 0xee0, 0xf02, 0xf24, 0xf46, 0xf68, 0xf8a, 0xfac, 0xfce, 0xff056 }57 ,58
59 // Square wave60 {61 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,62 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,63 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,64 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,65 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,66 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,67 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,68 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,69 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,70 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,71 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,72 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x073 }74
75};76
77#endif
Testing It Out
After you have uploaded the code, use the pushbuttons that you have hooked up to the breadboard to generate waveforms. If you have an oscilloscope, you can use it to visualize the different waveforms that you generate. You can control the signal frequency by using the potentiometer connected to
A0
.Troubleshoot
If the code is not working, there are some common issues we can troubleshoot:
- The wiring is incorrect.
- You have not installed or included all of the libraries.
- Make sure there are no missing curly brackets {}.
- We have not selected the right port and board.
Conclusion
In this example, we have learned how to generate waveforms by using the DAC features of the Arduino Due.
Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything wrong, you can edit this page here.
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.