LED Patch

Creating a wearable patch for my niece's satchel.

The satchel of my niece allows patches to be attached to it via zipper. You can buy simple round patches which are just think plastic discs with images printed on them, but that is too boring for me. So what I was thinking about was a battery powered blinking LED patch not just to make the patch more interesting but also to increase my niece's security by making her being seen when it gets dark.

Prototype 1

This is the code I wrote for it:

#define PIN_R 0
#define PIN_G 1
#define PIN_B 4
#define PIN_I 2
#define MAX_MODE 3

#define BREATH_MIN 20
#define BREATH_MAX 100
#define BREATH_DIFF 4

uint8_t mode = 0;
int last_r = 0;
int last_g = 0;
int last_b = 0;
int last_dr = 1;
int last_dg = 1;
int last_db = 1;
int last_i = 0;
unsigned long debouncetime = 0;

void setup() {
  ADCSRA = 0; // Disable analog-to-digital conversion

  pinMode(PIN_R, OUTPUT);
  pinMode(PIN_G, OUTPUT);
  pinMode(PIN_B, OUTPUT);

  // Prepare pin interrupt
  cli();                  // Disable interrupts
  PCMSK |= (1 << PIN_I);  // Enable interrupt handler (ISR) for PIN_I (PCINT1)
  GIMSK |= (1 << PCIE);   // Enable PCINT interrupt in the general interrupt mask
  pinMode(PIN_I, INPUT);  // Set pin as input pin - has dedecated pullup
  sei();                  // Last line of setup - re-enable interrupts
}

ISR(PCINT0_vect) {
  if (digitalRead(PIN_I) == LOW) {
    if (mode == MAX_MODE) {
      mode = 0;
      MCUCR&=~(1< BREATH_MAX) { r = BREATH_MAX; last_dr = random(BREATH_DIFF) - BREATH_DIFF; }
  int g = last_g + last_dg;
  if      (g < BREATH_MIN) { g = BREATH_MIN; last_dg = random(BREATH_DIFF) + 1; }
  else if (g > BREATH_MAX) { g = BREATH_MAX; last_dg = random(BREATH_DIFF) - BREATH_DIFF; }
  int b = last_b + last_db;
  if      (b < BREATH_MIN) { b = BREATH_MIN; last_db = random(BREATH_DIFF) + 1; }
  else if (b > BREATH_MAX) { b = BREATH_MAX; last_db = random(BREATH_DIFF) - BREATH_DIFF; }

  applyColor(r, g, b);

  delay(20);
}

void doPolice() {
  last_i++;
  if (last_i > 11) last_i = 0;
  switch (last_i) {
    case 0:
    case 2:
    case 4:
      applyColor(255, 0, 0);
      delay(100);
      break;
    case 6:
    case 8:
    case 10:
      applyColor(0, 0, 192);
      delay(100);
      break;
    case 1:
    case 3:
    case 5:
    case 7:
    case 9:
    case 11:
      applyColor(0, 0, 0);
      delay(50);
      break;
  }
}

void doFade() {
  int c;
  last_i++;
  if (last_i >= 768) last_i = 0;
  if (last_i < 256) {
    c = last_i;
    applyColor(c, 0, 255 - c);
  } else if (last_i < 512) {
    c = last_i - 256;
    applyColor(255 - c, c, 0);
  } else if (last_i < 768) {
    c = last_i - 512;
    applyColor(0, 255 - c, c);
  }
  delay(50);
}

void doSingle(int start) {
  switch (mode - start) {
    case 0: applyColor(255, 0,   0  ); break;
    case 1: applyColor(0,   255, 0  ); break;
    case 2: applyColor(0,   0,   255); break;
    case 3: applyColor(255, 160, 0  ); break;
    case 4: applyColor(255, 0,   255); break;
    case 5: applyColor(0,   255, 255); break;
  }
  delay(100);
}

void doSleep() {
  applyColor(0, 0, 0);
  MCUCR|=(1 << SM1);      // Enabling sleep mode and powerdown sleep mode
  MCUCR|= (1 << SE);      // Enabling sleep enable bit
  __asm__ __volatile__ ( "sleep" "\n\t" :: ); //Sleep instruction to put controller to sleep
}

void loop() {
  switch (mode) {
    case 0: // Breath
      doBreath();
      break;

    case 1:
      doPolice();
      break;

    case 2:
      doFade();
      break;

    case MAX_MODE: // Sleep
      doSleep();
      break;
  }
}

Over time though (and because my crude prototype didn't appeal to my niece), I continued to go crazy on it and used a 5x5 WS2812 LED display instead of simple LEDs.

ATtiny13a

Code Time high Time low Tollerance
0 0.400ns 0.800ns ±0.150ns
1 0.800ns 0.400ns ±0.150ns
Reset - ≥0.050ns -
Latch - ≥300ns -

At 9.6Mhz that is proximately 0.100ns per instruction so we need 12 instructions per code (1.250ns instead of 1.200ns which is easily withing the tollernce):

HHHHxxxxLLLLR
^   ^   ^   ^
0   4   8   12

The ATtiny13 has just 1024 bytes of storage and 64 bytes of RAM. To address 25 LEDs my plan is to use only two colors per image and store the image in 4 bytes.

This page was last edited on 2024-07-12 21:04

Powered by Wiki|Docs

This page was last edited on 2024-07-12 21:04

Bjørn Singer
Private wiki!

Powered by Wiki|Docs