Generate sound or output analog voltages with an Arduino. This Instructable will show you how to set up a really basic digital to analog converter so you can start generating analog waves of all shapes and sizes from a few digital pins on an Arduino. (This article is a companion to another Instructable I've written about sending audio into an Arduino, find that here)

Some ideas that come to mind:

sample based instrument- store samples on the Arduino or on an SD card and trigger playback with buttons or other types of controls. Check out my Arduino drum sampler for an idea of how to get started.
digital synthesizer- make saw, sine, triangle, pulse, or arbitrary waveshapes- check out my waveform generator to get started
MIDI to control voltage module/ MIDI synthesizer- receive MIDI messages and translate them into a voltage so you can control an analog synthesizer with MIDI, or use the MIDI data to output audio of a certain frequency
analog output- you may find yourself needing to generate analog voltages from your Arduino at some point, maybe to communicate with an analog device
effects box/digital signal processing- in combination with a microphone/audio input you can perform all kinds of digital signal manipulations and send the processed audio out to speakers. Check out my vocal effects box for an example.
audio playback device- make your own ipod. With the addition of an SD shield you could create your own Arduino mp3 player (check out the wave shield documentation for an idea of how to get started with the code). The circuits and code provided here are compatible with SD shields that communicate via SPI.

Feel free to use any of the info here to put together an amazing project for the DIY Audio Contest! We're giving away an HDTV, some DSLR cameras, and tons of other great stuff! The contest closes Nov 26.


(x9) 1/4 Watt 20kOhm Resistors Digikey 0KQBK-ND
(x7) 1/4 Watt 10kOhm Resistors Digiikey CF14JT10K0CT-ND
(x2) TS922IN Digikey 497-3049-5-ND I like these because they can be powered off the Arduino's 5V supply (one 924 works too, but they don't seem to be available on digikey at the moment)
(x1) 10kOhm potentiometer linear Digikey 987-1308-ND
(x1) 0.01uF capacitor Digikey 445-5252-ND
(x1) 220uF capacitor Digikey P5183-ND
(x1) 0.1uF capacitor Digikey 445-5303-ND
(x1) 1/4 Watt 3kOhm Resistor Digikey CF14JT3K00CT-ND
(x1) 1/4 Watt 10Ohm Resistor Digikey CF14JT10R0CT-ND
(x1) Arduino Uno Amazon

Additional Materials:

(1x) usb cable Amazon
(1x) breadboard (this one comes with jumper wires) Amazon
(1x) jumper wires Amazon

Step 1: Digital to Analog Converter

DAC stands for "digital to analog converter." Since the Arduino does not have analog out capabilities, we need to use a DAC to convert digital data (numbers/ints/bytes) to an analog waveform (oscillating voltage). A simple, easy to program, and cheap way to do this is to use something called an R2R resistor ladder. Essentially, it takes incoming digital bits (0V and 5V from Arduino), weights them, and sums them to produce a voltage between 0 and 5 volts (see the schematic in fig 2, taken from the Wikipedia resistor ladder page). You can think of a resistor ladder as a multi-leveled voltage divider.

The resistor ladder I'll be demonstrating in this tutorial is an 8-bit DAC, this means it can produce 256 (2^8) different voltage levels between 0 and 5v. I connected each of digital pins 0-7 to each of the 8 junctions in my 8 bit DAC (shown in figs 1 and 3).

I like using these resistor ladder DACs because I always have the materials around, they're cheap, and I think they're kind of fun, but they will not give you the highest quality audio. You can buy a chip that works in the exact same was as an R2R DAC (and will work with all the code in this instructable), but has internal, highly-matched resistors for better audio quality, I like this one bc it runs off a single 5V supply (you can even do stereo audio with it), but there are many more available, look for "parallel input, 8 bit, dac ic".

Alternatively, there are chips that take in serial data to perform digital to analog conversion. These chips are generally higher fidelity (definitely better quality that the resistor ladder DAC) and they only use two or three of the Arduino's output pins (as opposed to 8). Downsides are they are a little more challenging to program, more expensive, and will not work with the code in this Instructable, though I'm sure there are some other tutorials available. After a quick search on digikey, these looked good, for Arduino, try to find something that will run off a single 5V supply.

