Skip to content

Week 9: Input Devices

Week 9 Assignment:
  1. Group Assignment

    1. Probe an input device’s analog levels and digital signals
  2. Individual Assignment

    1. Measure something: add a sensor to a microcontroller board that you have designed and read it
Notes from the Lecture
  • they are multiple ways to get input in:

    • ports / pins
    • comparator -> the one who will told you voltage is higher or lower. you can do it quickly
    • A/D (Analog to Digital converter) -> give you a voltage and give you the number
    • I2C -> digital protocol we use, digital signal
  • READ THE DATA SHEET to know what the hardware actually does

GROUP ASSIGNMENT

Chai Huo Week 9 - Group Assignment

An Input Device’s Analog Levels and Digital Signals

Digital Signals

For the Week 9 assignment, I checked the digital signal from the Grove Touch Sensor.

I connected the probe tip to the 3.3V pin and the ground clip to GND.

The oscilloscope displayed the following waveform:

The vertical axis shows Voltage, while the horizontal axis shows Time.

For the vertical axis:

The vertical scale is 2V per square The waveform height is around 1.75 squares

This means:

Voltage = 2V × 1.75 = approximately 3.3V

For the horizontal axis:

The scale is 100 ms per square One full cycle takes 2 squares

This means:

Time per cycle = 100 ms × 2 = 200 ms

The signal shows approximately 3.3V and 200 ms per cycle.

The waveform starts at the HIGH state (top) and goes LOW (down) each time the touch sensor is pressed.

This indicates a pull-down behavior, where pressing the sensor changes the signal from HIGH to LOW.

INDIVIDUAL ASSIGNMENT

The input devices cardboard at Chaihuo Makers Space contains various modules, most of which are from Seeed’s Grove system.

This week, I experimented with different kinds of input devices, including a temperature sensor, touch sensor, mechanical keypad, thumb joystick, PIR motion sensor and RTC (Real-Time Clock).

For all the experiments, I used the XIAO ESP32C3 as the microcontroller.

The next part uses the Grove Base for XIAO to test different input devices. It helped me explore input devices more easily, so I’ve kept this documentation. Go to Using my own PCB to see testing done with my custom PCB made using CNC milling (updated on 23 April 2026).

Using Grove Base for XIAO

Since all of the input devices are part of Seeed’s Grove ecosystem, I used the Grove Base for XIAO as an expansion board. This board acts as a bridge between the Seeed Studio XIAO and the Grove modules.

Grove Base for XIAO Information:

Feature:

  • On-board Lithium Battery Charging and Management Function
  • Grove connectors ( Grove IIC x 2, Grove UART x 1 ), all 14 GPIO led out
  • Compact and Breakable Design
  • Flash SPI Bonding Pad Reserved
  • On-board Power Switch and Charging Status Indicator Light

Specifications:

Item Value
Operating Voltage 3.3V / 3.7V Lithium Battery
Load Capacity 800mA
Charging Current 400mA (Max)
Operating Temperature - 40°C to 85°C
Storage Temperature -55°C to 150°C
Grove Interface I2C 2 / UART 1

For programming, I used the Arduino IDE.

1. Temperature Sensor

  1. Prepare the materials needed:

    Grove - Temperature Sensor V1.2:

    This temperature sensor measures ambient temperature (the temperature of the surrounding environment) using a thermistor. It operates within a range of −40 to 125 °C and has an accuracy of ±1.5 °C.

    Specifications:

    Item Value
    Voltage 3.3V ~ 5V
    Zero Power Resistance 100 KΩ
    Resistance Tolerance ±1%
    Operating Temperature Range -40 ~ +125 ℃
    Nominal B-Constant 4250 ~ 4299K

  2. Connect Grove - Temperature Sensor to port A0 of Grove Base

  3. Plug XIAO ESP32C3 to Grove Base

  4. Connect XIAO ESP32C3 to PC via a USB-C cable

  5. Copy the following code into Arduino IDE and upload the code:

    #include <math.h>
    
    const int B = 4275000;            // B value of the thermistor
    const int R0 = 100000;            // R0 = 100k
    const int pinTempSensor = A0;     // Grove Temperature Sensor on A0
    
    float filteredTemp = 0;
    
    // Read averaged ADC value
    float readADC(int pin) {
    long sum = 0;
    const int samples = 20;
    
    for (int i = 0; i < samples; i++) {
        sum += analogRead(pin);
        delay(5);
    }
    
    return sum / (float)samples;
    }
    
    void setup() {
    Serial.begin(115200);
    delay(1000);
    
    analogSetPinAttenuation(pinTempSensor, ADC_11db); // improve range
    }
    
    void loop() {
    float a = readADC(pinTempSensor);
    
    // Convert ADC to resistance
    float R = R0 * (4095.0 / a - 1.0);
    
    // Convert resistance to temperature
    float temperature = 1.0 / (log(R / R0) / B + 1 / 298.15) - 273.15;
    
    // Smooth output (low-pass filter)
    if (filteredTemp == 0) {
        filteredTemp = temperature; // initialize
    } else {
        filteredTemp = 0.85 * filteredTemp + 0.15 * temperature;
    }
    
    // Output
    Serial.print("Raw Temp: ");
    Serial.print(temperature, 3);
    
    Serial.print(" | Filtered Temp: ");
    Serial.println(filteredTemp, 3);
    
    delay(200);
    }
    

  6. Open the Serial Monitor in the Arduino IDE by clicking Tools -> Serial Monitor. You should see results in the Serial Monitor, as shown below.

    It is shown that the temperature at that time is 25°C.

