{{ t.products }}

{{ live_data.products.length }}

{{ t.categories }}

{{ live_data.categories.length }}

{{ t.brands }}

{{ live_data.brands.length }}
Menu
If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!
If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!If you cannot find a specific electronic or automation spare part on our website or in the market, please contact us — quantity does not matter!

How to Make a Mini OLED Character with XIAO ESP32-C6?

•
Author: Senanur Yılmaz
•
Publish Time: 10.11.2026
•
Reading Time: 10 Minute
How to Make a Mini OLED Character with XIAO ESP32-C6?

In this guide, we’ll build a cute mini OLED character from scratch—one that changes facial expressions. Even if you’ve never built an electronic circuit before, you’ll see step by step where each wire goes, which program to upload, and how to send the code to the board.

What will happen when the project is finished? The character on the OLED screen will blink, look left and right, and display happy, sad, surprised, sleepy, or angry facial expressions. There is no motor in the project; the movements are created only by drawings on the screen.

1. Materials you’ll need

Safety: The soldering iron gets very hot; children should work with an adult. Do not puncture, crush, or short-circuit the LiPo battery, and do not connect the plus/minus terminals the wrong way around. Connect the battery last.

2. How does the system work?

The XIAO ESP32-C6 calculates the face to be drawn and sends it to the OLED display using a two-wire communication method called I2C. SDA is the data wire; it carries the drawing information. SCL is the clock wire; it determines the rhythm at which the data is sent. VCC and GND are the display’s power/electrical connections.

3. Wiring diagram

OLED wiring diagram with the real XIAO ESP32-C6 image

Shows red power, black minus/ground, green data, and blue clock connections.

Starting pointGoes toTask
OLED VCCXIAO 3V3Supplies safe 3.3 V power to the display.
OLED GNDXIAO GNDCommon minus/ground connection.
OLED SDAXIAO D4 / SDASends data to the display.
OLED SCLXIAO D5 / SCLCommunication clock.
Battery plus (+)Switch middle pinBrings the battery’s plus line to the switch.
Switch outer pinXIAO BAT+Connects to the battery when the switch is turned on.
Battery minus (−)XIAO BAT−Battery minus line.

Connecting the 3-pin slide switch

3-pin slide switch connection

This switch has three pins, but we’ll use only two: the middle pin and one of the outer pins. The other outer pin will remain unused. If the direction of the switch is reversed, swap the outer pin you’re using with the other outer pin.

Charging note: Since the switch fully disconnects the battery’s plus wire, when charging the battery via the XIAO’s USB-C connection, the switch must be in the ON position.

Soldering order

  1. Disconnect the USB cable and the battery from the circuit.
  2. First, prepare the OLED’s VCC, GND, SDA, and SCL wires.
  3. Solder these four wires to the XIAO according to the table.
  4. Solder the battery’s plus wire to the switch’s middle pin.
  5. Connect one of the switch’s outer pins to the BAT+ pad on the XIAO.
  6. Connect the battery’s minus wire to the XIAO BAT− pad.
  7. Use heat-shrink tubing or insulation so no metal is exposed.
  8. After confirming there is no short circuit, connect the battery.

4. The program we’ll use: Arduino IDE

Arduino IDE is a free program that sends the code we write to the XIAO board. From the Arduino IDE download page, download and install the version that matches your operating system.

Installing ESP32 board support

  1. Open Arduino IDE.
  2. Go to the File > Preferences menu.
  3. Add this address to the Additional Boards Manager URLs field:
    https://espressif.github.io/arduino-esp32/package_esp32_index.json
  4. Open the Boards Manager section from the left side.
  5. Search for esp32 and install version 3.0.0 or newer of the Espressif Systems package.
  6. Select Tools > Board > ESP32 Arduino > XIAO_ESP32C6.
  7. Connect the board to your computer with a USB-C data cable, then select the visible port from Tools > Port.

Installing the U8g2 display library

  1. Click the Library Manager icon on the left side of Arduino IDE.
  2. Type U8g2 in the search box.
  3. Install the U8g2 library prepared by Oliver Kraus.

5. Let’s do a small screen test first

Before moving on to the full animation code, checking that the display and wires work makes things easier. In Arduino IDE, select File > New Sketch, delete the incoming code, and paste the code below:

#include <Wire.h>
#include <U8g2lib.h>

