Week 10: Output Devices


Assignment

Group assignment: - Measure the power consumption of an output device
- Document the group work

Individual assignment: - Add an output device to a microcontroller board you have designed and program it to perform a specific task


Overview

During this week, I focused on working with output devices by designing and building a complete embedded system capable of controlling a stepper motor using my own custom PCB. This assignment was not only about making a motor rotate, but about developing a deeper understanding of how digital systems interact with physical components in real-world conditions.

The objective was to explore how a microcontroller can generate signals, how these signals are interpreted by external hardware such as motor drivers, and how these interactions result in controlled mechanical motion. In addition to that, this week required a strong focus on debugging, since real systems rarely work perfectly on the first attempt.

What makes this week especially important is that it combines multiple areas of knowledge: - Electronics and circuit design
- Embedded programming
- Signal processing and timing
- System integration
- Debugging and problem-solving

Through this project, I aimed to build a system that is not only functional but also well understood from both hardware and software perspectives.


System Architecture

The system I developed is composed of several interconnected components that work together to produce controlled output behavior.

The main components include:

  • A custom-designed PCB based on the ESP8266 microcontroller
  • A stepper motor driver (A4988 or similar)
  • A stepper motor as the mechanical output
  • An LCD display as a visual output interface
  • Breadboard and jumper wires for flexible connections

The architecture of the system can be described as follows:

The microcontroller acts as the central unit that generates control signals. These signals are sent to the motor driver, which translates them into high-power electrical signals suitable for driving the stepper motor. At the same time, the microcontroller communicates with the LCD display to provide visual feedback.

This creates a multi-output system where one controller manages both mechanical and visual outputs simultaneously. Understanding this architecture is important because it reflects how real embedded systems are designed in industry.


Hardware Design and Connections

The hardware setup required careful planning, attention to detail, and a clear understanding of how each component functions.

Stepper Motor Driver

The stepper motor driver plays a crucial role in the system. It acts as an intermediary between the low-power microcontroller and the high-power motor.

Key connections include:

  • STEP pin: receives pulse signals that define motor steps
  • DIR pin: determines the rotation direction
  • SLP (Sleep) pin: enables or disables the driver
  • RST (Reset) pin: controls internal reset behavior
  • VMOT: provides power to the motor
  • GND: common ground reference

The driver must be properly powered and enabled; otherwise, it will not respond to control signals.

Motor Connections

The stepper motor contains multiple coils that must be connected correctly to the driver outputs. Incorrect wiring of these coils can lead to vibration instead of rotation, or no movement at all.

PCB Integration

My custom PCB, based on ESP8266, provided the necessary control signals. Since the ESP8266 operates at 3.3V logic, all connections had to be compatible with this voltage level.

This stage required careful wiring and verification because even a small mistake in connections can lead to a non-functional system.


Control Mechanism

The microcontroller sends a series of HIGH and LOW signals to the STEP pin. By controlling the delay between these signals, I can adjust how fast the motor rotates.

The logic is simple but powerful: - Short delay → higher speed
- Long delay → slower speed

This demonstrates how digital signals can control physical movement with precision.


Initial Failure and Debugging Strategy

When I first powered the system and uploaded the code, the motor did not move at all. This was a critical moment because it highlighted the reality of working with embedded systems: even when everything appears correct, the system may still fail.

Instead of randomly changing components or rewriting code, I followed a structured debugging strategy:

  1. Verified all physical connections
  2. Checked if the microcontroller was outputting signals
  3. Reviewed the code logic
  4. Confirmed that the power supply was stable

This systematic approach is essential in engineering because it helps isolate the problem efficiently.


Isolating the Problem Using Arduino

To further diagnose the issue, I introduced a known working system: Arduino Uno.

By connecting the same driver and motor to Arduino and running a simple test program, I observed that the motor worked perfectly.

This experiment provided very important information:

  • The motor is functional
  • The driver is functional
  • The issue is not in these components

Therefore, the problem must be related to my custom PCB or wiring.

This step significantly reduced the number of possible causes and allowed me to focus my debugging efforts more effectively.

define dirPin  5
define dirPin  4
define stepsPerRevolution 200

