Week 9 — Output Devices

Final Result

Using rfid to open certain webpage

RFID pulling out the WebVR page I build during 3d scanning week

Last week for input device there were a lot of bug and the connection didn’t really work. To figure out the RFID Connection and also not waste parts

RC522 pins
Xiao soldering the pin
RC522 Soldering the pin

Debugging

  • verifying SPI pin mapping
          
#include <SPI.h>
void setup() {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("SPI Pins:");
  Serial.print("MOSI: "); Serial.println(MOSI);
  Serial.print("MISO: "); Serial.println(MISO);
  Serial.print("SCK : "); Serial.println(SCK);
}
void loop() {}
          
        

output:

          
SPI Pins:
MOSI: 3
MISO: 4
SCK : 2
          
        
  • the final correct connection
https://github.com/rafaelurben/circuitpy-nfc

          
            /*
 * --------------------------------------------------------------------------------------------------------------------
 * Example sketch/program showing how to read data from a PICC to serial.
 * --------------------------------------------------------------------------------------------------------------------
 * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid
 *
 * Example sketch/program showing how to read data from a PICC (that is: a RFID Tag or Card) using a MFRC522 based RFID
 * Reader on the Arduino SPI interface.
 *
 * When the Arduino and the MFRC522 module are connected (see the pin layout below), load this sketch into Arduino IDE
 * then verify/compile and upload it. To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M). When
 * you present a PICC (that is: a RFID Tag or Card) at reading distance of the MFRC522 Reader/PCD, the serial output
 * will show the ID/UID, type and any data blocks it can read. Note: you may see "Timeout in communication" messages
 * when removing the PICC from reading distance too early.
 *
 * If your reader supports it, this sketch/program will read all the PICCs presented (that is: multiple tag reading).
 * So if you stack two or more PICCs on top of each other and present them to the reader, it will first output all
 * details of the first and then the next PICC. Note that this may take some time as all data blocks are dumped, so
 * keep the PICCs at reading distance until complete.
 *
 * @license Released into the public domain.
 *
 * Typical pin layout used:
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 *
 * More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout
 */
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN         27          // check the P numbers in the xiao image
#define SS_PIN          1         // check the P numbers in the xiao image
MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance
void setup() {
	Serial.begin(9600);		// Initialize serial communications with the PC
	while (!Serial);		// Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
	SPI.begin();			// Init SPI bus
	mfrc522.PCD_Init();		// Init MFRC522
	delay(4);				// Optional delay. Some board do need more time after init to be ready, see Readme
	mfrc522.PCD_DumpVersionToSerial();	// Show details of PCD - MFRC522 Card Reader details
	Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}
void loop() {
	// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
	if ( ! mfrc522.PICC_IsNewCardPresent()) {
		return;
	}
	// Select one of the cards
	if ( ! mfrc522.PICC_ReadCardSerial()) {
		return;
	}
	// Dump debug info about the card; PICC_HaltA() is automatically called
	mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
          
        
  • output

RFID UID reading

          
            #include <SPI.h>
#include <MFRC522.h>
// Pins (match wiring above)
constexpr uint8_t PIN_SS  = 1;
constexpr uint8_t PIN_RST = D2;
MFRC522 mfrc522(PIN_SS, PIN_RST);
String uidToHex(const MFRC522::Uid &uid) {
  String s;
  for (byte i = 0; i < uid.size; i++) {
    if (uid.uidByte[i] < 0x10) s += "0";
    s += String(uid.uidByte[i], HEX);
  }
  s.toUpperCase();
  return s;
}
void setup() {
  Serial.begin(115200);
  while (!Serial) { delay(5); } // wait for Serial on some boards
  SPI.begin();
  mfrc522.PCD_Init();
  Serial.println("XIAO + RC522 ready. Tap a tag.");
}
void loop() {
  // Wait for a new card
  if (!mfrc522.PICC_IsNewCardPresent()) {
    delay(50);
    return;
  }
  if (!mfrc522.PICC_ReadCardSerial()) {
    delay(50);
    return;
  }
  String uidHex = uidToHex(mfrc522.uid);
  Serial.print("UID:");
  Serial.println(uidHex); // prints e.g. UID:04986F2A
  // Halt until tag removed (simple debounce)
  delay(200);
  while (mfrc522.PICC_IsNewCardPresent()) {
    delay(100);
  }
  delay(200);
}
          
        
RFID UID display prototype

Python Helper Script

  • setting up the environment (anaconda prompt)
          
conda create -n rfidhelper python=3.10 -y
conda activate rfidhelper
pip install pyserial
          
        
  • create a project folder and code in the project folder
          
cd "D:\school\A_MIT\1_2025Fall\6.9020 How to make almost anything\01_Assginments\week 9 output device\rfid_url_helper"
code .
          
        

PCB Design

OLED Screen

          
            #include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
  Serial.begin(115200);
  while(!Serial) {}
  Wire.setSDA(6);
  Wire.setSCL(7);
  Wire.begin();
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // change to 0x3D if scanner showed 0x3D
    Serial.println("SSD1306 init failed.");
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("OLED OK");
  display.display();
}
void loop() {}
          
        

