Posted on — Leave a comment

AI Robot Head Tracking Using Browser Vision (No Training, No Server)

Turn your head left, right, up, and down.
Open circuit Open circuit

Download FreeCAD project and STL files

Introduction

Most “AI robot face” demos rely on heavy machine-learning models, cloud APIs, or large datasets.
This project explores a different approach:

Using simple geometry and browser-based vision to create an expressive robot head that reacts to human movement in real time.

The robot head tracks left, right, up, and down head motion and mirrors it using animated eyes displayed on a small OLED screen — all controlled directly from a web browser.

No dataset.
No model training.
No server.

What This Project Does

  • Detects a human face using the browser camera
  • Estimates head orientation (yaw & pitch)
  • Sends motion data to an Arduino using Web Serial
  • Animates eye movement on a 0.96″ OLED display
  • Allows direction inversion (mirror correction) at runtime

The result is a small robot head that feels responsive and alive.

System Architecture

Browser Camera
      ↓
Face Geometry (MediaPipe)
      ↓
Yaw & Pitch Calculation
      ↓
Web Serial (USB)
      ↓
Arduino UNO
      ↓
OLED Eye Animation

All computation happens locally in the browser.

Hardware Used

  • Arduino UNO
  • 0.96″ OLED (SSD1306, I2C)
  • USB cable
  • 3D-printed enclosure

Software Stack

  • HTML + JavaScript
  • MediaPipe Face Mesh
  • Web Serial API
  • Arduino (C++)

Key Design Decisions

1. Pupils Move, Not Eyeballs

Moving only the pupils inside fixed eyeballs makes the face feel more natural and expressive.

2. Face-Relative Geometry

Head motion is measured relative to facial landmarks, not camera pixels.
This makes movement symmetric and stable.

3. Runtime Direction Flip

A toggle button allows instant correction for mirrored cameras without changing code.


Educational Value

This project can be used to teach:

  • Coordinate systems
  • Geometry-based tracking
  • Browser ↔ hardware communication
  • Human-centered design

It is suitable for classrooms, labs, and exhibitions.


Conclusion

This robot head demonstrates that intelligence is not just about models, but about understanding interaction.

By combining browser vision, simple math, and embedded hardware, we can build systems that feel responsive, expressive, and intuitive — without complexity.


Try It Live

Allow camera access, connect the Arduino, and move your head left, right, up, and down.

Posted on — Leave a comment

RGB LED with Arduino UNO/Nano

What is an RGB LED and What Are We Building Here?

An RGB LED is a special type of LED that contains three LEDs inside one package — Red, Green, and Blue.
Using these three colours, the Arduino can blend them at different brightness levels to produce hundreds of colours like yellow, cyan, purple, pink, white, sky-blue, etc.

In this example, we are using a Common-Cathode RGB LED, which means:

  • All three LEDs share one common negative (–) pin
  • The individual colour pins (R, G, B) must be connected through 220Ω resistors
  • The Arduino controls brightness using PWM pins
    • Red → D3
    • Green → D5
    • Blue → D6

This forms the basis for colour-mixing projects used in IoT, indicators, robots, and UI feedback systems.

Below, you can see the circuit wiring diagram, the mBlock representation, and the equivalent Arduino IDE code.
Finally, you can flash the firmware directly from this page using ExaSub’s online uploader — no Arduino IDE installation required.

Open circuit Open circuit

Arduino IDE CODE

// RGB LED with Arduino Nano
// Common Cathode RGB LED
// R -> D3, G -> D5, B -> D6

int redPin = 3;
int greenPin = 5;
int bluePin = 6;

void setup() {
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
}

void loop() {
  setColor(255, 0, 0);   // Red
  delay(800);

  setColor(0, 255, 0);   // Green
  delay(800);

  setColor(0, 0, 255);   // Blue
  delay(800);

  setColor(255, 255, 0); // Yellow (Red + Green)
  delay(800);

  setColor(80, 0, 255);  // Purple
  delay(800);

  setColor(0, 255, 255); // Cyan (Green + Blue)
  delay(800);

  setColor(255, 255, 255); // White
  delay(800);

  setColor(0, 0, 0);     // Off
  delay(800);
}

// Function to mix RGB
void setColor(int r, int g, int b) {
  analogWrite(redPin, 255 - r);    // common cathode → invert logic
  analogWrite(greenPin, 255 - g);
  analogWrite(bluePin, 255 - b);
}

Mblock Code

