Untitled

mail@pastecode.io avatar
unknown
plain_text
2 years ago
9.3 kB
0
Indexable
Never
#ifndef F_CPU
#define F_CPU 16000000UL // Set 16 MHz clock speed
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <Arduino.h>

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE ((((F_CPU / 16) + (USART_BAUDRATE / 2)) / (USART_BAUDRATE)) - 1)
#define N 8
#define MAX_SHOT 16
#define MAX_SHIP 5

// struct Ship {
//     int row;
//     int col;
//     int drow;
//     int dcol;

//     void setup(int row, int col, int drow, int dcol) {
//         this->row = row;
//         this->col = col;
//         this->drow = drow;
//         this->dcol = dcol;
//     }
// };

struct Button
{
    char c;
    int p;
    unsigned int state = 0;

    void setup(char c, int p)
    {
        this->c = c;
        this->p = p;
        state = 0;
    }

    bool debounce()
    {
        switch (c)
        {
        case 'c':
            state = (state << 1) | (!(PINC & (1 << p))) | 0xfe00;
            break;
        default:
            break;
        }

        return (state == 0xff00);
    }
};

void setupGame();

void setupPort();
void setupTimer();
void setupInterrupt();
void setupButton();
void setupUart();

int isGameFinish();

void turnOnSevenSegment();

void updateCoordinate(int sign);
void toggleXYMode();
void updateShipSunkedCount();
void replayGame();

int makeCoordinateInBound(int x);
int inMap(int row, int col);

int controlLedB[] = {0b000000, 0b111001, 0b100100, 0b110000, 0b011001, 0b010010, 0b000010, 0b111000, 0b000000, 0b010000, 0b111111};
int controlLedC[] = {1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1};
volatile int dRow[] = {0, 1};
volatile int dCol[] = {1, 0};

volatile int ledPointer = 0;
volatile int blinkLed = 0;
volatile int blinkLedCounter = 0;
volatile int softwareCounter = 0;
volatile int isSevenSegmentOn = 1;
volatile int isBtnShotActive = 1;

volatile int xCor = 1;
volatile int yCor = 1;
volatile int xyMode = 1;

volatile int gameMap[N][N] = {{1, 0, 1, 0, 0, 0, 0, 0},
                              {1, 0, 1, 0, 0, 0, 0, 0},
                              {0, 0, 0, 0, 0, 0, 0, 0},
                              {1, 0, 1, 0, 0, 0, 0, 0},
                              {1, 0, 1, 0, 0, 0, 0, 0},
                              {0, 0, 0, 0, 0, 0, 0, 0},
                              {1, 0, 0, 0, 0, 0, 0, 0},
                              {1, 0, 0, 0, 0, 0, 0, 0}};
// volatile int gameMap[N][N];
volatile int shotMap[N][N];
volatile int receivedByteCount = 0;
volatile int shipSunkedCount = 0;
volatile int hitCount = 0;
volatile int shotCount = 0;

Button btnUp;
Button btnDown;
Button btnXY;
Button btnReplay;

int main(void)
{

    // Setup software
    setupGame();

    // Setup all hardware
    setupPort();
    setupTimer();
    setupButton();
    setupUart();
    setupInterrupt();

    while (1)
    {
        if (TIFR1 & (1 << OCF1A))
        {
            isBtnShotActive = 1;
        }

        if (btnUp.debounce())
        {
            // Move up
            updateCoordinate(1);
            continue;
        }

        if (btnDown.debounce())
        {
            // Move down
            updateCoordinate(-1);
            continue;
        }

        if (btnXY.debounce())
        {
            // Toggle xy
            toggleXYMode();
            continue;
        }

        if (btnReplay.debounce())
        {
            setupGame();
            continue;
        }
    }
}

void setupGame()
{
    // Reset the data of the game
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            shotMap[i][j] = 0;
        }
    }

    receivedByteCount = shipSunkedCount = hitCount = shotCount = 0;
}

void setupPort()
{
    // Port for 7-segment LED and button
    DDRB = 0x3F;
    DDRC = 0x21;

    // Port for external interrupt button
    DDRD &= ~(1 << 2);
    DDRD |= (1 << 1);

    for (int i = 3; i <= 7; i++)
    {
        DDRD |= (1 << i);
    }
}

void setupTimer()
{

    // Timer 0 for control 7 segment
    TCCR0A |= (1 << WGM01);
    TCCR0B |= ((1 << CS01) | (1 << CS00));
    OCR0A = 255;

    // Timer 1 for stoping
    TCCR1B |= (1 << WGM12);
    TCCR1B |= (1 << CS12);
    OCR1A = 31249;
}

void setupInterrupt()
{
    // Interrupt for timer 1
    TIMSK0 |= (1 << OCIE0A);

    // Interrupt for rx
    UCSR0B |= (1 << RXCIE0);

    // Interrupt for button
    EICRA |= (1 << ISC01);
    EIMSK |= (1 << INT0);

    sei();
}

void setupButton()
{
    // Setup the button variable for implement the debounce functionality
    btnUp.setup('c', 1);
    btnDown.setup('c', 2);
    btnXY.setup('c', 3);
    btnReplay.setup('c', 4);
}

