This is an old revision of the document!


Joc Whac-A-Mole

Autor: Mușat-Mare Cristian-Cosmin

Grupa: 332CD

Îndrumător: Florin Stancu

Introducere

Proiectul presupune crearea unei variante simplificate a jocului clasic Whac-A-Mole. Cârtițele vor fi reprezentate de LED-uri care se vor aprinde la intervale din ce în ce mai mici, pe măsura ce jocul progresează, și vor avea un timeout la expirarea căruia se vor stinge, astfel jucătorul ratând șansa de a-și crește scorul. LED-urile vor avea asociate câte un buton care va fi acționat prin apăsare, ducând astfel la stingerea LED-ului asociat, respectiv omorârea cârtiței. Scorul va fi calculat în funcție de reacția cât mai rapidă a jucătorului (cu cât omoară cârtițele mai repede cu atât scorul va fi mai mare) și va fi afișat pe un ecran LCD.

Arhitecură

Schema bloc

Pentru a acționa LED-urile vor fi folosite timere și întreruperi.

De asemenea, pentru a contoriza scorul, se va măsura tensiunea la buton printr-un pin analogic și cu ajutorul ADC.

Pentru a afișa scorul pe LCD se va folosi protocolul SPI.

Design Hardware

Schema electrică

Componente

  • 1 Arduino Uno R3 ATmega328p
  • 4 Butoane
  • 4 Rezistențe
  • 4 LED-uri
  • 1 Breadboard
  • Fire jumper si normale
  • LCD SPI 1.44' (128×128) ST7735

Design Software

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SPI.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_ST7735.h>

#define NO_LED 4
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9
#define TIMEOUT 2.490368

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

double score = 0;
volatile bool led_on = false;
volatile bool timeout_occurred = false;
volatile int sel;
int look_at_voltage = -1;
volatile int timer2_ovf_count = 0;
volatile int timer0_ovf_count = 0;
volatile int timer2_total_ticks = 0;

void init_display() {
    tft.initR(INITR_BLACKTAB);
    tft.setTextColor(ST7735_WHITE);
    tft.fillScreen(ST7735_BLACK);
    tft.setTextSize(2);
    tft.setRotation(2);
}

ISR(TIMER1_COMPA_vect) {
    if (led_on == false) {
        timer2_total_ticks = 0;
        timer2_ovf_count = 0;
        TCNT2 = 0;
        sel = rand() % NO_LED + 2;
        PORTD |= (1 << sel);
        led_on = true;
        timeout_occurred = false;
        look_at_voltage = -1;
    }
}

ISR(TIMER1_COMPB_vect) {
    tft.fillRect(40, 20, 60, 20, ST7735_BLACK);
}

ISR(TIMER2_OVF_vect) {
    timer2_total_ticks += 256;
    timer2_ovf_count++;
    if (timer2_ovf_count == 76 && led_on == true) {
        led_on = false;
        timeout_occurred = true;
        look_at_voltage = -1;
        PORTD &= ~(1 << sel);
    }
}

ISR(TIMER0_COMPA_vect) {
  timer0_ovf_count++;
  if (timer0_ovf_count == 611) {
    if (OCR1A - 3906 > 15625) {
        OCR1A = OCR1A - 3906;
    }
    else {
        OCR1A = 46875;
    }
    TCNT1 = min(TCNT1, OCR1A - 1);
    timer0_ovf_count = 0;
  }
}

void my_setup() {
    DDRD |= (1 << PD3);
    DDRD |= (1 << PD2);
    DDRD |= (1 << PD4);
    DDRD |= (1 << PD5);

    TCCR1A = 0; 
    TCCR1B = 0;
    TCNT1 = 0;
    OCR1A = 46875;
    OCR1B = 15625;
    TCCR1B |= (1 << WGM12);
    TCCR1B |= (1 << CS12) | (1 << CS10);
    TIMSK1 |= (1 << OCIE1A) | (1 << OCIE1B);

    TCCR2A = 0;
    TCCR2B = 0;
    TCNT2 = 0;
    TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);
    TIMSK2 |= (1 << TOIE2);

    TCCR0A = 0;
    TCCR0B = 0;
    TCNT0 = 0;
    OCR0A = 255;
    TCCR0A |= (1 << WGM01);
    TCCR0B |= (1 << CS02) | (1 << CS00);
    TIMSK0 |= (1 << OCIE0A);
}

void adc_init(int port) {
    ADMUX |= (1 << REFS0);
    ADCSRA |= (1 << ADEN);
    ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    ADMUX &= ~(1 << MUX0);  
    ADMUX &= ~(1 << MUX1);  
    ADMUX &= ~(1 << MUX2);  
    ADMUX &= ~(1 << MUX3);
    if (port == 0) {
    }
    else if (port == 1) {
        ADMUX |= (1 << MUX0);
    }
    else if (port == 2) {
        ADMUX |= (1 << MUX1);
    }
    else if (port == 3) {
        ADMUX |= (1 << MUX1) | (1 << MUX0);
    }
    else if (port == 4) {
        ADMUX |= (1 << MUX2);
    }
    else if (port == 5) {
        ADMUX |= (1 << MUX2) | (1 << MUX0);
    }
}

int adc_read() {
    ADCSRA |= (1 << ADSC);
    while ((ADCSRA & (1 << ADSC)));
    int res = ADC;
    return res;
}

void my_loop() {
    for (int analog_pin = 0; analog_pin < NO_LED; analog_pin++) {
        adc_init(analog_pin);
        int analog_in = adc_read();
        int v_in = analog_in * (5.0 / 1024.0);
        if (v_in > 0) {
            look_at_voltage = analog_pin;
        }

        int voltage_to_check = -1;
        if (look_at_voltage == analog_pin) {
            voltage_to_check = v_in;
        } 
        if (voltage_to_check == 0 && led_on == true && !timeout_occurred) {
            timer2_total_ticks += TCNT2;
            TCNT1 = 0;
            PORTD &= ~(1 << sel);
            led_on = false;
            look_at_voltage = -1;
            double react_time = 0.000064 * timer2_total_ticks;
            double percent = react_time / TIMEOUT;
            score += (1 - percent);
            tft.setCursor(40, 20);
            tft.print("+");
            tft.print(1 - percent);
            tft.setCursor(40, 40);
            tft.print("SCORE");
            tft.fillRect(40, 60, 88, 128, ST7735_BLACK);
            tft.setCursor(40, 60);
            tft.print(score);
        }
    }
}

int main(void) {
    init();
    init_display();
    sei();
    my_setup();
    while (1) {
        my_loop();
    }
    return 0;
}
pm/prj2024/fstancu/cristian.musat2412.1716803059.txt.gz · Last modified: 2024/05/27 12:44 by cristian.musat2412
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0