#include "header.h" // ALTERNATE FUNCTIONS : // Table 14-9 : port D alternate functions // BUTTON1 SW1 PD2 : // -> INT0 (External Interrupt 0 Input) // -> PCINT18 (Pin Change Interrupt 18) // BUTTON2 SW2 PD4 : // -> XCK (USART External Clock Input/Output) // -> T0 (Timer/Counter 0 External Counter Input) // -> PCINT20 (Pin Change Interrupt 20) // EXTERNAL INTERRUPTS GROUP : // 13.2.4 : pin change interrupt controle register (PCICR) // -> bit PCIE2 for PCINT[23:16] (PCI2 Interrupt Vector) // PCMSK2 to enable each pin // INTERRUPT VECTORS NAME : // Table 12-6 : interrupts vectors // -> PCINT2_vect // ENABLE PIN CHANGE INTERRUPT : // 13.2.6 : PCMSK2 – Pin Change Mask Register 2 // -> (1 << PCINT20) | (1 << PCINT18) #define TIMER_TOP_MS 20 volatile uint8_t value = 0; volatile Boolean pressed = FALSE; volatile Boolean timer_0_init = FALSE; volatile Boolean timer_delay_enabled = FALSE; volatile uint16_t timer_delay = 0; void print_binary(int value) { int mask_3 = 0b1000; int bit_at_3 = value & mask_3; int bit_at_4 = bit_at_3 << 1; PORTB = (value & 0b111) + bit_at_4; } void increment_int() { // int *value = params->value; // int max = params->max; value = (value >= MAX) ? MAX : ++value; } void decrement_int() { // int *value = params->value; // int min = params->min; value = (value <= MIN) ? MIN : --value; } void increment_led() { // IncrementParams *params = (IncrementParams *)param; increment_int(); print_binary(value); } void decrement_led() { // IncrementParams *params = (IncrementParams *)param; decrement_int(); print_binary(value); } void timer0_init_1_ms() { TCCR0A |= (1 << WGM01); // CTC mode OCR0A = 249; // Compare match every 1ms (F_CPU / Prescaler = 16,000,000 / 64 = 250,000 ticks/sec) TIMSK0 |= (1 << OCIE0A); // Enable Compare Match A interrupt TCCR0B |= (1 << CS01) | (1 << CS00); // Prescaler 64 sei(); // Enable global interrupts timer_0_init = TRUE; } void launch_delay_ms(void) { if (!timer_0_init) { timer0_init_1_ms(); } CLEAR(PCICR, PCIE2); // disable interupt PCINT2 CLEAR(PCMSK2, PCINT20); CLEAR(PCMSK2, PCINT18); timer_delay = 0; timer_delay_enabled = TRUE; SET(PCIFR, PCIF2); // reset flag interrupt PCINT2 } ISR(TIMER0_COMPA_vect) { if (!timer_delay_enabled) { return; } timer_delay++; if (timer_delay >= TIMER_TOP_MS) { // TOGGLE_ELEM(LED1); timer_delay_enabled = FALSE; SET(PCICR, PCIE2); // re-enable interupt PCINT2 SET(PCMSK2, PCINT20); SET(PCMSK2, PCINT18); } } void on_press(int bit, void (*action)(void)) { // if ((TEST(PIND, bit)) == 0) { // action(); // _delay_ms(20); // while ((TEST(PIND, bit)) == 0) { // continue; // } // _delay_ms(20); // } launch_delay_ms(); if (!pressed) { // if ((TEST(PIND, bit)) == 0) { // } pressed = TRUE; action(); } else { pressed = FALSE; } } // write a program that incr/decr-ements a number with the buttons, using interrupts, empty infinite loop, and displays the result on LEDs in binary int main() { MODE_OUTPUT(LED1); MODE_OUTPUT(LED2); MODE_OUTPUT(LED3); MODE_OUTPUT(LED4); MODE_INPUT(BUTTON1); MODE_INPUT(BUTTON2); PULLUP_ON(BUTTON1); PULLUP_ON(BUTTON2); SREG |= ENABLE_GLOBAL_INTERRUPT; PCICR = (1 << PCIE2); // 13.2.4 : enable pin change interrupt, bit PCIE2 for PCINT[23:16], (Table 14-9 : alternates : PD2 - PCINT18, PD4 - PCINT20) PCMSK2 = (1 << PCINT20) | (1 << PCINT18); // 13.2.6 : enable individual pin chang interrupt while(1); } ISR(PCINT2_vect) { if (!TEST_PIN(BUTTON1)) { on_press(SW1, increment_led); } if (!TEST_PIN(BUTTON2)) { on_press(SW2, decrement_led); } }