One more note - there seems to be kind of a misconception abut 8 bit audio- that it always has to sound like the sounds effects from a Mario game- but 8bit audio with this really basic DAC can actually replicate the sounds of people's voices and instruments really well, I'm always amazed at the quality of sound that can come from a bunch of resistors.

<p>Would you please hint to how this project or your waveform generator project (that I got from Jameco) can output a suitable Dc/Ac voltage(considering the pot max amplitude ) to be hooked up to smartphone Microphone jack , without damaging the internal circuit of the smartphone.</p><p>Do I need to do a change to the software ,hardware or the power source?</p><p>Thanks.</p>
<p>I am doing a blind stick with ultrasonic sensor and voice guide where it tells if you should go left or right. Is it possible if i use this audio output?</p>
use a text to speech chip, it will be much easier:<br />http://www.instructables.com/id/Twitter-Enabled-Text-to-Speech/
<p>Hello! Nice tutorial. I want to make a low-pass filter like you for Arduino toneAC(). With toneAC, we're sending out of phase signals on two pins. How will I connect the resistor and capacitor? I need two resistors and two capacitors connected between every pin and ground? Or is sufficient one resistor and one capacitor between one pin and ground?</p>
<p>I did a test on the timings of direct port write. I used the following pins: PB1,PB0, PD7,PD6,PD5,PD4,PD3,PD2 ()leaving PD1 and PD0 for rx/tx). </p><p>PORTD = (PORTD &amp; B00000011)|((input&lt;&lt;2)&amp;B11111100);<br> PORTB = (PORTB &amp; B11111100)|((input&gt;&gt;6)&amp;B00000011);</p><p>These two lines set the input on the aforementioned pins with direct bit-banging write method described. The result is astonishing- It only takes ~1.6 usec to execute these two lines. So for interrupt service routine you get ample time to do other processing.</p><p>Here is the code:</p><p>#include &quot;Arduino.h&quot;<br>//The setup function is called once at startup of the sketch<br>uint8_t input=100;<br>String inputString=&quot;&quot;;<br>void setup()<br>{<br>// Add your initialization code here<br> Serial.begin(115200);<br>}<br><br>// The loop function is called in an endless loop<br>void loop()<br>{<br>//Add your repeated code here<br> testSerialEvent();<br> long sTime=millis();<br> for(long i=0;i&lt;100000;i++){<br> PORTD = (PORTD &amp; B00000011)|((input&lt;&lt;2)&amp;B11111100);<br> PORTB = (PORTB &amp; B11111100)|((input&gt;&gt;6)&amp;B00000011);<br> }<br> long eTime=millis()-sTime;<br> Serial.println(eTime);<br> Serial.print(&quot;[&quot;);<br> for(int i=1;i&gt;=0;i--){<br> Serial.print(((PORTB&amp;(1&lt;&lt;i))&gt;&gt;i));Serial.print(&quot; &quot;);<br> }<br> for(int i=7;i&gt;=2;i--){<br> Serial.print(((PORTD&amp;(1&lt;&lt;i))&gt;&gt;i));Serial.print(&quot; &quot;);<br> }<br> Serial.println(&quot;]&quot;);<br> delay(1000);<br> //output-every loop takes 170 msec that mean one iteration takes ~1.7 usec. Its too good.<br><br>}<br><br>void testSerialEvent(){<br> while(Serial.available()){<br> char c=(char)Serial.read();<br> inputString += c;<br> if (c == '\n') {<br> input=inputString.toInt();<br> inputString=&quot;&quot;;<br> Serial.print(&quot;Input-&gt;&quot;);Serial.println(input);<br> break;<br> }<br> }<br>}</p>
<p>Hello, I think this tutorial is wonderful, thank you so much for posting it, however I've run into a problem now. When I hook the Arduino up to an oscilloscope, it shows a perfect sine wave. However, when I plug my Arduino into my audio interface, so I can record the output on my computer, the signal becomes truncated and only has a peak to peak voltage of 80 mV. Could you please help me understand why this is happening, and what I can do to fix it?</p><p>Thank you.</p>
<p>Hi Amanda,<br>thankyou very much, all this is great.<br>I would use this project to generate a wave and split the signal from one output to multiple guitar amps through something like a plugboard(I believe it will be connected in paralel), do i need to change something in the scheme to send a good signal to all the speakers?</p><p>Thank you :)</p>
<p>Hi Amanda,</p><p>thx for the brilliant project. I sent the 6 most significant bits to PORTD and 2 to PORTB. I used the following commands to decrease the discontinuities as much as possible and also speed up the output by using just one instruction per port:</p><p>PORTD = x[i] &amp; B11111100 | PORTD &amp; (x[i] | B00000011); <br> PORTB = x[i] &amp; B00000011 | PORTB &amp; (x[i] | B11111100);</p><p>Now I go on to the analog part.</p><p>Thx, rgds,</p><p>Gabor</p>
<p>thank you for this excellent project</p>
<p>Hi <a href="http://www.instructables.com/member/amandaghassaei/" rel="nofollow">amandaghassaei</a>! Nice work!<br>I trying to do this project but i have one big problem. I can't hind TS922IN/24 in my country! and i don't have enough time to buy from other one. Isn't an alternative for TS922IN/24?</p>
<p>Hello Sir, I want to output an analog Signal using this tutorial, but my problem is I want my input to be digital, what I mean is, someone is going to send me a bunch of bits and then I want to output them into analog, My problem is I dont know how to read that incoming bits in my arduino. Do you have any codes for reading a bits in the pin of arduino. ? </p>
<p>did u hve get the ans, if yes...can u share it =)</p>
<p>hey can i use 8 analog out put from Arduino UNO . </p>
<p>Interesting question, but I see three problems with it:</p><p>1) The Uno only has 6 analog output pins; 3, 5, 6, 9, 10, and 11.</p><p>2) The are not true analog, but instead use square waves for &quot;Pulse Width Modulations&quot;, As a result, they'd be playing tones of approximately 490 Hz and 980 Hz into your sound.</p><p>3) You need to use eight pins that are all part of an eight-bit port so that you can enter one number, such as -- <strong>PORTD = 125;</strong> -- setting all eight pins at once. Otherwise, you'd have to set one pin at a time with digitalWrite() (or analogWrite) which would take too much time to keep up with your sound waves.</p>
<p>Hey..</p><p>First off, thank you for the great tutorials.</p><p>I'm trying to incorporate your instructable into my &quot;Arduino short range walkie talkie&quot; project.<br>I'm using a mems mic (https://www.sparkfun.com/products/9868) to record my voice. Can you help me out with how to reduce lag during tranmission?<br>I've tried decreasing delay during input but that rally doesnt seem to do the job.<br> </p>
<p>HI all,</p><p>at first i would like to THNX for cool tutorial. </p><p>I tried to use as output converter MCP4921 (with AH_MCP4921.h) but i am not able to get any &quot;audible&quot; sounds. Have anybody tried this D/A converter with this solution ?</p><p>Best regards</p><p>Jan</p>
<p>Hi, thanks for this great tutorial! </p><p>I've got limited inputs, so I was looking at using a serial-in DAC chip instead of using a ladder, do you think that this <a href="http://www.digikey.com/product-detail/en/MCP4901-E%2FP/MCP4901-E%2FP-ND/2332819" rel="nofollow">http://www.digikey.com/product-detail/en/MCP4901-E...</a> (MCP4901-E/P) would work? Could I just drop it in to your schematic as long as I handle the programming correctly?</p><p>Also, I hope to power some computer speakers (with their own amp/volume control) using this circuit. Since they'd have their own volume, I assume I don't need to install a potentiometer? Would the same buffer work, or would I need something bigger to support louder/larger speakers?</p><p>Thanks</p>
<p>Yeah that chip looks good, but (as you mentioned) the code will have to change a bit. If your speakers have their own amp, you can probably get away with connecting the output of the buffer to the input of your speaker's amp. It's possible you may need a little preamp in there, in that case you can use the amp in my schematic w a resistor in place of the potentiometer.</p>
<p>It also seems I'm going to need to run off 3V instead of 5V. I know I'll need a different DAC, but other than that: I assume I'll need a different DC offset capacitor? Are there any other components I'll need to change?</p>
<p>Hey, thanks for the tutorial! </p><p>The input tutorial works great. For this one, though, TS922IN <a href="http://www.digikey.com/scripts/dksearch/dksus.dll?vendor=0&keywords=ts922in" rel="nofollow">Digikey 497-3049-5-ND</a> is obsolete. I called Digikey and <a href="http://www.digikey.com/product-detail/en/TS922IDT/497-6035-1-ND/1632064" rel="nofollow">http://www.digikey.com/product-detail/en/TS922IDT/...</a> is the closest, but it's a surface mount chip. We are just gonna solder some wires and give it a go. </p>
<p>Could the bit manipulation be used to free up Digital pins 0 and 1 for serial communication? I have only one serial communication used so I can't use software serial for that. I have this code so far: </p><p>// bit manipulation, sending number 36 to 0 and 1. PORTB: digitalPin 8-13<br>//define variables:<br>boolean bit0state;<br>boolean bit1state;</p><p>//in your main loop():<br>bit0state = (36 &amp; B00000001)&gt;&gt;0;//get the zero bit of 36<br>bit1state = (36 &amp; B00000010)&gt;&gt;1;//get the first bit of 36<br><br>//send data to portd w/o disrupting pins 0 and 1<br>PORTD |= (36&amp;B11111100);//set high pins high using the number 36 with zeros replacing bits 0 and 1<br>PORTD &amp;= (36|B00000011);//set low pins low using the number 36 with ones replacing bits 0 and 1<br><br><br>//send data to portb w/o disrupting pins 9, 10, and 11, affect 8, 12 and 13 ???<br>PORTB |= 0 | (bit3state) | (bit5state&lt;&lt;4) | (bit6state&lt;&lt;5);//set high pins<br>PORTB &amp;= 255 &amp; ~(1-bit3state) &amp; ~((1-bit5state)&lt;&lt;4) &amp; ~((1-bit6state)&lt;&lt;5);//set low pins</p><p>i'm stuck at the last part where i send data to portb, which i only want to affect pins 11 and 12, in replacement of pins 0 and 1. Am I on the right track to do this? Thanks so much!</p>
<p>is the number 36 just an example? you can send out numbers less than 64 using only six bits, so you wouldn't even have to worry about pins 8, 12, and 13.</p><p>//send data to portd w/o disrupting pins 0 and 1<br>PORTD |= ((36&lt;&lt;2)&B11111100);<br>PORTD &= ((36&lt;&lt;2)|B00000011);</p>
<p>thanks for your reply! yup 36 is just an example. following what you did for the instructable :) what if I want to &quot;shift&quot; pins 0 and 1 back to pins 11 and 12? do I have to include this part? </p><p>//send data to portb w/o disrupting pins 9, 10, and 11, affect 8, 12 and 13<br>PORTB |= 0 | (bit3state) | (bit5state&lt;&lt;4) | (bit6state&lt;&lt;5);//set high pins<br>PORTB &amp;= 255 &amp; ~(1-bit3state) &amp; ~((1-bit5state)&lt;&lt;4) &amp; ~((1-bit6state)&lt;&lt;5);//set low pins</p>
<p>PORTB |= 0 | (bit0state&lt;&lt;4) | (bit1state&lt;&lt;5);//set high pins</p><p>PORTB &= 255 & ~((1-bit0state)&lt;&lt;4) & ~((1-bit1state)&lt;&lt;5);//set low pins</p><p>I'm pretty sure that will work for pins 12 and 13</p>
thanks so much! will try it out!
<p>Thanks for this instructable, very helpful. Can i use an AD712KNZ since they dont make the 922 anymore.</p>
yes, you might also check out the lm386 bc it doesn't require a dual power supply.
<p>Hello,</p><p>Thanks for your instructable! I am now managed to use this trick on one of my 8051 microcontroller!</p>
<p>Tnank you so much~! \(≧▽≦)/~ </p><p>1Question Plz:</p><p> How can I generate a sound like Mario-Gmae? I Love 8Bit music. Make a 8Bit synthesizer is my dream. T_T</p>
<p>Hey Amanda! Great job on this instructable, I'm using it to embase my work on a eletronic drum sound generator with Arduino (hopefully, one day I'll post here how to do it).</p><p>I'm writing to ask abuot that 0.01 uF and 10ohm resistor in parallel with the speaker and the DC offset capacitor. What are they used for?</p><p>Thanks in advance! </p>
<p>thanks! they're just threre to reduce noise, not a big deal if you don't have them</p>
<p>what's the upper limit on the sampling frequency for the arudino? can i get it up to 80kHz?</p>
<p>definitely, you could get up to a few hundred kHz with no problem. </p><p>One concern is that the resistor ladder dac that I show in this ible might not respond fast enough as you increase the sampling rate - this might end up applying a low pass filter on your output. I updated step 1 with a little more info about alternative DACs, you might check out the <a target="_blank" href="http://www.digikey.com/product-detail/en/TLC7528CN/296-1871-5-ND/277516">R2R DAC IC</a> I demonstrated in <a target="_blank" href="http://www.instructables.com/id/Stereo-Audio-with-Arduino/">this Instructable</a> (you can wire it up to only use one channel if you need), it has much better quality control then just throwing a bunch of resistors together on a breadboard and I think it will give you better results. It says the settling time for that DAC is 100ns, which should work fine for 80kHz sampling rate.</p><p>you will also have to change the frequency of the interrupt. For 40kZ I used this line:</p><p>OCR0A = 49;// = (16*10^6) / (40000*8) - 1</p><p>try this instead:</p><p>OCR0A = 24;// = (16*10^6) / (40000*8) - 1</p>
Just wanted to confirm this: since the TS922IN is now obsolete, would <a href="http://www.mouser.com/Search/ProductDetail.aspx?qs=UqMwQYdMOTar844FDvZpSw%3d%3d" rel="nofollow">this</a> be a sufficient replacement? Thank you!
that's going to be really hard to work w bc it's surface mount. Just get the lm386 chip and a couple of resistors and capacitors and wire it up like this: <br />http://www.hobby-hour.com/electronics/lm386-20.gif <br />it may need a 9v supply instead of 5v, I can't remember.
<p>I'm working my way through this trying to substitute the lm386 at Step 3. The gif you linked looks like the replacement for the amplifier. I can see the part that replaces the low pass filter (thanks to your excellent explanation of what that is) but I don't see anything that I recognize as being the DAC buffer. Is the buffer unnecessary with the lm386, or is it there and I don't recognize it?<br>Thanks!<br>PS I'm a software engineer, so use small words. :-)</p>
<p>actually, a resistor and capacitor only act as a low pass filter when the output signal is connected to the junction between them, <a target="_blank" href="http://tuxgraphics.org/toolbox/circuit-design-rc.gif">here</a> is a pic. You can see that switching the order of the components will turn it into a high pass filter. The lm386 circuit is not wired up the same way, so it won't act as a low pass filter. So here's what I would do:</p><p>arduino - dac - lm386 - low pass filter - output</p><p>you could also use a tl1072 or tl082 to replace both ts922's, but these require a +/- 9v supply, which is annoying.</p>
Awesome, thanks for the help!
<p>Ibirnam Is LM386 working instead of using TS922IN ?</p>
<p>near the end of the circuit, what's the 0.1uF capacitor and 10Ohm resistor for? another kind of filter?</p>
<p>not a filter, just helps make the DC offset more stable.</p>
Can you explain the DC offset more? I understand how a +2.5VDC offset works but am confused about this one. Thanks!
<p>I always think of it like this: the signal going into one side of the capacitor causes an alternating excess of positive or negative charge on one side of the cap. The other side of the cap reacts by accumulating opposite charge - this causes an alternating voltage on the opposite side of the cap. Since no current (or a negligible amount) actually gets passed across the cap, the DC voltage on one side does not transfer over to the other side, so the alternating voltage is centered around 0.</p>
I had to replace the TS922 with an LM386. I am trying to get step 3 working. Unfortunately I don't have an oscillator to verify I did things right in step 2. My issue is that when I connect my Adruino to my breadboard with this circuit the power LED dims and my computer no longer sees the Arduino. I tried unhooking the breadboard and then loading the program to my Arduino. That worked fine. When I connected everything back up, the LED came on immediately without ramping up. Any thoughts or ideas for me?
<p>sounds like you're shorting out one of the arduino's power pins (the strip of pins near the analog inputs). Double check those.</p>
How did you write your code in those squares that you scroll?<br> &nbsp;&nbsp;

About This Instructable




Bio: I'm a grad student at the Center for Bits and Atoms at MIT Media Lab. Before that I worked at Instructables, writing code for ... More »
More by amandaghassaei:OTCA Metapixel - Conway's Game of Life "9 Degrees of Freedom" IMU Twitter Controlled Pet Feeder 
Add instructable to: