11. Input devices¶
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¶
For my group assignment I was assigned to measuring the digital levels. Here is the link to our group website.
Touch Detection¶
We first attached a touch sensor to an RP2040 using jumper wires and an LED. The sensor detects a change in capacitance (your body adds capacitance). The microcontroller interprets this through a touch sensing pin or a digital signal from a touch module as a “touch event.” When it detects a touch event, it turns the LED on. When there’s no touch, it keeps the LED off.
Image of Wiring¶
Voltage Behavior¶
We attached the 2 nodes of the voltmeter to the ground and powered on the LED. Low voltage: 0V when the sensor is untouched. High voltage: 3.3V or 5V When the sensor is touched. We noticed that the voltage was about 3.3V
Individual¶
For my Individual project, I designed an acceleometer to sense the motion to blink an LED. The first step was to simulate it using a breadboard.
To check if the wiring was correct, I used a simple blink code to verify that the LED was working properly. The next step was to get the actual code that would allow the LED to blink whenever the board was rotated. First, I asked ChatGPT to provide a code that would light up an LED when the MPU6050 sensor detected rotation using a XIAO ESP32-C3. It provided me with the following code:
/*
MPU6050 Raw
A code for obtaining raw data from the MPU6050 module with the option to
modify the data output format.
Find the full MPU6050 library documentation here:
https://github.com/ElectronicCats/mpu6050/wiki
*/
#include "I2Cdev.h"
#include "MPU6050.h"
/* MPU6050 default I2C address is 0x68*/
MPU6050 mpu;
//MPU6050 mpu(0x69); //Use for AD0 high
//MPU6050 mpu(0x68, &Wire1); //Use for AD0 low, but 2nd Wire (TWI/I2C) object.
/* OUTPUT FORMAT DEFINITION----------------------------------------------------------------------------------
- Use "OUTPUT_READABLE_ACCELGYRO" if you want to see a tab-separated list of the accel
X/Y/Z and gyro X/Y/Z values in decimal. Easy to read, but not so easy to parse, and slower over UART.
- Use "OUTPUT_BINARY_ACCELGYRO" to send all 6 axes of data as 16-bit binary, one right after the other.
As fast as possible without compression or data loss, easy to parse, but impossible to read for a human.
This output format is used as an output.
--------------------------------------------------------------------------------------------------------------*/
#define OUTPUT_READABLE_ACCELGYRO
//#define OUTPUT_BINARY_ACCELGYRO
int16_t ax, ay, az;
int16_t gx, gy, gz;
bool blinkState;
void setup() {
/*--Start I2C interface--*/
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(38400); //Initializate Serial wo work well at 8MHz/16MHz
/*Initialize device and check connection*/
Serial.println("Initializing MPU...");
mpu.initialize();
Serial.println("Testing MPU6050 connection...");
if(mpu.testConnection() == false){
Serial.println("MPU6050 connection failed");
while(true);
}
else{
Serial.println("MPU6050 connection successful");
}
/* Use the code below to change accel/gyro offset values. Use MPU6050_Zero to obtain the recommended offsets */
Serial.println("Updating internal sensor offsets...\n");
mpu.setXAccelOffset(0); //Set your accelerometer offset for axis X
mpu.setYAccelOffset(0); //Set your accelerometer offset for axis Y
mpu.setZAccelOffset(0); //Set your accelerometer offset for axis Z
mpu.setXGyroOffset(0); //Set your gyro offset for axis X
mpu.setYGyroOffset(0); //Set your gyro offset for axis Y
mpu.setZGyroOffset(0); //Set your gyro offset for axis Z
/*Print the defined offsets*/
Serial.print("\t");
Serial.print(mpu.getXAccelOffset());
Serial.print("\t");
Serial.print(mpu.getYAccelOffset());
Serial.print("\t");
Serial.print(mpu.getZAccelOffset());
Serial.print("\t");
Serial.print(mpu.getXGyroOffset());
Serial.print("\t");
Serial.print(mpu.getYGyroOffset());
Serial.print("\t");
Serial.print(mpu.getZGyroOffset());
Serial.print("\n");
/*Configure board LED pin for output*/
pinMode(D2, OUTPUT);
}
void loop() {
/* Read raw accel/gyro data from the module. Other methods commented*/
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
//mpu.getAcceleration(&ax, &ay, &az);
//mpu.getRotation(&gx, &gy, &gz);
/*Print the obtained data on the defined format*/
#ifdef OUTPUT_READABLE_ACCELGYRO
Serial.print("a/g:\t");
Serial.print(ax); Serial.print("\t");
Serial.print(ay); Serial.print("\t");
Serial.print(az); Serial.print("\t");
Serial.print(gx); Serial.print("\t");
Serial.print(gy); Serial.print("\t");
Serial.println(gz);
#endif
#ifdef OUTPUT_BINARY_ACCELGYRO
Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));
Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));
Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));
Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));
Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));
Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));
#endif
/*Blink LED to indicate activity*/
blinkState = !blinkState;
digitalWrite(D2, blinkState);
}
When I put this code into my board the LED did not light up at all. I then went back into Chatgpt, and inputed both the failed code and the blink code to get as detailed as possibly. Here is the link to the entire process.
This is the final working code:
#include <Wire.h> // Standard I2C library
#include "I2Cdev.h" // Required by MPU6050 library
#include "MPU6050.h" // MPU6050 library by Electronic Cats/jrowberg
/* MPU6050 default I2C address is 0x68 */
MPU6050 mpu;
//MPU6050 mpu(0x69); // Use if AD0 pin is HIGH
//MPU6050 mpu(0x68, &Wire1); // Use if using a non-default Wire interface
// Define the LED pin (as specified, D2 for XIAO ESP32-C3)
const int ledPin = D2; // Or just 2 if D2 isn't defined in your board package
// Define the threshold for X-axis acceleration
// --- YOU WILL LIKELY NEED TO TUNE THIS VALUE ---
// Observe the 'ax' values printed to the Serial Monitor when the sensor is still
// and when you move it in the way you want to detect. Pick a value slightly
// above the resting noise level but below the movement level you want to trigger the LED.
// Raw values range roughly from -17000 to +17000 for +/-2g sensitivity (default).
const int accelThreshold = 15000; // Example threshold, adjust as needed! //orginally 4000 set to 3000
// Variables to store sensor data
int16_t ax, ay, az;
int16_t gx, gy, gz;
void setup() {
// Initialize Serial communication for debugging
Serial.begin(115200); // Use a common baud rate like 115200
while (!Serial); // Wait for Serial port to connect (optional, good practice)
Serial.println("Initializing I2C devices...");
// Initialize I2C communication
// For XIAO ESP32-C3, default SDA is D4, SCL is D5.
// Wire.begin() typically uses the default pins.
// If your MPU6050 is connected to different pins, specify them:
// Wire.begin(SDA_PIN, SCL_PIN); e.g. Wire.begin(D4, D5);
Wire.begin();
// Initialize MPU6050
Serial.println("Initializing MPU6050...");
mpu.initialize();
// Verify MPU6050 connection
Serial.println("Testing MPU6050 connection...");
if (mpu.testConnection()) {
Serial.println("MPU6050 connection successful");
} else {
Serial.println("MPU6050 connection failed! Check wiring.");
// Halt execution if the sensor isn't found
while (1);
}
// (Optional but recommended) Load calibration offsets if you have them
// Use a separate sketch (like MPU6050_Calibration) to find these values
// Serial.println("Applying MPU offsets (if any)...");
// mpu.setXAccelOffset(YOUR_OFFSET_X);
// mpu.setYAccelOffset(YOUR_OFFSET_Y);
// mpu.setZAccelOffset(YOUR_OFFSET_Z);
// mpu.setXGyroOffset(YOUR_GYRO_OFFSET_X);
// mpu.setYGyroOffset(YOUR_GYRO_OFFSET_Y);
// mpu.setZGyroOffset(YOUR_GYRO_OFFSET_Z);
// Initialize the LED pin as an output
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW); // Start with the LED off
Serial.println("Setup complete. Reading sensors...");
Serial.println("Move the sensor along the X-axis to trigger the LED.");
Serial.println("Raw Accelerometer readings (ax, ay, az):");
}
void loop() {
// Read raw accelerometer and gyroscope data
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
// Print the raw accelerometer values for debugging/tuning
Serial.print("ax: "); Serial.print(ax);
Serial.print("\tay: "); Serial.print(ay);
Serial.print("\taz: "); Serial.println(az);
// --- LED Control Logic ---
// Check if the absolute value of X-axis acceleration exceeds the threshold
if (abs(ax) > accelThreshold) {
// If acceleration is high enough, turn the LED ON
digitalWrite(ledPin, HIGH);
// Optional: Print a message when triggered
// Serial.println("X-Axis Threshold Exceeded - LED ON");
} else {
// Otherwise, turn the LED OFF
digitalWrite(ledPin, LOW);
}
// Add a small delay to prevent overwhelming the Serial portr
// and allow time for sensor readings to stabilize slightly.
// Adjust as needed, but avoid long delays for responsiveness.
delay(50);
}
Here is the video of my board correctly working:
The step was to create a skematic of the board I am going to mill.
In the symbol library, I added these symbols and their correct footprints
- Module_XIAO-ESP32C3 ----- fab:SeeedStudio_XIAO_ESP32C3
- LED ----- LED_SMD:LED_1206_3216Metric
- Conn_01x08_Pin ----- Connector_Molex:Molex_KK-396_A-41791-0008_1x08_P3.96mm_Vertical
- R_1206 ----- fab:R_1206
This is what the final schematic looked like:
I then connected each component in the PCB simulator
I then soldered my board and added all the necessary components.
I uploaded the working code onto my board and hereis the final result:
Reflection¶
This week gave me experience with input devices and interpreting both analog and digital signals. In the group assignment, I worked on a capacitive touch sensor. I watched how touch events produce clear HIGH/LOW digital outputs and using a voltmeter to confirm the signal behavior. For the individual assignment, I used an MPU6050 accelerometer with the XIAO ESP32-C3 to blink an LED when motion was detected. The process involved debugging initial code issues, tuning the acceleration threshold, and interpreting raw sensor data. Through trial and error, I refined the code until it responded accurately to movement. Creating the schematic, routing the board, and successfully uploading the final working code made the entire process come full circle. Overall, this week improved my confidence in integrating sensors, reading real-time data, and building functioning embedded systems from the ground up.
Here is the link to all the files for this week.