TeknoTrek
Published © GPL3+

HT16K33 4-Digit 16-Segment Display with Custom PCB

A custom-designed HT16K33-based 4-digit 16-segment display with I2C control, animations, and reusable firmware for embedded projects.

BeginnerProtip4 hours81
HT16K33 4-Digit 16-Segment Display with Custom PCB

Things used in this project

Hardware components

HT16K33 LED Driver (I2C)
×1
16-Segment LED Display
×4
Custom PCB (HT16K33 Display Board)
×1
Arduino-compatible Microcontroller (Uno / Nano / ESP32 / STM32)
×1
Pin Headers / Connectors
×4
220R Resistors
×4

Software apps and online services

Arduino IDE
Arduino IDE
Adafruit_LEDBackpack Library
Adafruit_GFX Library
Wire (I2C) Library
KiCad
KiCad

Hand tools and fabrication machines

Soldering Iron
Multimeter
Flux and Solder Wire
USB Cable

Story

Read more

Schematics

HT16K33 4-Digit 16-Segment Display

Code

State Machine Animations

C/C++
/*
  TeknoTrek YouTube Channel
   Electronics  Arduino  PCB Design  LED Animations  Embedded Systems

  For more projects and short tutorials:

   YouTube: https://www.youtube.com/@TeknoTrek

   Subscribe to support the channel and stay updated!
*/



#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>

Adafruit_AlphaNum4 display;

/* ===================== */
/* SEGMENT TANIMLARI     */
/* ===================== */
#define SEG_A  (1 << 0)
#define SEG_B  (1 << 1)
#define SEG_C  (1 << 2)
#define SEG_D  (1 << 3)
#define SEG_E  (1 << 4)
#define SEG_F  (1 << 5)
#define SEG_G  (1 << 6)
#define SEG_H  (1 << 7)
#define SEG_K  (1 << 8)
#define SEG_L  (1 << 9)
#define SEG_M  (1 << 10)
#define SEG_N  (1 << 11)
#define SEG_O  (1 << 12)
#define SEG_P  (1 << 13)
#define SEG_S  (1 << 15)

/* ===================== */
/* HARF TANIMLARI        */
/* ===================== */
uint16_t CHAR_T = SEG_A | SEG_B | SEG_L | SEG_O;
uint16_t CHAR_E = SEG_A | SEG_B | SEG_H | SEG_G | SEG_S | SEG_E | SEG_F;
uint16_t CHAR_K = SEG_H | SEG_G | SEG_S | SEG_M | SEG_P;
uint16_t CHAR_N = SEG_H | SEG_G | SEG_K | SEG_P | SEG_D | SEG_C;
uint16_t CHAR_O = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_H;
uint16_t CHAR_R = SEG_A | SEG_B | SEG_C | SEG_N | SEG_S | SEG_H | SEG_G | SEG_P;
uint16_t CHAR_SPACE = 0;

/* ===================== */
/* KAYAN METN           */
/* ===================== */
uint16_t text[] = {
  CHAR_T, CHAR_E, CHAR_K, CHAR_N, CHAR_O,
  CHAR_T, CHAR_R, CHAR_E, CHAR_K,
  CHAR_SPACE, CHAR_SPACE, CHAR_SPACE, CHAR_SPACE
};
#define TEXT_LEN (sizeof(text) / sizeof(text[0]))

/* ===================== */
/* STATE TANIMLARI       */
/* ===================== */
enum AnimationState {
  STATE_WAVE,
  STATE_MATRIX,
  STATE_FILL,
  STATE_PULSE,
  STATE_SCROLL   //  EN SON
};

AnimationState currentState = STATE_WAVE;
unsigned long stateStartTime = 0;
const unsigned long STATE_DURATION = 4000;

/* ===================== */
/* SETUP                 */
/* ===================== */
void setup() {
  Wire.begin();
  display.begin(0x70);
  display.clear();
  display.writeDisplay();
  randomSeed(analogRead(A0));
  stateStartTime = millis();
}

/* ===================== */
/* STATE GE          */
/* ===================== */
void nextState() {
  currentState = (AnimationState)((currentState + 1) % 5);
  stateStartTime = millis();
  display.clear();
}

/* ===================== */
/* LOOP                  */
/* ===================== */
void loop() {
  if (millis() - stateStartTime > STATE_DURATION) {
    nextState();
  }

  switch (currentState) {
    case STATE_WAVE:   animWave();   break;
    case STATE_MATRIX: animMatrix(); break;
    case STATE_FILL:   animFill();   break;
    case STATE_PULSE:  animPulse();  break;
    case STATE_SCROLL: scrollText(); break;
  }
}

