#include <avr/io.h>
#include <avr/interrupt.h>
// Constants for button debounce
#define DEBOUNCE_TIME 150 // in milliseconds
volatile int intensity = 0; // Duty cycle of PWM (0-255)
volatile bool updateDisplay = false; // Flag to update 7-segment display
const uint8_t segmentMap[10] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
// Update 7-segment display for common anode
void update7SegmentDisplay() {
uint8_t segments = segmentMap[intensity];
// Using PORTD for pins 4-7 and PORTB for pins 8, 10, 11
// Segment a (PD4)
if (segments & 0x01) PORTD &= ~(1 << PD4); // LOW
else PORTD |= (1 << PD4); // HIGH
// Segment b (PD5)
if (segments & 0x02) PORTD &= ~(1 << PD5); // LOW
else PORTD |= (1 << PD5); // HIGH
// Segment c (PD6)
if (segments & 0x04) PORTD &= ~(1 << PD6); // LOW
else PORTD |= (1 << PD6); // HIGH
// Segment d (PD7)
if (segments & 0x08) PORTD &= ~(1 << PD7); // LOW
else PORTD |= (1 << PD7); // HIGH
// Segment e (PB0)
if (segments & 0x10) PORTB &= ~(1 << PB0); // LOW
else PORTB |= (1 << PB0); // HIGH
// Segment f (PB2)
if (segments & 0x20) PORTB &= ~(1 << PB2); // LOW
else PORTB |= (1 << PB2); // HIGH
// Segment g (PB3)
if (segments & 0x40) PORTB &= ~(1 << PB3); // LOW
else PORTB |= (1 << PB3); // HIGH
updateDisplay = false;
}
// Interrupt Service Routine for INT0
ISR(INT0_vect) {
static unsigned long lastInterruptTime0 = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime0 > DEBOUNCE_TIME) {
if (intensity < 9) intensity += 1;
OCR1A = intensity * 28;
updateDisplay = true;
lastInterruptTime0 = interruptTime;
}
}
// Interrupt Service Routine for INT1
ISR(INT1_vect) {
static unsigned long lastInterruptTime1 = 0;
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime1 > DEBOUNCE_TIME) {
if (intensity > 0) intensity -= 1;
OCR1A = intensity * 28;
updateDisplay = true;
lastInterruptTime1 = interruptTime;
}
}
void setup() {
// Initialise the 7 segment display pins as Outputs
DDRD |= (1 << PD4) | (1 << PD5) | (1 << PD6) | (1 << PD7);
DDRB |= (1 << PB0) | (1 << PB2) | (1 << PB3);
update7SegmentDisplay(); // Initialize display to 0
// Initialise the LED pin as Output
DDRB |= (1 << PB1);
// Initialize PWM on pin D9
TCCR1A = (1 << WGM10) | (1 << COM1A1);
TCCR1B = (1 << CS11) | (1 << CS10); // Prescaler 64
OCR1A = 0; // Initial duty cycle
// Initialise Interrupt (Buttons)
EICRA = (1 << ISC01) | (0 << ISC00) | (1 << ISC11) | (0 << ISC10); // Rising edge for INT0 and INT1
EIMSK = (1 << INT0) | (1 << INT1); // Enable INT0 and INT1
sei(); // Enable global interrupts
}
void loop() {
if (updateDisplay) {
update7SegmentDisplay(); // Display the step 0-9
}
}