#include // AVR pin connected to the transmit output. // On ATmega328P boards, Arduino D2 maps to PD2. const byte DATA_PIN = 2; // Bit sequence to transmit. // Each array element represents one transmitted bit. // 1 = output HIGH, 0 = output LOW. const byte bitStream[] = { 1,0,1,1,0,0,1,0, 0,1,1,1,0,0,0,1 }; // Number of bits in the transmission buffer. const uint16_t NUM_BITS = sizeof(bitStream); // Variables shared between main loop and interrupt service routine. // volatile prevents compiler optimization because these values may change asynchronously. volatile uint16_t bitIndex = 0; volatile bool txComplete = false; volatile bool transmitting = false; // Timer1 interrupt handler. // Called every 300 us to output the next bit in the stream. void transmitISR() { if (bitIndex < NUM_BITS) { // Direct port manipulation is used instead of digitalWrite() // to minimize execution time and provide more consistent timing. if (bitStream[bitIndex]) PORTD |= _BV(PD2); // Set D2 HIGH else PORTD &= ~_BV(PD2); // Set D2 LOW bitIndex++; } else { // Transmission complete. // Return output line to idle LOW state. PORTD &= ~_BV(PD2); // Disable Timer1 interrupt until another transmission starts. Timer1.detachInterrupt(); transmitting = false; txComplete = true; } } // Initializes and begins a new bit transmission. void startTransmission() { // Reset transmission state. bitIndex = 0; txComplete = false; transmitting = true; // Output first bit immediately. // This avoids an initial timer-period delay before transmission begins. if (bitStream[bitIndex]) PORTD |= _BV(PD2); else PORTD &= ~_BV(PD2); bitIndex++; // Configure Timer1 to generate an interrupt every 300 microseconds. // This determines the bit period: // 300 us per bit = approximately 3333 bits/sec. Timer1.initialize(300); // Start periodic interrupts. Timer1.attachInterrupt(transmitISR); } void setup() { // Configure PD2 (Arduino pin 2) as an output. DDRD |= _BV(DDD2); // Set initial idle state LOW. PORTD &= ~_BV(PD2); // Initialize serial interface for transmission trigger input. Serial.begin(115200); Serial.println("Send any character to transmit."); } void loop() { // Start a transmission when serial input is received // and no transmission is currently active. if (Serial.available() && !transmitting) { char c = Serial.read(); Serial.print("Received: "); Serial.println(c); // Begin fixed bit-stream output. startTransmission(); } // Handle transmission completion outside the ISR. // Keeping Serial operations out of the ISR avoids timing problems. if (txComplete) { txComplete = false; Serial.println("Transmission complete."); } }