May 1, 2026
#include <avr/pgmspace.h>
// Define each code as a separate array in PROGMEM
const uint16_t c0[] PROGMEM = {3456, 1728, 432, 432, 432, 1296, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 1296, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 1296, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, 1296, 432, 432, 432, 1296, 432, 1296, 432, 1296, 432, 1296, 432, 432, 432, 432, 432, 1296, 432, 432, 432, 1296, 432, 1296, 432, 1296, 432, 1296, 432, 432, 432, 1296, 432, 74736};
const uint16_t c1[] PROGMEM = {3680, 3680, 460, 1840, 460, 1840, 460, 1840, 460, 1840, 460, 920, 460, 920, 460, 1840, 460, 920, 460, 1840, 460, 920, 460, 1840, 460, 920, 460, 920, 460, 920, 460, 920, 460, 920, 460, 1840, 460, 1840, 460, 920, 460, 1840, 460, 920, 460, 1840, 460, 920, 460, 1840, 460, 6900};
const uint16_t c2[] PROGMEM = {3680, 3680, 460, 1840, 460, 1840, 460, 1840, 460, 1840, 460, 920, 460, 920, 460, 1840, 460, 1840, 460, 1840, 460, 920, 460, 1840, 460, 920, 460, 920, 460, 920, 460, 920, 460, 920, 460, 1840, 460, 1840, 460, 920, 460, 920, 460, 920, 460, 1840, 460, 920, 460, 1840, 460, 6900};
const uint16_t c3[] PROGMEM = {9024, 4512, 564, 1692, 564, 1692, 564, 1692, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 1692, 564, 1692, 564, 1692, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 1692, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 1692, 564, 564, 564, 1692, 564, 1692, 564, 1692, 564, 1692, 564, 1692, 564, 1692, 564, 43992};
// A master table of all codes and their lengths
const uint16_t* const allCodes[] PROGMEM = {c0, c1, c2, c3};
const uint8_t codeLengths[] = {99, 52, 52, 68}; // Number of values in each array
const uint8_t totalCodes = 4;
void setup() {
pinMode(1, OUTPUT); // PB1 (Physical Pin 6)
}
void mark(uint16_t time) {
// 38kHz carrier logic for 8MHz ATtiny85
TCCR1 = _BV(CTC1) | _BV(PWM1A) | _BV(COM1A0) | _BV(CS10);
OCR1C = 104; // (8,000,000 / 38,000 / 2) - 1 approx 104
customDelay(time);
}
void space(uint16_t time) {
TCCR1 = 0; // Turn off carrier
digitalWrite(1, LOW);
customDelay(time);
}
// Handles durations longer than 16383us which delayMicroseconds fails at
void customDelay(uint16_t us) {
while (us > 15000) {
delayMicroseconds(15000);
us -= 15000;
}
delayMicroseconds(us);
}
void loop() {
for (uint8_t i = 0; i < totalCodes; i++) {
// Get pointer to the current code array from PROGMEM
uint16_t* currentCode = (uint16_t*)pgm_read_word(&(allCodes[i]));
uint8_t len = codeLengths[i];
for (uint8_t j = 0; j < len; j++) {
uint16_t duration = pgm_read_word(¤tCode[j]);
if (j % 2 == 0) mark(duration); // Even = Pulse
else space(duration); // Odd = Gap
}
space(0); // Ensure off
delay(200); // 200ms gap between different TV codes
}
delay(10000); // Wait 10 seconds before starting the whole list again
}