// For the Motorobit display, we first try the SH1106 driver.
U8G2_SH1106_128X64_NONAME_F_HW_I2C display(U8G2_R0, U8X8_PIN_NONE);

void setup() {
  Wire.begin(D4, D5);       // D4 = SDA, D5 = SCL
  display.begin();
  display.clearBuffer();
  display.setFont(u8g2_font_ncenB14_tr);
  display.drawStr(16, 38, "Hello!");
  display.sendBuffer();
}

void loop() {
  // We don’t do anything here because the text stays on the screen.
}

Check the code by pressing the checkmark in the top-left corner, then press the Upload button shaped like a right arrow. If you see “Hello!” on the screen, the connections are correct.

If the screen is still blank: The display controller might be SSD1306. Change U8G2_SH1106_128X64_NONAME_F_HW_I2C in the test code to U8G2_SSD1306_128X64_NONAME_F_HW_I2C and upload again.

6. Full animation code

The code below automatically finds the display’s 0x3C and 0x3D addresses; it draws the character, makes it blink, lets it look left and right, and shows different emotions.

#include <Wire.h>
#include <U8g2lib.h>

// If your display is SH1106, use this line.
U8G2_SH1106_128X64_NONAME_F_HW_I2C display(U8G2_R0, U8X8_PIN_NONE);

// If you don’t get an image with SH1106, comment out the line above and enable this one:
// U8G2_SSD1306_128X64_NONAME_F_HW_I2C display(U8G2_R0, U8X8_PIN_NONE);

enum Emotion {
  NORMAL,
  HAPPY,
  SAD,
  SURPRISED,
  SLEEPY,
  ANGRY
};

Emotion emotion = NORMAL;
int lookX = 0;
int targetLookX = 0;
bool eyesClosed = false;

unsigned long nextBlink = 0;
unsigned long eyesOpenTime = 0;
unsigned long nextMove = 0;

// Searches for the 0x3C or 0x3D address on the I2C bus.
byte findOledAddress() {
  byte possibleAddresses[] = {0x3C, 0x3D};

  for (byte i = 0; i < 2; i++) {
    Wire.beginTransmission(possibleAddresses[i]);
    if (Wire.endTransmission() == 0) {
      return possibleAddresses[i];
    }
  }
  return 0;
}

void drawEyes(int centerX, int centerY, bool leftEye) {
  if (eyesClosed || emotion == SLEEPY) {
    display.drawLine(centerX - 9, centerY, centerX + 9, centerY);
    display.drawLine(centerX - 7, centerY + 1, centerX + 7, centerY + 1);
    return;
  }

  int width = 18;
  int height = 25;

  if (emotion == SURPRISED) {
    width = 22;
    height = 30;
  }

  int x = centerX - width / 2 + lookX;
  int y = centerY - height / 2;
  display.drawRBox(x, y, width, height, 6);

  // For an angry face, draw a slanted black line over the eyes.
  if (emotion == ANGRY) {
    display.setDrawColor(0);
    if (leftEye) display.drawTriangle(x - 2, y - 1, x + width + 2, y - 1, x + width + 2, y + 8);
    else          display.drawTriangle(x - 2, y - 1, x + width + 2, y - 1, x - 2, y + 8);
    display.setDrawColor(1);
  }
}

void drawMouth() {
  switch (emotion) {
    case HAPPY:
      display.drawLine(51, 46, 58, 52);
      display.drawLine(58, 52, 64, 54);
      display.drawLine(64, 54, 70, 52);
      display.drawLine(70, 52, 77, 46);
      break;

    case SAD:
      display.drawLine(51, 55, 58, 49);
      display.drawLine(58, 49, 64, 47);
      display.drawLine(64, 47, 70, 49);
      display.drawLine(70, 49, 77, 55);
      break;

    case SURPRISED:
      display.drawCircle(64, 51, 7);
      break;

    case SLEEPY:
      display.drawLine(58, 52, 70, 52);
      break;

    case ANGRY:
      display.drawLine(54, 55, 64, 50);
      display.drawLine(64, 50, 74, 55);
      break;

    default:
      display.drawLine(58, 52, 70, 52);
      break;
  }
}

void drawFace() {
  display.clearBuffer();
  drawEyes(38, 29, true);
  drawEyes(90, 29, false);
  drawMouth();
  display.sendBuffer();
}

