Analog board on an Arduino Uno
The YL-40 PCF8591 module over I2C: its light sensor, thermistor and trimmer read with the Adafruit library, and its DAC following the trimmer. The whole build, an Arduino Uno and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 15 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $32. On Mokxi they're free.
What you'll learn
- I2C wiring with SDA and SCL
- Reading analog sensors through an external ADC
- Voltage dividers with a light sensor and thermistor
- Writing an analog output with a DAC
- Using a library for a chip
- Difficulty: Intermediate
- Time: About 15 minutes
- Board: Arduino Uno R3
- Parts: 3
How it works
The YL-40 module carries a PCF8591 chip: four 8-bit analog inputs and one analog output on two wires. It connects to the Uno's 5V and GND, with SDA on A4 and SCL on A5 for I2C.
On the module, a light sensor sits on input 0, a thermistor on input 1 and a trimmer on input 3. Each one forms a voltage divider. The sketch reads all three, then writes the trimmer value back to the analog output, so the module's LED follows the knob.
Every 250 ms it prints the three readings, each 0 to 255, and the output voltage. More light gives a lower light reading, and a warmer thermistor gives a lower temperature reading.
Parts list
3 parts, plus the jumper wires. They retail for about $32; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Half breadboard
- 1 × ADC and DAC, PCF8591 (YL-40)
Kits that can build it
This starter kit has every part in the circuit. Each kit's page lists what else it can build.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| ADC and DAC, PCF8591 (YL-40) pin VCC | Arduino Uno R3 pin 5V |
| ADC and DAC, PCF8591 (YL-40) pin GND | Arduino Uno R3 pin GND |
| ADC and DAC, PCF8591 (YL-40) pin SDA | Arduino Uno R3 pin A4 |
| ADC and DAC, PCF8591 (YL-40) pin SCL | Arduino Uno R3 pin A5 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Analog board: the YL-40 PCF8591 module's three sensors over I2C, and its
// DAC following the trimmer.
//
// YL-40 SDA -> A4 SCL -> A5 VCC -> 5 V GND -> GND (jumpers fitted)
//
// The PCF8591 is four 8-bit analog inputs and one analog output on two
// wires. On the YL-40 three of the inputs have a sensor on a jumper: the
// light-dependent resistor on AIN0, the thermistor on AIN1 and the blue
// trimmer on AIN3. Each is a divider, so the LDR reads lower in more light
// and the thermistor lower when warmer, which surprises everyone once.
//
// The library reads each channel twice and keeps the second byte, because
// the chip always sends the conversion before the one just asked for. The
// DAC copies the trimmer, so turning it brightens the LED on AOUT.
//
// Drag the three sliders on the module.
#include <Wire.h>
#include <Adafruit_PCF8591.h>
Adafruit_PCF8591 pcf = Adafruit_PCF8591();
void setup() {
Serial.begin(9600);
if (!pcf.begin()) {
Serial.println("Couldn't find PCF8591");
while (1) delay(10);
}
pcf.enableDAC(true);
Serial.println("Analog board: light, temperature and trimmer");
}
void loop() {
uint8_t light = pcf.analogRead(0);
uint8_t temperature = pcf.analogRead(1);
uint8_t trim = pcf.analogRead(3);
pcf.analogWrite(trim);
Serial.print("light ");
Serial.print(light);
Serial.print(", temperature ");
Serial.print(temperature);
Serial.print(", trim ");
Serial.print(trim);
Serial.print(", AOUT ");
Serial.print(pcf.int_to_volts(trim, 5.0));
Serial.println(" V");
delay(250);
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
It opens the serial port, then calls pcf.begin() to find the PCF8591 on the I2C bus. If the chip does not answer, it prints a message and stops forever in a while loop. Otherwise pcf.enableDAC(true) switches on the analog output so the module's LED can light.
void setup() {
Serial.begin(9600);
if (!pcf.begin()) {
Serial.println("Couldn't find PCF8591");
while (1) delay(10);
}
pcf.enableDAC(true);
Serial.println("Analog board: light, temperature and trimmer");
}loop sketch.ino
Each pass reads inputs 0, 1 and 3 with pcf.analogRead, giving light, temperature and trimmer values from 0 to 255. It sends the trimmer value to the DAC with pcf.analogWrite, so the output follows the knob. It then prints everything, converting the trim to volts with pcf.int_to_volts, and waits 250 ms.
void loop() {
uint8_t light = pcf.analogRead(0);
uint8_t temperature = pcf.analogRead(1);
uint8_t trim = pcf.analogRead(3);
pcf.analogWrite(trim);
Serial.print("light ");
Serial.print(light);
Serial.print(", temperature ");
Serial.print(temperature);
Serial.print(", trim ");
Serial.print(trim);
Serial.print(", AOUT ");
Serial.print(pcf.int_to_volts(trim, 5.0));
Serial.println(" V");
delay(250);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The serial monitor says it couldn't find the PCF8591 This project
Check that SDA goes to A4 and SCL to A5, and that VCC and GND are connected. Swapped data lines mean no chip answers. - The light and temperature numbers go the opposite way from what you expect This project
That is normal for these dividers. The light reading drops in more light and the temperature reading drops when it gets warmer. - The analog output does nothing. ADC and DAC
The DAC must be enabled by setting bit 6 (0x40) in the control byte. Then write the 8-bit value. Output is from 0 to Vref, and it cannot drive heavy loads. - ADC values are always one reading behind. ADC and DAC
The first byte returned is the previous conversion. Read and discard one byte, then use the second. Choose the channel in the control byte, with inputs 0 to 3. - Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected. - Pins misbehave or the board resets when you power motors or servos from it. Arduino Uno R3
Each I/O pin gives about 20 mA, 40 mA max. Power motors and servos from their own supply and join its ground to the Uno's GND.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.