#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define F_CPU 16000000UL
#define RESET_BUTTON PB0
#define STOP_BUTTON PB1
#define PLAY_BUTTON PB2
#define DISPLAY_PORT PORTD
#define DISPLAY_DDR DDRD
const uint8_t digitPatterns[] = {
// abcdefg
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
volatile uint16_t timerValue = 0;
volatile uint8_t running = 0;
volatile uint8_t displayDigit = 0;
void initializeDisplay() {
DISPLAY_DDR = 0xFF;
DDRC = 0xFF;
}
void initializeButtons() {
PCICR |= (1 << PCIE0);
PCMSK0 |= (1 << PCINT0) | (1 << PCINT1) | (1 << PCINT2);
}
void updateDisplay() {
uint8_t ones = timerValue % 10;
uint8_t tens = (timerValue / 10) % 10;
DISPLAY_PORT = digitPatterns[ones];
PORTC |= (1 << PC0);
_delay_ms(5);
PORTC = 0x00;
displayDigit = !displayDigit;
DISPLAY_PORT = !digitPatterns[tens];
PORTC |= (1 << PC1);
_delay_ms(5);
PORTC = 0x00;
}
ISR(PCINT0_vect) {
if (!(PINB & (1 << RESET_BUTTON))) {
timerValue = 0;
running = 0;
updateDisplay();
} else if (!(PINB & (1 << STOP_BUTTON))) {
running = 0;
} else if (!(PINB & (1 << PLAY_BUTTON))) {
running = 1;
}
}
void initializeTimer() {
TCCR1B |= (1 << WGM12); // CTC mode
OCR1A = 15624; // Compare value for 1-second interval at 16 MHz (16,000,000 / 1024)
TIMSK1 |= (1 << OCIE1A); // Enable Timer1 compare match interrupt
TCCR1B |= (1 << CS12) | (1 << CS10); // Set prescaler to 1024, starts the timer
}
ISR(TIMER1_COMPA_vect) {
if (running) {
timerValue++;
}
}
int main() {
initializeDisplay();
initializeButtons();
initializeTimer();
sei();
while (1) {
updateDisplay();
}
return 0;
}