2. Touch Sensor

  1. Prepare the materials needed:

    Grove - Touch Sensor:

    This sensor enables touch-based input by sensing capacitance changes caused by a nearby finger.

    Specifications:

    Item Value
    Operating Voltage 2.0V - 5.5V
    Operating Current(Vcc=3V) 1.5 - 3.0μA
    Operating Current(VDD=3V) 3.5 - 7.0μA
    Output Response Time 60 - 220ms
    Used Chipset TTP223-BA6
    Interface Digital Port

  2. Connect Grove - Touch Sensor to port D0 and Grove LED Socket to port D1 of Grove Base

  3. Plug XIAO ESP32C3 to Grove Base

  4. Connect XIAO ESP32C3 to PC via a USB-C cable

  5. Copy the following code into Arduino IDE and upload the code:

    const int TouchPin = D0;
    const int ledPin   = D1;
    
    void setup() {
        pinMode(TouchPin, INPUT);
        pinMode(ledPin, OUTPUT);
    }
    
    void loop() {
        int sensorValue = digitalRead(TouchPin);
    
        if (sensorValue == HIGH) {
            digitalWrite(ledPin, HIGH);
        } else {
            digitalWrite(ledPin, LOW);
        }
    }
    
    6. The LED turns on when we place our finger near the sensor, and it turns off when we move our finger away.

3. Mech Keypad

  1. Prepare the materials needed:

    Grove - Mech Keypad:

    A mechanical switch with a build-in LED

    Features

    • Programmable LED
    • Reliable mechanical structure
    • Extremely long operating Life

    Specifications:

    Item Value
    Operating Voltage 3.0V - 5.0V
    Insulation Resistance 100MΩ Min
    Contract Resistance 200 mΩ Max
    Operating Life without Load 20,000,000 times press

  2. Connect Grove - Mech Keypad to port D0 and Grove LED Socket to port D1 of Grove Base

  3. Plug XIAO ESP32C3 to Grove Base

  4. Connect XIAO ESP32C3 to PC via a USB-C cable

  5. Copy the following code into Arduino IDE and upload the code:

    This code is generated from ChatGPT

    const int buttonPin = D0;
    const int ledPin    = D1;
    
    bool ledState = false;      // current LED state
    bool lastButtonState = HIGH;
    bool currentButtonState;
    
    void setup() {
        pinMode(buttonPin, INPUT);
        pinMode(ledPin, OUTPUT);
    }
    
    void loop() {
        currentButtonState = digitalRead(buttonPin);
    
        // Detect button press (HIGH  LOW transition)
        if (lastButtonState == HIGH && currentButtonState == LOW) {
            ledState = !ledState;  // toggle LED
            digitalWrite(ledPin, ledState ? HIGH : LOW);
        }
    
        lastButtonState = currentButtonState;
    
        delay(50); // simple debounce
    }
    
    6. Toggle switch LED on and off

