#include #define LED0 PORTD5 // D5 #define LED1 PORTD6 // D6 #define LED2 PORTB0 // D8 #define LED3 PORTB1 // D9 #define BUILTIN_LED PORTB5 // D13 #define BUTTON_SLOW PINB2 // D10 #define BUTTON_FAST PINB3 // D11 #define COMPARE_MIN 1000 #define COMPARE_MAX 50000 volatile unsigned char counter = 0; volatile unsigned int compareValue = COMPARE_MAX; void setupIO() { // LEDs output DDRD |= (1 << LED0) | (1 << LED1); DDRB |= (1 << LED2) | (1 << LED3) | (1 << BUILTIN_LED); // Buttons input with pull-up DDRB &= ~((1 << BUTTON_SLOW) | (1 << BUTTON_FAST)); PORTB |= (1 << BUTTON_SLOW) | (1 << BUTTON_FAST); // Pin change interrupt for D10/D11 PCICR |= (1 << PCIE0); PCMSK0 |= (1 << PCINT2) | (1 << PCINT3); } // Setup Timer1 with COMPA (counter) and COMPB (1Hz LED) void setupTimer1() { TCCR1A = 0; TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // CTC, prescaler 64 OCR1A = compareValue; // 4-bit counter update speed OCR1B = 249999; // 1 Hz = (16e6 / 64) / 250000 TIMSK1 = (1 << OCIE1A) | (1 << OCIE1B); } // Show counter value on 4 LEDs void updateLEDs(unsigned char val) { if (val & 0x01) PORTD |= (1 << LED0); else PORTD &= ~(1 << LED0); if (val & 0x02) PORTD |= (1 << LED1); else PORTD &= ~(1 << LED1); if (val & 0x04) PORTB |= (1 << LED2); else PORTB &= ~(1 << LED2); if (val & 0x08) PORTB |= (1 << LED3); else PORTB &= ~(1 << LED3); } // Counter interrupt (frequency adjustable) ISR(TIMER1_COMPA_vect) { counter = (counter + 1) & 0x0F; updateLEDs(counter); } ISR(TIMER1_COMPB_vect) { PINB |= (1 << BUILTIN_LED); // Toggle built-in LED } // Button interrupt: handle speed control ISR(PCINT0_vect) { static unsigned char lastState = 0xFF; unsigned char current = PINB; // Falling edge: slow down if (!(current & (1 << BUTTON_SLOW)) && (lastState & (1 << BUTTON_SLOW))) { if (compareValue < COMPARE_MAX) { compareValue <<= 1; if (compareValue > COMPARE_MAX) compareValue = COMPARE_MAX; } } // Falling edge: speed up if (!(current & (1 << BUTTON_FAST)) && (lastState & (1 << BUTTON_FAST))) { if (compareValue > COMPARE_MIN) { compareValue >>= 1; if (compareValue < COMPARE_MIN) compareValue = COMPARE_MIN; } } lastState = current; } void setup() { cli(); setupIO(); setupTimer1(); sei(); } void loop() { static unsigned int lastValue = 0; cli(); if (compareValue != lastValue) { TIMSK1 &= ~(1 << OCIE1A); OCR1A = compareValue; TIMSK1 |= (1 << OCIE1A); lastValue = compareValue; } sei(); }