Week 10 Output Devices

Objectives

  • Group assignment:Measure the power consumption of an output device
  • Individual assignment: Add an output device to a microcontroller board you've designed, and program it to do something.
  • Group Assignment

    In this week's assignment, I learned how to measure the power consumption of an output device using a bench power supply. We tested an MG90S servo motor connected to a custom PCB by running a servo sweep program through the Arduino IDE. By setting the power supply to 5V and observing the current draw during operation, we found the servo consumed a maximum of around 0.3A, resulting in a power usage of approximately 1.5W. This helped me understand how to monitor and calculate power consumption in practical setups.

    To know more, visitGroup Assignment.

    Output Devices

    An output device is a hardware component that receives data or commands from a microcontroller, processor, or computer and converts them into a form that humans can perceive or use. These devices translate electronically processed information into visual, auditory, or mechanical outputs to interact with the real world. This week I wanted to explore OLED display.

    OLED Display (Organic Light Emitting Diode)

    An OLED display is a small screen that produces its own light to show text and graphics. It is low power, easy to use with microcontrollers, and commonly connected using I2C (SDA, SCL).

    oled layer structure

    Source.

    How do OLEDs work?

    An OLED is a type of LED in which the emitting layer is made of organic compounds that produce light when an electric current is applied. The layer typically consists of a polymer substance sandwiched between two electrodes, a cathode, and an anode. When a current is applied, it causes the organic molecules to emit light.

    OLEDs work similarly to LEDs, but instead of using n-type and p-type semiconductor layers, they use organic compound layers to produce light.

    What makes OLED special?

    Why we use OLED in projects

    Common type used

    Basic connections

    Advantages of OLED

    Coin Vibration Motor (ERM)

    Coin Type Vibration Motor (ERM)

    A coin-type vibration motor is a compact actuator used to generate vibration in electronic devices. It works on the principle of an eccentric rotating mass (ERM), where a small unbalanced weight attached to a DC motor shaft rotates to produce vibration. Due to its flat and lightweight design, it is commonly used in wearable devices, mobile phones, and alert systems. In this project, the motor is used as an output device to provide haptic feedback and notification signals.

    Vibrator Inside

    Source.

     Working Principle

    Vibration strength depends on:

     Mechanical Specifications

    Parameter Typical Value
    Shape Flat Coin Type
    Diameter 8 mm 12 mm
    Thickness 2.5 mm 4 mm
    Weight ~3 grams
    Mounting Adhesive backing (double tape)

    Parameter Typical Value
    Rated Voltage 3V (2V,5V range)
    Current Consumption 60 100 mA
    Starting Voltage ~2V
    Speed ~10,000 RPM
    Control PWM supported

    Seeed Studio XIAO RP2040

    Overview

    The Seeed Studio XIAO RP2040 is a compact and powerful microcontroller board based on the RP2040 chip developed by Raspberry Pi. It features a dual-core ARM Cortex-M0+ processor and is designed for embedded systems, IoT devices, and wearable electronics. Due to its small size and high performance, it is widely used in modern electronics projects.

     Working Principle

     Mechanical Specifications

    Parameter Typical Value
    Board Size 21 mm A— 17.5 mm
    Weight ~2 grams
    Connector USB Type-C
    Mounting Castellated Pins / SMD Pads

    Electrical Specifications

    Parameter Typical Value
    Microcontroller RP2040 (Dual-core ARM Cortex-M0+)
    Operating Voltage 3.3V
    Input Voltage 5V via USB Type-C
    Clock Speed Up to 133 MHz
    Flash Memory 2 MB
    SRAM 264 KB
    GPIO Pins 11 multifunction GPIO
    ADC 12-bit (up to 4 channels)
    PWM Channels Up to 16
    Communication I2C, SPI, UART
    USB USB 1.1 (Device & Host)

    Pin Configuration

    Fabrication Notes

    Applications

    Pinout Diagram

    Source.

    NeoPixel LED (WS2812B)

    Source.

    Overview

    NeoPixel LEDs (WS2812B) are individually addressable RGB LEDs with an integrated driver chip. Each LED can display a wide range of colors and brightness levels using a single data line. They are widely used in interactive projects, decorative lighting, and embedded systems.

    Working Principle

     Mechanical Specifications

    Parameter Typical Value
    Package Type SMD 5050
    Size 5 mm A— 5 mm
    Mounting SMD / LED Strip / Module

    Electrical Specifications

    Parameter Typical Value
    Operating Voltage 5V
    Current (per LED) ~60 mA (max brightness white)
    Logic Voltage 3.3V 5V compatible
    Communication Single-wire digital protocol
    Control Signal PWM (internal)
    Data Rate ~800 kHz
    Color Type RGB (Red, Green, Blue)
    Color Depth 24-bit (16 million colors)

    Pin Configuration

    Fabrication Notes

    Applications

    I2C Connector (SMD JST Port)

    Overview

    The I2C connector is a compact Surface Mount Device (SMD) interface used to connect external modules such as OLED displays and sensors. It simplifies wiring by providing a standardized 4-pin interface for power and communication using the I2C protocol. This connector is widely used in embedded systems and modular electronics projects.

     Working Principle

     Mechanical Specifications

    Parameter Typical Value
    Connector Type JST / SMD Connector
    Mounting Type Surface Mount Device (SMD)
    Pin Count 4 Pins
    Pitch 1.0 mm 2.0 mm
    Orientation Right Angle / Top Entry
    Material Plastic Housing with Metal Contacts
    Color White / Beige
    Dimensions Approx. 5 mm A— 4 mm A 3 mm

    Electrical Specifications

    Parameter Typical Value
    Operating Voltage 3.3V / 5V
    Current Rating Up to 1A (typical)
    Communication Protocol I2C (Two-wire)
    Signal Lines SDA, SCL

    Pin Configuration

    Pin Function
    1 VCC (3.3V / 5V)
    2 GND
    3 SDA (Serial Data)
    4 SCL (Serial Clock)

    Fabrication Notes

    Applications

    Tactile Push Button Switch

    Note on Input Control

    Although this week focuses on output devices, a tactile push button was used in the design to control and switch between different output modes such as vibration patterns, LED effects, and display states. The button acts as a simple user interface to interact with the system.

    Working of MOSFET

    A MOSFET (Metal-Oxide-Semiconductor Field-Effect Transistor) controls current flow between its source and drain terminals by varying the voltage applied to its gate. It consists of a semiconductor body with an insulating oxide layer separating the gate from the channel. When a voltage is applied to the gate, an electric field modifies the conductivity of the channel, allowing or restricting current flow. MOSFETs operate in two modes: enhancement mode, where no current flows without a gate voltage, and depletion mode, where a conductive channel exists by default and can be turned off with a gate voltage. There are two main types: N-channel MOSFETs, where electrons are the primary charge carriers and current flows when the gate is positively biased, and P-channel MOSFETs, where holes are the charge carriers and current flows when the gate is negatively biased. N-channel MOSFETs are generally preferred for high-speed and high-efficiency applications due to their lower resistance and faster switching characteristics.Here I am using an N-channel MOSFET.

    Source.

    Simple Explanation

    Part Function
    Gate (G) Control pin that receives signal from microcontroller
    Drain (D) Connected to load (motor/light)
    Source (S) Connected to ground
    Rin (Gate Resistor) Limits current from input signal and protects MOSFET
    Rgs (Pull-down Resistor) Keeps MOSFET OFF when no input signal is present
    Working (ON State) When input voltage is HIGH, MOSFET turns ON and current flows from drain to source, powering the load
    Working (OFF State) When input is LOW, MOSFET turns OFF and stops current flow

    Designing PCB in KiCad

    The circuit uses a XIAO RP2040 as the main controller, along with a MOSFET to drive a vibration motor, a Schottky diode for protection, a NeoPixel (WS2812B) LED for visual output, resistors for signal stability, a push button for input, and an I2C connector to connect devices like an OLED display.

    This circuit uses an N-channel MOSFET to control a vibration motor from a microcontroller signal. A Schottky diode is added across the motor to protect the circuit from reverse voltage spikes.

    This is a NeoPixel (WS2812B) RGB LED connected to 5V and GND, controlled by a single data pin from the microcontroller. It can display different colors based on the signal received.

    This is an I2C connector with 4 pins: VCC (3.3V), GND, SDA, and SCL. It is used to connect devices like an OLED display or sensors to the microcontroller.

    This is a touch pad input connected to the microcontroller, where touching the pad changes the signal. The resistor to ground helps stabilize the signal and detect touch properly.

    This is an SMD XIAO RP2040 microcontroller module, which acts as the main control unit of the circuit. It reads inputs (button/touch) and controls outputs like the motor and NeoPixel LED using its GPIO pins.

    This is a push button switch with a pull-up resistor, where the resistor keeps the signal HIGH and pressing the button connects it to GND (LOW). It is used as a simple input for the microcontroller.

    This is a 4-pin SMD header (I2C interface) providing 3.3V, GND, SDA, and SCL connections. It is used to easily connect external modules like sensors or an OLED display.

    These constraints settings in KiCad define the minimum values for track width, spacing, via size, and clearances to ensure the PCB is manufacturable and avoids short circuits or design errors.

    These PCB tracks are copper paths that connect all components like the XIAO RP2040, MOSFET, NeoPixel, and connectors, allowing signals and power to flow through the circuit. The routing is done carefully to avoid overlap, maintain spacing, and ensure reliable connections.

    Use ruleschecker to verify the connections. Now we have to change the file to gerber format. Then I uploded the gerber files in Gerber to png. software to convert it to PNG format. For double layer PCB we have five layers to mill.

    PCB Output

    Milling the PCB

    The Roland Modela MDX-20 machine is used for PCB milling. We need to manually set the zero position (X, Y, and Z axes). Load the 1/64" engraving bit and set the X and Y axes at a corner of the board. Then, lower the bit slowly until it just touches the PCB surface and set Z = 0. After that, upload the top trace layer, calculate the toolpath, and send the file to the machine for milling.

    After milling the first layer, carefully replace the bit to 1/32" drill bit for vias, holes and outline cuts.Re-zero only the Z-axis, keeping X and Y unchanged. Resume milling.

    Load the engraving bit and zero the Z-axis again. Run the bottom layer trace milling. Then change the bit.Cut the PCB outline using 1/32" end mill. Here is the final result.

    Assembling the components

    I requested the components from fabstash and collected it from the inventory. I used ineractive HTML BOM in KiCad to get the list of components. It is also highlights were to place components in the pcb.

    The following components were used to design and fabricate the PCB for the vibration feedback system:

    Note: The image was partially masked because some component labels were incorrectly written during selection. The masking was done to avoid confusion.

    The PCB was assembled by soldering all components

    Inspecting the PCB

    The first step is microscope inspection, which focuses on visually examining the PCB for physical defects. Check for issues such as poor solder joints, solder bridges, cracked components, or broken traces. Ensure that all components are correctly placed and aligned.

    Testing

    The PCB was tested for short circuits and voltage drops using a USB tester and power supply.The circuit worked properly with stable voltage and no short circuit issues.

    Programmming the PCB

    Code Reference

    This code was developed with the assistance of ChatGPT.

    #include 
    #include 
    #include 
    
    #define SCREEN_WIDTH 128
    #define SCREEN_HEIGHT 32
    
    #define SDA_PIN D4
    #define SCL_PIN D5
    #define BUTTON_PIN D7
    #define MOTOR_PIN D2
    
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
    
    int mode = 1;
    bool lastButtonState = HIGH;
    
    unsigned long pressStart = 0;
    int intensity = 80;
    
    void setup() {
      pinMode(BUTTON_PIN, INPUT_PULLUP);
      pinMode(MOTOR_PIN, OUTPUT);
    
      Wire.setSDA(SDA_PIN);
      Wire.setSCL(SCL_PIN);
      Wire.begin();
    
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
      display.setRotation(1);  // portrait
    
      display.clearDisplay();
      updateDisplay();
    }
    
    void loop() {
      bool buttonState = digitalRead(BUTTON_PIN);
    
      if (lastButtonState == HIGH && buttonState == LOW) {
        pressStart = millis();
      }
    
      if (lastButtonState == LOW && buttonState == HIGH) {
        unsigned long pressTime = millis() - pressStart;
    
        if (pressTime > 800) {
          if (mode != 4) {
            intensity += 30;
            if (intensity > 255) intensity = 80;
          }
        } else {
          mode++;
          if (mode > 4) mode = 1;
    
          if (mode == 1) intensity = 80;
          if (mode == 2) intensity = 150;
          if (mode == 3) intensity = 255;
          if (mode == 4) intensity = 0;
        }
    
        updateDisplay();
        delay(200);
      }
    
      lastButtonState = buttonState;
    
      analogWrite(MOTOR_PIN, intensity);
    }
    
    void updateDisplay() {
      display.clearDisplay();
      display.setTextColor(WHITE);
    
      int16_t x1, y1;
      uint16_t w, h;
    
      // 🔹 MODE (small)
      display.setTextSize(1);
      String title = "MODE";
      display.getTextBounds(title, 0, 0, &x1, &y1, &w, &h);
      int xTitle = (32 - w) / 2;
    
      // 🔹 NUMBER (big)
      display.setTextSize(2);
      String text = (mode == 4) ? "0" : String(mode);
      display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
      int xNum = (32 - w) / 2;
    
      // 🔥 vertical center
      int startY = 40;
    
      // Draw
      display.setTextSize(1);
      display.setCursor(xTitle, startY);
      display.println(title);
    
      display.setTextSize(2);
      display.setCursor(xNum, startY + 12);
      display.println(text);
    
      display.display();
    }

    Hero Shot

    Mistakes

    On FInal Project time WIth Help of saheen I tried on a new pcb

    This time, I integrated both input and output devices together, and Shaheen suggested using a thermistor instead of the DS18B20.

    this is my new skematic i tried at the time of final project so i redesigned it with help of saheen

    This is my new pcb layout look like

    Check the traces using rules checker tool. from file -> Fabrication outputs -> gerbers , we get the gerber format. the gerber files are uploaded in gerber2PNG software to convert it to png format.

    this is the converted gerber files to png format

    Rest of the process are same as we done before

    this is my new final pcb after milling

    this is components i took for new pcb and attiny 1624 i desolderd from my old pcb

    this is the new pcb after soldering

    this is the code i used for testing the new pcb

    /*
      Thermistor + PTC Heater Controller — ATtiny1624 (megaTinyCore)
      
      Thermistor: VCC → 4.7kΩ → PA6 → Thermistor → GND
      Heater:     PA5 → N-channel MOSFET gate → PTC heater
      
      State machine:
        HEATING     → heater full ON until temp ≥ 60 °C
        MAINTAINING → bang-bang ±0.5 °C for 3 minutes
        COOLING     → heater OFF, returns to room temp
    */
    
    #include <math.h>
    
    // ── Pins ──────────────────────────────────────────────────────────────────────
    #define THERM_PIN   PIN_PA6
    #define HEATER_PIN  PIN_PA5
    
    // ── Circuit constants ─────────────────────────────────────────────────────────
    const float VCC     = 5.0;
    const float R_FIXED = 4700.0;
    
    // ── Thermistor (Beta equation) ────────────────────────────────────────────────
    const float BETA      = 3950.0;
    const float T0_KELVIN = 298.15;   // 25 °C in Kelvin
    const float R0        = 100000.0; // 100 kΩ at 25 °C
    
    // ── ADC ───────────────────────────────────────────────────────────────────────
    const int   NUM_SAMPLES = 16;
    const float ADC_MAX     = 1023.0;
    
    // ── Heater setpoint & hysteresis ─────────────────────────────────────────────
    const float TARGET_TEMP = 60.0;   // °C
    const float HYST_HIGH   = 60.5;   // turn heater OFF above this
    const float HYST_LOW    = 59.5;   // turn heater ON below this
    
    // ── Hold duration ─────────────────────────────────────────────────────────────
    const unsigned long HOLD_MS = 3UL * 60UL * 1000UL; // 3 minutes
    
    // ── State machine ─────────────────────────────────────────────────────────────
    enum HeaterState { HEATING, MAINTAINING, COOLING };
    HeaterState state = HEATING;
    unsigned long holdStart = 0;
    
    // ─────────────────────────────────────────────────────────────────────────────
    void setup() {
      Serial.begin(115200);
    
      pinMode(HEATER_PIN, OUTPUT);
      digitalWrite(HEATER_PIN, LOW);  // safe start — heater off
    
      analogReference(VDD);
      analogReadResolution(10);
    
      delay(2000);
      Serial.println("Heater Controller — ATtiny1624");
      Serial.println("Target: 60 C  |  Hold: 3 minutes");
      Serial.println("------------------------------------");
    
      // Begin heating immediately
      digitalWrite(HEATER_PIN, HIGH);
      Serial.println("[STATE] HEATING");
    }
    
    // ── ADC helpers ───────────────────────────────────────────────────────────────
    float readVoltage() {
      long sum = 0;
      for (int i = 0; i < NUM_SAMPLES; i++) {
        sum += analogRead(THERM_PIN);
        delay(2);
      }
      return (sum / (float)NUM_SAMPLES / ADC_MAX) * VCC;
    }
    
    float voltageToResistance(float v) {
      if (v <= 0.0 || v >= VCC) return -1.0;   // open / short fault
      return R_FIXED * v / (VCC - v);
    }
    
    float resistanceToCelsius(float r) {
      if (r <= 0) return NAN;
      float invT = (1.0 / T0_KELVIN) + (1.0 / BETA) * log(r / R0);
      return (1.0 / invT) - 273.15;
    }
    
    // ─────────────────────────────────────────────────────────────────────────────
    void loop() {
      float voltage    = readVoltage();
      float resistance = voltageToResistance(voltage);
      float tempC      = resistanceToCelsius(resistance);
    
      if (isnan(tempC) || resistance < 0) {
        digitalWrite(HEATER_PIN, LOW);
        Serial.println("ERROR: Sensor fault — heater OFF for safety");
        delay(1000);
        return;
      }
    
      switch (state) {
    
        case HEATING:
          digitalWrite(HEATER_PIN, HIGH);
          if (tempC >= TARGET_TEMP) {
            holdStart = millis();
            state = MAINTAINING;
            Serial.println("[STATE] MAINTAINING");
          }
          break;
    
        case MAINTAINING: {
          if (tempC >= HYST_HIGH) {
            digitalWrite(HEATER_PIN, LOW);
          } else if (tempC <= HYST_LOW) {
            digitalWrite(HEATER_PIN, HIGH);
          }
          if (millis() - holdStart >= HOLD_MS) {
            digitalWrite(HEATER_PIN, LOW);
            state = COOLING;
            Serial.println("[STATE] COOLING — heater OFF");
          }
          break;
        }
    
        case COOLING:
          digitalWrite(HEATER_PIN, LOW);
          break;
      }
    
      Serial.print("Temp: ");
      Serial.print(tempC, 1);
      Serial.print(" C  |  R: ");
      Serial.print(resistance / 1000.0, 2);
      Serial.print(" kOhm  |  V: ");
      Serial.print(voltage, 3);
      Serial.print(" V  |  Heater: ");
      Serial.print(digitalRead(HEATER_PIN) ? "ON " : "OFF");
      Serial.print("  |  State: ");
    
      switch (state) {
        case HEATING:     Serial.print("HEATING    "); break;
        case MAINTAINING: {
          unsigned long secs = (HOLD_MS - (millis() - holdStart)) / 1000;
          Serial.print("MAINTAIN  ");
          Serial.print(secs / 60);
          Serial.print("m ");
          Serial.print(secs % 60);
          Serial.print("s left");
          break;
        }
        case COOLING:     Serial.print("COOLING    "); break;
      }
      Serial.println();
    
      delay(1000);
    }

    this code is made with claude ai the here below i give proment i used to genarate this code

    ihave been designed and milled a pcb.this pcb consist of 1 themistor and 1 ptc 12heater .and iam usinf attiny 1624 ic for this pcb.i connected thermister in PA6 using this code/*
      Thermistor Reader — ATtiny1624 (megaTinyCore)
      Circuit: VCC → 4.7kΩ → PA7 (AIN7) → Thermistor → GND
      ⚠ USART0 remapped via Serial.swap(1):
          TX → PA1  (connect to USB-Serial adapter)
          RX → PA2  (unused)
      This frees PA7 from its default USART0-RX role.
    */
    #include <math.h>
    #define THERM_PIN   PIN_PA6
    const float VCC       = 5;
    const float R_FIXED   = 4700.0;
    const float BETA      = 3950.0;
    const float T0_KELVIN = 298.15;
    const float R0        = 100000.0;
    const int   NUM_SAMPLES = 16;
    const float ADC_MAX   = 1023.0;
    void setup() {
      Serial.begin(115200);
      analogReference(VDD);
      analogReadResolution(10);
      delay(2000);
      Serial.println("Thermistor Reader - ATtiny1624");
      Serial.println("--------------------------------");
    }
    float readVoltage() {
      long sum = 0;
      for (int i = 0; i < NUM_SAMPLES; i++) {
        sum += analogRead(THERM_PIN);
        delay(2);
      }
      float raw = sum / (float)NUM_SAMPLES;
      return (raw / ADC_MAX) * VCC;
    }
    float voltageToResistance(float v) {
      if (v <= 0.0 || v >= VCC) return -1;
      return R_FIXED * v / (VCC - v);
    }
    float resistanceToCelsius(float r) {
      if (r <= 0) return NAN;
      float invT = (1.0 / T0_KELVIN) + (1.0 / BETA) * log(r / R0);
      return (1.0 / invT) - 273.15;
    }
    void loop() {
      float voltage    = readVoltage();
      float resistance = voltageToResistance(voltage);
      float tempC      = resistanceToCelsius(resistance);
      float tempF      = tempC * 9.0 / 5.0 + 32.0;
      if (isnan(tempC) || resistance < 0) {
        Serial.println("ERROR: Sensor fault - check wiring");
      } else {
        Serial.print("Temp: ");
        Serial.print(tempC, 1);
        Serial.print(" C  /  ");
        Serial.print(tempF, 1);
        Serial.print(" F    |  R_th: ");
        Serial.print(resistance / 1000.0, 2);
        Serial.print(" kOhm    |  V_adc: ");
        Serial.print(voltage, 3);
        Serial.println(" V");
      }
      delay(1000);
    }.this code workes perfectley no error .so next ineed to connect heater to PA5 pin along with nchannel mosphet.ineed to make heater with 60degree cel.heater need to be turn up to 60 degreen and continue in 60degree and after 3 miniute turn off back to room temparature

    while testising i tapped both heater and thermister with heat resisting tape

    Conclusion

    i tried 2 pcb one pcb in output week with vibration motor and oled display. after that on time of final project i tried a new pab with input and out put i goot result what i need

    Useful Links

    Tools & Technologies Used

    The programming for this project was developed using Arduino IDE .

    The PCB for this project was designed using KiCad , an open-source electronic design automation (EDA) tool.

    AI tools such as ChatGPT were used to assist in generating code, debugging, and improving documentation.

    Download Files

    Download ZIP File