Skip to content

Electronics

I will be documenting my progress with electronics in this page.

Code is written with the help of ChatGPT


Input devices

Sensor for the iPads

To make sure I use the best sensor to sense the presense of the iPads, I decided to test out some of them

Hall-effect sensor

Hall effect sensors are sensors that can detect the presence of a magnetic field. Mr. Rico suggested that I try it out.

Here are the connections I made with my Xiao ESP32C3 board and my sensor.

Sensor Board
VCC 5V
GND GND
Signal pin D0

This is the code I used along with the prompt I used to generate it from ChatGPT.

Write a code that programs my hall effect sensor, connected to my Xiao ESP32C3, to detect the presence of a magnet.

#define HALL_PIN 2  // GPIO2, change if needed

void setup() {
  pinMode(HALL_PIN, INPUT);
  Serial.begin(115200);
}

void loop() {
  int sensorValue = digitalRead(HALL_PIN);

  if (sensorValue > 0) {
    Serial.println("Magnet detected!");
  } else {
    Serial.println("No magnet.");
  }
  Serial.print(sensorValue);
  delay(300);
}

Results

Conclusion

As you might have also noticed from the video above, the sensor was not able to detect the presence of a magnet very well. It had to be in a very weird certain position for the sensor to be able to detect it😔 Additionally, the magnet had to be in physical contact with the sensor which is why I am not considering using this sensor for now.


Photoresistor light sensor

A photoresistor light sensor also known as LDR(light dependent resistor) is a sensor which detects light levels. This is a very simplified flowchart showing you how it works:

More light → lower resistance → more current flows

Less light (dark) → higher resistance → less current flows

Here is the connections I made with the sensor and my Xiao ESP32C3 baord.

Sensor Board
VCC 5V
GND GND
Signal pin A0

The prompt I used to generate the code is:

Write a code that programs my LDR, connected to my Xiao ESP32C3, to detect the light levels.

Here is the code:

#define LIGHT_SENSOR_PIN 2  // This must match the wire connected to DO

void setup() {
  Serial.begin(9600);
  pinMode(LIGHT_SENSOR_PIN, INPUT);
}

void loop() {
  int sensorValue = digitalRead(LIGHT_SENSOR_PIN);
  Serial.print("Sensor Value: ");
  Serial.println(sensorValue);
  delay(300);
}

Results

Conclusion

The LDR gave me pretty accurate results. However, I am still unsure wheter I should use it or not because since the iPad will already be in a dark slot, I don’t think an iPad being there will make much of a difference to the light intensity there. I also tried a IR sensor but it is not working right now. I will try it again and decide!


IR sensor

This is the setup.

I went through this tutorial.

This is the code I got from the above link.

int IRSensor = 9; // connect IR sensor module to Arduino pin D9
int LED = 2; // connect LED to Arduino pin 13

void setup(){
  Serial.begin(115200); // Init Serial at 115200 Baud Rate.
  Serial.println("Serial Working"); // Test to check if serial is working or not
  pinMode(IRSensor, INPUT); // IR Sensor pin INPUT
  pinMode(LED, OUTPUT); // LED Pin Output
}

void loop(){
  int sensorStatus = digitalRead(IRSensor); // Set the GPIO as Input
  if (sensorStatus == 1) // Check if the pin high or not
  {
    // if the pin is high turn off the onboard Led
    digitalWrite(LED, LOW); // LED LOW
    Serial.println("no motion"); // print Motion Detected! on the serial monitor window
  }
  else  {
    //else turn on the onboard LED
    digitalWrite(LED, HIGH); // LED High
    Serial.println("Motion Detected!"); // print Motion Ended! on the serial monitor window
  }
  delay(1000);  // Delays for 1000 milliseconds (1 second)
}

The code basically programs the sensor to sense the presence of an object in front of it and it is displayed in the serial moniter. The LED in my board also turns on when an object is in front.

Results!

Problem

