This shows you the differences between two versions of the page.
|
pm:prj2026:florin.stancu:dinu.merceanu [2026/05/13 20:36] dinu.merceanu [Electrical schematic] |
pm:prj2026:florin.stancu:dinu.merceanu [2026/05/13 22:48] (current) dinu.merceanu [Introduction] |
||
|---|---|---|---|
| Line 3: | Line 3: | ||
| <note tip> | <note tip> | ||
| - | A two-player reaction time game inspired by the Romanian TV show "Ce spun romanii". Three red LEDs light up one by one, then turn off simultaneously after a random delay — this is the start signal. The first player to press their button wins: their blue LED lights up and an OLED display shows the winner and their reaction time in milliseconds. | + | A two-player reaction time game inspired by the Romanian TV show "Ce spun romanii" and by the start lights of Formula 1. Three red LEDs light up one by one, then turn off simultaneously after a random delay — this is the start signal. The first player to press their button wins: their blue LED lights up and an OLED display shows the winner and their reaction time in milliseconds. |
| The goal of the project is to create a simple yet engaging interactive game that tests the reflexes of two players. The idea started from TV shows where contestants must react as fast as possible to a visual signal. | The goal of the project is to create a simple yet engaging interactive game that tests the reflexes of two players. The idea started from TV shows where contestants must react as fast as possible to a visual signal. | ||
| The project is useful as a practical demonstration of hardware interrupts, timers and I2C communication on an AVR microcontroller, while also being an accessible example of an interactive embedded system. | The project is useful as a practical demonstration of hardware interrupts, timers and I2C communication on an AVR microcontroller, while also being an accessible example of an interactive embedded system. | ||
| Line 56: | Line 56: | ||
| | GND | All components | Common ground | | | GND | All components | Common ground | | ||
| - | ==== Electrical schematic ==== | + | ==== Hardware Schematic Diagram ==== |
| - | + | {{ :pm:prj2026:florin.stancu:hardwareschematicdiagram.png?800 |}} | |
| - | {{ :pm:prj2026:florin.stancu:electrialschematic.jpg?nolink&500 |}} | + | |
| ==== Signal diagram ==== | ==== Signal diagram ==== | ||
| Line 72: | Line 71: | ||
| ===== Software Design ===== | ===== Software Design ===== | ||
| + | ==== Development Environment ==== | ||
| - | <note tip> | + | The firmware was developed using **PlatformIO** integrated into **Visual Studio Code**, |
| - | Descrierea codului aplicaţiei (firmware): | + | targeting the ATmega328P with the Arduino framework (used only as a build system — |
| - | * mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR) | + | all peripheral control is done via direct AVR register access, without any Arduino |
| - | * librării şi surse 3rd-party (e.g. Procyon AVRlib) | + | library functions). |
| - | * algoritmi şi structuri pe care plănuiţi să le implementaţi | + | |
| - | * (etapa 3) surse şi funcţii implementate | + | Upload is done via the **xplainedmini** protocol using avrdude, over USB. |
| - | </note> | + | |
| + | ==== Third-party Libraries and Sources ==== | ||
| + | |||
| + | No external libraries were used. All drivers were implemented from scratch using | ||
| + | AVR-libc headers only: | ||
| + | |||
| + | * ''<avr/io.h>'' — register definitions | ||
| + | * ''<avr/interrupt.h>'' — ISR macro and sei()/cli() | ||
| + | * ''<util/delay.h>'' — _delay_ms() for debouncing | ||
| + | |||
| + | The SSD1306 OLED driver, TWI/I2C driver, USART driver, and timer modules were | ||
| + | written entirely by hand, inspired by the laboratory implementations provided | ||
| + | during the PM course. | ||
| + | |||
| + | ==== File Structure ==== | ||
| + | |||
| + | ^ File ^ Role ^ | ||
| + | | ''src/main.cpp'' | Game logic, state machine, ISR definitions | | ||
| + | | ''src/uptime.cpp'' | Timer2 CTC — 1ms system tick counter | | ||
| + | | ''src/timers.cpp'' | Timer1 CTC — reaction time measurement | | ||
| + | | ''src/twi.cpp'' | I2C/TWI driver using AVR hardware TWI module | | ||
| + | | ''src/ssd1306.cpp'' | SSD1306 OLED driver with 5x7 bitmap font | | ||
| + | | ''src/usart.cpp'' | UART driver for serial debug output | | ||
| + | | ''include/uptime.h'' | uptime_ms() declaration | | ||
| + | | ''include/timers.h'' | Timer1_init/start/stop/get_ms declarations | | ||
| + | | ''include/twi.h'' | TWI function declarations and frequency config | | ||
| + | | ''include/ssd1306.h'' | SSD1306 function declarations | | ||
| + | | ''include/usart.h'' | USART function declarations | | ||
| + | |||
| + | ==== Algorithms and Data Structures ==== | ||
| + | |||
| + | **Game state machine** | ||
| + | |||
| + | The game runs as a sequential state machine inside the main loop: | ||
| + | |||
| + | - ''IDLE'' — display shows "READY", waiting for SW0 (PB7) press | ||
| + | - ''COUNTDOWN'' — LED1, LED2, LED3 light up one by one at 1s intervals using non-blocking timing via uptime_ms(). External interrupts INT0/INT1 are active during this phase to detect false starts. | ||
| + | - ''RANDOM DELAY'' — all 3 LEDs remain on for a random interval (1–3 seconds), generated via rand() seeded with uptime_ms() | ||
| + | - ''GO'' — LEDs turn off, Timer1 starts counting reaction time | ||
| + | - ''RESULT'' — first player to press wins. If a false start was detected, the offending player is disqualified. Results are shown on OLED and serial. | ||
| + | |||
| + | **Non-blocking timing** | ||
| + | |||
| + | All delays during the countdown and random delay phases use the pattern: | ||
| + | |||
| + | <code c> | ||
| + | uint32_t t = uptime_ms(); | ||
| + | while ((uptime_ms() - t) < 1000 && !false_start_p1 && !false_start_p2); | ||
| + | </code> | ||
| + | |||
| + | This allows the main loop to remain responsive to false start interrupts even | ||
| + | while waiting. | ||
| + | |||
| + | **False start detection** | ||
| + | |||
| + | External interrupts INT0 (PD2) and INT1 (PD3) are configured for falling edge | ||
| + | detection. ISRs set volatile flags only if ''game_started == 0'': | ||
| + | |||
| + | <code c> | ||
| + | ISR(INT0_vect) { if (!game_started) false_start_p1 = 1; } | ||
| + | ISR(INT1_vect) { if (!game_started) false_start_p2 = 1; } | ||
| + | </code> | ||
| + | |||
| + | **Reaction time measurement** | ||
| + | |||
| + | Timer1 is initialized in CTC mode at 16MHz with prescaler 8, generating an | ||
| + | interrupt every 1ms (OCR1A = 1999). A volatile counter ''reaction_ticks'' | ||
| + | increments in the ISR. Timer1_start() resets and enables it; Timer1_get_ms() | ||
| + | reads the counter atomically using cli()/sei(). | ||
| + | |||
| + | **I2C communication** | ||
| + | |||
| + | The TWI hardware module is configured for 100kHz SCL frequency. The SSD1306 | ||
| + | driver sends initialization commands on startup, then writes character bitmaps | ||
| + | page by page using twi_start/twi_write/twi_stop sequences. | ||
| + | |||
| + | **OLED font rendering** | ||
| + | Characters are stored as a 5x7 bitmap font in Flash memory (PROGMEM) for | ||
| + | 58 ASCII characters (space through Z). Each character is 5 bytes wide plus | ||
| + | 1 byte spacing. ssd1306_print_str() renders a string at a specified page row (0–7). | ||
| ===== Rezultate Obţinute ===== | ===== Rezultate Obţinute ===== | ||