LED Triangle Animation IR LED


June 12, 2026


// --- PIN DEFINITIONS ---
const int irPin = 4; // PB4 (Physical Pin 3)
const int led1  = 0; // PB0 (Physical Pin 5)
const int led2  = 1; // PB1 (Physical Pin 6)
const int led3  = 2; // PB2 (Physical Pin 7)

// --- LED STATE VARIABLES ---
unsigned long lastLedUpdate = 0;
const unsigned long ledInterval = 40; // 40ms (0.04s) gap between LED stages
uint8_t currentLed = 0;

void setup() {
  pinMode(irPin, OUTPUT); 
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
}

// --- NON-BLOCKING LED ANIMATION ---
void updateLEDs() {
  unsigned long currentMillis = millis();
  
  // Check if 40ms have passed since the last update
  if (currentMillis - lastLedUpdate >= ledInterval) {
    lastLedUpdate = currentMillis;

    // Turn all LEDs off first
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);

    // Light the current LED in the sequence
    if (currentLed == 0) digitalWrite(led1, HIGH);
    else if (currentLed == 1) digitalWrite(led2, HIGH);
    else if (currentLed == 2) digitalWrite(led3, HIGH);

    // Advance to the next LED, looping back to 0 after 2
    currentLed++;
    if (currentLed > 2) currentLed = 0;
  }
}

// --- SMART DELAY ---
// Replaces standard delay() so the LEDs keep animating during the gaps
void smartDelay(unsigned long ms) {
  unsigned long start = millis();
  while (millis() - start < ms) {
    updateLEDs();
  }
}

// --- IR CARRIER LOGIC ---
void mark(uint32_t time) {
  TCCR1 = _BV(CTC1) | _BV(CS10);     
  GTCCR = _BV(PWM1B) | _BV(COM1B1);  

  OCR1C = 210; 
  OCR1B = 105; 
  
  customDelay(time);
}

void space(uint32_t time) {
  TCCR1 = 0; 
  GTCCR = 0; 
  digitalWrite(irPin, LOW); 
  
  customDelay(time);
}

void customDelay(uint32_t us) {
  while (us > 15000) {
    delayMicroseconds(15000);
    us -= 15000;
  }
  delayMicroseconds(us); 
}

// --- MAIN LOOP ---
void loop() {
  // Reset the LED sequence for a fresh run
  currentLed = 0;
  lastLedUpdate = millis();

  for (uint8_t i = 0; i < totalCodes; i++) {
    
    const uint8_t* currentCode = (const uint8_t*)pgm_read_word(&(allCodes[i]));
    uint8_t len = codeLengths[i];
    uint16_t baseUnit = baseUnits[i];

    for (uint8_t rep = 0; rep < 2; rep++) {
      
      for (uint8_t j = 0; j < len; j++) {
        // Update the LED animation between every single bit transmission
        updateLEDs(); 
        
        uint8_t multiplier = pgm_read_byte(&currentCode[j]);
        uint32_t duration = (uint32_t)multiplier * baseUnit;

        if (j % 2 == 0) mark(duration); 
        else space(duration);           
      }
      space(0); 
      
      // Keep LEDs animating during the 150ms intra-code gap
      smartDelay(150); 
    }

    // Keep LEDs animating during the 100ms inter-code gap
    smartDelay(100); 
  }
  
  // --- END OF CYCLE BEHAVIOR ---
  // Turn all three LEDs on simultaneously
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);
  
  // Hold them on for exactly 1 second (standard delay is fine here 
  // since we explicitly want the animation paused while they are all lit)
  delay(1000); 
  
  // Loop automatically restarts from the top, immediately resuming IR and sequential LEDs
}