Embedded Programming

Week 04

Writing software to control hardware for dedicated tasks

Embedded Programming

Group Assignment

Comparing development workflows and programming microcontrollers from different architectures.

Group Page

What is it?

Is the process of writing software specifically designed to control hardware devices that perform dedicated tasks. Unlike general-purpose computers, these systems are integrated directly into machines to manage inputs and outputs in real-time.

Key Characteristics:

  • Specific Functionality: The code is optimized for a single, predefined purpose.
  • Hardware Interaction: It communicates directly with sensors, actuators, and communication modules.
  • Resource Management: It operates on microcontrollers with limited memory requiring high efficiency.

Software used

For the development of this project, the following tools were used:

Program Description
Thonny Is a lightweight Integrated Development Environment (IDE) specifically designed for people who are new to programming, especially in Python.
Wokwi A powerful online simulator for testing ESP32, Arduino, and electronics in the browser without needing physical hardware.
Cirkit Designer A specialized tool for creating professional circuit diagrams, breadboard layouts, and organizing project documentation.
Arduino IDE The standard software for writing, compiling, and uploading code (sketches) to microcontrollers via a USB connection.

The workflow:

  1. Simulate in Wokwi to verify the logic.
  2. Document the wiring using Cirkit Designer.
  3. Deploy the final code to the physical board using Arduino IDE (C++) or Thonny (Python).

Microcontroller Families

Broadly speaking, these are the microcontrollers that exist:

Family Example Use Case
AVRArduinoIdeal for interactive projects using C/C++ programming. [cite: 17]
RPRP2040Combines high performance and affordability, ideal for simple applications. [cite: 17]
ESPESP32 (most common)Versatile for IoT projects with Wi-Fi and Bluetooth connectivity. [cite: 17]

Data sheet

The intention of my project for this week is to make a conveyor belt, because since the "Crystal-Inator" is a production process, it needs to go through several stages. In this first phase of development, I solely focused on having the motor that will turn the belt advance for a certain distance and stop for 5 seconds, which would be the time used to carry out the corresponding process.

Electronic materials used

Material Use in my process
Microcontroller Acts as the "brain" of the system. In the initial stage, it facilitates learning with C++ language. In the final stage, the ESP32 will manage the movement of the belt and transmit production data (piece count) via Wi-Fi/Bluetooth towards a monitoring interface.
H-Bridge TB66 / Driver A controller (such as the A4988 or TB66) is used to manage the power received by the motor. Its function is to translate low-current logic signals from the microcontroller into high-current pulses needed to move the belt, allowing precise control of speed and stop times.
Stepper Motor It is the actuator in charge of providing mechanical movement to the conveyor belt. A stepper motor was chosen to guarantee exact stops at specific points of the process, allowing the belt to advance and stop in a controlled manner according to the time programmed in the code.
laser cut 02

Representation of the materials in my simulation


In a first stage, I consider that it would be good to use a microcontroller from the "AVR" family, as they provide the basic functions and are programmable in C++. This is especially helpful when connecting it physically, since I am very new to programming. However, for the final stage of my project, I believe the best option is to directly use an "ESP32" microcontroller. Since there will be cameras for production monitoring, it would be ideal for that output data to reach another device via Wi-Fi or Bluetooth to maintain better control and record the number of pieces produced. The camera part will be done at another time, but for now, the main intention of the code was to have the stepper motor rotate to advance and stop for a period of time. With this in mind, the relevant information I looked for in the Datasheets was:

Technical Comparison (Datasheet)

Click into the links below in the name of the component to view the datasheets.

Feature ESP32 (using A4988) Arduino Uno (using A4988)
Current Limit 2 A (Maximum per phase) 2 A (Maximum per phase)
Load Supply Voltage 8 V to 35 V 8 V to 35 V
Timing Diagram 1 µs (Min STEP pulse) 1 µs (Min STEP pulse)

My simulation

I used Wokwi to simulate the conveyor belt. I started from a base code provided by my advisor and evolved it with the help of AI.

My advisor shared a basic code with me that used similar elements and setups; however, it did not have the same purpose. In that original version, the intention was for the stepper motor to complete one turn and then reverse its direction, while an LED turned on and off depending on the direction of the spin. The explanation of that process and the code development is provided below.