The issue I faced in the beginning was the sensor always sensing something although nothing was in front of it. This was because the sensitivity of it was very high. This could be fixed by simply turning the potentiometer!

Conclusion

The IR sensor was pretty easy to work with. It also gave me pretty accurate results. Therefore, I think I will use this sensor. YAY!


PN532 RFID module

Testing with Arduino UNO

When I was testing the RFID modules, it did not work, so I concluded that none of the RFID modules at the lab works. However, with a very HUGE help from my instructor Mr. Anith Ghalley I was able to make the PN532 work. THANK YOU SO MUCH SIR!

I went through this web page and its manual.

UART mode

One of the advantages of the PN532 module over the RC522 module is that it can use different protocols to communicate. I will be interfacing the module in the UART mode. To set it to your desired mode, refer to the table below to change your DIP switch accordingly.

Image source

This is how my DIP switch looks like after configuring it to UART mode.

Make the following connections with your RFID module and your Arduino UNO.

Image source

Libraries

To install the library required to program your module, visit this link and clone the repository by donwloading it as a .zip file. After that, go to that .zip folder and extract it. Copy the following contents from the folder and paste it in your library folder of your Arduino IDE.

Next, open your Arduino IDE. Goto Examples > PN532 > iso14443a_uid.

Mofidy the code to fit the mode you chose which in my case is the UART mode.

#if 0
  #include <SPI.h>
  #include <PN532_SPI.h>
  #include "PN532.h"

  PN532_SPI pn532spi(SPI, 10);
  PN532 nfc(pn532spi);

/* When the number after #elif set as 1, it will be switch to HSU Mode*/
#elif 1
  #include <PN532_HSU.h>
  #include <PN532.h>

  PN532_HSU pn532hsu(Serial);
  PN532 nfc(pn532hsu);

/* When the number after #if & #elif set as 0, it will be switch to I2C Mode*/
#else 
  #include <Wire.h>
  #include <PN532_I2C.h>
  #include <PN532.h>
  #include <NfcAdapter.h>

  PN532_I2C pn532i2c(Wire);
  PN532 nfc(pn532i2c);
#endif

void setup(void) {
  Serial.begin(115200);
  Serial.println("Hello!");

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }

  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); 
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); 
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);

  // Set the max number of retry attempts to read from a card
  // This prevents us from waiting forever for a card, which is
  // the default behaviour of the PN532.
  nfc.setPassiveActivationRetries(0xFF);

  // configure board to read RFID tags
  nfc.SAMConfig();

  Serial.println("Waiting for an ISO14443A card");
}

void loop(void) {
  boolean success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);

  if (success) {
    Serial.println("Found a card!");
    Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
    Serial.print("UID Value: ");
    for (uint8_t i=0; i < uidLength; i++) 
    {
      Serial.print(" 0x");Serial.print(uid[i], HEX); 
    }
    Serial.println("");
    // Wait 1 second before continuing
    delay(1000);
  }
  else
  {
    // PN532 probably timed out waiting for a card
    Serial.println("Timed out waiting for a card");
  }
}

NOTE: In the PN532_HSU pn532hsu(Serial); line of code, remember to change it from Serial1 to Serial in case you are using the Arduino UNO, instead of other boards like Arduino Mega, Leonardo, or Micro. I had made that mistake earlier.

Results

EXTRA: Using this module instead of the RC522 module reduces the number of pins required by the RFID reader from 5 to 2 which also solves my problem of the Xiao not having enough pins. so YAY. The board I am using is the Tsheyang-duino, which you can get more information about here.


Testing with my board

To try it with my Xiao board, I first sent this prompt to ChatGPT to be sure about the connections I have to make between the two components and for it to generate a code that works the same way.

This is the prompt:

this is the connection made between my rfid board and my Arduino UNO in UART mode:'GND (Ground) <-> GND Vcc (Power supply) <-> 5V Tx (Clock) <-> D3 Rx (Data) <-> D2' by looking at this, what connections do I have to make between my Xiao esp32c3 and the same RFID module to make it work the same way it does with the Arduino UNO?

Here are the connections I made.

Sensor Board
VCC 3.3
GND GND
TX GPIO 7
RX GPIO 6

This is the code it generated after some debugging.

#include <PN532_HSU.h>
#include <PN532.h>

// Use Serial1 on ESP32-C3: default TX = GPIO 6, RX = GPIO 7
PN532_HSU pn532hsu(Serial1);
PN532 nfc(pn532hsu);

void setup(void) {
  // Serial for debugging
  Serial.begin(115200);
  while (!Serial); // Wait for USB Serial
  Serial.println("Hello from XIAO ESP32-C3!");

  // Start hardware serial for PN532
  Serial1.begin(115200, SERIAL_8N1, 7, 6); // RX = GPIO7, TX = GPIO6

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.println("Didn't find PN53x board");
    while (1); // halt
  }

  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); 
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); 
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);

  nfc.setPassiveActivationRetries(0xFF);
  nfc.SAMConfig();
  Serial.println("Waiting for an ISO14443A card...");
}

void loop(void) {
  boolean success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  uint8_t uidLength;

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);

  if (success) {
    Serial.println("Found a card!");
    Serial.print("UID Length: "); Serial.print(uidLength, DEC); Serial.println(" bytes");
    Serial.print("UID Value: ");
    for (uint8_t i = 0; i < uidLength; i++) {
      Serial.print(" 0x"); Serial.print(uid[i], HEX);
    }
    Serial.println("");
    delay(1000);
  } else {
    Serial.println("Timed out waiting for a card");
  }
}

Here is the result!

YAY!


Output devices

Electromagnet

Incorporating a switch

I will be learning how to control an electromagnet with a switch.

Results

Learnings

From this activity, I was able to find out that 1 electromagnet was not going to be strong enough to lock the door of my project in place, which is why I will now be using a minimum of 2 electromagnets in my final project.

You will be able to get more details in my documentation for week 8.


Testing strength

To test if the electromagnets were strong enough for my door or not, I tested it with an adaptor at the lab with Mr. Anith Ghalley. This is how it looks like:

Mr. Anith also explained how I should connect my relay module to the design which was very helpful.

Conclusion

The electromagnets were pretty strong even when I increased the number of electromagnets whose power was supplied by the adaptor. This made me confident that the door in my final project will lock just fine. Now, I will try to see if there we can find a material just like the one in the electromagnet so that I can use it to lock the door instead of using 2 electromagnets together.


MCU - Xiao ESP32C3

The MCU I will be using for my final project baord is the ESP32C3.

I made the first demo of my board for my final project. It consists of 1 elctromagnet, RFID reader, and a pressure sensor.

Here is my complete soldered board:

NOTE: this documentation was done before I decided to use an IR sensor; thus I made the board for a pressure sensor.


RFID card and solenoids

Now, I will attempt to work with both the RFID module and the solenoid together. The goal is to be able to control the electromagnet with the RFID card.

Here is the prompt I entered ChatGPT(the loml):

this is the code I have which connects my Xiao board to my PN532 RFID module. Now, I will need to incorporate a solenoid to it (REES52 DC 12V KK-P25/20 8KG Lifting Solenoid Electromagnet to be specific) with a relay module which is powered by a12V DC adaptor. Initially the solenoid should be magnetized. Whenever I scan a card, the solenoid should be demagnetized and when I scan it again, it should be magnetized. The scanning of the RFID card will magnetize and demagnetize the magnetize vice versa. How do I make the connections and write a code for me.

This is the code generated.

#include <PN532_HSU.h>
#include <PN532.h>

// RFID via Serial1 (GPIO6=TX, GPIO7=RX)
PN532_HSU pn532hsu(Serial1);
PN532 nfc(pn532hsu);

// Relay control pin
const int relayPin = 10;
bool solenoidOn = true;  // Start with solenoid magnetized (relay ON)

