Use your Arduino and PC as a fast Storage Oscilloscope.

The Arduino can reliably gather voltage readings at a frequency of between 141 and 153 KiloHertz.

1000 data readings can be taken in around 6.8ms .

Transfered to a PC, these points can be accurately plotted against time.
This Instructable will show you how the analogue input can be repeatedly added to a 1000 byte buffer and then transferred to a serial monitor. The data is collected using a high frequency interrupt, whose period can be accurately determined. The frequency can be altered to produce a range of possible periods.

I have written a PC interface to display the data and control the arduino. My PC program is presented as is - it would take a very long instructable to explain it!

The data output from the Arduino is not complex. I am sure others will write interfaces for the operating system of their choosing ....

I have written two slightly different versions for the Arduino data capture. One utilizes software triggering for when an accurate change in voltage is required, before the oscilloscope triggers. The second, uses hardware edge triggering based on an interrupt on Arduino pin 2. The hardware version runs a little faster at the highest frequency.


I did a minor rewrite today (31/8/2014). The PC interface now includes the option to set the voltage reference to accurately reflect the real value of the Arduino "5V" line. There are also small adjustments to the Arduino software.


As of 6/9/2014 I have developed a slightly modified version of the Software Triggered version which runs at up to 227.3 KHz on my Mega, using register commands to directly control single conversion reads. If there is interest, let me know.

The ADC Arduino Mega information is to be found in pages 242-260 of the Amtel atmega328p manual.


As of 29/9/2015 the PC and Arduino software have been updated.

The video is best viewed in High definition (720p), full screen:

Step 1: Requirements

Arduino Mega 2560 (Let me know if other arduino types work)

The following component works- alternatives may be viable (with program tweaking- I leave that to you!)

LCD Keypad Shield http://www.hobbytronics.co.uk/arduino-lcd-keypad-...


