June 11, 2026
void setup() {
// PB4 (Physical Pin 3) is Arduino pin 4
pinMode(4, OUTPUT);
}
void mark(uint32_t time) {
// 38kHz carrier logic for 8MHz ATtiny85
// Shifted to use Channel B for PB4 (OC1B) output
TCCR1 = _BV(CTC1) | _BV(CS10); // CTC mode, no prescaler
GTCCR = _BV(PWM1B) | _BV(COM1B1); // Enable PWM B, clear on match
// 8,000,000 / 38,000 = 210.5
OCR1C = 210; // Timer resets at 210 to hit 38kHz
OCR1B = 105; // Duty cycle is exactly half of OCR1C (50%) for Channel B
customDelay(time);
}
void space(uint32_t time) {
TCCR1 = 0; // Turn off main timer
GTCCR = 0; // Turn off PWM Channel B
digitalWrite(4, LOW); // Ensure PB4 stays low
customDelay(time);
}
// Handles durations longer than 16383us which delayMicroseconds fails at
void customDelay(uint32_t us) {
while (us > 15000) {
delayMicroseconds(15000);
us -= 15000;
}
delayMicroseconds(us); // Handle the remainder
}
void loop() {
for (uint8_t i = 0; i < totalCodes; i++) {
// 1. Get pointer to the current code array
const uint8_t* currentCode = (const uint8_t*)pgm_read_word(&(allCodes[i]));
// 2. Get the length and base unit for this specific code
uint8_t len = codeLengths[i];
uint16_t baseUnit = baseUnits[i];
// 3. Repeat each code exactly twice
for (uint8_t rep = 0; rep < 2; rep++) {
for (uint8_t j = 0; j < len; j++) {
// Read the 8-bit multiplier from PROGMEM
uint8_t multiplier = pgm_read_byte(¤tCode[j]);
// Calculate actual duration
uint32_t duration = (uint32_t)multiplier * baseUnit;
if (j % 2 == 0) mark(duration); // Even = Pulse
else space(duration); // Odd = Gap
}
space(0); // Ensure off
// Standard 150ms gap between identical blasts so the TV recognizes them
delay(150);
}
// 100ms gap before moving to the next TV brand
delay(100);
}
// No delay here; the list immediately starts over from the beginning
}