This shows you the differences between two versions of the page.
pm:prj2025:eradu:mara.fichios [2025/05/23 13:40] mara.fichios [Hardware Design] |
pm:prj2025:eradu:mara.fichios [2025/05/24 16:12] (current) mara.fichios [Results] |
||
---|---|---|---|
Line 6: | Line 6: | ||
**Project Summary:** | **Project Summary:** | ||
+ | The PianoBit project is an innovative and educational digital mini-piano that utilizes an Arduino Uno as the core control unit. Designed to mimic the functionality of a basic piano, the system includes a 4x4 button matrix, a set of 16 LEDs, an active buzzer, and an LCD screen. The aim of the project is to build a simple, interactive musical instrument while exploring various hardware techniques such as button matrix scanning, LED multiplexing, and sound generation. | ||
+ | |||
+ | ===== General Description ===== | ||
+ | |||
+ | <note tip> | ||
*PianoBit is a digital mini-piano constructed using an Arduino Uno, a 4x4 matrix of buttons, 16 corresponding LEDs, and an active buzzer. | *PianoBit is a digital mini-piano constructed using an Arduino Uno, a 4x4 matrix of buttons, 16 corresponding LEDs, and an active buzzer. | ||
*The core objective of the project is to emulate the behavior of a basic electronic piano with 16 keys. It is designed to explore efficient hardware management using direct multiplexing, thus eliminating the need for dedicated shift registers. | *The core objective of the project is to emulate the behavior of a basic electronic piano with 16 keys. It is designed to explore efficient hardware management using direct multiplexing, thus eliminating the need for dedicated shift registers. | ||
Line 11: | Line 16: | ||
*The system provides a practical and educational platform for understanding key matrix scanning, LED multiplexing, and sound generation, while also working with registers and Arduino. | *The system provides a practical and educational platform for understanding key matrix scanning, LED multiplexing, and sound generation, while also working with registers and Arduino. | ||
- | ===== General Description ===== | ||
- | <note tip> | ||
- | The PianoBit system uses **multiplexing** for the button matrix and **shift registers** for controlling the 16 LEDs. The block-level overview includes: | ||
- | * **Control Unit**: Arduino Uno – this is the brain of the system. It handles logic, controls the button matrix scanning, drives the LEDs, and generates the buzzer tone based on button presses | + | </note> |
- | * **Button Matrix**: a 4x4 matrix of buttons, which is multiplexed to fit within the available I/O pins on the Arduino | + | |
- | * **Output Module**: 16 LEDs – controlled by two 74HC595 shift registers via **daisy chaining**, allowing us to use only 3 Arduino pins for controlling all 16 LEDs. | + | |
- | * **Shift Registers (74HC595)**: two shift registers are used to control the 16 LEDs. We are using daisy chaining to link the shift registers, thus controlling multiple outputs (LEDs) using a minimal number of I/O pins. | + | |
- | * **Audio Module**: an active buzzer connected to the Arduino to play different musical tones based on the pressed key. | + | |
- | * **Display Module**: an I2C LCD connected via the SDA (A4) and SCL (A5) lines on the Arduino. This LCD provides a simple two-wire communication interface to display user feedback such as the currently pressed note, instructions, and system status. The I2C interface reduces wiring complexity and frees up Arduino pins for other uses. | + | |
- | |||
- | </note> | ||
{{:pm:prj2025:eradu:schema_bloc_pianobit2.drawio.png?300x350|}} | {{:pm:prj2025:eradu:schema_bloc_pianobit2.drawio.png?300x350|}} | ||
- | {{:pm:prj2025:eradu:lcd_version_piano.png?750x600|}} | ||
- | {{:pm:prj2025:eradu:lcd_version_piano2.png?750x600|}} | ||
- | {{:pm:prj2025:eradu:pianobit_circuit3.png?750x600|}} | ||
- | Here's a breakdown of how the key components are connected: | ||
- | * The matrix is made up of 16 buttons arranged in 4 rows and 4 columns. The row pins are set as outputs and columns as inputs with internal pull-up resistors. The Arduino reads the columns one by one by activating each row. | + | The block diagram illustrates how the core modules of the PianoBit project are functionally interconnected to achieve real-time user interaction. |
- | * The shift registers control the LEDs. The Data Pin (DS) connects to an Arduino pin (e.g., Pin 11), the Clock Pin (SH_CP) connects to Pin 13, and the Latch Pin (ST_CP) connects to Pin 12. We use daisy chaining to connect the second shift register's data input to the first shift register's output. | + | At the center of the system lies the Arduino Uno, which acts as the main control unit. It manages data flow between input and output modules, orchestrating the behavior of the piano. The button matrix connects directly to the Arduino's digital pins, and the Arduino detects exactly which key has been pressed. This key is translated into a musical note. Once a key is identified, the Arduino triggers two parallel outputs: it sends a corresponding frequency signal to the buzzer, generating an audible tone and it lights up the matching LED by transmitting data serially to the shift registers. These convert the serial input into parallel output, illuminating the specific LED assigned to the pressed key. |
- | * The buzzer is connected to a pin on the Arduino (Pin 10). The Arduino will use PWM to control the sound output, and the message is displayed on the LCD that is connected to 5V and GND, while the SDA is connected to the anaolg pin on the Arduino A4 and SCL to A5. | + | |
- | **Program Flow:** | + | Simultaneously, the Arduino communicates with the I2C LCD display to visually show the name of the note being played. This communication happens via the I2C protocol using only two data lines (SCL and SDA), allowing the LCD to operate without consuming multiple digital I/O pins.All modules draw power from a shared 5V supply. This architecture ensures that pressing a single key results in synchronized audio, visual, and textual feedback, making the PianoBit both interactive and educational. |
- | + | ||
- | * **Setup Phase:** | + | |
- | * Initialize serial communication for debugging. | + | |
- | * Initialize I2C communication registers manually. | + | |
- | * Initialize the LCD display by sending low-level commands over I2C. | + | |
- | * Set initial LCD message to prompt user ("Apasa o nota:"). | + | |
- | * Configure timer to run in CTC mode, generating interrupts to multiplex button matrix rows. | + | |
- | * Enable pin change interrupts on column inputs to detect button presses immediately. | + | |
- | * Configure pins controlling the shift registers (for LEDs) and buzzer. | + | |
- | * Clear all LEDs and set initial states. | + | |
- | + | ||
- | * **Interrupt Service Routines (ISRs):** | + | |
- | * **Timer1 Compare Match ISR:** | + | |
- | - Cycles through the rows of the button matrix by setting the previous row HIGH (inactive) and the next row LOW (active). | + | |
- | - This multiplexing allows scanning one row at a time. | + | |
- | * **Pin Change Interrupts (PCINT0 and PCINT2):** | + | |
- | - Triggered on any change on the column input pins. | + | |
- | - Sets a flag (`keypadChanged`) to indicate that a keypad scan should be performed. | + | |
- | + | ||
- | * **Main Loop (`loop`):** | + | |
- | * If the `keypadChanged` flag is set by the ISR: | + | |
- | - Perform a keypad scan to detect button presses/releases. | + | |
- | - Clear the `keypadChanged` flag. | + | |
- | - Record the time of this scan. | + | |
- | * Otherwise, if a certain time (`scanInterval`) has passed since the last scan: | + | |
- | - Perform a periodic keypad scan to ensure no button press is missed. | + | |
- | + | ||
- | * **Keypad Scanning (`scanKeypad`):** | + | |
- | * For each row: | + | |
- | - The active row is LOW (due to Timer1 ISR multiplexing). | + | |
- | - Read the column input pins directly from hardware registers. | + | |
- | - Detect if any button in the active row is pressed by checking which column reads LOW. | + | |
- | * Calculate the index of the pressed button based on the row and column. | + | |
- | * Implement debouncing by checking if the detected button remains stable for a debounce period (`buttonStableDelay`). | + | |
- | * If a stable button press is detected: | + | |
- | - Update the LCD to display the pressed note. | + | |
- | - Start playing the corresponding tone on the buzzer. | + | |
- | - Light up the corresponding LED by updating the shift registers. | + | |
- | - Log the pressed button and frequency on the serial monitor. | + | |
- | * If no button is pressed (release detected): | + | |
- | - Stop the buzzer. | + | |
- | - Turn off all LEDs. | + | |
- | - Reset the LCD message to the prompt. | + | |
- | + | ||
- | * **LED Update (`updateLED`):** | + | |
- | * Generate a 16-bit pattern with only the bit corresponding to the pressed button set. | + | |
- | * Temporarily disable interrupts to avoid glitches during data shifting. | + | |
- | * Shift out the pattern into two chained 74HC595 shift registers (high byte first, then low byte). | + | |
- | * Re-enable interrupts. | + | |
- | + | ||
- | * **Debounce Mechanism:** | + | |
- | * Detects changes in button state. | + | |
- | * Resets a timer whenever a change is detected. | + | |
- | * Only confirms a button state change if stable for at least 50 milliseconds. | + | |
- | * Prevents false triggering caused by mechanical switch bounce. | + | |
Line 130: | Line 65: | ||
For the LEDs, I used 74HC595 shift registers to control 16 LEDs with only 3 I/O pins (Data, Clock, and Latch). The shift registers are connected in daisy-chain mode, meaning the output of the first shift register is connected to the input of the second. This allows the Arduino to control a total of 16 outputs (8 from each shift register) while only using 3 pins, significantly reducing the number of I/O pins required for controlling the LEDs. | For the LEDs, I used 74HC595 shift registers to control 16 LEDs with only 3 I/O pins (Data, Clock, and Latch). The shift registers are connected in daisy-chain mode, meaning the output of the first shift register is connected to the input of the second. This allows the Arduino to control a total of 16 outputs (8 from each shift register) while only using 3 pins, significantly reducing the number of I/O pins required for controlling the LEDs. | ||
</note> | </note> | ||
+ | |||
+ | Below there are some pictures that showcase the whole circuit: | ||
+ | |||
+ | {{:pm:prj2025:eradu:lcd_version_piano.png?750x600|}} | ||
+ | {{:pm:prj2025:eradu:lcd_version_piano2.png?750x600|}} | ||
+ | {{:pm:prj2025:eradu:pianobit_circuit3.png?750x600|}} | ||
===== Pin Usage ===== | ===== Pin Usage ===== | ||
Line 259: | Line 200: | ||
| `ISR(PCINT2_vect)` | Pin Change Interrupt Service Routine for Port D columns that signals when keypad state has changed. | | | `ISR(PCINT2_vect)` | Pin Change Interrupt Service Routine for Port D columns that signals when keypad state has changed. | | ||
| `ISR(PCINT0_vect)` | Pin Change Interrupt Service Routine for Port B columns that signals when keypad state has changed. | | | `ISR(PCINT0_vect)` | Pin Change Interrupt Service Routine for Port B columns that signals when keypad state has changed. | | ||
+ | |||
+ | |||
+ | |||
+ | **Program Flow:** | ||
+ | |||
+ | * **Setup Phase:** | ||
+ | * Initialize serial communication for debugging. | ||
+ | * Initialize I2C communication registers manually. | ||
+ | * Initialize the LCD display by sending low-level commands over I2C. | ||
+ | * Set initial LCD message to prompt user ("Apasa o nota:"). | ||
+ | * Configure timer to run in CTC mode, generating interrupts to multiplex button matrix rows. | ||
+ | * Enable pin change interrupts on column inputs to detect button presses immediately. | ||
+ | * Configure pins controlling the shift registers (for LEDs) and buzzer. | ||
+ | * Clear all LEDs and set initial states. | ||
+ | |||
+ | * **Interrupt Service Routines (ISRs):** | ||
+ | * **Timer1 Compare Match ISR:** | ||
+ | - Cycles through the rows of the button matrix by setting the previous row HIGH (inactive) and the next row LOW (active). | ||
+ | - This multiplexing allows scanning one row at a time. | ||
+ | * **Pin Change Interrupts (PCINT0 and PCINT2):** | ||
+ | - Triggered on any change on the column input pins. | ||
+ | - Sets a flag (`keypadChanged`) to indicate that a keypad scan should be performed. | ||
+ | |||
+ | * **Main Loop (`loop`):** | ||
+ | * If the `keypadChanged` flag is set by the ISR: | ||
+ | - Perform a keypad scan to detect button presses/releases. | ||
+ | - Clear the `keypadChanged` flag. | ||
+ | - Record the time of this scan. | ||
+ | * Otherwise, if a certain time (`scanInterval`) has passed since the last scan: | ||
+ | - Perform a periodic keypad scan to ensure no button press is missed. | ||
+ | |||
+ | * **Keypad Scanning (`scanKeypad`):** | ||
+ | * For each row: | ||
+ | - The active row is LOW (due to Timer1 ISR multiplexing). | ||
+ | - Read the column input pins directly from hardware registers. | ||
+ | - Detect if any button in the active row is pressed by checking which column reads LOW. | ||
+ | * Calculate the index of the pressed button based on the row and column. | ||
+ | * Implement debouncing by checking if the detected button remains stable for a debounce period (`buttonStableDelay`). | ||
+ | * If a stable button press is detected: | ||
+ | - Update the LCD to display the pressed note. | ||
+ | - Start playing the corresponding tone on the buzzer. | ||
+ | - Light up the corresponding LED by updating the shift registers. | ||
+ | - Log the pressed button and frequency on the serial monitor. | ||
+ | * If no button is pressed (release detected): | ||
+ | - Stop the buzzer. | ||
+ | - Turn off all LEDs. | ||
+ | - Reset the LCD message to the prompt. | ||
+ | |||
+ | * **LED Update (`updateLED`):** | ||
+ | * Generate a 16-bit pattern with only the bit corresponding to the pressed button set. | ||
+ | * Temporarily disable interrupts to avoid glitches during data shifting. | ||
+ | * Shift out the pattern into two chained 74HC595 shift registers (high byte first, then low byte). | ||
+ | * Re-enable interrupts. | ||
+ | |||
+ | * **Debounce Mechanism:** | ||
+ | * Detects changes in button state. | ||
+ | * Resets a timer whenever a change is detected. | ||
+ | * Only confirms a button state change if stable for at least 50 milliseconds. | ||
+ | * Prevents false triggering caused by mechanical switch bounce. | ||
+ | |||
+ | |||
Line 271: | Line 273: | ||
</note> | </note> | ||
+ | |||
+ | {{:pm:prj2025:eradu:pb_1.jpg?512x382|}}\\ | ||
+ | {{:pm:prj2025:eradu:pb_2.jpg?512x382|}}\\ | ||
+ | {{:pm:prj2025:eradu:pb_3.jpg?382x512|}} {{:pm:prj2025:eradu:pb_4.jpg?382x512|}} {{:pm:prj2025:eradu:pb_5.jpg?382x512|}} {{:pm:prj2025:eradu:pb_6.jpg?382x512|}}\\ | ||
+ | |||
+ | |||
+ | |||
+ | |||
===== Conclusions ===== | ===== Conclusions ===== |