Simple Buffer box to accept analogue voltages: (Only required if you don't already have voltage buffers)

NE5534P op amp

22pf, 10nf capacitors

Two 100K variable resistors

22K, 4k7, 12K, two 470K resistors, 0.25W ok

10K precision resistor (1%)

Two 1K variable resistors

10uF electrolytic capacitor, 16V or more

Copper Stripboard, Plastic Box, Connectors and soldering equipment

A multimeter

Balanced +-9V supply (At least +-6V is needed to allow the NE5534P to produce 5V at the output)


A PC with a windows operating system. I have tested my interface on XP, Windows 7 and windows 8.

(Or make your own software interface.)

<p>My latest version runs at up to 238 Khz, has a touchscreen lcd and additional signal analysis. It can also log the the data to an SD card.</p>
<p>Dear David,</p><p>can you give the code?</p><p>Regards</p><p>Pacman</p>
<p>Following limited interest I have placed a copy of my 238Khz oscilloscope software at:</p><p><a href="http://www.davepatterson.me.uk/public/OscilloscopeTurbosainlibpot.zip" rel="nofollow">http://www.davepatterson.me.uk/public/Oscilloscope...</a></p><p>The code has adequate annotation. I offer it without support.</p><p>The required hardware:</p><p>Arduino mega 2560</p><p>Sainsmart 3.2 inch lcd and shield: $24.99 </p><p><a href="http://www.sainsmart.com/sainsmart-3-2-tft-lcd-display-sainsmart-tft-lcd-adjustable-shield-for-arduino-2560-r3-1280-a082-plug.html" rel="nofollow">http://www.sainsmart.com/sainsmart-3-2-tft-lcd-di...</a></p><p>A sd card to fit the sainsmart shield (less than 2GB)</p><p>A good quality potentiometer between 5V and ground with the wiper to analogue 4. Any value that will not pull a large current. (This sets the trig level)</p><p>Any signal conditioning circuit of your choice- connected to analogue 0.</p><p>David</p>
<p>Thank You for sharing Your work! Recently I got big interest in simple DIY scopes, I was collecting resources and projects around the Net, and found this yours too. Can not try it right away, need to get display, but I am pretty sure I will. From Your point of view, will be there modifications, or is it okay &quot;as is&quot;, and should be considered final? Thanks!</p>
<p>Hi JurisP1,</p><p>my 238KHz code is the fastest internal ADC version I have written. It uses a mega and a colour touch screen display by sain.</p><p>I have written code to run at 1.2 MHz. using the parallel interface on the ADC TLV571 chip.</p><p>As a starting point, the code and details in this instructable work well.</p><p>Regards,</p><p>David</p>
<p>Thanks for answer! Yes, I did see on YouTube Your video with external ADC, are details and code of that also public somewhere? Thank You!</p>
<p>Sorry, no.</p>
<p>Hi Pacman,</p><p>should there be sufficient interest, I may write an instructable over the winter months. </p><p>You will find this a useful starting point on using the mega with a touch screen:</p><p><a href="https://www.instructables.com/id/Make-an-Oscilloscope-Using-the-SainSmart-Mega2560-/?ALLSTEPS" rel="nofollow">https://www.instructables.com/id/Make-an-Oscillosco...</a></p><p>.</p><p>Regards,</p><p>David</p>
<p>Dear David,</p><p>thank you for that very useful instruction. </p><p>However, I got the problem that your oscilloscope software on the PC does not connect properly to the serial port.</p><p>The Arduino serial monitor works well (on COM3), i.e. proper replies are comming. But when trying to capture in your oscilloscpe application, the message &quot;The arduino timed out&quot; comes. Nothing is displayed. If I leave the serial monitor open at the same time, I get the message &quot;Data handling error 8005 Port already open&quot;. Means that connection is tried on the right port. What could be?</p><p>By the way: I changed the texts as sent by Arduino a bit. I hope this cannot cause the problem.</p><p>I am running the PC under Windows 8.</p><p>Best Regards</p><p>Albert</p>
<p>Hi Albert,</p><p>A couple of things to establish:</p><p>What version of the arduino operating system are you using?</p><p>Did you install the chart support and ocx files successfully?</p><p>Using the original software triggering version:</p><p>What does the lcd show? (take a picture)</p><p>Have you set the visual basic oscilloscope software to a baud rate of 115200?</p><p>I suggest a junk wait of 0 and timeout Never. (Default installation timeout is 30 seconds)</p><p>What happens when you click on port 3 on the pc oscilloscope? ( Take a screen shot)</p><p>What happens when you select capture on the pc oscilloscope (Take a screen shot)</p><p>I have checked the zip files on a windows 8 pc a few minutes ago - everything installed and ran ok.</p><p>It would be useful if you could post the picture and screen shots</p><p>Remember there is a pwm square wave option-</p><p>send test from the pc oscilloscope and the connect port 3 to analogue 1</p><p>Cheers,</p><p>David</p>
<p>Hello David,</p><p>thank you for your quick reply. You helped me already! It was the &quot;junk wait&quot; parameter which I had not understood and which I set to 3 just in the believe &quot;the higher the better&quot;. Sorry! </p><p>By the way: How did you increase the sample rate to 238 Khz?</p><p>Regards</p><p>Albert</p>
<p>Hi Albert,</p><p>Glad you got it sorted.</p><p>To achieve the turbo rate requires taking control of analogue data capture completely. I might write a detailed instructable on this later this year. Here are the key points (good luck) :</p><p>// Defines for setting register bits<br>#ifndef mysbi<br>#define mysbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))<br>#endif</p><p>#define BUF_SIZE 1000;</p><p>const byte check = 1&lt;&lt;ADSC;</p><p>boolean triggered;</p><p>boolean writeit;</p><p>byte oldval, newval;</p><p>cli(); // disable interrupts<br>ADCSRA = 0; // clear ADCSRA register<br>ADCSRB = 0; // free running - only has effect if ADATE in ADCSRA=1<br>ADMUX |= adport; //set up continuous sampling of analog pin adport <br>ADMUX |= (1 &lt;&lt; REFS0); // set reference voltage to Vcc<br>ADMUX |= (1 &lt;&lt; ADLAR); // left align the ADC value- so we can read highest 8 bits from ADCH register only</p><p>ADCSRA |= (1 &lt;&lt; ADPS1); // prescalar 4<br> mysbi(ADCSRA,ADEN); // enable ADC<br> sei(); // enable interrupts</p><p><br> /* Fast read via registers<br> cf pages 242-260 of ATmega328P manual<br> &quot;A single conversion is started by writing logical 1 to<br> the ADC Start conversion bit ADSC. This bit stays high<br> as long as the conversion is in progress and will be cleared<br> by hardware when the conversion is completed.&quot; <br><br> &gt;= 237.2 KHz !!!!!<br> */<br><br> // First conversion- initialises ADC<br> mysbi(ADCSRA,ADSC);<br> while((ADCSRA &amp; check)== check); // wait for ADSC byte to go low<br> // New conversion and use current ADCSRA value for trigger<br> byte startit = ADCSRA | check;<br> ADCSRA = startit;<br> while (!triggered){<br> // wait for adc conversion <br> while((ADCSRA &amp; check)== check);<br> newval = ADCH;<br> // New conversion<br> ADCSRA = startit;<br> trip = newval-oldval;<br> if(!trigplus) trip = -trip;<br> if (trip &gt; trigger) triggered=true; else oldval=newval;<br> }<br> starttime=micros();<br> for(unsigned int i = 0; i &lt; BUF_SIZE; i++){<br> // wait for conversion<br> while((ADCSRA &amp; check)== check);<br> bufa[i]=ADCH;<br> // New conversion<br>ADCSRA = startit;<br> } <br> endtime=micros();<br> mycbi(ADCSRA,ADEN); // disable ADC<br> writeit=true;<br> }<br>}</p><p>Cheers,</p><p>David</p>
<p>Hi David,</p><p>thanks for your description. If I understand correctly, you make two things:</p><p>- You don't use the auto trigger mode. Instead you set the ADSC bit &quot;manually&quot; each time you have read the conversion value.</p><p>- You are waiting for the conversions completed in the main loop by polling the ADSC bit to go low. Means you don't use an interrupt service routine (O.k. but why is there the sei() command after setting the ADC?).</p><p>What of the two measures brings the main effect?</p><p>Best Regards</p><p>Albert </p>
<p>Hi Albert,</p><p>1) Yes to no auto trigger and initiate adc conversion directly.</p><p>2) Yes to waiting for end of conversion.</p><p>3) sei() required because cli() used prior to altering registers. It is not good practice to change registers with the possibility of a system interrupt affecting the change.</p><p>4) The speed is gained by not allowing repeated readings on a dedicated adc port to be interrupted. Both 1) and 2) are required to achieve this. Without 2) successive readings would be un-reliable at best.</p><p>I admit to having to study the atmega manual repeatedly before evolving this code.</p><p>There are easier ways to get an (even) higher frequency scope- The 1.2 Mhz TLV571 adc chip is relatively easy to use and has a parallel interface.</p><p>Regards,</p><p>David</p>
<p>Hi David,</p><p>thank you very much for the explanations.</p><p>I selected your example mainly to learn about optimal use of the ADC functions. As a by-product I may use the data sampling functions for &quot;hardware debugging&quot; in later projects. An external ADC chip seems to be not necessary for the moment.</p><p>Best Regards</p><p>Albert </p>
<p>Analogue to digital converter TLV571. 1179KHz.</p><p>View video in HD fullscreen:</p><p>.</p><p><iframe allowfullscreen="" frameborder="0" height="281" src="//www.youtube.com/embed/ElW326jNbQY" width="500"></iframe></p><p>.</p>
<p>Re the turbo code:</p><p>I missed including this definition-</p><p>// Defines for clearing register bits<br>// will not work with certain loaded libraries if called cbi (same applies to sbi)<br>#ifndef mycbi<br>#define mycbi(sfr, bit) (_SFR_BYTE(sfr) &amp;= ~_BV(bit))<br>#endif</p><p>.</p><p>Open the video full screen:</p><p><iframe allowfullscreen="" frameborder="0" height="281" src="//www.youtube.com/embed/_HgqC2uYQQA" width="500"></iframe></p>
<p>I only just came across this David. Very well put together intstructable, and thank you very much for sharing your knowledge. I'll be following any future work with interest.</p>
<p>Very nice! One option (for about the same cost) is to use the Teensy 3.1 (http://www.pjrc.com/teensy/teensy31.html) which is a lot faster, especially the A/D conversion (I think it can be done with DMA).</p>
<p>A useful link.</p><p>The teensy appears to be 3.3V based. So the Arduino and PC program would run incorrectly, without modification. I have no idea whether the same interrupts and register controls are available on the Teensy. The serial route out is also unclear to me. Not exactly a drop in solution?</p>
<p>Indeed, with the Teensy 3.1 running at 72 Meg and with 64k RAM it seems to me that this beautiful PC interface could be done justice!! We could be looking at a scope fast enough to debug normal Arduinos!!</p>
<p>please more info on how to utilise the ADC register. i really need to learn the details</p><p> plez!!!</p>
<p>Hi KipsD,</p><p>The code is fully annotated.</p><p>Have a look at step 3 above and void startad() plus ISR(ADC_vect) in the code.</p><p>Refer to pages 242-260 of the amtel manual I attached to the first page. </p><p>There is also information in step 6 of my instructable on saving wav files:</p><p><a href="https://www.instructables.com/id/Arduino-Mega-Audio-File-logging/?ALLSTEPS" rel="nofollow">https://www.instructables.com/id/Arduino-Mega-Audio...</a></p><p>Let me know if something fails to make sense.</p>
<p>i'm very preciate your reply. </p><p>i'm very sorry to ask this question. </p><p>i have 1 question instead of doing 1000 reading. can i use the adc interupt to take a reading between 1 second which is control by timer 1 interupt and each time the interupt timer1 is flagged it will take realtimeclock calculation. </p><p>example:</p><p>timer 1 interupt each second to take the rtc value.</p><p>during interval of one second the adc will kick on reading and display on serial monitor with the rtc value(like timestamp). </p><p>will it work? </p><p>right now i experimenting on how fast the the data can be recorded using arduino , but i'm not so good on programing. <br><br>so far i only know how to manipulate the ADC clock and still learning ADC interupt.</p>
<p>Hi,</p><p>If you only want to take 1 reading every second, your question is not really anything to do with rapid data analysis.</p><p>For 1 period of 1s I suggest polling the millis() function and look for the difference between the current millis() time and the loop start time being a multiple of 1000 mS. No need to set up an interrupt, manipulate the adc clock, or alter the number of bits the adc returns. The calls to the rtc device will be chip specific and are well documented for common devices.</p><p>With a 1 second interval you will have time to output to the serial monitor within the interval.</p><p>Note that, if you do set the code within an interrupt routine, you can not output to the serial monitor from within the interrupt service routine. Depending on the interrupt used millis() can be affected.</p><p>The millis() function resets to zero (&quot;rolls over&quot;) after a number of days- not a problem if you run your program non continuously. However for a continuous logging situation you will need to allow for the reset in your code.</p>
I'm sorry for the misinformation about the reading<br>I want to take rapid reading between the the timer 1 interupt which occur every second..<br>My purpose is take 500 reading or more to plot a smooth sinewave for 1volt AC (50 herzt) input signal..
<p>I still would not use an interrupt to initiate a process which has a period of 1 s.</p><p>The 500 readings will require an interrupt service routine (Or code which starts a new adc reading directly) You will need to store the readings in memory and then output to the serial port.</p><p>If you study my code the continuous run option will do the work for you. Add a suitable delay to the run re-start section and you will be nearly there.</p>
<p>A great and well written instructable very detailed and very interesting. thank you for sharing.</p>
Thanks for that!
<p>Cool! Thanks for sharing this!</p>

About This Instructable




More by DavidPatterson:Arduino Mega GPS with LCD and SD Logging Arduino High speed Oscilloscope with PC interface Playing audio sound files ( wav ) with an Arduino 
Add instructable to: