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:
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?
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?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).
-
That’s an interesting question, even if only to define the limits of "mildly accurate" imposed by the Uno platform. You may need to break your coding down a piece at a time, asking all three questions at once may constrain the answers you receive. I think the analogReference() function may assist with the first question. arduino.cc/reference/en/language/functions/analog-io/…RowanP– RowanP2022年06月25日 10:31:06 +00:00Commented Jun 25, 2022 at 10:31
-
@rowanp thanks for the help with analogreference. I will edit the question for better defining mildly accurate.infinite– infinite2022年06月25日 11:52:43 +00:00Commented Jun 25, 2022 at 11:52
-
When ever hardware is pushed to its limits I find one needs to be very familiar with both the hardware and software. Just for starters, consider Python is 100s if not over 1000 times slower then, say, compiled C. I say this even though it sounds like you are running Python on other than an Arduino. At the other end of the spectrum, even though the ADC has 10 bits this does not necessarily mean you can get 1024 steps of resolution for any single sample. Noise will likely reduce this considerably.st2000– st20002022年06月25日 15:31:07 +00:00Commented Jun 25, 2022 at 15:31
-
@st2000 I understand that Python is much slower than C. So will using Matlab as the data analyzer on the other end give better results? since it is C-based or should I just test that?infinite– infinite2022年06月25日 15:39:24 +00:00Commented Jun 25, 2022 at 15:39
-
2You won't get anywhere near 500 kS/s (kilosamples per second) with an Uno. The ADC accuracy degrades as you speed up its clock, and it becomes essentially garbage past 1 MHz (which gives 76.9 kS/s). See ADC conversion on the Arduino, by Nick Gammon.Edgar Bonet– Edgar Bonet2022年06月25日 20:02:13 +00:00Commented Jun 25, 2022 at 20:02
1 Answer 1
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.
-
1You might want to consider using a Teensy 3.x or Teensy 4.x instead of an Arduino R3. Teensy 4.1 has a CPU speed of 600MHz vs R3 of 16MHz. Both use Arduino, and both are in the same price rangestarship15– starship152022年06月28日 19:39:43 +00:00Commented Jun 28, 2022 at 19:39
Explore related questions
See similar questions with these tags.