Week 8: Input Devices

We in the EECS group started our week with our usual, extremely useful walkthrough by Anthony. This week focused on soldering using the reflow technique.

Anthony explained everything clearly and demonstrated how to make (almost) perfect joints using reflow. Then, we got the chance to try it on our own. You can see the result of my first reflow test below.

thermocouple

Now, onto the assignment. This week's task is to measure something by adding a sensor to a microcontroller board we previously designed and then read data from it.

This week sounded fun, and I wanted to try a lot of different input devices, from a camera module, distance sensors, and audio input to acoustic wave sensors, temperature sensors, and other transducers. But unfortunately, I couldn’t give my 100% to HTMAA this week because I had my general exam Part II on Thursday and was fully packed on Friday. I usually spend Saturday as my creative day, brainstorming fun ideas for assignments. However, this weekend I was sick and couldn't give my best.

Despite losing a few days, I tried to test as many input devices as possible. My first idea was to read and display temperature from the thermocouple I use in my experiments. The second was to work with a displacement sensor, and the third was to test the camera sensor on the ESP32S3, which I need for my final project.

Project 1: Thermocouple

I wanted to use a sensor relevant to my research, so I chose a thermocouple. In a recent experiment, I used a thermocouple to heat a sample up to 250°C over two hours, starting from room temperature. Once it reached 250°C, I held it there for 30 minutes to ensure temperature stability. This setup involved a feedback control system with the thermocouple for sensing, a heating band, and a temperature controller from COL-INT TECH. While the device had a small LED screen to show target and current temperatures, it couldn’t record data directly into the data acquisition system. Adding this feature felt perfect for this week’s project.

Thermocouple setup

My first step was understanding the thermocouple's output and splitting the signal to feed both the data acquisition system and the temperature controller. With Anthony’s guidance, I designed the circuit board. He explained how different components, like op-amps, pull-up resistors, and resistor-capacitor combos, work together to convert digital signals to analog.

Explanation from Anthony

Here’s the design of my board:

Schamatic

Explanation from Anthony

PCB Layout

Explanation from Anthony

For this project, I needed several components:

  • Raspberry Pi Pico W
  • Thermocouple (from my lab)
  • MAX31855 (for analog-to-digital conversion and cold-junction compensation)
  • LED display
  • Other components like resistors, capacitors, and connection pins

My goal was not just to read the thermocouple’s output but also to connect this system to the lab’s data acquisition system. This way, I could record temperature alongside other experimental data, allowing me to relate temperature changes to other measurements.

The MAX31855 took a while to arrive from Amazon, so I worked on other sensors in the meantime. Once it arrived, I connected all the parts to test them, but of course, it didn’t work on the first try. The Pico W wouldn’t boot, likely because I had reused it from a previous project, where I’d removed it with a hot air gun. There’s a good chance I fried it in the process.

Full Circuit

A closer look at the MAX31855 breakout board:

MAX31855 breakout board

After hours of troubleshooting, I decided to make a new board. Unfortunately, the milling machine was having issues, especially with the Z-axis setting for the milling bit. Anthony temporarily fixed this with a jumper cable workaround.

Milling the new board

I modified the board design a bit, as you can see on the left. After soldering, everything looked promising.

New and Old Boards

It’s working! I rewrote some code and got it running. I attached an OLED display. The data acquisition and buzzer part I am not doign this time.

Working board

This is the complete setup for my temperature sensor project—it’s been quite a journey, and I even worked on this during week 9.

Complete setup working

