In the previous tutorial, we discussed analog output in the form of PWM signals when using Arduino . We generate an Arduino PWM wave using the analogWrite function that approximates a rectified sine wave. It then uses this analog output to attenuate a LED .
A controller can interface and interact with external electronic components and devices in five possible ways: digital output, digital input, analog output, analog input, and serial communication.
In this tutorial, we will discuss analog input. Most sensors output analog voltage proportional to a physical quantity (such as temperature, humidity, pressure, light intensity, etc.).
A controller can interpret the value of the physical quantity by detecting the magnitude of this analog voltage. Additionally, most controllers have built-in analog-to-digital converter (ADC) channels that detect analog voltage from sensors and convert it to a digitized reading. The digitized values are compared with the sensor sensitivity curve by user-defined programs to derive the value of the physical quantity.
Detecting unipolar vs. unipolar voltages bipolar
For analog input, controllers have an integrated peripheral called an analog-to-digital converter (ADC). Most microcontrollers can only detect unipolar voltages and not bipolar voltages. The same happens with Arduino boards.
Arduino's built-in AVR microcontrollers can also only detect unipolar voltages. These analog voltages typically range from ground (0V) to their operating voltage (5/3.3V). The reason Arduino and most other microcontrollers have ADCs that can only detect unipolar voltages is that the ADC features are only built for interfacing sensors. Sensors generally emit non-periodic unipolar voltages.
However, analog-to-digital conversion is used in a number of different applications, such as music recording, digital signal processing, digital coding, digital imaging, and more (in addition to sensors and instrumentation).
Many of these applications require analog-to-digital conversion of periodic signals or signals that may be bipolar in nature. In these cases, the Arduino (and many other microcontrollers) may need to interface with external bipolar-to-unipolar converters.
Analog to digital conversion
Analog signals are continuous in nature and do not have a fixed range of values. To measure analog voltages, these signals must be converted into digital signals. The digital signal obtained after conversion is a binary number of predefined resolution (such as 8/10/12/14/16 bits), which is proportional to the magnitude of the analog voltage.
The value of this binary number depends on the reference voltage to which the analog signal is compared and the resolution of the value. This means that the higher the resolution, the lower the reference voltage. And, to be more precise, the analog voltage will be measured at any instant of the signal.
The peripheral – which converts the analog voltage into a digital value – is called an analog-to-digital converter. ADCs are built to use different types of modulation techniques to perform this conversion, such as Pulse Code Modulation (PCM), Delta Modulation, Adaptive Delta Modulation, Successive Approximation, and so on.
Different modulation techniques vary in how they work, although the result is always a quantization of the analog signal. It is then encoded into a binary number.
There are many popular architectures (constructions) for designing ADCs. The most popular ADC architectures are direct/flash conversion, successive approximation (SAR), pipeline, sigma-delta, ramp comparison, Wilkinson, double slope, and time-interleaved architecture. ADCs integrated into AVR controllers used on Arduino boards typically have SAR ADCs.
Another important factor to consider in analog-to-digital conversion is the sampling rate. The sampling rate is the time rate at which the analog signal voltage is sampled. For example, if an analog signal is sampled at a rate of 50 kHz, this means that the voltage of the analog signal is measured every 20 microseconds. However, if the signal is plotted after conversion, the sampling rate will be higher and the sampled signal will be much closer to the real analog signal.
Analog input using Arduino
Arduino boards use different AVR/SAMD/SAM microcontrollers. Most of these microcontrollers have at least six ADC channels that are typically multiplexed to a SAR ADC. The resolution of an integrated ADC can vary from board to board, although the ADC on most boards has a resolution of at least 10 bits.
The default voltage reference is always the board operating voltage, so boards can “sense” unipolar voltages from ground (0V) to 5 or 3.3V. You can also set the voltage reference to predefined internal voltages or to an external voltage source.
On some Arduino boards, the voltage reference for analog-to-digital conversion can be set individually for each channel.
The sampling rate of the analog signal is set by pre-scaling the clock used by the integrated controller. The sampling frequency is always a factor of the controller clock frequency, where the factor is determined by the built-in prescaler.
For lower resolution (such as 8-bit), the ADC may use a higher frequency to maximize the sampling rate.
The ADC capabilities of different Arduino boards are summarized here.
Analog input using Arduino UNO
Arduino UNO has six analog input channels. The ATmega328P controller in the UNO has a 10-bit successive approximation ADC, which is connected to an 8-channel analog multiplexer. This analog multiplexer allows eight single-ended voltage inputs on the port A pins of the controller. Single-ended voltage input refers to ground (0V).
In SAR ADC, the comparator essentially compares the input voltage with the successively narrow range of voltages. At each step, the input voltage is compared to a voltage from an internal DAC (digital to analog converter), where the output of the DAC is the midpoint of the selected voltage range.
At each step, the approximation is stored in a successive approximation record (SAR). So, let's assume a voltage of 3.2 V is sampled from an analog signal. It is the first compared to 2.5V (midpoint of 0 and 5V).
- Since 3.2V is greater than 2.5V, it will be compared next with 3.75V (the midpoint of 2.5 and 5V).
- Since 3.2V is less than 3.75V, it will next be compared with 3.125V (the midpoint of 2.5 and 3.75V), and so on.
Since the SAR ADC in the ATmega328P has 10-bit resolution, the input voltage is successively approximated 10 times to obtain a 10-bit digital readout. However, if it were an 8-bit SAR ADC, it would take eight successive approximations to obtain the 8-bit digital value, and so on.
In each successive approximation, a bit of the digital value is obtained starting from MSB to LSB (this means that in the first approximation, the MSB of the digital value is obtained and in the next approximation, the bit close to the MSB is obtained). If in a successive approximation the input voltage is greater than the midpoint of the selected voltage range, the obtained bit will be 1. If the input voltage is lower than the midpoint of the selected voltage range, the obtained bit will be 0.
Since the ADC has 10-bit resolution, the output digital reading can range from 0 to 1023 (2^10).
Taking the example of 3.2 V, with 5 V reference in a 10-bit SAR ADC, the successive approximations can be summarized here.
If we compare this to the equation for a standard single-ended ADC conversion, the results are:
ADC = (V IN /V REFERENCE ) * 1024
AC = (3.2V/5V) * 1024
= 655.36 = 655 or (b1010001111)
The ADC has a 7-bit prescaler and can use 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, or 1/128 of the controller clock frequency. The successive approximation circuit requires a clock frequency of 50 to 200 kHz. Because the controller is clocked on a 16 MHz crystal, even if a 1/128 prescale is used for the sampling input voltage, the ADC clock frequency is 125 kHz.
From the ADC timing diagrams, you can see that the ADC takes 25 ADC clock cycles for the first conversion and 13 ADC clock cycles for normal single-ended conversions. This means that if the 1/128 prescale is selected, it will take 200 microseconds (1/125KHz *25) for the first sample and 104 microseconds (1/125KHz *13) for the other readings.
For automatically triggered conversions, the ADC takes 13.5 clock cycles (108 microseconds for one conversion). For the other pre-scaler, this conversion time must be even lower. Typically, this ADC takes 65 to 260 microseconds for conversion, sampling analog inputs at a rate of up to 15k SPS (samples per second).
The default voltage reference is 5V. Other voltage references available on Arduino boards are listed in this table.
The ATmega328P has the following internal registers, which are associated with the operation of the ADC.
Before starting a conversion, the first voltage reference and analog channel must be selected by configuring an ADMUX register. To enable ADC, the ADEN bit of the ADCSRA register must be set.
To start the conversions, after the ADC is enabled, the ADSC bit of the ADCSRA register must also be set. The first conversion takes 25 ADC clock cycles, while normal conversions take 13 ADC clock cycles. When the conversion is complete, the ADIF bit of the ADCSRA register is set (check the ADC timing diagram) and the ADSC bit is cleared.
When ADIF is set, the ADC data records – and both ADCL and ADCH – are updated. The value of these registers must be retrieved when the ADIF is configured to obtain a digital reading of the analog signal.
The ADPS2:0 bits of the ADCSRA register are used to select the prescaler and determine the division factor between the system clock frequency and the ADC input clock. The ADLAR bit of the ADMUX register determines how the ADC data registers (ADCL and ADCH) are populated.
If the ADATE bit of the ADCSRA register is set, automatic ADC triggering is enabled. In this case, the source that triggers the ADC conversion is determined by the ADTS2:0 bits of the ADCSRB register. The trigger source can be a timer/counter, external interrupt or analog comparator.
The analogRead function
To detect the analog voltage of a sensor (or any source), the analogRead function is used.
This function has the following source code:
In the analogRead function, the first analog input channel must be selected according to the argument passed to the function. Then the ADMUX and ADCSRB registers are assigned values. The function tracks the ADSC bit of the ADCSRA register in a loop. Whenever the bit is set, it reads the values that are updated in the ADCL and ADCH registers.
The function returns the value of the ADCL and ADCH records as an integer. The function has this syntax:
analog readout (pin)
It only takes one argument, which is a valid pin number where analog input is expected. It returns the analog reading which can range from 0 to 1023 for a 10-bit resolution, or from 0 to 4095 for a 12-bit resolution. Therefore, it must be assigned to a variable that can store the retrieved analog reading. The value obtained from the variable can then be used to plot the analog signal or to make a decision according to a user-defined program.
The analogReference function
It is possible to set a different voltage reference for ADC when using Arduino. By default, the voltage reference is always the board's operating voltage. The voltage reference can be changed or set using the analogReference function.
This function has the following source code:
The function has the following syntax:
analogReference(type)
This function takes a single argument, which is an option for the voltage reference. The options that can be passed to this function for different Arduino boards are already mentioned in the voltage reference table above. This function returns nothing.
The first analogRead readings may not be accurate when changing the analog reference. Therefore, if the analogReference function is called, the first readings returned by the analogRead function must be ignored in the user-defined program.
If the external voltage is defined as an analog reference, it must never be lower than 0V (bipolar voltages are not allowed on the analog pins) and must not be higher than 5V (overvoltage can damage the pin or even the integrated controller).
An internal 32K resistor is connected to the AREF pin. To set an external voltage as a reference, it must be supplied through an external resistor. The external resistor will form a voltage divider with the internal resistor on the AREF pin and the voltage reference can be safely set without worry of damaging the pin or controller.
The analogReadResolution function
The MKR, Due and Zero cards have multiple resolution options for analog-to-digital conversion. The default resolution is 10 bits. However, lower or higher resolutions (up to 32) can be used on these cards. The ADC resolution can be changed by the analogReadResolution function.
This function has the following syntax:
analog read resolution (bits)
The chunks argument determines the resolution of the analog reading returned by the analogRead function. It can take any value from 1 to 32. It should be noted that when setting the resolution above 12, approximations may be impaired. Ideally, use 8-, 10-, or 12-bit resolutions unless there is a strict demand to choose a higher resolution.
If a resolution is set that the card is not capable of, analogRead will return a reading at the highest resolution possible on that card, with zeros padded for the extra resolution. Likewise, if a lower resolution is set that is beyond the card's capabilities, analogRead will return a reading at the lowest resolution possible on that card - with the LSB bits discarded to match the selected resolution.
Potentiometer Controlled LED Blink Rate Recipe
In this recipe, we will detect the analog voltage with the help of a potentiometer and use the variation in the analog voltage to change the blinking duration of an LED.
Required components
1. Arduino UNO x1
2. LEDx1
3. 330 Ohm Resistor x1
4. 10K/100K Pot x1
5. Breadboard x1
6. Male-to-male bonding wires or connecting wires
Circuit Connections
First, connect the Arduino UNO digital I/O pin 5 to the LED anode. Then connect the cathode of the LED with a 330 Ohm series resistor and ground the other terminal of the resistor.
Take the potentiometer and connect its fixed terminals 1 and 3 to ground and 5V, respectively. Connect the variable terminal 2 of the potentiometer to the analog input A5 of the Arduino UNO. DC supply voltage and ground can be supplied to the circuit from the 5V power pin and one of the ground pins of the Arduino UNO.
Circuit Diagram
Arduino Sketch
int sensorPin = A5;
int ledPin = 5;
int analog value = 0;
empty configuration {
pinMode(ledPin, OUTPUT);
}
empty loop {
analogVal = analogRead(sensorPin);
digitalWrite(ledPin, HIGH);
delay(analogVal);
digitalWrite(ledPin, LOW);
delay(analogVal);
}
How the project works
The circuit is designed to change the blink rate of the LED by sensing the voltage of a trimmer potentiometer. The variable end of the trimmer is connected to pin A5 of the UNO, while its fixed ends are connected to ground and VCC (5V DC).
The analog voltage at the variable end of the trimmer can be varied between 0 and 5V by turning the trimmer knob. This voltage is applied to the analog input A5 of the Arduino UNO .
The trimmer's analog voltage is read using the analogRead function, which returns a value between 0 and 1023. The analog reading is used as a delay interval in milliseconds between turning the LED on and off. When the potentiometer knob is close to the fixed terminal connected to ground, the low analog voltage is applied to the analog pin A5 and the low analog reading is recorded.
Thus, the delay interval between turning the LED on/off remains between 40 to 70 milliseconds and the LED blinks at a higher frequency. When the knob is turned near the fixed terminal connected to VCC, the high analog voltage is applied to pin A5 and the high analog reading is recorded. The LED on/off delay interval remains between 800 and 1000 milliseconds, and the LED blinks at a lower frequency.
Programming guide
The three global variables are defined by:
- The sensorPin to indicate the analog input pin
- The ledPin to indicate the digital pin where the LED is connected
- The analogVal to store the analog reading
The sensorPin is assigned a value of A5 where the trimmer is connected, and the ledPin is assigned a value of 5 where the LED is connected.
In the setup function, the pin where the LED is interfaced is configured as an output using the pinMode function. In the loop function, the analog reading on pin A5 is obtained through the analogRead function and is stored in the analogVal variable.
The LED is interconnected so that pin 5 serves as a current source for it. Pin 5 is set to HIGH using the digital write function so that the LED begins to glow. A delay equal to the analog reading is provided by calling the delay function, with analogVal as an argument. The LED is then turned off by setting pin 5 to LOW using the digitalWrite function.
Again, a delay equal to the analog reading is provided by calling the delay function with analogVal as an argument.
Potentiometer Controlled LED Dimming Recipe
In this recipe, we will detect analog voltage using a potentiometer and changing the analog voltage to dim an LED.
Requirements
Here, the required components, circuit connections, and circuit diagram are all the same as mentioned above, “Potentiometer Controlled LED Blink Rate Recipe”.
Arduino Sketch
int sensorPin = A5;
int ledPin = 5;
int analog value = 0;
empty configuration {
pinMode(ledPin, OUTPUT);
}
empty loop {
analogVal = analogRead(sensorPin);
analogWrite(ledPin, analogVal/4);
}
How the project works
This circuit is designed to fade an LED using a potentiometer. The analog voltage is applied to pin A5 of the Arduino through a trimmer potentiometer. This analog voltage is read using the analogRead function.
This function returns a value between 0 and 1023. This value is divided by four to get a value between 0 and 255, and then passed as a duty cycle argument to the analogWrite function. The analogWrite function produces a PWM signal on pin 5 where the LED is connected.
- When the analog input at pin A5 is low, the analog reading remains between 40 and 50. When this reading (after a factor of four) is passed as duty cycle, a low duty cycle PWM wave is generated at pin 5 of the UNO and the LED remains off.
- When the analog input at pin A5 is high, the analog reading remains between 800 and 1000. When this reading (after a factor of four) is passed as duty cycle, a high duty cycle PWM wave is generated at pin 5 of the UNO and the LED lights up.
Programming Guide
The three global variables are defined as follows:
- The sensorPin to indicate the analog input pin
- The ledPin to indicate the digital pin where the LED is connected
- The analogVal to store the analog reading.
The sensorPin is assigned a value of A5 where the trimmer is connected and the ledPin is assigned a value of 5 where the LED is connected.
In the setup function, the pin where the LED is interfaced is configured as an output using the pinMode function. In the loop function, the analog reading on pin A5 is obtained through the analogRead function and is stored in the analogVal variable.
The LED is interconnected so that pin 5 serves as a current source for it. A PWM wave is generated at pin 5 by calling the analogWrite function in which the duty cycle is defined for the analog reading (factored by four).
The analog reading is factored by four and the duty cycle value must be between 0 and 255, while the analog reading can be between 0 and 1023.
As the analog voltage on pin A5 of the UNO increases, the duty cycle increases and the LED becomes brighter. As the analog voltage at pin A5 of the UNO decreases, the duty cycle decreases and the LED turns off.
In the next tutorial, we will discuss interfacing an RGB LED using Arduino.
(tagsToTranslate)Arduino