void setup() {
  Serial.begin(115200);
  delay(300);

  Wire.begin(D4, D5);  // XIAO ESP32-C6: D4 SDA, D5 SCL
  byte address = findOledAddress();

  if (address == 0) {
    Serial.println("OLED not found. Check the cables.");
    while (true) delay(1000);
  }

  // Since the U8g2 address is requested in an 8-bit format, we shift it left by 1 bit.
  display.setI2CAddress(address << 1);
  display.begin();

  randomSeed(micros());
  nextBlink = millis() + random(2000, 6000);
  nextMove = millis() + random(1500, 4000);

  Serial.print("OLED found. Address: 0x");
  Serial.println(address, HEX);
}

void loop() {
  unsigned long now = millis();

  // Start blinking.
  if (!eyesClosed && now >= nextBlink) {
    eyesClosed = true;
    eyesOpenTime = now + 150;
  }

  // Re-open the eyes after 150 milliseconds.
  if (eyesClosed && now >= eyesOpenTime) {
    eyesClosed = false;
    nextBlink = now + random(2000, 6000);
  }

  // Choose a new look or emotion at certain intervals.
  if (now >= nextMove) {
    if (random(100) < 40) {
      targetLookX = random(-5, 6);
    } else {
      emotion = (Emotion)random(0, 6);
      targetLookX = 0;
    }
    nextMove = now + random(1500, 4000);
  }

  // Slowly approach the target so the look doesn’t jump instantly.
  if (lookX < targetLookX) lookX++;
  if (lookX > targetLookX) lookX--;

  drawFace();
  delay(33);  // About 30 frames per second
}

7. Easy explanation of the code

Code sectionWhat does it do?
#include linesEnables I2C communication with Wire and OLED drawing with U8g2.
enum EmotionList of facial expressions the character can show.
findOledAddress()Automatically detects whether the screen is 0x3C or 0x3D.
drawEyes()Draws the eyes’ position, size, and whether they’re closed.
drawMouth()Draws a different mouth shape depending on the selected emotion.
setup()Runs only once when the board powers on; prepares the display.
loop()Keeps running while the board is on; manages blinking and emotion changes.
delay(33)Keeps the animation smooth by drawing about 30 frames per second.

8. Uploading the code to the board

  1. In Arduino IDE, open a new sketch and paste the full code.
  2. In Tools > Board, make sure XIAO_ESP32C6 is selected.
  3. Select the board’s port from Tools > Port.
  4. Compile the code with the checkmark.
  5. Upload the code to the board using the right-arrow button.
  6. When the upload is complete, the screen will come to life within a few seconds.

If you don’t see the board, your USB-C cable might be charging-only. Try another USB data cable. If uploading doesn’t start, press the BOOT button on the XIAO, then press the RESET button once, release BOOT, and upload again.

9. Troubleshooting

ProblemCheck
The screen is completely offCheck that VCC is connected to 3V3 and GND is connected to GND.
The screen is on but there’s no imageCheck the SDA/D4 and SCL/D5 wires; try the SSD1306 line instead of SH1106.
“OLED not found” messageOpen the Serial Monitor in Arduino IDE with 115200 baud; look for broken solder joints or a short circuit.
Code doesn’t compileMake sure the U8g2 library and the latest ESP32 board package are installed.
Board not listed in portsTry another USB data cable or a different USB port.
Doesn’t work on batteryCheck that the middle pin and one outer pin of the switch are used, and verify the BAT+ and BAT− polarity.
Battery isn’t chargingWith the USB-C connected, set the switch to the ON position.
The board keeps rebootingCheck that the battery isn’t empty and that the solder joints aren’t touching each other.

10. If you’ll use a 3D-printed enclosure

The 3D model files for the project we took inspiration from are on GitHub. But before you print directly, measure the parts. In this project, the OLED board is about 35.5 × 33.5 mm, the battery is about 24 × 15.5 × 6.7 mm, and the selected switch body is about 10.5 × 5.5 mm. You may need to scale the model up because the original enclosure’s switch opening could be smaller.

Conclusion

Now you have a portable mini character powered by the XIAO ESP32-C6, an I2C OLED display, a small LiPo battery, and a slide switch. First do a simple “Hello!” test, then switch to the full animation code—this makes it easier to spot any connection issues.

Source video for the project: Building a Tiny OLED Keychain
Sample source code: TechTalkies / 123_Keychain
Official XIAO ESP32-C6 getting started guide: Seeed Studio Wiki

Share
T-Soft | Premium