Original code simulation


My advisor's code

              // Testing Driver, Stepper Motors, and ESP32
              // This code manages a stepper motor using a driver like the A4988.

              #define x_paso 15   // Defines the STEP pin for the X-axis motor
              #define x_dire 2    // Defines the DIR (Direction) pin for the X-axis motor
              #define x_habi 4    // Defines the ENABLE pin for the X-axis motor

              // Global Variables
              int retardo = 3000; // Delay in microseconds. A lower number makes the rotation faster.
              int tiempo = 220;   // The number of steps the motor will take (effectively the duration of the turn).

              // Setup runs once when the board is powered on
              void setup() {
                // Set all motor control pins as OUTPUT so the ESP32 can send signals to the driver
                pinMode(x_paso, OUTPUT); 
                pinMode(x_dire, OUTPUT); 
                pinMode(x_habi, OUTPUT);     
              }    

              void loop() {
                // Logic: 1 and 0 are Boolean states for the DIR pin. 
                // Direction 1 (HIGH) usually results in clockwise rotation, while 
                // Direction 0 (LOW) results in counter-clockwise rotation, 
                // depending on how the motor wires are connected to the driver.
                giro(x_paso, x_dire, x_habi, 1); 
                delay(500); // Short pause before changing direction
                giro(x_paso, x_dire, x_habi, 0); 
                delay(500);
              }

              /**
              * void giro: This is a custom function created to avoid repeating code. 
              * It receives four parameters: the Step pin, the Direction pin, the Enable pin, 
              * and the desired direction (0 or 1). This allows you to control any motor 
              * using the same logic block.
              */
              void giro(int paso_, int dire_, int habi_, int dir) { 
                
                // digitalWrite(habi_, LOW): Most drivers are "Active Low." 
                // Sending a LOW signal enables the driver so it can energize the motor coils.
                digitalWrite(habi_, LOW);   

                // Check which direction was requested
                if(dir == 0) { 
                  digitalWrite(dire_, LOW); // Set the physical direction pin to LOW
                  
                  // for(int i=0; i < tiempo; i++): This is a loop that repeats the instructions inside.
                  // It starts with 'i' at 0, and as long as 'i' is less than 'tiempo' (220), 
                  // it executes the code and then adds 1 to 'i' (i++). 
                  // This effectively tells the motor to take exactly 220 pulses (steps).
                  for(int i = 0; i < tiempo; i++) {  
                    
                    // Creating a Pulse:
                    digitalWrite(paso_, HIGH);   // Send a HIGH signal to trigger the start of a step.
                    delayMicroseconds(retardo);  // Wait to maintain the signal (defines speed).
                    digitalWrite(paso_, LOW);    // Send a LOW signal to complete the square wave pulse.
                    delayMicroseconds(retardo);  // Wait before the next pulse.
                  }
                }

                if(dir == 1) { 
                  digitalWrite(dire_, HIGH); // Set the physical direction pin to HIGH
                  for(int i = 0; i < tiempo; i++) {   
                    digitalWrite(paso_, HIGH);      
                    delayMicroseconds(retardo);          
                    digitalWrite(paso_, LOW);       
                    delayMicroseconds(retardo);  
                  }
                }

                // digitalWrite(habi_, HIGH): This disables the driver after the movement is done.
                // When HIGH, the driver stops sending current to the motor. This prevents 
                // the motor and driver from overheating while idle, but the motor 
                // will "let go" and can be turned easily by hand.
                digitalWrite(habi_, HIGH);   
              }
            

AI Assistance

First prompt used

Prompt used in Gemini: "In my new code I want the stepper motor to keep turning, and every turn stop for 5 seconds and then continue moving in the same direction. Now, I want it to no longer stop to change direction. Also, tell me in my original code which lines are the ones that turn the LED on and off; on the other hand, I want you to modify the code so that these lines are either changed or disappear, since this LED will no longer exist in my new simulation. Additionally, I want you to make a comparative table telling me the changes you made from the original code to the new code. If possible, I want you to generate an image (using the image I am attaching below as a reference) so that you can make the new image showing me how to correctly connect all the components for this new code. Also, explain to me what that arrow at the bottom of the stepper motor is."

laser cut 02

This was the image I upload to Gemini

Second prompt used

