Skip to content

Week 9: Inputs

Our assignment:

Group Assignment: probe an input device's analog levels and digital signals

Individual Assignment: measure something: add a sensor to a microcontroller board that you have designed and read it


Group Assignment

Find our group assignment documented here and my documented learnings below.

Oscilloscope

To probe analog levels and digital signals with the oscilloscope, I began by using my ping pong board which I finally got a working board of (see more on that documented below). I hooked it up to one of the board's potentiometer inputs and saw as I moved the slide up it approached ~4.6V or so and as I moved it down it approached 0V. Sadly, the board short circuited after one of my ground probes likely brushed against a nearby 5V pin and the Arduino Nano (and need to check the other components) got fried 😔. I learned my lesson tho! In the future, I'll be sure to hook the ground probe with a safe distance from other pins.

Photo Light Dependent Resistor (Analog)

Instead of pong, I instead probed a Photo Light Dependent Resistor (analog input) and a button (digital input) using a breadboard and the general use microntroller board I design based on Adrian's page (documented below).

I learned a quick overview about these components on this Electrical4U webpage. Basically, a photo light dependent resistor is a resistor that provides less resistance in the presence of more light and more resistance in the pressence of less light. This is because of photoconductivity where the semiconductor material's conductivity is reduced when light is absorbed by the material.

Photo light dependent resistor on breadboard

Photo Light Dependent Resistor circuit set up. This has a high value 22KΩ resistor. Just power and ground are connected.

photo sensor

Read from the oscilloscope with just the room light levels and no interference. The light oscillates slightly up and down demonstrating how the light in the room isn't consistent

photo sensor

When I covered the sensor with my thumb to block away light from the sensor, the voltage read from the oscilloscope gets higher

photo sensor

When I flashed more light on the sensor the voltage read gets lower

Button (Digital)

Next, I set up a button circuit with example code in Arduino for turning an onboard LED light on and off. Adapted version reproduced below:

/*
Button

Turns on and off a light emitting diode(LED) connected to chip pin 17,
when pressing a pushbutton attached to pin 2.

created 2005
by DojoDave <http://www.0j0.org>
modified 30 Aug 2011
by Tom Igoe

This example code is in the public domain.

https://docs.arduino.cc/built-in-examples/digital/Button/

Adapted by angela for Fab Lab Academy 2026 for XIAO RP2040 board
*/

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;  // the number of the pushbutton pin
const int ledPin = 17;    // the number of the LED pin

// variables will change:
int buttonState = 0;  // variable for reading the pushbutton status

void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);

// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
} else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
}
}

button input osc

Button circuit set up. When I click and release, the onboard user controlled red LED pin on the board turns on and off.

button input osc

Read from the oscilloscope. When I click the button, it goes low. When released, it returns high. You can see the rising edge as it goes from low to high.

button input osc

After intentionally clicking the button not so smoothly, you can see the bounce at the microsecond scale.

Multimeter

Used the multimeter to measure change in voltage as well with the two circuits from above. Had to get creative with documentation since the multimeter requires two hands so bear with me with the set-up! 😅

Photo Light Dependent Resistor (Analog)

photo LDR input multimeter

The multimeter's voltage read at regular room lighting. I have the ground probe at ground and the other probe is carefully placed touching the leg of the photo light dependent resistor that it not at ground. Here the read is about 2.41V.

photo LDR input multimeter

The multimeter's voltage read when I cover the sensor. As expected from the oscilloscope, it goes up to about 3.11V

photo LDR input multimeter

The multimeter's voltage read when I flashed light on my phone camera. As expected, the voltage read goes down to about 1.11V

Button
Now onto the button...

button input multimeter

At its regular state, the voltage read is 3.31V

button input multimeter

When pressed, the voltage read is 0V

See group page for video documentation of the multimeter.

Logic Analyzer

FAB NODA has the Lonely binary Logic Analyzer Set which uses Logic 2 and PulseView software. It is an 8 channel, 24MHz logic analyzer. I followed along this quickstart guide to install the software and start learning how to use it.

This site describes the logic analyzer as as a tool for making sense of digital signals in electronic circuits, likening it to a stethoscope listening for a heartbeat. It displays these digital signals as waveforms.

Will also did a demo for Castor and I since this was our first time using it. We practiced using different circuits Castor and I created from a simple blinking LED to the pong board to the accelerometer sensor. Later, I borrowed the logic analyzer to practice using it with my photo light dependent resistor and button.

Button (Digital)

This time I tried the button first. Since this is a digital input, it worked nicely withe the binary logic analyzer's capabilities. For this simple task, it's fairly easy to set up.