Flash Arduino UNO/Nano Directly From Browser Click on Button

Note: Nano with old bootloader is not supported. Use the code with the arduino IDE for the Nano with old bootloader.

Posted on — Leave a comment

3D printer setting for shiny prints

I made a Cylindrical box for storing my leftover spices. So i made it, sliced it and let it to print. It was a H: 100mm , R: 60mm.

On roughly about 20mm i changed the speed of the printer to just 25%.

I found out that at 25% of the speed the print lines are shiny and when i resumed the print after few mm i got that dull look.

So if you want to prints to come out shiny use low speeds. under 40mm/s for outer shell.

But there is a catch since it is running slowly the more material will come out of the nozzle and you have to adjust the flow rate for it.

Posted on — Leave a comment

Make a Joystick-Controlled Car with ESP32 and NodeMCU

Are you interested in making a remote-controlled car using ESP32 and NodeMCU? In this project, we will use a joystick module to control a car wirelessly. This is a fun and simple way to explore ESP-NOW communication and motor control!


What You Need

To build this joystick-controlled car, you will need:

  • ESP32 (for the remote controller)
  • NodeMCU (ESP8266) (for the car)
  • Joystick module
  • L298N motor driver
  • Two DC motors (500 RPM Johnson motors)
  • Two wheels (70mm diameter, 20mm width)
  • LM2596 voltage regulator (to power NodeMCU)
  • Power source (3S battery or similar)
  • Jumper wires

How It Works

  • The ESP32 reads joystick movements and sends commands wirelessly using ESP-NOW.
  • The NodeMCU receives these commands and controls the motors accordingly.
  • The car moves forward, backward, left, and right based on joystick input.

Wiring Connections

Remote (ESP32 + Joystick Module)

  • Joystick VCC → ESP32 3.3V
  • Joystick GND → ESP32 GND
  • Joystick X-axis → ESP32 GPIO 34
  • Joystick Y-axis → ESP32 GPIO 35

Car (NodeMCU + L298N Motor Driver + Motors)

  • Motor 1 IN1 → NodeMCU D1
  • Motor 1 IN2 → NodeMCU D2
  • Motor 2 IN1 → NodeMCU D3
  • Motor 2 IN2 → NodeMCU D4
  • Motor 1 ENA → NodeMCU D5
  • Motor 2 ENB → NodeMCU D6
  • LM2596 Output (3.3V/5V) → NodeMCU Vin
  • LM2596 Ground → NodeMCU GND

ESP32 Code for the Remote

#include <esp_now.h>
#include <WiFi.h>

// Define DEBUG to enable or disable serial debug statements
//#define DEBUG  // Comment this line to disable debug statements

const int xPin = 34;  // X-axis connected to GPIO 34
const int yPin = 35;  // Y-axis connected to GPIO 35

// Define thresholds for dead zone (adjust as needed)
const float DEAD_ZONE_THRESHOLD = 0.2;  // Joystick values within ±0.2V are considered centered

uint8_t broadcastAddress[] = {0xCC, 0x50, 0xE3, 0x0D, 0x15, 0x09};

typedef struct struct_message {
  char command[32];
  int b;
} struct_message;

struct_message myData;
esp_now_peer_info_t peerInfo;

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  #ifdef DEBUG
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  #endif
}

void setup() {
    #ifdef DEBUG
    Serial.begin(115200);
    #endif

    WiFi.mode(WIFI_STA);

    if (esp_now_init() != ESP_OK) {
        #ifdef DEBUG
        Serial.println("Error initializing ESP-NOW");
        #endif
        return;
    }

    esp_now_register_send_cb(OnDataSent);
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;
    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        #ifdef DEBUG
        Serial.println("Failed to add peer");
        #endif
        return;
    }
}