Prompt used in Gemini: "Alright, now give me the code with the specifications from my previous question for this new circuit shown in the image you generated."

Circuit Evolution

Advisor´s simulation

Here you can find the link to my advisor's simulation in Wokwi.

View Simulation

My simulation

Here you can find the link to my simulation in Wokwi.

View Simulation

Comparative table of code changes

Feature Original Code New Code Reason for Change
LED Definitions #define led 33 and pinMode(led, OUTPUT); Removed The LED is no longer part of the circuit.
LED Control digitalWrite(led, HIGH/LOW); Removed The LED is no longer part of the circuit.
giro() Function giro(x,y,z,dir) was defined and called twice (dir 1 and 0). Integrated into loop The new behavior is simpler; it doesn't require changing directions or disabling the driver in every turn.
Time Variable int tiempo = 220; (controlled the duration of "steps"). Replaced by int pasos_por_vuelta = 200; Now focuses on completing an exact turn (200 steps is standard for 1.8° motors) instead of an arbitrary duration.
loop() Block Called giro() twice with different directions and delay(500) in between. For loop (one direction) followed by delay(5000). The motor now rotates continuously in one direction, stops for 5 seconds after each turn, and then continues.
Direction Pin Toggled between LOW and HIGH inside the giro() function. Set to digitalWrite(x_dire, HIGH); only once in setup(). The motor always turns in the same direction. You can change HIGH to LOW in setup if you want it to rotate the opposite way.
Enable Pin digitalWrite(habi_, LOW) at the start and HIGH at the end of giro(). Set to digitalWrite(x_habi, LOW); only once in setup(). The driver remains always enabled so the motor doesn't lose its position or "let go" between turns.
Comments Focused on direction alternating and LED behavior. Updated to reflect continuous rotation and 5-second stops. To improve the understanding of the new code's logic.

Final Code (C++)


// Test for Driver, Stepper Motors, and ESP32
// This version is optimized for a conveyor belt that rotates in one direction.

#define x_paso 15   // Defines the STEP pin for the X-axis motor
#define x_dire 2    // Defines the DIR (Direction) pin for the X-axis motor
#define x_habi 4    // Defines the ENABLE pin for the X-axis motor

// Global Variables
int retardo = 3000;         // Delay in microseconds; a lower number makes the rotation faster
int pasos_por_vuelta = 200; // Standard for 1.8-degree motors (360° / 1.8° = 200 steps)

// Setup runs once when the board is powered on
void setup() {
  // Configures the pins as OUTPUT to send control signals to the motor driver
  pinMode(x_paso, OUTPUT);
  pinMode(x_dire, OUTPUT);
  pinMode(x_habi, OUTPUT);

  // The Enable pin is set to LOW once to keep the driver always active
  // This prevents the motor from losing its position or "letting go" between turns
  digitalWrite(x_habi, LOW); 

  // The direction is fixed to HIGH at the start because the motor moves continuously in one direction
  // You can change HIGH to LOW here if you need to reverse the fixed rotation sense
  digitalWrite(x_dire, HIGH); 
}     

void loop() {
  // This 'for' loop executes exactly 200 steps to complete one full rotation
  // 'int i = 0' starts the counter, 'i < pasos_por_vuelta' sets the limit, 
  // and 'i++' adds one step per cycle until the turn is complete
  for(int i = 0; i < pasos_por_vuelta; i++){
    // Creating a Step Pulse:
    digitalWrite(x_paso, HIGH);    // Switches the step pin to HIGH to initiate a physical step
    delayMicroseconds(retardo);   // Maintains the HIGH state for a specific duration (defines speed)
    digitalWrite(x_paso, LOW);     // Switches the step pin to LOW to complete the pulse cycle
    delayMicroseconds(retardo);   // Wait time before the next pulse begins
  }
  
  // After completing a full turn (200 steps), the motor stops for 5000 milliseconds
  // This 5-second pause represents the time needed to carry out the corresponding process
  delay(5000); 
}

/* * NOTE ON CODE EVOLUTION:
 * The original 'giro' function and LED control (pin 33) were removed
 * because the conveyor belt now follows a simpler, one-direction continuous path.
 * All logic is integrated into the loop to ensure predictable movement and timing.
 */
            

Original code simulation