void setup() {
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {

  // Clockwise
  digitalWrite(dirPin, HIGH);

  for (int i = 0; i < stepsPerRevolution; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(2000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2000);
  }

  delay(1000);

  // Counterclockwise
  digitalWrite(dirPin, LOW);

  for (int i = 0; i < stepsPerRevolution; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
  }

  delay(1000);

  // 5 revolutions fast clockwise
  digitalWrite(dirPin, HIGH);

  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);

  // 5 revolutions fast counterclockwise
  digitalWrite(dirPin, LOW);

  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);
}

Root Cause Analysis

After careful inspection, I discovered the main issue:

The SLP (Sleep) and RST (Reset) pins of the driver were not connected to 3.3V.

Why This Is Important

The SLP pin disables the driver when it is LOW.
The RST pin resets the internal logic of the driver.

If these pins are not properly connected: - The driver remains inactive
- It ignores all incoming control signals

Solution

After connecting both SLP and RST pins to 3.3V: - The driver became active
- The motor started responding immediately

This was a critical learning moment. It showed that even a small missing connection can completely prevent a system from working.


LCD Integration

To make the project more advanced and interactive, I added an LCD display.

The purpose of the LCD was to provide visual feedback about the system. Instead of having a system that only performs mechanical actions, I wanted to include a user interface.

Possible information displayed: - System status
- Motor activity
- Messages

This transforms the system into a more complete embedded application.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// LCD address
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {

  // I2C: SDA = 13, SCL = 12
  Wire.begin(13, 12);

  lcd.init();
  lcd.backlight();

  lcd.setCursor(0, 0);
  lcd.print("Hello");

  lcd.setCursor(0, 1);
  lcd.print("Abdikarim");
}

void loop() {
}

LCD Testing

Before integrating the LCD into the full system, I tested it independently.

I uploaded a simple program to display the message:

Hello Abdikarim

This test ensured: - Correct wiring
- Proper communication protocol
- Functional display

Testing components individually reduces complexity and helps identify issues early.


Full System Integration

After verifying all components individually, I integrated them into a single system.

The final system includes: - Custom PCB controlling everything
- Stepper motor system for mechanical output
- LCD for visual output

System Behavior

  • The microcontroller sends signals to control motor movement
  • The driver translates signals into motion
  • The LCD displays system information

This demonstrates a complete embedded system with multiple outputs working together.


Final Result

The final system successfully demonstrates a fully functional output device system.

It includes: - Reliable motor control
- Functional LCD output
- Stable hardware integration

This project represents the full engineering workflow: from design → implementation → debugging → final result.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// LCD address 
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Motor pins
#define stepPin 5   // GPIO5 (D1)
#define dirPin  4   // GPIO4 (D2)

#define stepsPerRevolution 200

int speedDelay = 1500; 

void setup() {

  // I2C LCD: SDA = 13, SCL = 12
  Wire.begin(13, 12);

  lcd.init();
  lcd.backlight();

  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);

  lcd.setCursor(0, 0);
  lcd.print("System Ready");
  lcd.setCursor(0, 1);
  lcd.print("Abdi Project");

  delay(1500);
  lcd.clear();
}

void loop() {

  lcd.setCursor(0, 0);
  lcd.print("Speed: ");
  lcd.print(speedDelay);
  lcd.print("   "); 

  lcd.setCursor(0, 1);
  lcd.print("Stepper Running");

  digitalWrite(dirPin, HIGH);

  for (int i = 0; i < stepsPerRevolution; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(speedDelay);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(speedDelay);
  }

  delay(500);

  digitalWrite(dirPin, LOW);

  for (int i = 0; i < stepsPerRevolution; i++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(speedDelay);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(speedDelay);
  }

  delay(500);

  speedDelay -= 200;

  if (speedDelay < 400) {
    speedDelay = 1500;
  }
}


Reflection and Learning Outcomes

This project greatly improved my understanding of embedded systems.

I learned: - How stepper motors operate
- How drivers interpret control signals
- How to design and connect hardware systems
- How to debug problems systematically

Key Insight

The most important lesson was understanding that:

A system can fail due to a very small mistake, and only a structured debugging process can reveal the real issue.

This experience also showed the importance of reading datasheets carefully and understanding how each component works.


Future Application

The knowledge gained from this project will be directly applied in my Final Project.

I now have a strong understanding of: - Motor control systems
- Circuit design principles
- Debugging techniques

This will allow me to build more advanced systems such as robotics, automation devices, or mechanical control systems.


Files

  • Source code
  • PCB design files
  • Documentation

Download the project