2

I'm trying to make a mildly accurate oscilloscope using Arduino Uno R3 and I've done some research on the best method to do so. First of all I need to measure the voltage with a rather high sampling rate and then I'm going to transfer my data through the serial port and plot the data using Python or Matlab.

According to what I have read the analogread() function will cause some delay and therefore some inaccuracies and thus it is not suitable for my purpose.

I found on this website some good info about how I should write my code, but I have some questions:

  1. I want my reference voltage to be 1.1 V so that by dividing it to 1023 parts I will have an accuracy of about 1 mV. How should I edit the mentioned code in order to do so?

  2. The code in the void loop() setup is of no use to me (I prefer not to save the measured data on the Arduino and then send to my PC because of memory limitations). After deleting it will the data still be sent to the serial port?

  3. Will sending the data through the serial port affect my sample rate/accuracy? I mean how does it effect my accuracy?

P.S: by mildly accurate this is what I mean: I want to measure voltage accurately with 1 mV precision for frequencies of max. 500 kHz (a bit less or more won't hurt).

ocrdu
  • 1,795
  • 3
  • 12
  • 24
infinite
  • 23
  • 3

1 Answers1

2

I want my reference voltatge to be 1.1v so that by dividing it to 1023 parts I will have the accuracy of about 1mv.

You will have a resolution of about 1 mV. The accuracy will be significantly worse than that due to the imperfections of the ADC (offset error, gain error, non-linearity) and noise.

how should I edit the mentioned code in order to do so?

The reference is configured by the bits REFS0 and REFS1 of the ADMUX register. The internal 1.1 V reference is selected by setting both bits, as shown in table 24-3 of the datasheet. You can then patch the original code like this:

@@ -8,7 +8,7 @@
   ADCSRA = 0;             // clear ADCSRA register
   ADCSRB = 0;             // clear ADCSRB register
   ADMUX |= (0 & 0x07);    // set A0 analog input pin
-  ADMUX |= (1 << REFS0);  // set reference voltage
+  ADMUX |= (1 << REFS0) | (1 << REFS1);  // set reference voltage
   ADMUX |= (1 << ADLAR);  // left align ADC value to 8 bits from ADCH register

// sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]

the code in the void loop() setup is of no use for me (I prefer not to save the measured data on the arduino and then send to my pc because of memory limitations). after deleting it will the data still be sent to the serial port?

In the linked code, loop() is the only function sending anything to the serial port. If you remove it, nothing will be sent. You could Serial.write() in the ISR though, in which case an empty loop() would be fine.

Note that writing to Serial from within an ISR is generally discouraged. Your situation though (an oscilloscope code) is one of the very few cases where it does make sense to do so.

will sending the data through the serial port affect my sample rate/accuracy?

It can certainly affect your sampling rate. Serial.write() is usually non-blocking, as all it does is write the data to the RAM-based transmit buffer. If the buffer fills up, however, Serial.write() will block waiting for the serial port to actually send the data, and make enough room in the buffer.

This means that, in order for the oscilloscope to not miss samples, you have to make sure that the serial port can send the data at least as fast as the ADC is acquiring it.

Example calculation: If you clock the ADC at 1 MHz, you get one sample every 13 µs. You can follow the example given in the code you linked to, and discard the last two bits in order to transmit only 8 bits of the sample. Transmitting those in plain binary will take 10 “bits” worth of the serial port bandwidth (one start bit, 8 data bits and one stop bit). Each bit should then take less than 1.3 µs, which translates to a baud rate of 769,231 bits per second. You will probably have no other choice than configuring the serial port for 1 Mb/s.

If you want to transmit the whole 10 bits of the ADC readings, you will have to lower the sampling rate by a factor two.

At this point you may notice that the serial port, rather than the ADC, is the bottleneck for the performance of your oscilloscope. If this is too limiting, you may consider building a scope that works by bursts: it stores a burst of samples in memory, then sends it at a leisurely rate through the serial port.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81