/* ===================== */
/* ANMASYONLAR          */
/* ===================== */

//  Wave
void animWave() {
  static uint8_t d = 0, b = 0;
  display.clear();
  display.writeDigitRaw(d, (1 << b));
  display.writeDisplay();

  b++;
  if (b >= 16) { b = 0; d = (d + 1) % 4; }
  delay(30);
}

//  Matrix
void animMatrix() {
  display.clear();
  for (int d = 0; d < 4; d++) {
    display.writeDigitRaw(d, random(0x0000, 0xFFFF));
  }
  display.writeDisplay();
  delay(80);
}

//  Dolma
void animFill() {
  static uint16_t frame = 0;
  frame = (frame << 1) | 1;
  if (frame == 0xFFFF) frame = 0;

  for (int d = 0; d < 4; d++) {
    display.writeDigitRaw(d, frame);
  }
  display.writeDisplay();
  delay(120);
}

//  Pulse
void animPulse() {
  static bool on = false;
  on = !on;

  for (int d = 0; d < 4; d++) {
    display.writeDigitRaw(d, on ? 0xFFFF : 0x0000);
  }
  display.writeDisplay();
  delay(200);
}

//  Kayan "teknoTrek" (SON ANMASYON)
void scrollText() {
  static int pos = 0;

  display.clear();
  display.writeDigitRaw(0, text[pos]);
  display.writeDigitRaw(1, text[pos + 1]);
  display.writeDigitRaw(2, text[pos + 2]);
  display.writeDigitRaw(3, text[pos + 3]);
  display.writeDisplay();

  pos++;
  if (pos > TEXT_LEN - 4) pos = 0;
  delay(300);
}

Flower Animation

C/C++
/*
  TeknoTrek YouTube Channel
   Electronics  Arduino  PCB Design  LED Animations  Embedded Systems

  For more projects and short tutorials:
   YouTube: https://www.youtube.com/@TeknoTrek

   Subscribe to support the channel and stay updated!
*/


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>

Adafruit_AlphaNum4 display;

/******** SEGMENT TANIMLARI ********/
#define SEG_A (1 << 0)
#define SEG_B (1 << 1)
#define SEG_C (1 << 2)
#define SEG_D (1 << 3)
#define SEG_E (1 << 4)
#define SEG_F (1 << 5)
#define SEG_G (1 << 6)
#define SEG_H (1 << 7)
#define SEG_K (1 << 8)
#define SEG_L (1 << 9)
#define SEG_M (1 << 10)
#define SEG_N (1 << 11)
#define SEG_O (1 << 12)
#define SEG_P (1 << 13)
#define SEG_R (1 << 14)
#define SEG_S (1 << 15)

/******** HALKA TANIMLARI ********/
uint16_t innerRing[] = {
  SEG_K, SEG_L, SEG_M, SEG_N,
  SEG_P, SEG_O, SEG_R, SEG_S
};

uint16_t outerRing[] = {
  SEG_A, SEG_B, SEG_C, SEG_D,
  SEG_E, SEG_F, SEG_G, SEG_H
};

#define INNER_LEN 8
#define OUTER_LEN 8

/******** ZAMANLAMALAR ********/
#define STEP_TIME   140
#define DIGIT_WAVE  180
#define HOLD_TIME   500
#define CLEAR_TIME  300

/******** STATE MACHINE ********/
enum State {
  FLOWER_INNER,
  FLOWER_OUTER,
  HOLD_FULL,
  CLEAR_ALL
};

State currentState = FLOWER_INNER;

uint32_t lastTick = 0;
int digitIndex = 0;
int stepIndex  = 0;

uint16_t digitState[4] = {0, 0, 0, 0};

void setup() {
  Wire.begin();
  display.begin(0x70);
  display.clear();
  display.writeDisplay();
}

