Operácie

Simon's Game

Zo stránky SensorWiki

Záverečný projekt predmetu MIPS / LS2024 - Ondrej Tarcal


Zadanie

Cieľom zadania bolo naprogramovať Simon's game. V skratke hra by mala fungovať tak, že doska generuje náhodnú sekvenciu a my ju musíme následne zopakovať.

Doska Arduino UNO R3.

Literatúra:


Analýza a opis riešenia

Tento program som vytvoril na ovládanie štyroch LEDiek pomocou joysticku. Najprv sa navrhlo samotné ovládanie LEDiek joystickom. Následne som dokódoval aby sa najprv LEDky rozsvietili v náhodnej sekvencii. Nakoniec som dokódoval aby po doznení danej sekvencie uživateľ danú sekvenciu zopakoval a program vyhodnotí, či sa sekvencia rovná alebo nerovná roszvietením LEDiek. Joystick sa taktiež využil na zresetovanie a opakované spustenie novej sekvencie aby sa nemusel využívať reset button na doske Arduino.

RGB LED.

Nezabudnite doplniť schému zapojenia!

Schéma zapojenia joysticku a LEDiek.


Program

1. Definície a Inicializácie

Naprv sa preddefinovali makrá pre LEDky a ich polohy a mŕtve zóny joysticka. Inicializácia ADC prevodníka, čítanie z ADC, inicializacia LEDiek, tlačidla na joysticku a kontrola stlačenia tlačidla

2. Funkcie pre samotnú hru

zobrazenie LEDiek, generovanie náhodných sekvencií a následne zobrazenie sekvencií cez LEDky. Získanie sekvencie od uživateľa cez joystick, kontrola sekvencie a indikácia úspechu alebo neúspechu


#include <avr/io.h>

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdbool.h>

#define F_CPU 16000000UL

#define LED_LEFT    PD2
#define LED_RIGHT   PD3
#define LED_DOWN    PD4
#define LED_UP      PD5

#define BUTTON_PIN  PD6

#define THRESHOLD_X_MIN 300
#define THRESHOLD_X_MAX 700
#define THRESHOLD_Y_MIN 300
#define THRESHOLD_Y_MAX 700

void ADC_Init() {
    ADMUX = (1 << REFS0); // Set ADC reference to AVCC
    ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Zapne ADC a nastavi predelicku na 128
}

uint16_t ADC_Read(uint8_t channel) {
    ADMUX = (ADMUX & 0xF0) | (channel & 0x0F); // Select ADC channel
    ADCSRA |= (1 << ADSC); // zacne jednotkovu konverziu
    while (ADCSRA & (1 << ADSC)); // caka na dokoncenie konverzie
    return ADC; // vrati ADC hodnotu
}

void LED_Init() {
    DDRD |= (1 << LED_LEFT) | (1 << LED_RIGHT) | (1 << LED_DOWN) | (1 << LED_UP);
    PORTD &= ~((1 << LED_LEFT) | (1 << LED_RIGHT) | (1 << LED_DOWN) | (1 << LED_UP));
}

void Button_Init() {
    DDRD &= ~(1 << BUTTON_PIN); // tlacitko na joysticku input bude
    PORTD |= (1 << BUTTON_PIN); //  pull-up resistor 
}

bool isButtonPressed() {
    return !(PIND & (1 << BUTTON_PIN)); // Return true if button is pressed
}

void displayLED(int ledIndex) {
    PORTD &= ~((1 << LED_LEFT) | (1 << LED_RIGHT) | (1 << LED_DOWN) | (1 << LED_UP));

    switch (ledIndex) {
        case 1:
            PORTD |= (1 << LED_LEFT);
            break;
        case 2:
            PORTD |= (1 << LED_RIGHT);
            break;
        case 3:
            PORTD |= (1 << LED_DOWN);
            break;
        case 4:
            PORTD |= (1 << LED_UP);
            break;
        default:
            break;
    }
}

void generateRandomSequence(int sequence[], int length) {
    for (int i = 0; i < length; i++) {
        sequence[i] = (rand() % 4) + 1; // Random cislo medzi 1 az 4
    }
}