button input logic analyzer

I hooked up the logic analyzer to ground (black wire). And I hooked up its channel one to the button's circuit (yellow wire).

button input logic analyzer

As I pressed the button and released, the logic analyzer shows the read going from high to low.

Photo Light Dependent Resistor (Analog)

Since this is an analog sensor, I was interested to see how this would go. I noticed that simply covering the sensor on and off made no change in the logic analyzer. But when I turned my phone flashlight on it and removed it that caused the logic analyzer to put out the high and low readings. From the multimeter leadings, the extra light gets the voltage down to 1V which is less ambiguous than the voltage reads when the sensor is just taking in room lightening or blocked from light.

photo light sensor input logic analyzer

I hooked this circuit to channel 7 in the logic analyzer (see the purple line on the screen). When the light from the camera flashed the logic analyzer read the input as low

Check out group assignment page for videos of these too!

Measure Something

For this week's assignment, I decided to create a capacitive touch sensor to add to a general use microcontroller board. I referred to Adrian's page heavily as a resource. However, I used a Raspberry Pi Pico (link to datasheet) for the microcontroller to get practice with that. After getting stuck around making footprints for the touchpad, I also prompted Deepseek for guidance on how to design the circuit for the capacitive touch sensor. Link to prompt language, response, and sources used.

First, I made the capacitive touch sensor board. That way I could go ahead and mill for breadboard testing.

footprint Kicad

Took me a while to figure this one out! This is my footprint for the touchpad which I also created a schematic symbol for and learned the difference between the function of those things. Made the pad type SMD

PCB design touch pad

PCB design for my touchpad. In honor of my sun and rising signs, I made it in the shape of the Aquarius symbol.Also, I added extra pads around the resistor pad to give space in case I needed to adjust those values by adding more resistors. Came out a little big but we'll see how that goes...

Time to mill...

PCB board milled

Milled the board and deburred

Time to test on breadboard...

I added the 470KΩ resistor for pulling down to ground and the 1KΩ resistror for current limiting to signal.

After soldering the Raspberry Pi Pico board to pins, I hooked everything up using a breadboard. Then got to work on the code...

Installed library in Arduino IDE: Raspberry Pi Pico/RP2040/RP2350 package by Earle Philhower

raspberry pi pico pinout

Pinout of the Raspberry Pi Pico from the datasheet for reference

Uploaded code provided on Adrian's page and changed the LED pin to the corresponding pin on the PICO board pin 25. And the pins set for the 2 sensors actually already corresponded to the Raspberry Pi Pico since its the same RP2040 Microcontroller. And thankfully, that worked!

Code

To make better since of the code, I referred to Arduino's language reference documentation and also this CPP Scripts website to read through block-by-block to help me understand. I took notes in the code below.

Adrian's Code Reproduced Below (I just made sure to "#define LED 25") with my notes added:

//Fab Academy 2026 - Fab Lab León
//Touch + LED                           
//Fab-Xiao
// This version has angela's notes added

//Define LED as a constant at pin 25

#define LED 25

// Define number of touch sensors as a constant at 2

#define N_TOUCH 2

//Define threshold for what is considered a touch at 2

#define THRESHOLD 2

//stores pins for touch pads as integers: 27 and 26. However, I'm confused since the pins are set for these pads and won't vary, why is this not defined as a constant, like the LED above?

int touch_pins[N_TOUCH] = {27, 26};

//stores values for touch pads as variable integers, starting at zero

int touch_values[N_TOUCH] = {0};

//stores mapped values (done later in the code) as variable integers, starting at zero
int touch_mapped[N_TOUCH] = {0};

//holds value of "pin_touched_now" as false
bool pin_touched_now[N_TOUCH] = {false};

//void indicates a function does not return a value and is used to perform actions without having to return the data to the caller. This is a big chunk of code that functions to sense and quantify the touch on the touchpad.

