Lab 2 — Digital I/O

Sam Stromberg
4 min readSep 12, 2021

Building on the first lab last week, I explored the use of pulse-width modulation (PWM) to simulate analog output from my microcontroller board, as well as using the Serial Monitor function in the Arduino IDE to dynamically control the board using keyboard input.

The initial setup for the board was a fairly straightforward extension of the Lab 1 circuit, running the three LEDs in parallel. There were some physical/spatial considerations in this case, in that we wanted the three bulbs close together (to make it easier to mix their illumination), and in that, in order to use PWM, each circuit had to be controlled with a compatible output pin (denoted on the PCB with a ~; six of the digital output pins have this capability). I landed my circuits on pins 9, 10, and 11 for R, G, and B, respectively, and used matching-colored jumper wires for visual clarity.

The physical circuit

I played around with a few different configurations on the breadboard before reaching this solution, because I wanted the LEDs close together but didn’t want to snip their legs (or the legs of the resistors) for later usage. As well, I found that running jumper wires back to ground added a lot of visual clutter, so I went ahead and cut some small wires to size instead. Connections between the Arduino and breadboard are still made with jumpers to allow them to move a little bit relative to each other. I could have placed the LEDs ahead of their resistor(s) in the circuit, and so used a single resistor after landing the LEDs on the ground bus, but I vaguely remember being instructed to always keep resistors in front of their loads (in case of an accidental short, maybe?).

Components

  • Arduino Uno / USB-to-Serial cable
  • Mini breadboard
  • Red, blue, and green LEDs
  • 3x 220-ohm resistors
  • Hand-cut and jumper wires
  • Paper bag, tissue paper, tape to make light diffuser

Code

First, I adapted the ‘Fade’ sample sketch to make sure I understood what was happening in the code and to explore the color space I’m working in. Next, I modified the part of the code reading input from the Serial Monitor to read the first character and step the brightness of the corresponding LED up by 10% of its maximum value (~25).

char serInString[100]; // array that will hold the different bytes of the string. 100=100characters;
// -> you must state how long the array will be else it won’t work properly
char colorCode;
int r_value;
int g_value;
int b_value;

int redPin = 9; // Red LED, connected to digital pin 9
int greenPin = 10; // Green LED, connected to digital pin 10
int bluePin = 11; // Blue LED, connected to digital pin 11

void setup() {
pinMode(redPin, OUTPUT); // sets the pins as output
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
Serial.begin(9600);

r_value = 127;
g_value = 127;
b_value = 127;

analogWrite(redPin, r_value); // set them all to mid brightness
analogWrite(greenPin, g_value); // set them all to mid brightness
analogWrite(bluePin, b_value); // set them all to mid brightness
Serial.println(“choose a color (r/g/b):”);
}

void loop () {
// clear the string
memset(serInString, 0, 100);
//read the serial port and create a string out of what you read
readSerialString(serInString);

colorCode = serInString[0]; // we only need the color code
if( colorCode == ‘r’ || colorCode == ‘g’ || colorCode == ‘b’ ) {
//colorVal = atoi(serInString+1);
Serial.print(“brightening color “);
Serial.print(colorCode);
Serial.println();
serInString[0] = 0; // indicates we’ve used this string
if(colorCode == ‘r’) {
r_value += 25;
analogWrite(redPin, r_value);
if(r_value > 230) {
r_value = 1;
Serial.print(“r max brightness reached”);
Serial.println();
}
}
else if(colorCode == ‘g’) {
g_value += 25;
analogWrite(greenPin, g_value);
if(g_value > 230) {
g_value = 1;
Serial.print(“g max brightness reached”);
Serial.println();
}
}
else if(colorCode == ‘b’) {
b_value += 25;
analogWrite(bluePin, b_value);
if(b_value > 230) {
b_value = 1;
Serial.print(“b max brightness reached”);
Serial.println();
}
}
}

delay(100); // wait a bit, for serial data
}

//read a string from the serial and store it in an array
//you must supply the array variable
void readSerialString (char *strArray) {
int i = 0;
if(!Serial.available()) {
return;
}
while (Serial.available()) {
strArray[i] = Serial.read();
i++;
}
}

Further Exploration

Because the LEDs provide directed illumination, I found that a multi-layer diffuser greatly improved the blending of colors. I trimmed a white paper lunch bag down and taped a layer of tissue paper inside to act as the first layer, which worked fairly well, even in bright, natural light.

I found the LEDs to have somewhat different apparent brightness, at least in the lighting conditions I was testing them in. An equal mix of blue and green light looked very blue to me, and while I could create orange readily, I found amber or yellow to be harder to locate.

Images of Diffuser

Lining a paper bag with tissue paper
The purple blended quite well.
When red and green were blended together, it seemed like red dominated.

--

--

Sam Stromberg

2nd-year Masters student at the UC Berkeley School of Information. Moving into Product; interested in data and uncertainty, sensor data, behavioral change.