4. Thumb Joystick

  1. Prepare the materials needed:

    Grove - Thumb Joystick

    Grove Thumb Joystick uses two approximately 10k potentiometers for the X and Y axes, allowing it to detect movement in two dimensions by producing analog signals.

    Specifications:

    Item Min Typical Max Unit
    Working Voltage 4.75 5.0 5.25 V
    Output Analog Value (X-Coordinate) 206 516 798 \
    Output Analog Value (Y-Coordinate) 203 507 797 \

  2. Connect Grove - Thumb Joystick to the A0/A1 of Grove Base by using the 4-pin grove cable

  3. Plug XIAO ESP32C3 to Grove Base

  4. Connect XIAO ESP32C3 to PC via a USB-C cable

  5. Copy the following code into Arduino IDE and upload the code:

    This code is generated from ChatGPT

    /*
    Thumb Joystick demo for XIAO ESP32C3
    Grove Thumb Joystick connected to A0 & A1
    */
    
    const int pinX = 2;  // A0  GPIO2
    const int pinY = 3;  // A1  GPIO3
    
    void setup()
    {
        Serial.begin(115200);
    
        // Optional: set ADC resolution (default is 12-bit)
        analogReadResolution(12);
    }
    
    void loop()
    {
        int sensorValue1 = analogRead(pinX);
        int sensorValue2 = analogRead(pinY);
    
        Serial.print("X: ");
        Serial.print(sensorValue1);
        Serial.print("  Y: ");
        Serial.println(sensorValue2);
    
        delay(200);
    }
    
  6. When we move the joystick, we can see the X and Y values change in the Serial Monitor.

5. PIR Motion Sensor

  1. Prepare the materials needed:

    Grove - PIR Motion Sensor

    This sensor is designed to detect movement, typically from human movement.

    Features:

    • Grove compatible interface
    • Adjustable detecting distance
    • Adjustable holding time

    Specifications:

    Item Value
    Operating Voltage 3V–5V
    Operating Current(VCC = 3V) 100uA
    Operating Current(VCC = 5V) 150uA
    Measuring Range 0.1 - 6m
    Default detecting distance 3m
    Holding Time 1 - 25s
    Working Wave Length 7 - 14um
    Detecting Angle 120 degrees

  2. Connect Grove - PIR Motion Sensor to port D2 of Grove Base

  3. Plug XIAO ESP32C3 to Grove Base

  4. Connect XIAO ESP32C3 to PC via a USB-C cable

  5. Copy the following code into Arduino IDE and upload the code:

    This code is generated from ChatGPT

    #define PIR_MOTION_SENSOR D2  // 👈 use a Grove digital port
    
    int lastState = LOW;
    
    void setup()
    {
        pinMode(PIR_MOTION_SENSOR, INPUT);
        Serial.begin(115200);
    }
    
    void loop()
    {
        int currentState = digitalRead(PIR_MOTION_SENSOR);
    
        if (currentState != lastState)
        {
            if (currentState == HIGH)
            {
                Serial.println("🚶 Motion detected!");
            }
            else
            {
                Serial.println("👀 Motion ended");
            }
    
            lastState = currentState;
        }
    
        delay(50);
    }
    
    6. If motion just started -> “🚶 Motion detected!”, if motion just stopped -> “👀 Motion ended”

6. RTC (Real Time Clock)

  1. Prepare the materials needed:

    Grove - RTC

    This module supports I2C and uses R1225 battery to keep accurate time (including leap years) in 12- or 24-hour format up to the year 2100.

    Specifications:

    Item Value
    PCB Size 2.0cm*4.0cm
    Interface 2.0mm pitch pin header
    IO Structure SCL, SDA, VCC, GND
    ROHS YES
    VCC 3.3 ~ 5.5V
    Logic High Level Input 2.2 ~ VCC+0.3 V
    Logic Low Level Input -0.3 ~ +0.8 V
    Battery Voltage 2.0~3.5 V

  2. Connect Grove - RTC to port I2C of Grove Base

  3. Plug XIAO ESP32C3 to Grove Base

  4. Connect XIAO ESP32C3 to PC via a USB-C cable

  5. Download the RTC Library

  6. Open Arduino IDE. Click on Sketch -> Include Library -> Add .ZIP Library

  7. Check if the library install correctly. Click on File -> Examples -> Grove - RTC DS1307 -> SetTimeAndDisplay

  8. Copy the following code into Arduino IDE and upload the code:

    This code is generated from ChatGPT

    #include <Wire.h>
    #include "DS1307.h"
    
    #define SDA_PIN 6
    #define SCL_PIN 7
    
    DS1307 rtc;  // renamed from "clock" to "rtc"
    
    void setup()
    {
        Serial.begin(115200);
    
        Wire.begin(SDA_PIN, SCL_PIN);
    
        rtc.begin();
    
        // Set time once, then comment out
        rtc.fillByYMD(2026, 3, 20);
        rtc.fillByHMS(12, 0, 0);
        rtc.fillDayOfWeek(FRI);
    
        rtc.setTime();
    }
    
    void loop()
    {
        printTime();
        delay(1000);
    }
    
    void printTime()
    {
        rtc.getTime();
    
        Serial.print(rtc.hour, DEC);
        Serial.print(":");
        Serial.print(rtc.minute, DEC);
        Serial.print(":");
        Serial.print(rtc.second, DEC);
        Serial.print("  ");
    
        Serial.print(rtc.month, DEC);
        Serial.print("/");
        Serial.print(rtc.dayOfMonth, DEC);
        Serial.print("/");
        Serial.print(rtc.year + 2000, DEC);
    
        Serial.print("  ");
    
        switch (rtc.dayOfWeek)
        {
            case MON: Serial.print("MON"); break;
            case TUE: Serial.print("TUE"); break;
            case WED: Serial.print("WED"); break;
            case THU: Serial.print("THU"); break;
            case FRI: Serial.print("FRI"); break;
            case SAT: Serial.print("SAT"); break;
            case SUN: Serial.print("SUN"); break;
        }
    
        Serial.println();
    }
    
    9. In the Serial Monitor, we can see the time, date, and day:

Using My Own PCB

In this experiment, I used the Grove Touch Sensor as the primary input device to detect touch interactions and display the results on an OLED screen.

(Updated on 23 April 2026)

  1. Prepare the materials needed:

    Grove - Touch Sensor:

    The Grove Touch Sensor is a capacitive touch module based on the TTP223-BA6 chipset. It detects touch input by measuring changes in capacitance when a finger comes close to or touches the sensor surface.

    Unlike mechanical buttons, this sensor has no moving parts, which makes it more durable and reliable for long-term use. It is also highly sensitive and can detect even light touches.

    How It Works:

    • The sensor continuously monitors the capacitance on its electrode.
    • When a finger approaches, the capacitance increases.
    • The onboard chip processes this change and outputs a digital signal:
      • HIGH (1) -> Touch detected
      • LOW (0) -> No touch

    Specifications:

    Item Value
    Operating Voltage 2.0V - 5.5V
    Operating Current(Vcc=3V) 1.5 - 3.0μA
    Operating Current(VDD=3V) 3.5 - 7.0μA
    Output Response Time 60 - 220ms
    Used Chipset TTP223-BA6
    Interface Digital Port

  2. Circuit Connections:

    • Connect the Grove Touch Sensor signal pin to GPIO 8
    • Connect the OLED display: SDA -> GPIO 6 and SCL -> GPIO 7
  3. Power Connection:

    Connect the XIAO ESP32C3 to your computer using a USB-C cable.

  4. Upload the Code:

    Copy and upload the following code using the Arduino IDE:

    (This code is generated from ChatGPT)

    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    
    #define SCREEN_WIDTH 128
    #define SCREEN_HEIGHT 64
    #define OLED_RESET -1
    
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
    
    // Touch Sensor Pin (Using GPIO 8 as requested)
    const int touchPin = 8; 
    
    int counter = 0;
    bool lastTouchState = false;
    
    void setup() {
    Serial.begin(115200);
    
    // Initialize I2C with your specific pins (SDA=6, SCL=7)
    Wire.begin(6, 7);
    
    // Initialize Touch Sensor
    pinMode(touchPin, INPUT);
    
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
        Serial.println(F("OLED failed"));
        for(;;);
    }
    
    // Initial Screen Setup
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setTextSize(1);
    display.setCursor(20, 20);
    display.print("Touch to Start");
    display.display();
    
    Serial.println("Touch Sensor Initialized on GPIO 8");
    }
    
    void loop() {
    // Read sensor (TTP223 is HIGH when touched)
    bool currentTouchState = digitalRead(touchPin);
    
    // Check for the moment the sensor is FIRST touched
    if (currentTouchState == HIGH && lastTouchState == LOW) {
        counter++;
    
        if (counter > 10) {
        counter = 1;
        }
    
        Serial.print("Touch! New Count: ");
        Serial.println(counter);
    
        updateDisplay();
    
        // Simple debounce to prevent rapid-fire counting
        delay(150); 
    }
    
    lastTouchState = currentTouchState;
    delay(10); // Stability delay
    }
    
    void updateDisplay() {
    display.clearDisplay();
    
    // Header
    display.setTextSize(1);
    display.setCursor(35, 0);
    display.print("TOUCH COUNT");
    display.drawFastHLine(0, 12, 128, SSD1306_WHITE);
    
    // Big Number
    display.setTextSize(4);
    if (counter < 10) {
        display.setCursor(52, 25);
    } else {
        display.setCursor(40, 25);
    }
    display.print(counter);
    
    display.display();
    }
    
  5. Expected Output:

    Each time the sensor is touched:

    • The counter increases by 1
    • The value is displayed on the OLED
    • After reaching 10, the counter resets back to 1 and repeats

    This behavior is achieved by detecting the rising edge of the touch signal (transition from LOW to HIGH), ensuring that each touch is counted only once.