void setupUart()
{
    UBRR0H = (BAUD_PRESCALE >> 8);
    UBRR0L = (BAUD_PRESCALE);
    UCSR0C = ((1 << UCSZ00) | (1 << UCSZ01));
    UCSR0B |= ((1 << RXEN0) | (1 << TXEN0));
}

int isGameFinish()
{
    return shipSunkedCount >= MAX_SHIP || shotCount >= MAX_SHOT;
}

void turnOnSevenSegment() {
    // Turn on the port to display exactly 1 digit
    PORTD |= (1 << (ledPointer + 3));

    switch (ledPointer)
    {
    case 0:
        // Display the no of ships sunk
        PORTB = controlLedB[shotCount % 10];
        PORTC = controlLedC[shotCount % 10];
        break;
    case 1:
        // Display the no of hits
        PORTB = controlLedB[shotCount / 10];
        PORTC = controlLedC[shotCount / 10];
        break;
    case 2:
        // Display the no of shots (digit 1)
        PORTB = controlLedB[hitCount];
        PORTC = controlLedC[hitCount];
        break;
    case 3:
        // Display the no of shots (digit 0)
        PORTB = controlLedB[shipSunkedCount];
        PORTC = controlLedC[shipSunkedCount];
        break;
    case 4:
        // Display xy coordinate
        PORTB = controlLedB[(!xyMode) ? xCor : yCor];
        PORTC = controlLedC[(!xyMode) ? xCor : yCor];
        break;
    default:
        // Reset to turn off
        PORTB = controlLedB[0];
        PORTC = controlLedC[0];
    }

    // Move to the next digit
    ledPointer = (ledPointer + 1) % 5;
}

void updateCoordinate(int sign)
{
    if (isGameFinish())
    {
        return;
    }

    // Update xy
    xCor += (!xyMode) ? sign : 0;
    yCor += (xyMode) ? sign : 0;

    // Avoid the coordiate move out the range 1 - 8
    xCor = makeCoordinateInBound(xCor);
    yCor = makeCoordinateInBound(yCor);
}

void toggleXYMode()
{
    if (isGameFinish())
    {
        return;
    }

    xyMode = 1 - xyMode;
}

void updateShipSunkedCount()
{
    shipSunkedCount = 0;

    for (int row = 0; row < N; row++)
    {
        for (int col = 0; col < N; col++)
        {
            for (int i = 0; i < 2; i++)
            {
                int nextRow = row + dRow[i], nextCol = col + dCol[i];

                if (shotMap[row][col] && shotMap[nextRow][nextCol])
                {
                    shipSunkedCount++;
                }
            }
        }
    }
}

void replayGame() 
{

}

int makeCoordinateInBound(int x)
{
    x = (x > 8) ? 1 : x;
    x = (x < 1) ? 8 : x;
    return x;
}

int inMap(int row, int col)
{
    return row >= 0 && row < N && col >= 0 && col < N;
}

ISR(TIMER0_COMPA_vect)
{

    if (isGameFinish())
    {
        // When the game is finished
        for (int i = 3; i <= 7; i++)
        {
            PORTD &= ~(1 << i);
        }

        if (isSevenSegmentOn) {
            turnOnSevenSegment();
        }

        softwareCounter++;

        if (softwareCounter == 800) {
            isSevenSegmentOn = 1 - isSevenSegmentOn;
            softwareCounter = 0;
        }        

        return;
    }

    // Turn off the port for display digit
    for (int i = 3; i <= 7; i++)
    {
        PORTD &= ~(1 << i);
    }

    turnOnSevenSegment();
}

// ISR(USART_RX_vect)
// {
//     char receivedByte;
//     receivedByte = UDR0;

//     if (receivedByte == '0' || receivedByte == '1')
//     {
//         int row = receivedByteCount / N, col = receivedByteCount % N;
//         gameMap[row][col] = receivedByte - '0';
//         receivedByteCount = (receivedByteCount + 1) % (N * N);
//     }
// }

ISR(INT0_vect)
{
    sei();

    if (!isBtnShotActive)
    {
        return;
    }

    if (isGameFinish())
    {
        return;
    }

    
    TIFR1 |= (1 << OCF1A);
    isBtnShotActive = 0;

    // The target shot
    volatile int row = yCor - 1, col = xCor - 1;
    xCor = yCor = xyMode = 1;

    // Increase shot count
    shotCount++;

    // Do nothing if the cell is already shot or it has no ship
    if (shotMap[row][col] || !gameMap[row][col])
    {
        return;
    }

    // Increase the hitted shot
    hitCount++;
    shotMap[row][col] = 1;
    updateShipSunkedCount();


    for (int j = 0; j < 3; j++)
    {
        Serial.println("Turn");
        // PORTC |= (1 << 5);
        // _delay_ms(1000);
        // PORTC &= ~(1 << 5);
        // _delay_ms(1000);

        PORTD |= (1 << 1);
        _delay_ms(1000);
        PORTD &= ~(1 << 1);
        _delay_ms(1000);        
    }
}