7. (Important) Chapter ADC
We have learned how to control the brightness of an LED through PWM and that PWM is not a real analog signal. In this chapter, we will learn how to read analog values via an ADC Module and convert these analog values into digital.
7.1. Project Read the Voltage of Potentiometer
In this project, we will use the ADC function of an ADC Module to read the voltage value of a potentiometer.
7.1.1. Component List
|
|
Rotary potentiometer x1 |
|
ADC module x1
|
|
Jumper Wire x16 |
|
This product contains only one ADC module , there are two types, PCF8591 and ADS7830. For the projects described in this tutorial, they function the same. Please build corresponding circuits according to the ADC module found in your Kit.
ADC module: PCF8591 |
ADC module: ADS7830 |
||
|---|---|---|---|
|
|
|
|
7.1.2. Circuit knowledge
7.1.2.1. ADC
An ADC is an electronic integrated circuit used to convert analog signals such as voltages to digital or binary form consisting of 1s and 0s. The range of our ADC module is 8 bits, that means the resolution is 2^8=256, so that its range (at 3.3V) will be divided equally to 256 parts.
Any analog value can be mapped to one digital value using the resolution of the converter. So the more bits the ADC has, the denser the partition of analog will be and the greater the precision of the resulting conversion.
Subsection 1: the analog in range of 0V-3.3/256 V corresponds to digital 0;
Subsection 2: the analog in range of 3.3 /256 V-2*3.3 /256V corresponds to digital 1;
......
The resultant analog signal will be divided accordingly.
7.1.2.2. DAC
The reversing this process requires a DAC, Digital-to-Analog Converter.
The digital I/O port can output high level and low level (0 or 1), but cannot output an intermediate voltage value.
This is where a DAC is useful. The DAC module PCF8591 has a DAC output pin with 8-bit accuracy, which can divide VDD (here is 3.3V) into 28=256 parts. For example, when the digital quantity is 1, the output voltage value is 3.3/256 *1 V, and when the digital quantity is 128, the output voltage value is 3.3/256 *128=1.65V, the higher the accuracy of DAC, the higher the accuracy of output voltage value will be.
7.1.3. Component knowledge
7.1.3.1. Potentiometer
Potentiometer is a resistive element with three Terminal parts. Unlike the resistors that we have used thus far in our project which have a fixed resistance value, the resistance value of a potentiometer can be adjusted. A potentiometer is often made up by a resistive substance (a wire or carbon element) and movable contact brush. When the brush moves along the resistor element, there will be a change in the resistance of the potentiometer’s output side (3) (or change in the voltage of the circuit that is a part). The illustration below represents a linear sliding potentiometer and its electronic symbol on the right.
Between potentiometer pin 1 and pin 2 is the resistive element (a resistance wire or carbon) and pin 3 is connected to the brush that makes contact with the resistive element. In our illustration, when the brush moves from pin 1 to pin 2, the resistance value between pin 1 and pin 3 will increase linearly (until it reaches the highest value of the resistive element) and at the same time the resistance between pin 2 and pin 3 will decrease linearly and conversely down to zero. At the midpoint of the slider the measured resistance values between pin 1 and 3 and between pin 2 and 3 will be the same.
In a circuit, both sides of resistive element are often connected to the positive and negative electrodes of power. When you slide the brush “pin 3”, you can get variable voltage within the range of the power supply.
7.1.3.2. Rotary potentiometer
Rotary potentiometers and linear potentiometers have the same function; the only difference being the physical action being a rotational rather than a sliding movement.
7.1.3.3. PCF8591
The PCF8591 is a single-chip, single-supply low power 8-bit CMOS data acquisition device with four analog inputs, one analog output and a serial I2C-bus interface. The following table is the pin definition diagram of PCF8591.
SYMBOL |
PIN |
DESCRIPTION |
TOP VIEW |
|---|---|---|---|
AIN0 |
1 |
Analog inputs (A/D converter) |
|
AIN1 |
2 |
||
AIN2 |
3 |
||
AIN3 |
4 |
||
A0 |
5 |
Hardware address |
|
A1 |
6 |
||
A2 |
7 |
||
Vss |
8 |
Negative supply voltage |
|
SDA |
9 |
I2C-bus data input/output |
|
SCL |
10 |
I2C-bus clock input |
|
OSC |
11 |
Oscillator input/output |
|
EXT |
12 |
external/internal switch for oscillator input |
|
AGND |
13 |
Analog ground |
|
Vref |
14 |
Voltage reference input |
|
AOUT |
15 |
Analog output(D/A converter) |
|
Vdd |
16 |
Positive supply voltage |
See also
For more details about PCF8591, please refer to the datasheet which can be found on the Internet.
7.1.3.4. ADS7830
The ADS7830 is a single-supply, low-power, 8-bit data acquisition device that features a serial I2C interface and an 8-channel multiplexer. The following table is the pin definition diagram of ADS7830.
SYMBOL |
PIN |
DESCRIPTION |
TOP VIEW |
|---|---|---|---|
CH0 |
1 |
Analog input channels (A/D converter) |
|
CH1 |
2 |
||
CH2 |
3 |
||
CH3 |
4 |
||
CH4 |
5 |
||
CH5 |
6 |
||
CH6 |
7 |
||
CH7 |
8 |
||
GND |
9 |
Ground |
|
REF in/out |
10 |
Internal +2.5V Reference,External Reference Input |
|
COM |
11 |
Common to Analog Input Channel |
|
A0 |
12 |
Hardware address |
|
A1 |
13 |
||
SCL |
14 |
Serial Clock |
|
SDA |
15 |
Serial Sata |
|
+VDD |
16 |
Power Supply, 3.3V Nominal |
7.1.3.5. I2C communication
I2C (Inter-Integrated Circuit) has a two-wire serial communication mode, which can be used to connect a micro-controller and its peripheral equipment. Devices using I2C communications must be connected to the serial data line (SDA), and serial clock line (SCL) (called I2C bus). Each device has a unique address which can be used as a transmitter or receiver to communicate with devices connected via the bus.
7.1.4. Circuit with ADS7830
Schematic diagram |
Hardware connection. If you need any support,please feel free to contact us via: This product contains only one ADC module.
|
7.1.5. Circuit with PCF8591
Schematic diagram
|
Please keep the chip mark consistent to make the chips under right direction and position. |
7.1.6. Configure I2C and Install Smbus
7.1.6.1. Enable I2C
The I2C interface in Raspberry Pi is disabled by default. You will need to open it manually and enable the I2C interface as follows:
Type command in the Terminal:
$ sudo raspi-config
Then open the following dialog box:
Choose “3 Interfacing Options” then “I4 I2C” then “Yes” and then “Finish” in this order and restart your RPi. The I2C module will then be started.
Type a command to check whether the I2C module is started:
$ lsmod | grep i2c
If the I2C module has been started, the following content will be shown. “bcm2708” refers to the CPU model. Different models of Raspberry Pi display different contents depending on the CPU installed:
7.1.6.2. Install I2C-Tools
Next, type the command to install I2C-Tools. It is available with the Raspberry Pi OS by default.
$ sudo apt-get install i2c-tools
I2C device address detection:
$ i2cdetect -y 1
When you are using the PCF8591 Module, the result should look like this:
Here, 48 (HEX) is the I2C address of ADC Module (PCF8591).
When you are using ADS, the result should look like this:
Here, 4b (HEX) is the I2C address of ADC Module (ADS7830).
7.1.7. Code
7.1.7.1. C Code ADC
For C code for the ADC Device, a custom library needs to be installed.
Use
cdcommand to enter folder of the ADC Device library.
$ cd ~/Freenove_Kit/Libs/C-Libs/ADCDevice
Execute command below to install the library.
$ sh ./build.sh
A successful installation, without error prompts, is shown below:
Next, we will execute the code for this project.
First, observe the project result, and then learn about the code in detail.
Hint
If you have any concerns, please contact us via: support@freenove.com
Use
cdcommand to enter 07.1.1_ADC directory of C code.
$ cd ~/Freenove_Kit/Code/C_Code/07.1.1_ADC
Use following command to compile
ADC.cppand generate the executable fileADC.
$ g++ ADC.cpp -o ADC -lwiringPi -lADCDevice
Then run the generated file
ADC.
$ sudo ./ADC
After the program is executed, adjusting the potentiometer will produce a readout display of the potentiometer voltage values in the Terminal and the converted digital content.
The following is the code:
1/**********************************************************************
2* Filename : ADC.cpp
3* Description : Use ADC module to read the voltage value of potentiometer.
4* Author : www.freenove.com
5* modification: 2020/03/06
6**********************************************************************/
7#include <wiringPi.h>
8#include <stdio.h>
9#include <ADCDevice.hpp>
10
11ADCDevice *adc; // Define an ADC Device class object
12
13int main(void){
14 adc = new ADCDevice();
15 printf("Program is starting ... \n");
16
17 if(adc->detectI2C(0x48)){ // Detect the pcf8591.
18 delete adc; // Free previously pointed memory
19 adc = new PCF8591(); // If detected, create an instance of PCF8591.
20 }
21 else if(adc->detectI2C(0x4b)){// Detect the ads7830
22 delete adc; // Free previously pointed memory
23 adc = new ADS7830(); // If detected, create an instance of ADS7830.
24 }
25 else{
26 printf("No correct I2C address found, \n"
27 "Please use command 'i2cdetect -y 1' to check the I2C address! \n"
28 "Program Exit. \n");
29 return -1;
30 }
31
32 while(1){
33 int adcValue = adc->analogRead(0); //read analog value of A0 pin
34 float voltage = (float)adcValue / 255.0 * 3.3; // Calculate voltage
35 printf("ADC value : %d ,\tVoltage : %.2fV\n",adcValue,voltage);
36 delay(100);
37 }
38 return 0;
39}
In this code, a custom class library “ADCDevice” is used. It contains the method of utilizing the ADC Module in this project, through which the ADC Module can easily and quickly be used. In the code, you need to first create a class pointer adc, and then point to an instantiated object.
Note
An instantiated object is given a name and created in memory or on disk using the structure described within a class declaration.
1ADCDevice *adc; // Define an ADC Device class object
2......
3adc = new ADCDevice();
Then use the member function detectIC(addr) in the class to detect the I2C module in the circuit. Different modules have different I2C addresses. Therefore, according to the different addresses, we can determine what the ADC module is in the circuit. When the correct module is detected, the pointer adc will point to the address of the object, and then the previously pointed content will be deleted to free memory. The default address of ADC module PCF8591 is 0x48, and that of ADC module ADS7830 is 0x4b.
1if(adc->detectI2C(0x48)){ // Detect the pcf8591.
2 delete adc; // Free previously pointed memory
3 adc = new PCF8591(); // If detected, create an instance of PCF8591.
4}
5else if(adc->detectI2C(0x4b)){// Detect the ads7830
6 delete adc; // Free previously pointed memory
7 adc = new ADS7830(); // If detected, create an instance of ADS7830.
8}
9else{
10 printf("No correct I2C address found, \n"
11 "Please use command 'i2cdetect -y 1' to check the I2C address! \n"
12 "Program Exit. \n");
13 return -1;
14}
When you have a class object pointed to a specific device, you can get the ADC value of the specific channel by calling the member function analogRead (chn) in this class
1int adcValue = adc->analogRead(0); //read analog value of A0 pin
Then according to the formula, the voltage value is calculated and displayed on the Terminal.
1float voltage = (float)adcValue / 255.0 * 3.3; // Calculate voltage
2printf("ADC value : %d ,\tVoltage : %.2fV\n",adcValue,voltage);
7.1.7.2. Reference
- class ADCDevice
This is a base class. All ADC module classes are its derived classes. It has a real function and a virtual function.
int detectI2C(int addr);
This is a real function, which is used to detect whether the device with given I2C address exists. If it exists, return 1, otherwise return 0.
analogRead(int chn);
This is a virtual function that reads the ADC value of the specified channel. It is implemented in a derived class.
- class PCF8591:public ADCDevice
- class ADS7830:public ADCDevice
These two classes are derived from the ADCDevice class and mainly implement the function analogRead(chn).
int analogRead(int chn);
This returns the value read on the supplied analog input pin.Parameter chn: For PCF8591, the range of chn is 0, 1, 2, 3. For ADS7830, the range of is 0, 1, 2, 3, 4, 5, 6, 7
You can find the source file of this library in the folder below:
$ ~/Freenove_Kit/Libs/C-Libs/ADCDevice/