void update_touch() {

    //declares variable for "t" as an integer. declares integer variable "t_max" and initializes it with 200; declares integer variable for "p"
    int t;
    int t_max = 200;
    int p;

    //for is used for repetitive operations and repeats a block of statements in the curly brackets. Initializes 'i' to 0, check if its less than number of touchpads, and if so executes the block subsequently incrementing i by one.

    for (int i = 0; i < N_TOUCH; i++) {
        //establishes "p" as touch pins
        p = touch_pins[i];

        //sets the behavior of the pin p as an output
        pinMode(p, OUTPUT);

        // writes low value to pin p (i.e. ground). Does it faster (?)
        digitalWriteFast(p, LOW);

        //pauses the program for 25 microseconds
        delayMicroseconds(25);

        //sets the behavior of pin p as an input and enables the internal pull-up resistor
        pinMode(p, INPUT_PULLUP);

        //sets "t" variable at zero
        t = 0;

        //loops continuously until this condition becomes false: it is NOT the case that the value of pin p AND "t" is less than 200. This one is stumping me...

        while (!digitalReadFast(p) && t < t_max) {
        t++;
        }

        stores value of t for the touch pad
        touch_values[i] = t;

        // Maps a number from one range to another. Maps the values for the touchpad from the current range of 0 to t_max TO a target range of 0 to 255.

        touch_mapped[i] = map(touch_values[i], 0, t_max, 0, 255);

        //pin of touched pad is assigned value of the touch value if (?) it is greater than the threshhold
        pin_touched_now[i] = touch_values[i] > THRESHOLD;
}
}

//function that runs at start of program to prep environment for main program loop

void setup() {

//initialize serial communication at 115200 baud
Serial.begin(115200);

//sets the behavior of LED as an output
pinMode(LED, OUTPUT);

//turns on the LED
digitalWrite(LED, HIGH);
}

//used to execute block of code repeatedly. standard function that runs after setup

void loop() {
update_touch();

// If the first (?) touchpad is touched, turn on the LED. Otherwise, turn off the LED.
if (pin_touched_now[1]) {
    digitalWrite(LED, HIGH);
} else {
    digitalWrite(LED, LOW);
}

// Show the values as mapped from that earlier function in the serial monitor for both touchpads
Serial.print("Touch 27: ");
Serial.print(touch_mapped[0]);
Serial.print(" | Touch 26: ");
Serial.println(touch_mapped[1]);

// pauses program for 50 milliseconds
delay(50);
}

touch sensor test

Testing the touchpad on the breadboard

serial monitor touchpad

As I pressed on each touchpad, the serial monitor displays the varying values for each pin

Next up: designing a general use microcontroller board. This process really helped me better understand the pinouts for the Raspberry Pi Pico as I needed to consider what pins where needed for the anticipated inputs/outputs, considering analog inputs like my touch sensor, I2C, PWM, etc.

Then I learned we were ordering some Xiao RP2040 boards and I decided to pivot to using that board instead.

general pcb board kicad

Layout of my general use board. A simplified version of Adrian's example

After milling and stuffing the board, I was ready to put it all together...

finished PCB board

Board

In the code, I made a small edit to use the built-in LEDs. I also increased the threshold for what constitutes a touch because when the board was just sitting on its own there was a small number (between 5-15). So I set the threshold at 20.(See design files for this.)

testing touchpad with board

Using my touch pad with the general board

As I press and release each touch pad, you can see the values recorded in the serial monitor of Arduino's IDE. They increase when sensors are touched then dip back down to their base readings when not.

Ping Pong Update!

This week, I updated my ping pong board design by routing ground rather than making a ground plane. It finally worked! The screen was upside down so I ended up switching the potentiometer input pins so it could be used just fine with a different orientation.

pong week 9 update

Working board! And it operated much more smoothly with all the components. The button worked seamlessly to reset the game. And both potentiometers moved each corresponding paddle with ease. It almost made the game too easy so one idea Castor had was to make the paddles smaller (or even further, smaller with each point scored) to make it more challenging. Unfortunately, I short circuited the board when probing with the oscilloscope so I'll need to replace the nano board but it's reassuring how much I've improved in soldering in just a week.

Learning

Before completing the assignments documented above, I practiced using the various sensors we have in the lab. See below for documentation:

Pressure, Temperature, Humidity Sensor

Using an Adafruit Metro ESP32-S2 and an Adafruit BME280, I used this page on Adafruit's website to learn how to set this sensor up. (Instead of a TMP117 however, I had the BME280 so I adjusted for that). I pulled up an example code available in Arduino examples under Adafruit BME280 library called "bme280test."Reproduced below:

/***************************************************************************
    This is a library for the BME280 humidity, temperature & pressure sensor

    Designed specifically to work with the Adafruit BME280 Breakout
    ----> http://www.adafruit.com/products/2652

    These sensors use I2C or SPI to communicate, 2 or 4 pins are required
    to interface. The device's I2C address is either 0x76 or 0x77.

    Adafruit invests time and resources providing this open source code,
    please support Adafruit andopen-source hardware by purchasing products
    from Adafruit!

    Written by Limor Fried & Kevin Townsend for Adafruit Industries.
    BSD license, all text above must be included in any redistribution
    See the LICENSE file for details.
    ***************************************************************************/

    #include <Wire.h>
    #include <SPI.h>
    #include <Adafruit_Sensor.h>
    #include <Adafruit_BME280.h>

    #define BME_SCK 13
    #define BME_MISO 12
    #define BME_MOSI 11
    #define BME_CS 10

    #define SEALEVELPRESSURE_HPA (1013.25)

    Adafruit_BME280 bme; // I2C
    //Adafruit_BME280 bme(BME_CS); // hardware SPI
    //Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

    unsigned long delayTime;

    void setup() {
        Serial.begin(9600);
        while(!Serial);    // time to get serial running
        Serial.println(F("BME280 test"));

        unsigned status;

        // default settings
        status = bme.begin();  
        // You can also pass in a Wire library object like &Wire2
        // status = bme.begin(0x76, &Wire2)
        if (!status) {
            Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
            Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
            Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
            Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
            Serial.print("        ID of 0x60 represents a BME 280.\n");
            Serial.print("        ID of 0x61 represents a BME 680.\n");
            while (1) delay(10);
        }

        Serial.println("-- Default Test --");
        delayTime = 1000;

        Serial.println();
    }


    void loop() { 
        printValues();
        delay(delayTime);
    }


    void printValues() {
        Serial.print("Temperature = ");
        Serial.print(bme.readTemperature());
        Serial.println(" °C");

        Serial.print("Pressure = ");

        Serial.print(bme.readPressure() / 100.0F);
        Serial.println(" hPa");

        Serial.print("Approx. Altitude = ");
        Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
        Serial.println(" m");

        Serial.print("Humidity = ");
        Serial.print(bme.readHumidity());
        Serial.println(" %");

        Serial.println();
    }

bme adafruit sensor test bme serial monitor output

Wired up the sensor to the Adafruit Metro board and uploaded code. Note: this board has an on-off switch. Don't forget to turn it on! In the Serial Monitor menu on Arduino IDE, it periodically displays the temperature, pressure, approximate altitude, and humidity. It's a little over 70 degrees F in the lab today!

3-Axis Accelerometer

Next, I tried using the Adafruit LIS3DH board (click link for datasheet). After installing the Adafruit LIS3DH library in Arduino, I worked through more example code provided within Arduino's IDE. For example, I tried out the "tapdemo" example. Code reproduced below:

tap demo

Hooking up the LIS3DH board and testing the Tap Demo. This allows you to detect a single or double tap on the sensor

Digital Proximity, Ambient Light, RGB, and Gesture Sensor

Up next, Sparkfun's APDS-9960 board (see link for data sheet). After soldering this board to some pins and referring to this resource on sparkfun's website, I ran through more example code.

color board

The data pops up in Serial Monitor but doesn't change with different issues. I tried troubleshooting with the multimeter but didn't see an issue. This may be an issue with the sensor on the board.

Keypad

Up next, I hooked up a membrane keypad and installed the "Keypad" library in Arduino by Mark Stanley, Alexander Brevig. For guidance, I referred to Wokwi which has an example simulation and a page on the membrane keypad. Since I am using the Metro ESP32-32 board, I just adjusted the code to match the pins I was using. Reproduced below:

// Arduino code example from Wokwi user urish. Angela changed the pins to the ones used for Adafruit's Metro ESP32-32 board.

#include <Keypad.h>

const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};

uint8_t colPins[COLS] = { 8, 7, 6, 5 }; // Pins connected to C1, C2, C3, C4
uint8_t rowPins[ROWS] = { 12, 11, 10, 9 }; // Pins connected to R1, R2, R3, R4

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

void setup() {
Serial.begin(9600);
}

void loop() {
char key = keypad.getKey();

if (key != NO_KEY) {
    Serial.println(key);
}
}

keypad

Testing my keypad

Some Lessons Learned from This Week

  • When using the XIAO RP2040 Microcontroller with Arduino, use the chip pin not the XIAO pin in the code
  • For testing/probing, it's helpful to have a pin you can dedicate to ground that is out of the way of power/other pins. I accidentally short-circuited my ping pong board when using the oscilloscope because the ground probe slightly touched the 5V pin.
  • Remember to use "INPUT_PULLUP" in Arduino code for digital input pins to use the internal pull-up resistors to keep the pin from floating. Especially with buttons!
  • Buttons can be tricky to place in a circuit. If using a breadboard just plop it in the center because the way it'll fit makes it more intuitive which side of legs are connected.

Design Files

Here is a link to my design files from this week.