8-Button Piano – Interrupt Driven Code

Our 8-Button Piano is driven purely by interrupts. Utilizing the in-class example for button handling, we configured all 8 of our buttons as input using the GPIO ports available on the ATMega328P Xplained Mini microcontroller. In order to achieve a level of attainable modularity with our design, we utilized predefined macros to indicate the data direction register, port, and pin numbers for each of our buttons. 

Button Macro Configurations

With these macros defined, the remainder of the interrupts system was driven by three methods: get_key_press(), init_timers(), and init_io(). The first of these methods to be called was init_timers(), which first clears the global interrupt flag, then sets bit 0 (CS10) of TC1 Control Register B to 1, which enables the clock with no prescaling. It is important to note that the microcontroller is using normal waveform generation mode rather than a variant of pulse width modulation. After enabling the clock, the function makes a further modification to the TC1 Interrupt Mask Register by setting bit 0 (TOIE) to 1, which enables overflow interrupt. Finally, it calls the sei() function from the avr/interrupt.h library which sets the global interrupt flag.

Timer Initialization Method

Next, the init_io() function is called to initialize the I/O, as defined previously by the button macros. Namely, this method sets each pin in DDRD as an input by setting the respective bit in the register to 1. Furthermore, it enables the pull-up resistors by setting each of the 8 bits in register PORTD to 1 as well.

I/O (Button) Initialization Method
Main Function Loop

The final two components of our interrupt driven system are the interrupt handler and main methods. The interrupt handler is executed every time the TIMER1_OVF_vect vector is generated, which by the settings initialized in init_timers(), is approximately every 8 milliseconds. This handler then updates the key_state and key_press variables that are then referenced in an infinite loop within the main function every time the get_key_press() function is called. If this function returns true for a specific button, then the respective function to generate the desired tone is executed.