Final RFID input and OLED output

          
            // XIAO RP2040 + RC522 + 0.96" I2C OLED (SSD1306)
// Keeps UID on screen for HOLD_MS after tag removal.
#include <Wire.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ---------- TUNABLE ----------
constexpr uint32_t HOLD_MS = 2500;   // how long to keep UID after tag is removed
// -----------------------------
// ---------- OLED ----------
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ---------- RC522 ----------
constexpr uint8_t PIN_SS  = 1;   // change to D3 if that's your SS wiring
constexpr uint8_t PIN_RST = 27;  // if RST is tied to 3V3 you can still keep this
MFRC522 mfrc522(PIN_SS, PIN_RST);
// ---------- STATE ----------
enum class UiState { IDLE, SHOWING };
UiState uiState = UiState::IDLE;
unsigned long lastSeenMs = 0;
String lastUID;
// ---------- helpers ----------
String uidToHex(const MFRC522::Uid &uid) {
  String s;
  for (byte i = 0; i < uid.size; i++) {
    if (uid.uidByte[i] < 0x10) s += "0";
    s += String(uid.uidByte[i], HEX);
  }
  s.toUpperCase();
  return s;
}
void showReady() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("XIAO + RC522");
  display.println("Ready for tag...");
  display.display();
}
void showUID(const String &uidHex) {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("Tag detected:");
  display.setTextSize(2);
  display.setCursor(0, 20);
  display.println(uidHex);
  display.display();
}
// ---------- setup ----------
void setup() {
  Serial.begin(115200);
  while (!Serial) { delay(5); }
  // I2C (OLED)
  Wire.setSDA(6);
  Wire.setSCL(7);
  Wire.begin();
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
      Serial.println("OLED not found at 0x3C/0x3D. Check wiring.");
      for(;;) { delay(1000); }
    }
  }
  showReady();
  // SPI (RFID)
  SPI.begin();
  mfrc522.PCD_Init();
  Serial.println("Ready. Tap a tag.");
}
// ---------- loop ----------
void loop() {
  // If a card is present, read it and update "last seen" time
  if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
    String uidHex = uidToHex(mfrc522.uid);
    // Only redraw/print if the UID changed or we were idle
    if (uiState != UiState::SHOWING || uidHex != lastUID) {
      Serial.print("UID:");
      Serial.println(uidHex);
      showUID(uidHex);
      lastUID = uidHex;
    }
    lastSeenMs = millis();
    uiState = UiState::SHOWING;
    // Be polite with the card
    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
  }
  // If we're showing a UID, keep it up until HOLD_MS after last sighting
  if (uiState == UiState::SHOWING) {
    if (millis() - lastSeenMs > HOLD_MS) {
      uiState = UiState::IDLE;
      showReady();
    }
  }
  // Small idle delay to reduce CPU noise
  delay(20);
}
          
        
Bread board prototype