void loop() {
  uint32_t now = millis();

  switch (currentState) {

    /********   HALKA ********/
    case FLOWER_INNER:
      if (now - lastTick >= STEP_TIME) {
        lastTick = now;

        if (stepIndex < INNER_LEN) {
          digitState[digitIndex] |= innerRing[stepIndex];
          display.writeDigitRaw(digitIndex, digitState[digitIndex]);
          display.writeDisplay();
          stepIndex++;
        } else {
          stepIndex = 0;
          digitIndex++;
          if (digitIndex >= 4) {
            digitIndex = 0;
            currentState = FLOWER_OUTER;
          }
          lastTick += DIGIT_WAVE;
        }
      }
      break;

    /********  DI HALKA ********/
    case FLOWER_OUTER:
      if (now - lastTick >= STEP_TIME) {
        lastTick = now;

        if (stepIndex < OUTER_LEN) {
          digitState[digitIndex] |= outerRing[stepIndex];
          display.writeDigitRaw(digitIndex, digitState[digitIndex]);
          display.writeDisplay();
          stepIndex++;
        } else {
          stepIndex = 0;
          digitIndex++;
          if (digitIndex >= 4) {
            digitIndex = 0;
            currentState = HOLD_FULL;
            lastTick = now;
          }
          lastTick += DIGIT_WAVE;
        }
      }
      break;

    /********  TAM DOLU BEKLE ********/
    case HOLD_FULL:
      if (now - lastTick >= HOLD_TIME) {
        currentState = CLEAR_ALL;
        lastTick = now;
      }
      break;

    /********  TEMZLE ********/
    case CLEAR_ALL:
      if (now - lastTick >= CLEAR_TIME) {
        for (int i = 0; i < 4; i++) digitState[i] = 0;
        display.clear();
        display.writeDisplay();
        currentState = FLOWER_INNER;
        digitIndex = 0;
        stepIndex = 0;
        lastTick = now;
      }
      break;
  }
}

Leading Zero Secret Countre

C/C++
/*
  TeknoTrek YouTube Channel
   Electronics  Arduino  PCB Design  LED Animations  Embedded Systems

  For more projects and short tutorials:
   YouTube: https://www.youtube.com/@TeknoTrek

   Subscribe to support the channel and stay updated!
*/


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>

Adafruit_AlphaNum4 display;

/* ================= SEGMENT TANIMLARI ================= */
#define SEG_A (1 << 0)
#define SEG_B (1 << 1)
#define SEG_C (1 << 2)
#define SEG_D (1 << 3)
#define SEG_E (1 << 4)
#define SEG_F (1 << 5)
#define SEG_G (1 << 6)
#define SEG_H (1 << 7)
#define SEG_K (1 << 8)
#define SEG_L (1 << 9)
#define SEG_M (1 << 10)
#define SEG_N (1 << 11)
#define SEG_O (1 << 12)
#define SEG_P (1 << 13)
#define SEG_R (1 << 14)
#define SEG_S (1 << 15)

/* ================= RAKAMLAR =================
   3 rakam dzeltilmitir (G OFF, E ON)
*/
uint16_t digits[10] = {
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_H,        // 0
  SEG_C | SEG_D,                                                        // 1
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G | SEG_N | SEG_S,        // 2
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_N | SEG_S,        // 3
  SEG_C | SEG_D | SEG_H | SEG_N | SEG_S,                                // 4
  SEG_A | SEG_B | SEG_D | SEG_E | SEG_F | SEG_H | SEG_N | SEG_S,        // 5
  SEG_A | SEG_B | SEG_D | SEG_E | SEG_F | SEG_G | SEG_H | SEG_N | SEG_S,// 6
  SEG_A | SEG_B | SEG_M | SEG_O,                                        // 7
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_H |
  SEG_N | SEG_S,                                                        // 8
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_H |
  SEG_N | SEG_S                                                         // 9
};

void setup() {
  Wire.begin();
  display.begin(0x70);
  display.clear();
  display.writeDisplay();
}

void loop() {
  static uint16_t count = 0;

  display.clear();

  uint8_t d0 = (count / 1000) % 10;
  uint8_t d1 = (count / 100)  % 10;
  uint8_t d2 = (count / 10)   % 10;
  uint8_t d3 = count % 10;

  bool started = false;

  if (d0 != 0) {
    display.writeDigitRaw(0, digits[d0]);
    started = true;
  }

  if (started || d1 != 0) {
    display.writeDigitRaw(1, digits[d1]);
    started = true;
  }

  if (started || d2 != 0) {
    display.writeDigitRaw(2, digits[d2]);
    started = true;
  }

  // Son digit her zaman yazlr
  display.writeDigitRaw(3, digits[d3]);

  display.writeDisplay();

  count++;
  if (count > 9999) count = 0;

  delay(100);
}

Credits

TeknoTrek
1 project • 0 followers
YouTube electronics creator sharing DIY circuits, PCB designs, Arduino projects, and hands-on engineering tutorials.

Comments