void loop() {
    int xValue = analogRead(xPin);  // Read X-axis value
    int yValue = analogRead(yPin);  // Read Y-axis value

    float xVoltage = (xValue * 3.3) / 4095;  // Convert to voltage (0-3.3V)
    float yVoltage = (yValue * 3.3) / 4095;  // Convert to voltage (0-3.3V)

    #ifdef DEBUG
    Serial.print("X Voltage: "); Serial.print(xVoltage);
    Serial.print(" | Y Voltage: "); Serial.println(yVoltage);
    #endif

    // Check if the joystick is within the dead zone (centered)
    if (abs(xVoltage - 1.65) < DEAD_ZONE_THRESHOLD && abs(yVoltage - 1.65) < DEAD_ZONE_THRESHOLD) {
        strcpy(myData.command, "S"); // Stop (centered)
        myData.b = 0;  // No movement
    }
    // Check for movement outside the dead zone
    else if (xVoltage > (1.65 + DEAD_ZONE_THRESHOLD)) {
        strcpy(myData.command, "F"); // Forward
        myData.b = xVoltage;
    } else if (xVoltage < (1.65 - DEAD_ZONE_THRESHOLD)) {
        strcpy(myData.command, "B"); // Backward
        myData.b = xVoltage;
    } else if (yVoltage > (1.65 + DEAD_ZONE_THRESHOLD)) {
        strcpy(myData.command, "L"); // Left
        myData.b = yVoltage;
    } else if (yVoltage < (1.65 - DEAD_ZONE_THRESHOLD)) {
        strcpy(myData.command, "R"); // Right
        myData.b = yVoltage;
    }

    // Send the command via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    #ifdef DEBUG
    if (result == ESP_OK) {
        Serial.println("Sent with success");
    } else {
        Serial.println("Error sending the data");
    }
    #endif
    
    delay(20);  // Small delay to make output readable
}

NodeMCU Code for the Car

#include <ESP8266WiFi.h>
#include <espnow.h>

// Structure to receive data
typedef struct struct_message {
  char a[32];
  int b;
  float c;
  bool d;
} struct_message;

struct_message myData;

// Pin definitions
#define LED_PIN 2  // Onboard LED pin (D4 on ESP8266)
#define M1_ENA D5   // Motor 1 PWM (Speed)
#define M2_ENB D6   // Motor 1 PWM (Speed)
#define M1_IN1 D1  // Motor 1 input 1
#define M1_IN2 D2  // Motor 1 input 2
#define M2_IN1 D3  // Motor 2 input 1
#define M2_IN2 D4  // Motor 2 input 2

// Default speeds (adjust these values experimentally)
int speedLeft = 800;   // 0-1023 (80% speed)
int speedRight = 700;  // Right motor slightly slower

// Callback function when data is received
void OnDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("Data received: ");
  Serial.println(myData.a);
  Serial.print("value received: ");
  Serial.println(myData.b);

  // Control motors based on received character
  if (strcmp(myData.a, "F") == 0) {
    // Move forward
    analogWrite(M1_ENA, speedLeft);
    analogWrite(M2_ENB, speedRight);
    digitalWrite(M1_IN1, HIGH); digitalWrite(M1_IN2, LOW);
    digitalWrite(M2_IN1, HIGH); digitalWrite(M2_IN2, LOW);
    digitalWrite(LED_PIN, LOW);  // Turn on LED (inverted logic on ESP8266)
  } else if (strcmp(myData.a, "B") == 0) {
    // Move backward
    analogWrite(M1_ENA, speedLeft);
    analogWrite(M2_ENB, speedRight);
    digitalWrite(M1_IN1, LOW); digitalWrite(M1_IN2, HIGH);
    digitalWrite(M2_IN1, LOW); digitalWrite(M2_IN2, HIGH);
    digitalWrite(LED_PIN, HIGH);  // Turn off LED (inverted logic on ESP8266)
  } else if (strcmp(myData.a, "L") == 0) {
    // Turn left
    analogWrite(M1_ENA, speedLeft);
    analogWrite(M2_ENB, speedRight);
    digitalWrite(M1_IN1, LOW); digitalWrite(M1_IN2, HIGH);
    digitalWrite(M2_IN1, HIGH); digitalWrite(M2_IN2, LOW);
  } else if (strcmp(myData.a, "R") == 0) {
    // Turn right
    analogWrite(M1_ENA, speedLeft);
    analogWrite(M2_ENB, speedRight);
    digitalWrite(M1_IN1, HIGH); digitalWrite(M1_IN2, LOW);
    digitalWrite(M2_IN1, LOW); digitalWrite(M2_IN2, HIGH);
  }
  else if (strcmp(myData.a, "S") == 0) {
    // Turn right
    analogWrite(M1_ENA, 0);
    analogWrite(M2_ENB, 0);
    digitalWrite(M1_IN1, HIGH); digitalWrite(M1_IN2, LOW);
    digitalWrite(M2_IN1, LOW); digitalWrite(M2_IN2, HIGH);
  } else {
    // Stop motors
    analogWrite(M1_ENA, 0);
    analogWrite(M2_ENB, 0);
    //   digitalWrite(M1_IN1, LOW); digitalWrite(M1_IN2, LOW);
    //   digitalWrite(M2_IN1, LOW); digitalWrite(M2_IN2, LOW);
  }
}

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);

  // Initialize pins
  pinMode(LED_PIN, OUTPUT);
  pinMode(M1_IN1, OUTPUT);
  pinMode(M1_IN2, OUTPUT);
  pinMode(M2_IN1, OUTPUT);
  pinMode(M2_IN2, OUTPUT);

  // Ensure motors and LED are off initially
  digitalWrite(LED_PIN, HIGH);  // LED off (inverted logic on ESP8266)
  digitalWrite(M1_IN1, LOW); digitalWrite(M1_IN2, LOW);
  digitalWrite(M2_IN1, LOW); digitalWrite(M2_IN2, LOW);

  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Initialize ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Register the receive callback
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
  // Nothing to do here
}

