Input devices
This week I channeled the mantra: "You make mistakes, but that's how you learn" (or something like htat).
Erwin's lesson
Below are a few concepts about input devices, from Erwin's lecture, that are worth understanding.
Signals (basic)
There are two types of signals:
Analog, which is continuous and we measure points along the wave.
Digital, which is either on or off.
- Converting analog signals to digital signals turns voltage into a value.
- Converters come in different resolutions, for instance: 8bit (0-255) can measure in 255 steps.
GPIO pins
General Purpose Input-Output
- GPIO pins read either low or high.
- LOW: 0 - 1/3rds VCC
- HIGH: 2/3rds VCC - 1 VCC.
- A GPIO reading is undefined between 1/3rds VCC and 2/3rds.
Pull-up / pull-down resistors
The purpose of pull-up/pull-down resistors is to prevent the pin from "floating" in an undefined state, which could lead to unpredictable behavior.
- A pull-up resistor connects the pin to VCC, ensuring it reads HIGH when not driven.
- A pull-down resistor connects the pin to ground, ensuring it reads LOW when not driven.
NB. Many microcontrollers have internal pull-up/pull-down resistors that can be enabled in software.
This is a diagram that Erwin drew to help explain PU/PD resistors.
Interfaces - protocol
ie. how components communicate.
- 1wire/two wire (twi): communicates over gnd and vcc -- data transmitted over the one cable.
- I2C: uses 7 bit addresses clock and data signals (different to Serial, which uses baudrate).
- SPI: exchanges bits between microcontrollers or sensor + MCU -- uses pins instead of addresses.
- PWM: for noisy environments.
- Serial:
Rx
/Tx
receive transmit with a baudrate. Serial runs on 1 to 1 communication, meaning you need a new serial port for other devices.
Button noise
There's a small amount of noise when you push in a button, just before the button has totally bridged the connection.
This input noise can mess up readings. There are two main ways to deal with the noise:
- In software (ie. code that says to ignore the first 10 ms)
- Using a capacitor
When taking the software approach, MCU's with an Aref (analog reference) signal can be used to show what the clean voltage is as a reference.
The other approach is using a capacitor, as Erwin explains, visualized below:
The SI system
The 7 core values that we use (aka The SI system) to define (pretty much) everything. They are:
- seconds
- meters
- grams
- amperes
- kelvins
- moles
- candelas
Everything else is defined by these values, for example, how to calculate Volts.
1 Volt = 1kg⋅m²⋅s⁻³⋅A⁻¹
Group project
During the group assignment we set connected various input devices to an Arduino and interpreted the results.
Microwave radar (RCWL-0516)
Our tests didn't seem to work. The output pin of the sensor was connected to an LED on a breadboard. The LED flashes didn't correlate with the movements we made.
The multimeter indicated that there were no broken circuits.
After extensive debugging and still no improvement, we opted to move on and check a sensor that we knew was in good working condition.
Ultrasonic (HCSR04)
This is Henk's favorite sensor. In 2018, he documented about using it to measure the thickness of ice.
The sensor has four pins, two of which are for emitting and receiving ultrasonic pulses. To get a better idea of how the sensor worked, we hooked up a logic analyzer to some of the pins.
To better understand the readings, we decided to hook the sensor up to a logic analyzer (Irja took really good notes on this).
Input values from the sensor (on Arduino's serial monitor):
Here we can see the relationship between echo and trigger signals.
The sensor takes 180.92 ms to process an Out of range
value. While it processes that, no other signals are sent out, which results in a delay.
We also connected the logic analyzer to the serial communication. The 3rd row gives back a reading when values are printed in the serial monitor. Below, Sam wrote something in the serial monitor. The bottom row shows that.
Individual project
My initial focus was to get each component on the Henkduino board to do it's most basic functions.
- Turn the LED on.
- Get the button to turn the LED on and off.
- Get readings from the phototransistor in the Serial Monitor.
It took me ages to figure out why the LED wasn't blinking. I had tested it with the multimeter at Waag, so I knew that the connection was ok. In the end, it turned out the issue was that I had the ledPin
defined as D3 rather than D2.
Once I got all of the pins correctly defined, everything worked. YEEHAW!
Here are the readings of the light that I got in my serial monitor:
This was my first spiral / most basic code, to check that everything worked:
const int ledPin = D2; // define LED
const int buttonPin = D10; // define button
const int photoPin = D0; // define phototransistor
int buttonState = 0; // define the button's initial state with a value
void setup() {
Serial.begin(9600); // set up communication frequency with the computer
pinMode(ledPin, OUTPUT); // define pin type
pinMode(buttonPin, INPUT);
pinMode(photoPin, INPUT);
}
void loop() {
int lightLevel = analogRead(photoPin); // read the photoPin's value and define it as an integer
Serial.println(lightLevel); // print that value
delay(100);
buttonState = digitalRead(buttonPin); // Read button state
if (buttonState == HIGH) { // If button is pressed
digitalWrite(ledPin, HIGH); // Turn LED on
} else {
digitalWrite(ledPin, LOW); // Turn LED off
}
}
VL53L1X project (with programmer)
Some important definitions
I2C - I2C is a two-wire serial communication protocol using a serial data line (SDA) and a serial clock line (SCL).
Multiplexer - an electronic device that allows multiple input signals to be selected and transmitted over a single output line.
Programmer - a device used to upload code or firmware to a microcontroller.
Breakout board - an electronic device that allows multiple input signals to be selected and transmitted over a single output line
My goal was to make a circuit using the TOF sensor. I felt that this was a good option for my final project. The stepper motor controlling the toilet seat lifter could be activated by someone's foot coming close enough to the TOF sensor.
Most of the Fab academy documentation that I found for TOF sensors used Adafruit breakout boards.
As we didn't have any available at Waag, I decided to try and make my own.
After some searching, I stumbled on Sparkfun's breakout board, which came with a nice schematic!
Click here to learn more about Jumpers.
There was a bit of confusion in the SparkFun schematic around what Jumpers were. My understanding is that they are connections to pull-up resistors that can be soldered or unsoldered depending on if there are already pull up resistors in the circuit or not.
I asked AI to help me understand more about Jumpers.
I began recreating the Sparkfun breakout board in KiCad, but eventually decided to rather follow the Pololu breakout board schematic.
In the end, I was running out of time and decided to simplify my project. However, I learned a lot about the VL53L1X.
Resources specific to the VL53L1X:
VL53L1X project (with XIAO board)
XSHUT and INT/GPIO
XSHUT and GPIO1 purposes (AI report)
XSHUT: Power Saving -- The primary reason to use the SHUT pin is to conserve power. When you don't need the sensor to be actively measuring distances, you can pull the SHUT pin LOW to put the sensor into a low-power state. This is important for battery-powered applications.
GPIO1/INT on the VL53L1X is to a digital pin on the microcontroller (optional, for interrupt).
NB. The capacitors are used for decoupling and noise filtering, which are essential for stable operation.
The datasheet indicates that we need to use a pull-up resistor for the XSHUT pin.
The VL53L1X's XSHUT pin requires a pull-up to a valid logic high voltage (e.g., 2.8V or 3.3V) to keep the sensor enabled. Without a pull-up resistor, the XSHUT pin would remain low due to the RP2040's default pull-down state, which would disable the sensor.
Adding a 10k pull-up resistor to 3.3V is generally a safe choice. It ensures the XSHUT pin remains in a defined state and protects against floating inputs.
Schematic design
NB. Make sure to check what resistors and capacitors are available in the lab before completing the PCB layout.
I designed and milled my PCB, only to realize that we didn't have the specific resistors that I had planned my circuit around.
Digital files
Clearance and simulated path view check
The TOF sensor has 12 tiny pads, that have 0.3mm between them, but the diameter settings of the milling bit I used was 0.4mm. This resulted in a bad mill.
NB. In the future, make sure to look at the simulated path view to check if the mill looks right.
The updated tool diameter of 0.3mm worked.
There was actually evidence in KiCad that this might be an issue. I wasn't able to draw traces as my settings weren't small enough (0.3mm).
Mill: offset settings
I realized that I was slightly confused about the offset number
setting.
For the F.Cu milling I had chosen an offset of 0, because I wanted to clear out all of the empty areas on my board. That's a HUGE waste of time.
The Offset number
should have been = 4 for this project. Offset number
= 1 on Edge.cuts, as we don't need to offset the cutting of the border!
Also worth remembering: the Mill depth on Edge.cuts should start at 0.3 mm
not 0.003 in
.
Make sure to have the Fill edge cuts
box selected on the Gerber to PNG tool for the F.Cu layer.
Soldering the TOF sensor
NB. Don't use too much solder.
- Add reflow
- Dab with tip onto the copper areas being soldered
- Put a tiny bit down and spread it around
- Place component
- Use hot airgun to activate the solder (first take off protective film over sensor)
Reflow makes the solder spread out and lie flat on the copper.
Careful of the part melting and check with a microscope if the solder has worked.
Useful resource: Here are some extra Soldering tips from Kris
Test board
Henk gave me an I2C code to check on the controller, but I was having issues with sending code from Arduino.
The loading of the code kept getting stuck on "Resetting /dev/cu.usbmodem101".
After much debugging and learning about boot mode, Sam noticed that, actually, I had my pins set up incorrectly.
WRONG:
HOW IT SHOULD BE:
THE ISSUE (mixing up the schematic numbers from the actual pin numbers):
FIXED:
TRY AGAIN:
I milled a new board, flowed/soldered the parts on, and tested again.
However, the LEDs on the XIAO weren't turning on when plugged onto my PCB.
The beep test 'beeped' when I had the multimeter on ground
and power
. There was a short circuit somewhere.
I took off the capacitors.
Still beeping.
Took off the TOF.
No longer beeping.
Sam reflowed the sensor on and it didn't beep, but I still wasn't able to get an I2C reading in Arduino's Serial monitor.
The week ended without me being able to get the TOF circuit to work.
Useful resources:
VL53L0/1XV2 breakout board
Hello, this is Dylan from the future (networking week)
I came back to the TOF sensor, so that I would have something to communicate with for networking week. I hooked a TOF breakout board to a XIAO RP2040 and used an example code.
Here are the .png files of my PCB
Voila!
It worked.
/*
This example shows how to take simple range measurements with the VL53L1X. The
range readings are in units of mm.
*/
#include <Wire.h> // Enables I2C communication between the Arduino and the VL53L1X sensor
#include <VL53L1X.h>
VL53L1X sensor;
void setup()
{
while (!Serial) {}
Serial.begin(115200);
Wire.begin();
Wire.setClock(400000); // use 400 kHz I2C
// Sets a timeout of 500 ms for sensor operations
sensor.setTimeout(500);
if (!sensor.init())
{
Serial.println("Failed to detect and initialize sensor!");
while (1);
}
// Use long distance mode and allow up to 50000 us (50 ms) for a measurement.
// You can change these settings to adjust the performance of the sensor, but
// the minimum timing budget is 20 ms for short distance mode and 33 ms for
// medium and long distance modes. See the VL53L1X datasheet for more
// information on range and timing limits.
sensor.setDistanceMode(VL53L1X::Long); // "Long" mode allows for measurements up to 4 meters
sensor.setMeasurementTimingBudget(50000); // How long the sensor spends on each measurement - A longer timing budget improves accuracy but reduces speed
// Start continuous readings at a rate of one measurement every 50 ms (the
// inter-measurement period). This period should be at least as long as the
// timing budget.
sensor.startContinuous(50);
}
void loop()
{
Serial.print(sensor.read());
if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
Serial.println();
}