void displayLEDSequence(int sequence[], int length) {
    for (int i = 0; i < length; i++) {
        displayLED(sequence[i]);
        _delay_ms(5000); // kazdu led vysvieti na dany cas
        displayLED(0); // vypne vsetky ledky
        _delay_ms(2000); // medzera pred dalsou ledkou vysvietenou
    }
}

void getUserInputSequence(int userSequence[], int length) {
    for (int i = 0; i < length; i++) {
        bool inputReceived = false;

        // Wait for a valid input from the joystick
        while (!inputReceived) {
            if (isButtonPressed()) return; // zresetuje sekvenciu ak sa zatlaci joystick

            uint16_t xAxisValue = ADC_Read(0);
            uint16_t yAxisValue = ADC_Read(1);

            if (xAxisValue < THRESHOLD_X_MIN) {
                userSequence[i] = 1; // Left
                inputReceived = true;
            } else if (xAxisValue > THRESHOLD_X_MAX) {
                userSequence[i] = 2; // Right
                inputReceived = true;
            } else if (yAxisValue < THRESHOLD_Y_MIN) {
                userSequence[i] = 3; // Down
                inputReceived = true;
            } else if (yAxisValue > THRESHOLD_Y_MAX) {
                userSequence[i] = 4; // Up
                inputReceived = true;
            }

            // rozsvieti tu LEDku ktoru ma podla inputu
            if (inputReceived) {
                displayLED(userSequence[i]);
                _delay_ms(2000); // Small delay to show the LED
                displayLED(0); // Turn off the LED
            }
        }
    }
}

bool checkUserInput(int sequence[], int userSequence[], int length) {
    for (int i = 0; i < length; i++) {
        if (sequence[i] != userSequence[i]) {
            return false; // nespravny input
        }
    }
    return true; // sekvencie sa zhoduju
}

void indicateSuccess() {
    // ak sedi sekvencia rozsvieti ledky
    PORTD |= ((1 << LED_LEFT) | (1 << LED_RIGHT) | (1 << LED_DOWN) | (1 << LED_UP));
    _delay_ms(1000);
    PORTD &= ~((1 << LED_LEFT) | (1 << LED_RIGHT) | (1 << LED_DOWN) | (1 << LED_UP));
}

void indicateFailure() {
    // ak nesedi sekvencia rozsvieti inak rozsvieti ledky
    for (int i = 0; i < 3; i++) {
        PORTD |= ((1 << LED_LEFT) | (1 << LED_DOWN));
        _delay_ms(200);
        PORTD &= ~((1 << LED_LEFT) | (1 << LED_DOWN));
        _delay_ms(200);
    }
}

int main(void) {
    ADC_Init();
    LED_Init();
    Button_Init();

    srand(42); // Initialize random number generator

    int sequenceLength = 4;
    int sequence[sequenceLength];
    int userSequence[sequenceLength];

    while (1) {
        generateRandomSequence(sequence, sequenceLength);
        displayLEDSequence(sequence, sequenceLength);

        getUserInputSequence(userSequence, sequenceLength);

        if (isButtonPressed()) {
            // zresetuje sekvenciu ak je stlaceny joystick
            continue;
        }

        bool sequenceMatched = checkUserInput(sequence, userSequence, sequenceLength);

        if (sequenceMatched) {
            indicateSuccess();
        } else {
            indicateFailure();
        }

        // caka na resetu tlacitko pred zacatim novej sekvencie
        while (!isButtonPressed()) {
            _delay_ms(100);
        }
        
        // Small delay to debounce the button press
        _delay_ms(200);
    }

    return 0;
}
#include <avr/io.h>

void adc_init(void);                                   // A/D converter initialization

unsigned int adc_read(char a_pin);

Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:

Zdrojový kód: OndrejTarcal_Simons_game


Overenie

Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku záverečnej obrazovky pred resetom. Vypísaný je tu priemerný čas a najlepší čas.

Aplikácia.

Video:

Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.