How to Upload the Code

  1. Upload the remote code to your ESP32.
  2. Upload the car code to your NodeMCU.
  3. Power up both devices and check serial monitor outputs for debugging.

Testing the Car

  1. Move the joystick forward → The car moves forward.
  2. Move the joystick backward → The car moves backward.
  3. Move the joystick left → The car turns left.
  4. Move the joystick right → The car turns right.
  5. Release the joystick (center position) → The car stops.

3d Printed parts

Since when i made this car. I had Johnson motors of 500RPM. But i did not had any bracket so i designed the brackets in FreeCAD and printed on Creality ender 3 v3 KE printer.

Posted on — Leave a comment

CREALITY Ender-3 V3 KE

I bought the printer from wol3d’s New Delhi office.
I am a electronics guy but i have inclination towards the 3d printing world. The feeling that you can design and make something in front of you. It’s a slow process but this printer comes with a slicer software which is fast.

Build Volume : 220 x 220 x 240 mm

The best thing is the auto bed leveling on this printer. I do not have to adjust the four corner bolts and rub a paper under the nozzle. It is done automatically done.


Till now the results are amazing.

I have noticed that the prints depends upon a lot of things:

  • Filament Quality :
    I have used a few filaments samples i got my hand on they were old and new. The old one which are above one year old open packet are just brittle they clog the printer every now and then. and one time it was so break while in the extruder which set my heart racing as i don’t want new printer to clog and change its nozzle. Thankfully the nozzle clogged removed when i inserted the fresh PLA and forced it into the extruder.
    So yes always use new filament. And also some filament are bad weather they are new or old.
  • Bed adhesion
  • Print Temp
  • Slicer Setting
Posted on — Leave a comment

A Step-by-Step Guide on Installing OpenCV with pip in Windows

OpenCV, or Open Source Computer Vision Library, is a powerful and widely-used open-source computer vision and machine learning software library. It provides a plethora of tools and functions for image and video processing, making it an essential resource for developers, researchers, and hobbyists. Installing OpenCV on a Windows system can be a straightforward process when using the Python package manager, pip. In this article, we’ll walk you through the steps to install OpenCV on your Windows machine using pip.

Prerequisites:

Before diving into the installation process, ensure that you have the following prerequisites:

  1. A Windows operating system.
  2. Python installed on your machine. You can download the latest version of Python from the official website: https://www.python.org/downloads/.

Installation Steps:

Follow these step-by-step instructions to install OpenCV using pip in Windows:

Step 1: Open a Command Prompt

Press Win + R to open the Run dialog, type cmd, and press Enter. This will open the Command Prompt.

Step 2: Upgrade pip

Ensure that your pip is up-to-date by running the following command:

pip install --upgrade pip

This ensures that you have the latest version of pip installed.

Step 3: Install NumPy

NumPy is a prerequisite for OpenCV, as it is used for numerical operations. Install it by running:

pip install numpy

Step 4: Install OpenCV

Now, you can install the OpenCV package using the following command:

pip install opencv-python

This command will download and install the latest stable version of OpenCV along with its dependencies.

Step 5: Verify the Installation

To ensure that OpenCV has been successfully installed, open a Python interpreter or create a simple Python script and import the cv2 module:

import cv2
print(cv2.__version__)

This should print the installed OpenCV version, confirming that the installation was successful.

Posted on — Leave a comment

How to make an Obstacle Avoiding Vehicle using Arduino UNO

Arduino Sketch

#define m1p 7
#define m1n 6

#define m2p 5
#define m2n 4

#define echopin 9
#define trigpin 10