void setup() {
  // Debug serial
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Starting...");

  // Setup RFID Serial1
  Serial1.begin(115200, SERIAL_8N1, 7, 6);
  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (!versiondata) {
    Serial.println("Didn't find PN53x board");
    while (1); // halt
  }

  Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
  Serial.print("Firmware ver. ");
  Serial.print((versiondata >> 16) & 0xFF, DEC);
  Serial.print('.');
  Serial.println((versiondata >> 8) & 0xFF, DEC);

  nfc.setPassiveActivationRetries(0xFF);
  nfc.SAMConfig();
  Serial.println("Waiting for ISO14443A card...");

  // Relay setup
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, HIGH);  // Turn relay ON initially (solenoid magnetized)
}

void loop() {
  uint8_t uid[7];   // Buffer for UID
  uint8_t uidLength;

  if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
    Serial.println("Card Detected!");
    Serial.print("UID: ");
    for (uint8_t i = 0; i < uidLength; i++) {
      Serial.print(" 0x"); Serial.print(uid[i], HEX);
    }
    Serial.println();

    // Toggle solenoid state
    solenoidOn = !solenoidOn;
    digitalWrite(relayPin, solenoidOn ? HIGH : LOW);

    Serial.print("Solenoid is now ");
    Serial.println(solenoidOn ? "MAGNETIZED (relay ON)" : "DEMAGNETIZED (relay OFF)");

    delay(1000); // Debounce delay to avoid multiple toggles per scan
  } else {
    delay(200); // Check every 200ms
  }
}

This is how the setup looks like for now:

Results

Although you may not be able to see it very clearly in the video, since the magnet I used for that was very weak, it still magnitized and demagnized with the scanning of the card. Trust.


VERY IMPORTANT LESSON

MY LAPTOP BROKE DOWN

So apparantly, while I was away, my colleague accidently burned down my laptop by connecting her microcontroller to both her external power source and my laptop while she was trying to upload her code. The resulting back‑feed fried my laptop’s power rail, taking the SSD and all of my unsynced final project code and KiCad design files with it. This “unfortunate event” taught me a very important lesson.

First of all, since I had to rewrite all my code, it taught me to commit every significant progess or files consistently to my remote git repository because you never know when such things might happen. Trust me, writing all my code again from scratch and not having the kicad files of my final project board was not fun.


Final project board

luckily, although I had not commited my kicad files, I had created my rml file for my final project board. This is how my final project board looks like after milling and soldering it.

Here is an image of my PCB design which I found later on:

and my schmetic design:


Full working electronic system

PROOF OF LIFE

Now, I connected all my components to my Xiao board and did my final programming so that the system works together.

This is the prompt I entered in ChatGPT to generate me the full working code:

hey i need help writing an arduino sketch for my final project.
i'm using a PN532 RFID module (in UART mode on Serial1, tx=7, rx=6) with a XIAO ESP32-C3. when a card is scanned, i want it to demagnetize an electromagnet that's connected to a relay on pin D8 (LOW = demagnetized, HIGH = magnetized).

i also have 5 IR sensors connected to D2, D3, D4, D5, and D6. after demagnetizing the lock for like 2 seconds, i want to read the values from all the sensors. if the IR sensor detects motion (LOW), say "Motion Detected", else "No Motion".