Now, everything is running smoothly. Feel free to try making the temperature sensor yourself! The PCB design is updated and ready for use with the Pico.

                                #include <SPI.h>    
                                #include <Wire.h>
                                #include <Adafruit_MAX31855.h>
                                #include <Adafruit_GFX.h>
                                #include <Adafruit_SSD1306.h>

                                // Define MAX31855 pins
                                #define MAXDO   13       // Data Out pin
                                #define MAXCS   14       // Chip Select pin
                                #define MAXCLK  15       // Clock pin

                                // Initialize the thermocouple instance with software SPI
                                Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);

                                // OLED display dimensions
                                #define SCREEN_WIDTH 128
                                #define SCREEN_HEIGHT 64

                                // Create an SSD1306 display object connected to I2C
                                Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, -1);

                                void setup() {
                                // Initialize Serial for debugging
                                Serial.begin(9600);

                                // Initialize I2C for the display with custom pins
                                Wire1.setSDA(10);         // Set custom SDA pin
                                Wire1.setSCL(11);         // Set custom SCL pin
                                Wire1.begin();            // Start I2C with custom pins

                                Serial.println("Initializing MAX31855...");

                                // Initialize the thermocouple sensor
                                delay(500); // Delay for sensor stability
                                if (!thermocouple.begin()) {
                                    Serial.println("ERROR: MAX31855 not detected.");
                                    while (1) delay(10); // Halt if initialization fails
                                }

                                // Initialize the OLED display with the correct address
                                if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Check for address 0x3C
                                    Serial.println("ERROR: SSD1306 allocation failed.");
                                    for(;;); // Halt if display initialization fails
                                }

                                Serial.println("Initialization successful.");
                                }

                                void loop() {
                                // Read the temperature in Celsius from the thermocouple
                                double celsius = thermocouple.readCelsius();
                                double fahrenheit = celsius * 9.0 / 5.0 + 32.0;  // Convert Celsius to Fahrenheit

                                // Clear previous content from the display buffer
                                display.clearDisplay();
                                display.setTextSize(2);          // Set text size (1 is small, readable)
                                display.setTextColor(SSD1306_WHITE); // Set text color to white
                                display.setCursor(0, 0);         // Start writing at top-left corner

                                if (isnan(celsius)) {
                                    // Handle errors if temperature data isn't available
                                    Serial.println("Thermocouple fault(s) detected!");
                                    display.println("Thermocouple fault!");

                                    uint8_t error = thermocouple.readError();
                                    if (error & MAX31855_FAULT_OPEN) {
                                    Serial.println("FAULT: Open connection.");
                                    display.println("FAULT: Open.");
                                    }
                                    if (error & MAX31855_FAULT_SHORT_GND) {
                                    Serial.println("FAULT: Short to GND.");
                                    display.println("FAULT: Short to GND.");
                                    }
                                    if (error & MAX31855_FAULT_SHORT_VCC) {
                                    Serial.println("FAULT: Short to VCC.");
                                    display.println("FAULT: Short to VCC.");
                                    }
                                } else {
                                    // Display temperature in the format: "T = xx °C || xx °F"
                                    Serial.print("T = ");
                                    Serial.print(celsius);
                                    Serial.print(" °C || ");
                                    Serial.print(fahrenheit);
                                    Serial.println(" °F");

                                    display.print("T = ");
                                    display.print(celsius);
                                    display.print(" C || ");
                                    display.print(fahrenheit);
                                    display.println(" F");
                                }

                                // Render content to OLED
                                display.display();
                                delay(1000); // Delay for readability and sensor stability
                                }

                                
                        

Project 2: Distance Measurement

Distance measurement is a key parameter in my experiments. I've used larger laser sensors and strain gauges before, but I hadn’t tried these tiny, calibrated distance sensors. Typically, we use pre-calibrated sensors that connect directly to the data acquisition system, so there’s no coding beyond understanding basic parameters.

Anthony provided me with VL53L0X sensors—tiny laser-based distance sensors. I designed the circuit board and connected everything. This board is straightforward, with an ESP32C3 microcontroller, a five-pin connector for an LED screen to display the distance, and the VL53L0X sensor. First, I read the datasheet carefully, which explained the need for pull-up resistors and capacitors, so I designed and milled the circuit board accordingly.

Schamatic

Explanation from Anthony

PCB Layout

Explanation from Anthony

After soldering, I began coding based on class notes with some tweaks, but the sensor didn’t initialize. At this point, I added the LED screen to display the measured distance.

Frustration kicked in! My Pico board for the temperature sensor wasn’t cooperating, and the distance board wasn’t recognizing the sensor. Ah, the joys of electronics, haha!

Frustration with scattered boards

The LED display was working fine, so I got a head start on week 9's assignment. Now, my job is to read the sensor’s data and display it on the LED screen, which is already set up.

Hello World Print

Despite my microcontroller not communicating with the VL53L0X sensor, it displayed a reading of 65535 mm, likely a default value caused by the input voltage, which the microcontroller mistakenly read as sensor data.

Incorrect distance on screen