void motor_forward();
void motor_stop();
void motor_left();
void motor_right();
void motor_back();

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(m1p, OUTPUT);
  pinMode(m1n, OUTPUT);
  pinMode(m2p, OUTPUT);
  pinMode(m2n, OUTPUT);

  pinMode(echopin, INPUT);
  pinMode(trigpin, OUTPUT);
}

long duration, distance;

void loop() {
  // put your main code here, to run repeatedly:

  digitalWrite(trigpin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigpin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigpin, LOW);
  duration = pulseIn(echopin, HIGH);
  distance = (duration *0.0343 / 2);
  Serial.println(distance);
 // Serial.println(" cm");
  //delay(1000);
  //Serial.println(distance);               //print data serially
  if (distance > 25) {                   // if distance is more than 25 move bot forward
    motor_forward();
    delay(20);
    motor_forward(); 
    
  }
  else {
   // motor_stop();
    //delay(500);
   // motor_back();
   // delay(3000);
    motor_stop();                   // if distance is less than 25 move bot right
    delay(50);
    motor_back();
    delay(100);
     motor_right();
    delay(100);
  }
 
}
void motor_back(){
  digitalWrite(m1p, LOW);
  digitalWrite(m1n, HIGH);
  digitalWrite(m2p, HIGH);
  digitalWrite(m2n, LOW);
}
void motor_forward(){
  digitalWrite(m1p, HIGH);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, LOW);
  digitalWrite(m2n, HIGH);
}
void motor_stop(){ 
  digitalWrite(m1p, LOW);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, LOW);
  digitalWrite(m2n, LOW);
}
void motor_left(){
  digitalWrite(m1p, HIGH);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, LOW);
  digitalWrite(m2n, LOW);
}
void motor_right(){
  digitalWrite(m1p, LOW);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, HIGH);
  digitalWrite(m2n, LOW);
}

Code Explanation

The code is a simple obstacle avoidance program for a robot using an ultrasonic sensor and two motors. Let’s break down the code and explain each section:

#define m1p 7
#define m1n 6
#define m2p 5
#define m2n 4
#define echopin 9
#define trigpin 10

In this section, the code defines constants for motor pins (m1p, m1n, m2p, m2n) and pins for the ultrasonic sensor (echopin for echo and trigpin for trigger).

void motor_forward();
void motor_stop();
void motor_left();
void motor_right();
void motor_back();

Here, the code declares five functions (motor_forward, motor_stop, motor_left, motor_right, motor_back) that will be used to control the movement of the robot.

void setup() {
  Serial.begin(9600);
  pinMode(m1p, OUTPUT);
  pinMode(m1n, OUTPUT);
  pinMode(m2p, OUTPUT);
  pinMode(m2n, OUTPUT);
  pinMode(echopin, INPUT);
  pinMode(trigpin, OUTPUT);
}

In the setup function, the serial communication is initialized, and the pin modes for motor control and the ultrasonic sensor are set.

long duration, distance;

Here, two variables duration and distance are declared to store the duration of the ultrasonic pulse and the calculated distance, respectively.

void loop() {
  digitalWrite(trigpin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigpin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigpin, LOW);
  duration = pulseIn(echopin, HIGH);
  distance = (duration * 0.0343 / 2);
  Serial.println(distance);

  if (distance > 25) {
    motor_forward();
    delay(20);
    motor_forward(); 
  } else {
    motor_stop();
    delay(50);
    motor_back();
    delay(100);
    motor_right();
    delay(100);
  }
}

In the loop function, the ultrasonic sensor is triggered to measure the distance. If the measured distance is greater than 25, the robot moves forward. Otherwise, it stops, moves back a bit, and then turns right.

void motor_back() {
  digitalWrite(m1p, LOW);
  digitalWrite(m1n, HIGH);
  digitalWrite(m2p, HIGH);
  digitalWrite(m2n, LOW);
}

void motor_forward() {
  digitalWrite(m1p, HIGH);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, LOW);
  digitalWrite(m2n, HIGH);
}

void motor_stop() {
  digitalWrite(m1p, LOW);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, LOW);
  digitalWrite(m2n, LOW);
}

void motor_left() {
  digitalWrite(m1p, HIGH);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, LOW);
  digitalWrite(m2n, LOW);
}

void motor_right() {
  digitalWrite(m1p, LOW);
  digitalWrite(m1n, LOW);
  digitalWrite(m2p, HIGH);
  digitalWrite(m2n, LOW);
}

