An analog-to-digital converter (or ADC for short) is a device or microcontroller feature which converts an analog input voltage to a numeric value which a user program can use.

The output resolution of the number received from and ADC can vary from 8-bit to 24-bit, corresponding to the number of digital discrete outputs and the smallest detectable difference between input voltage.

## Principles

Digital circuits like a microcontroller or computer can only understand binary logic. However, sensors such as the VEX Line Tracker and VEX Gyro often provide a continuously varying output voltage level. Since a standard digital input would do a poor job, providing a useless 1-bit value, an analog-to-digital converter is used to convert the voltage to a number. Common ADCs vary from 8-bit to 16-bit precision, which dictates how many different values could theoretically be produced by an input voltage. In practice, noise limits the precision of any ADC to between 0.5 and 2 bits less than its stated value.

Many ADCs found in microcontroller applications operate on SAR (successive approximation register) principles. This method begins by guessing a number midway through the range of possible values, and performs a binary search by comparing the input voltage in the analog domain to the voltage produced by a digital-to-analog converter with the current guess as input. After a few iterations, the guesses will converge on the closest numeric representation to the specified input voltage. Alternatively, integrating ADCs are very slow but provide highly accurate readings, and sigma-delta ADCs are commonly used for applications requiring high bit depths at moderate sampling rates.

Analog inputs are seldom 5-volt tolerant if the microcontroller's I/O voltage is less than 5 volts, due to the high sensitivity of the conversion circuitry required.

# Usage

## Accuracy and noise

Analog inputs can be highly accurate, but are vulnerable to line noise generated by other sensors, VEX motors, and long cables. The effective number of bits, or ENOB, is a measure reflecting how many usable bits of precision an ADC has when noise is present. Noise inflicted from electromagnetic fields can be virtually eliminated by using twisted pair cables with a ground connection, as the field will be positive half the time and negative the other half to cancel out the noise. For particularly sensitive signals, steel parts can be used to act as RF shielding.

Noise also can come from direct electrical sources. Strategically inserting small-valued capacitors at key points near potential noise sources can reduce noise, especially that generated from digital circuits switching on and off. In particular, noise on the analog reference voltage will severely affect the reading. Isolating this supply pin from noisy digital circuits using capacitors or even a separate voltage regulator can pay dividends for ADCs.

## Sampling

A common use for analog-to-digital converters is to sample a signal from a sensor at periodic intervals. While this may seem as simple as using analogRead in a repeating loop, there are hidden nuances, especially if the signal is to be later reconstructed. Software jitter and latency in the sampling loop must be minimized.

The input signal must also be band-limited to prevent aliasing problems like those shown in the picture, as the program can easily be misled into thinking that one frequency is present when another is actually the cause. To eliminate this problem, add a low-pass filter to prevent signals higher than 1/2 the sampling rate from reaching the ADC. Even with such a filter in place, one should sample at least four times faster than the fastest frequency that must be understood for reasons explained in the reconstruction section.

Sampling even faster (16 times the desired frequency or higher), known as oversampling, allows the precision of the ADC to be increased by averaging multiple samples together. This cancels out noise to increase the signal-to-noise ratio (SNR) and therefore the effective number of bits. A frequency analysis of the input signal using an Oscilloscope is the most useful way to determine the maximum expected frequency and appropriate filtering/sampling strategy.

## Reconstruction

Oftentimes, a signal is sampled from an analog system with the intent on processing it and displaying the output to the user. Digital signal processing only operates on the signal at discrete points in time, so the signal values between these points must be filled in during display.

The simplest method, known as zero-order hold, draws horizontal lines with a step discontinuity at each sample. While extremely economical on processing power, the resulting signal often looks very blocky. The most common method, linear interpolation, draws lines to connect each sampled value to strike a balance between signal quality and CPU usage. While sinc interpolation produces a very smooth, accurate signal, it is computationally expensive.

# Sample code

For the VEX Cortex using PROS, the following code structure is recommended:

`// Function samples the ADC at 1 KHzvoid sampleADC() {    unsigned int port1, port2;    clock_t now = millis();    while (1) {        // Read in the desired analog ports        port1 = analogRead(1);        port2 = analogRead(2);        // Perform processing        /* { } */        // Precise delay function accounts for the time taken by processing        // 1UL -> 1 ms (1 KHz), adjust as necessary for sensor used        // Note that rates over 1 KHz cannot be achieved using user mode, as this        // could starve the CPU. See the kernel mode drivers page for details.        taskDelayUntil(&now, 1UL);    }}​// Called when the robot is powered onvoid initialize() {    // This will create a task that is always runnning, even if robot is disabled    // To run the sampling task in only one mode (autonomous() or operatorControl()),    // use taskRunLoop() instead.    taskCreate(sampleADC, TASK_DEFAULT_STACK_SIZE, NULL, TASK_PRIORITY_DEFAULT + 1, NULL);}`

If the sensor value must be corrected for a zero-rate offset (a sensor like a Gyro or Accelerometer), use `analogReadCalibrated()` with an `analogCalibrate()` in the initialize function. When doing so, make sure that the robot is stable during power-on.