Anthony, Sam, Alec, and I tried every troubleshooting trick we knew, but the issue persisted.

Trying different solutions

This is the board giving me trouble! I tried multiple debugging techniques, checked the soldering on the tiny VL53L0X sensor, tested the wiring, and even used jumper wires, but nothing seemed to work.

Full Circuit

After hours of debugging, I decided to start fresh with a new board and a new sensor. Anthony also gave me a VL53L0X sensor on a breakout board, which didn't require soldering.

Below, you can see the new board side-by-side with the old one for comparison. Still, the problem persisted on the new board.

New and Old Boards

Initially, I suspected poor soldering on the tiny sensor, which I had reflowed to attach. After extensive debugging, we figured the problem likely stemmed from imperfect soldering between the PCB and the sensor.

After extensive debugging

Even after solving the power issue, the board still didn’t work. So, I used the VL53L0X breakout board, which—bingo!—worked perfectly. We checked the accuracy by comparing the laser-measured distance with a tape measure, and it was spot-on.

Checking accuracy of measurement

The distance measurement project had a happy ending, and it’s working fine. Hurray!!!

I also connected the OLED display to show the distance.

                            #include <Wire.h>
                            #include <VL53L0X.h>
                            #include <Adafruit_GFX.h>
                            #include <Adafruit_SSD1306.h>
                            
                            #define SCREEN_WIDTH 128  // OLED display width, in pixels
                            #define SCREEN_HEIGHT 64  // OLED display height, in pixels
                            #define OLED_RESET    -1   // Reset pin (-1 if sharing Arduino reset pin)
                            #define SCREEN_ADDRESS 0x3C  // I2C address for OLED, typically 0x3C or 0x3D
                            
                            // Initialize the VL53L0X sensor
                            VL53L0X sensor;
                            
                            // Initialize the OLED display
                            Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
                            
                            void setup() {
                            Serial.begin(9600);
                            Wire.begin();
                            
                            // Initialize OLED display
                            if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
                                Serial.println(F("SSD1306 allocation failed"));
                                while(1);  // Loop forever if OLED init fails
                            }
                            display.clearDisplay();
                            display.setTextSize(1);
                            display.setTextColor(SSD1306_WHITE);
                            display.setCursor(0, 0);
                            display.println("Distance:");
                            display.display();
                            
                            // Initialize the VL53L0X sensor
                            Serial.println("Initializing sensor...");
                            sensor.setTimeout(500);
                            if (!sensor.init()) {
                                Serial.println("Failed to detect and initialize sensor!");
                                display.setCursor(0, 20);
                                display.println("Sensor failed!");
                                display.display();
                                while (1);  // Halt on error
                            }
                            
                            // Optional sensor modes
                            #if defined LONG_RANGE
                                sensor.setSignalRateLimit(0.1);
                                sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
                                sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
                            #endif
                            
                            #if defined HIGH_SPEED
                                sensor.setMeasurementTimingBudget(20000);  // Timing budget to 20ms
                            #elif defined HIGH_ACCURACY
                                sensor.setMeasurementTimingBudget(200000); // Timing budget to 200ms
                            #endif
                            }
                            
                            void loop() {
                            int distance = sensor.readRangeSingleMillimeters();
                            
                            // Print distance to serial monitor
                            Serial.print("Distance: ");
                            Serial.print(distance);
                            Serial.println(" mm");
                            
                            // Display distance on OLED
                            display.clearDisplay();
                            display.setCursor(0, 0);
                            display.println("Distance:");
                            display.setCursor(0, 20);
                            
                            if (sensor.timeoutOccurred()) {
                                Serial.println(" TIMEOUT");
                                display.println("TIMEOUT");
                            } else {
                                display.print(distance);
                                display.println(" mm");
                            }
                            
                            display.display();  // Show on OLED
                            delay(500);         // Adjust delay as needed
                            }
                        

Project 3: Camera Module

I wanted to experiment with the camera module as an initial step for my final project and as part of this week's assignment. The camera module connects directly to the ESP32S3, so there was no need to design a separate circuit board. I had an ESP32S3 on hand, but spent hours troubleshooting because the connection with the camera module wasn’t working. After seeing my struggle, Anthony took me to the CBA lab to grab an ESP32S3 from their inventory, which worked perfectly!

thermocouple

thermocouple