These functions define the motor control logic for moving the robot in different directions. For example, motor_forward makes the robot move forward by setting the appropriate motor pins.

In summary, this code implements a basic obstacle avoidance mechanism for a robot using an ultrasonic sensor. If the robot detects an obstacle within 25 cm, it stops, moves back a bit, and then turns right. Otherwise, it continues moving forward. The motor control is achieved through the defined functions that set the appropriate pin states for the motor driver.

Posted on — Leave a comment

How to use attachInterrupt() in Arduino IDE to toggle an LED

Arduino, with its user-friendly environment and a vast array of libraries, opens up a world of possibilities for electronic enthusiasts and hobbyists. One of the key features that makes Arduino a versatile platform is the ability to use interrupts. In this blog post, we will explore the use of attachInterrupt() in the Arduino IDE to toggle an LED with the press of a button.

Understanding attachInterrupt()

The attachInterrupt() function in Arduino is a powerful tool that allows you to execute a specified function (interrupt service routine or ISR) when a certain condition occurs on a digital pin. This capability is particularly useful for handling external events without constantly polling the pin in the main loop, thus improving efficiency and responsiveness.

For more documentation visit the lin below.

https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

Components Required

Before we delve into the code, let’s gather the necessary components for this project:

  1. Arduino board (e.g., Arduino Uno)
  2. LED
  3. Resistor (220-330 ohms)
  4. Push button
  5. Jumper wires

Wiring the Circuit

Connect the components as follows:

  • Connect the longer leg of the LED (anode) to a current-limiting resistor (220-330 ohms) then the other end of the resistor to pin A2 on the Arduino.
  • Connect the shorter leg of the LED (cathode) GND on the Arduino.
  • Connect one side of the push button to pin 2 on the Arduino.
  • Connect the other side of the push button to the GND on the Arduino.

The Arduino Sketch

Now, let’s dive into the Arduino sketch that utilizes attachInterrupt() to toggle the LED state when the button is pressed.


int led=A2;
int button=2;
volatile byte state = LOW;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(led, OUTPUT);
  pinMode(button, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2),blink,CHANGE);
}

void blink()
{
  state = !state;
}

void loop()
{
  digitalWrite(led, !state);
}

Breaking Down the Code

  • We define led and button as the respective pin numbers for the LED and the push button.
  • volatile byte state is a variable that holds the state of the LED, and it’s marked as volatile to indicate that it can be modified in an ISR.
  • In the setup() function, we set the LED pin and button pin modes. Additionally, we attach an interrupt to the button using attachInterrupt(), specifying the function blink to be executed on a state change (CHANGE) of the button pin.
  • The blink() function toggles the state variable when the interrupt is triggered.
  • In the loop() function, we continuously update the LED state based on the value of the state variable.
Posted on — Leave a comment

How to use Mini STM32 v3.0 USB Port as Virtual Com Port

To use USB port of the mini STM32 v3. We need to configure the USB port and for that, we have to look at the schematics.

You can view the Full schematic here https://www.exasub.com/development-kit/mini-stm32-v3-0/mini-stm32-v3-0/

From the schematics, we see that there are three pins associated with the USB port.
1. PA11
2. PA12
3. PD2

The Pins PA11 and PA12 are
PA11 – USB D-
PA12 – USB D+

These two pins will be configured by the stm32cube ide when you enable the USB device.

PD2 should be configured as GPIO pin.
Because the USB FS implementation says to pull up the D+ line to 3.3V.
The pull up is performed by the S8550 PNP transistor.
So by making the PD2 pin LOW, we enable the USB FS, since it makes the D+ pull up.

We also need to select the Communication Device Class as Class For FS IP.

After configuring the cube mx project. we can proceed to generate code.

The code needs to add the following header file

/* USER CODE BEGIN Includes */
#include "usbd_cdc_if.h"
#include "string.h"
/* USER CODE END Includes */

and then in the main() function. you can write this code in while loop

  /* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
  /* USER CODE END 2 */


/* USER CODE BEGIN WHILE */
uint8_t *data = "Hello World from USB CDC\r\n";
  while (1)
  {
	  CDC_Transmit_FS(data, strlen(data));
	  HAL_Delay (1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

After uploading the code to your microcontroller. It will be displayed in your windows device manager as “USB Serial Device”.

You can Connect to the Com port using the serial terminal software such as YAT, Putty or CoolTerm etc.
Note: Since it is a virtual com port, you dont have to set a specific baud rate.