then i want to send the scanned RFID UID and the 5 IR sensor results to a Google Sheet using a Google Apps Script Web App URL (i'll replace it later).

after sending the data, re-magnetize the electromagnet (set relay pin HIGH) and wait 3 seconds before allowing another scan.

also make sure the code prints everything nicely in serial so i can debug. use HTTPClient, WiFi, and PN532_HSU libraries.

can you write the full code for this?

Here are the results:

#include <WiFi.h>
#include <HTTPClient.h>
#include <PN532_HSU.h>
#include <PN532.h>

// Wi-Fi credentials
const char* ssid = "your_wifi_name";
const char* password = "your_wifi_password";

// Google Apps Script Web App URL
const String googleScriptURL = "https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec";

// Define pins
const int RELAY_PIN = D8;
const int IR_SENSOR_PINS[5] = {D2, D3, D4, D5, D6}; // Update pin numbers as per your wiring

PN532_HSU pn532hsu(Serial1);
PN532 nfc(pn532hsu);

void setup(void) {
  Serial.begin(115200);
  while (!Serial);

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected to Wi-Fi");

  // Setup relay and IR sensor pins
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, HIGH); // Magnetize initially

  for (int i = 0; i < 5; i++) {
    pinMode(IR_SENSOR_PINS[i], INPUT);
  }

  // Start Serial1 for PN532
  Serial1.begin(115200, SERIAL_8N1, 7, 6);
  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (!versiondata) {
    Serial.println("Didn't find PN53x board");
    while (1);
  }

  nfc.setPassiveActivationRetries(0xFF);
  nfc.SAMConfig();
  Serial.println("Waiting for an ISO14443A card...");
}

void loop(void) {
  uint8_t uid[7];
  uint8_t uidLength;

  if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
    Serial.println("Found a card!");

    String uidString = "";
    for (uint8_t i = 0; i < uidLength; i++) {
      uidString += String(uid[i], HEX);
    }
    uidString.toUpperCase();
    Serial.print("UID: ");
    Serial.println(uidString);

    // Demagnetize
    digitalWrite(RELAY_PIN, LOW);
    Serial.println("Demagnetized electromagnet");
    delay(6000);

    // Read all 5 IR sensors
    String irResults[5];
    for (int i = 0; i < 5; i++) {
      int status = digitalRead(IR_SENSOR_PINS[i]);
      irResults[i] = (status == LOW) ? "Motion Detected" : "No Motion";
      Serial.println("IR Sensor " + String(i + 1) + ": " + irResults[i]);
    }

    // Send data to Google Sheets
    if (WiFi.status() == WL_CONNECTED) {
      HTTPClient http;
      String fullURL = googleScriptURL + "?uid=" + uidString;

      for (int i = 0; i < 5; i++) {
        String key = "&ir" + String(i + 1) + "=" + irResults[i];
        key.replace(" ", "%20");
        fullURL += key;
      }

      Serial.println("Sending to: " + fullURL);

      http.begin(fullURL);
      int httpResponseCode = http.GET();

      if (httpResponseCode > 0) {
        Serial.print("Data sent. Response code: ");
        Serial.println(httpResponseCode);
        String response = http.getString();
        Serial.println("Server response: " + response);
      } else {
        Serial.print("Error sending data. HTTP response code: ");
        Serial.println(httpResponseCode);
      }

      http.end();
    }

    // Re-magnetize
    digitalWrite(RELAY_PIN, HIGH);
    Serial.println("Re-magnetized electromagnet");
    delay(3000);
  } else {
    Serial.println("Waiting for card...");
    delay(1000);
  }
}

This is the code I had uploaded to the Apps Scripts :

function doGet(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  var uid = e.parameter.uid;
  var ir1 = e.parameter.ir1;
  var ir2 = e.parameter.ir2;
  var ir3 = e.parameter.ir3;
  var ir4 = e.parameter.ir4;
  var ir5 = e.parameter.ir5;

  sheet.appendRow([new Date(), uid, ir1, ir2, ir3, ir4, ir5]);

  return ContentService.createTextOutput("Success");
}

Here is a full video of the results.

This is how it gets updated in the spreadsheet.

Explanation of the code

Here is a VERY breif overview of what the code is supposed to do:

  1. Reads an RFID card

  2. Unlocks the system turning off the electromagnets

  3. Checks if iPads are present using IR sensors. The students have exaclty 6 seconds to take or return an iPad until the IR sensor senses it.

  4. Sends this data to Google Sheets along with the UID of the RFID card scanned and the timestap of when it was scanned.

  5. Then locks the door/box again using the magnet


Thank you!

The template for this website was provided by Mr. Anith Ghalley and used with his permission


Last update: June 23, 2025