the3

mail@pastecode.io avatar
unknown
plain_text
a year ago
18 kB
2
Indexable
Never
/*
 * File:   main.c
 * Author: altug
 *
 * Created on May 23, 2023, 4:40 PM
 */

#include "the3.h"
#include "lcd.h"
#include <stdio.h>

#define teamA 0
#define teamB 1
#define ACTIVE_MODE 0
#define INACTIVE_MODE 1
//special char indexes
#define TEAM_A 0
#define TEAM_B 1
#define TEAM_A_SELECTED 2
#define TEAM_B_SELECTED 3
#define FRISBEE_REAL 4
#define FRISBEE_TARGET 5
#define TEAM_A_WITH_FRISBEE 6
#define TEAM_B_WITH_FRISBEE 7
#define SEGMENT_A   PORTDbits.RD0
#define SEGMENT_B   PORTDbits.RD1
#define SEGMENT_C   PORTDbits.RD2
#define SEGMENT_D   PORTDbits.RD3
#define SEGMENT_E   PORTDbits.RD4
#define SEGMENT_F   PORTDbits.RD5
#define SEGMENT_G   PORTDbits.RD6

// Common pins (for common cathode display)



typedef struct coordinate {
    byte x;
    byte y;
}coordinate;

typedef struct Player{
    byte id;
    byte selected_shape;
    byte default_shape;
    byte with_frisbee;
    byte shape;
    coordinate prev_coor;
    coordinate coor;
    byte team;
}Player;

typedef struct Frisbee{
    coordinate prev_coor;
    coordinate coor;
    byte shape;
}Frisbee;

typedef struct Game{
    
}Game;

byte checkOtherPlayers(coordinate new_coor);
byte edgeCheck(coordinate coor);
byte hasFrisbee(coordinate coor);
byte gameBegins();
void nextStep();
void drawToLCD(Player *player, Frisbee *frisbee);


unsigned short x;
unsigned short number_of_steps;
byte char_ind = 0;
byte selected_player = 0;
byte rb_flag = 0x00;
byte changes;
byte counter_timer = 0;
byte game_speed = 4;
byte blink_operation = 0;
byte game_mode = INACTIVE_MODE;
byte frisbee_index = 0;
byte teamA_points = 0;
byte teamB_points = 0;

Player players[4];
Frisbee targetFrisbee;
Frisbee realFrisbee;

byte isEqualCoor(coordinate a, coordinate b){
    return a.x == b.x && a.y == b.y;
}

void score_to_team(byte team){
    if(team == TEAM_A) teamA_points++;
    else if(team == TEAM_B) teamB_points++;
}

byte roundBegins(){
    game_mode = ACTIVE_MODE;
    frisbee_index = 0;
       // Turn on Timer0
    number_of_steps = compute_frisbee_target_and_route(realFrisbee.coor.x, realFrisbee.coor.y);
    targetFrisbee.coor.x = frisbee_steps[number_of_steps-1][0];
    targetFrisbee.coor.y = frisbee_steps[number_of_steps-1][1];
    TMR0 = 3500;
    T0CONbits.TMR0ON = 1;
    return game_speed;
    
}

byte edgeCheck(coordinate coor){
    return (coor.x > 0 && coor.x < 17 && coor.y > 0 && coor.y <5);
}
byte hasFrisbee(coordinate coor){
    return ((realFrisbee.coor.x == coor.x )&& (realFrisbee.coor.y == coor.y ) );
}

byte checkOtherPlayers(coordinate new_coor){
    for(byte i=0; i<4; i++){
        if(i != selected_player){
            Player* other_player = &players[i];
            if(new_coor.x == other_player->coor.x && new_coor.y == other_player->coor.y) return 0x00;
        }
    }
    return 0x01;
}



void move_rb(byte index,int dir_x, int dir_y){
    Player *player = &players[index];
    coordinate candidate_coor = player->coor;
    candidate_coor.x += dir_x;
    candidate_coor.y += dir_y;
    player->prev_coor = player->coor;
    if (edgeCheck(candidate_coor) ){
        if(checkOtherPlayers(candidate_coor)){
            if(hasFrisbee(candidate_coor)){
                player->shape = player->with_frisbee;
            }
            LCDGoto(player->coor.x, player->coor.y);
            LCDStr(" ");
            player->coor = candidate_coor;
            
        }
    }
    
    drawToLCD(player, NULL);
}

void move(byte index,int dir_x, int dir_y){
    Player *player = &players[index];
    coordinate candidate_coor = player->coor;
    candidate_coor.x += dir_x;
    candidate_coor.y += dir_y;
    player->prev_coor = player->coor;
    if (edgeCheck(candidate_coor) ){
        if(checkOtherPlayers(candidate_coor)){
            player->coor = candidate_coor;
            
        }
    }
}

void randomMoves(){
    for(int i=0; i<4; i++){
        Player* player = &players[i];
        if(player->id != selected_player)
        {
            unsigned short rnd_short = random_generator(9);
            switch(rnd_short){
                case 1:
                    break;
                case 2:
                    move(player->id,0,-1);
                    break;
                case 3:                   
                    move(player->id,1,-1);
                    break;
                case 4:
                    move(player->id, 1,0);
                    break;
                case 5:
                    move(player->id, 1,1);
                    break;
                case 6:
                    move(player->id, 0,1);
                    break;
                case 7:
                    move(player->id,-1,1);
                    break;
                case 8:
                    move(player->id,-1,0);
                    break;
            }
            
        }
    }
}

void roundEnd(){
    game_mode = INACTIVE_MODE;
    //LCDGoto(targetFrisbee.coor.x, targetFrisbee.coor.y);
    //LCDStr(" ");
    T0CONbits.TMR0ON = 0;   // Turn off Timer0 initially

}

void frisbeeMove(){
    byte should_erase = 1;
    byte is_catched = 0;
    coordinate old_coor = realFrisbee.coor;

    

    for(int i=0;  i<4; i++){
        Player* temp_player = &players[i];
        if(isEqualCoor(temp_player->coor, old_coor)){
            should_erase = 0;
            if(temp_player->id == selected_player){
                temp_player->shape = temp_player->selected_shape;
            }
            else{
                temp_player->shape = temp_player->default_shape;
            }
            //drawToLCD(temp_player, NULL);
        }
        if(isEqualCoor(temp_player->coor, realFrisbee.coor)){
            if(isEqualCoor(targetFrisbee.coor, realFrisbee.coor)){
                is_catched = 1;
            }
            temp_player->shape = temp_player->with_frisbee;      
        }
    }
    if(should_erase){
        LCDGoto(old_coor.x, old_coor.y);
        LCDStr(" ");
    }
    if(is_catched == 0){
        drawToLCD(NULL, &realFrisbee);
    }
    if(isEqualCoor(realFrisbee.coor, targetFrisbee.coor) || is_catched ){
        roundEnd();
    }

}

void winner(byte id){
    Player *player = &players[id];
    score_to_team(player->team);
}

void drawStep(){
    byte draw_frisbee = 1;
    signed char crossed_id = -1;
    byte target_reached = isEqualCoor(realFrisbee.coor, targetFrisbee.coor);
    Player *selected_p = &players[selected_player];
    if(isEqualCoor(selected_p->coor, realFrisbee.coor)){
        if(target_reached) crossed_id = selected_p->id;
        selected_p -> shape = selected_p->with_frisbee;
        draw_frisbee = 0;
    }
    if(isEqualCoor(selected_p->coor, realFrisbee.prev_coor)){
        selected_p -> shape = selected_p->selected_shape;
    }
    
    LCDGoto(realFrisbee.prev_coor.x, realFrisbee.prev_coor.y );
    LCDStr(" ");
    drawToLCD(selected_p, NULL);

    for(int i=0; i<4; i++){
        if(i != selected_player){
            Player *player = &players[i];
            if (isEqualCoor(player->prev_coor, player->coor) == 0){
                LCDGoto(player->prev_coor.x, player->prev_coor.y);
                LCDStr(" ");
            }
            drawToLCD(player, NULL);
            if(isEqualCoor(realFrisbee.coor, player->coor)){//random catches
                if( target_reached) 
                    crossed_id = player->id;
                draw_frisbee = 0;
            }
 
        }
    }
    
    if (target_reached){
        if(crossed_id == -1) 
            drawToLCD(NULL, &realFrisbee);
        else {
            if(selected_player == crossed_id){
                winner(crossed_id);
            }
            
        }
        roundEnd();
        
    }
    else if( draw_frisbee ) drawToLCD(NULL, &realFrisbee);
   
    
}
void updateData(){
    realFrisbee.prev_coor = realFrisbee.coor;
    realFrisbee.coor.x = frisbee_steps[frisbee_index][0];
    realFrisbee.coor.y = frisbee_steps[frisbee_index][1];
    frisbee_index++;
    randomMoves();
    drawStep();
}

void __interrupt() ISR()
{
    changes = PORTB;

   
    
    if (INTCONbits.TMR0IF)  // Check if Timer0 overflow interrupt flag is set
    {
        CONVERT = 1;
        //rb_flag = 0x00;
        // Your code to handle the Timer0 overflow interrupt
        TMR0 = 3500;
        if(game_mode == ACTIVE_MODE ) {
            if(blink_operation){
                drawToLCD(NULL, &targetFrisbee);
                blink_operation = 0;
            }
            else{
                LCDGoto(targetFrisbee.coor.x, targetFrisbee.coor.y);
                LCDStr(" ");
                blink_operation = 1;
            }
            //target coordinatlarinin lcdye yazilmasi
            if(++counter_timer == game_speed){
                updateData();
                counter_timer = 0;
        }
    }

        INTCONbits.TMR0IF = 0;
    }
    

    if (INTCONbits.RBIF) //portb<7:4>
    {      
        changes ^= 0xFF;
        if ((changes >>= 4) == 1){
            move_rb(selected_player,0,-1);
            
        }
        else if ((changes >>= 1) == 1){
            move_rb(selected_player,1,0);
           
        }
        else if ((changes >>= 1 )== 1){
            move_rb(selected_player,0,1);
        
        }
        else if ((changes >>= 1 )== 1){
            move_rb(selected_player,-1,0);
        }
        
        // Your code to handle the RB0 interrupt
        PORTA = PORTB;
        // Clear the RB0 interrupt flag
        INTCONbits.RBIF = 0;
        rb_flag++;
    }
    else if (INTCONbits.INT0IF){
        roundBegins();
        INTCONbits.INT0IF = 0;
    }
    else if (INTCON3bits.INT1F){
        if(PORTBbits.RB1 == 1){
        Player* p_player = &players[selected_player];
        if(p_player->shape == p_player->with_frisbee) return;
        if(hasFrisbee(p_player->coor))
            p_player->shape = p_player->with_frisbee;
        else p_player->shape = p_player->default_shape;
        selected_player = (++selected_player) % 4;
        Player *a_player = &players[selected_player];
        a_player->shape = a_player->selected_shape;
        drawToLCD(p_player, NULL);
        drawToLCD(a_player, NULL);
        }
        INTCON3bits.INT1F = 0;
    }
    
}

void initializePlayers(Player *players){
    players[0].id = 0;
    players[0].shape = TEAM_A_SELECTED;
    players[0].selected_shape = TEAM_A_SELECTED;
    players[0].default_shape = TEAM_A;
    players[0].with_frisbee = TEAM_A_WITH_FRISBEE;
    players[0].coor.x = 3;
    players[0].coor.y = 2;
    players[0].team = teamA;

    players[1].id = 1;
    players[1].shape = TEAM_A;
    players[1].selected_shape = TEAM_A_SELECTED;
    players[1].default_shape = TEAM_A;
    players[1].with_frisbee = TEAM_A_WITH_FRISBEE;
    players[1].coor.x = 3;
    players[1].coor.y = 3;
    players[1].team = teamA;

    players[2].id = 2;
    players[2].shape = TEAM_B;
    players[2].selected_shape = TEAM_B_SELECTED;
    players[2].default_shape = TEAM_B;
    players[2].with_frisbee = TEAM_B_WITH_FRISBEE;
    players[2].coor.x = 14;
    players[2].coor.y = 2;
    players[2].team = teamB;

    players[3].id = 3;
    players[3].shape = TEAM_B;
    players[3].selected_shape = TEAM_B_SELECTED;
    players[3].default_shape = TEAM_B;
    players[3].with_frisbee = TEAM_B_WITH_FRISBEE;
    players[3].coor.x = 14;
    players[3].coor.y = 3;
    players[3].team = teamB;
    return; 
}

void initializeFrisbee(Frisbee *real, Frisbee *target){
    real->coor.x = 9;
    real->coor.y = 2;
    real->shape = FRISBEE_REAL;
    
    target->coor.x = 1;
    target->coor.y = 1;
    target->shape = FRISBEE_TARGET;
    
}

void initSpecialCharacters(){
    LCDAddSpecialCharacter(TEAM_A, &teamA_player);
    LCDAddSpecialCharacter(TEAM_B, &teamB_player);
    LCDAddSpecialCharacter(TEAM_A_SELECTED, &selected_teamA_player);
    LCDAddSpecialCharacter(TEAM_B_SELECTED, &selected_teamB_player);
    LCDAddSpecialCharacter(FRISBEE_REAL, &frisbee);
    LCDAddSpecialCharacter(FRISBEE_TARGET, &frisbee_target);
    LCDAddSpecialCharacter(TEAM_A_WITH_FRISBEE, &selected_teamA_player_with_frisbee);
    LCDAddSpecialCharacter(TEAM_B_WITH_FRISBEE, &selected_teamB_player_with_frisbee);
    
}

// either draws player or frisbee to lcd
void drawToLCD(Player *player, Frisbee *frisbee){
   
   
    if( player ){
        LCDGoto(player->coor.x,player->coor.y);
        LCDDat(player->shape);
        
    }
    else if (frisbee){
        LCDGoto(frisbee->coor.x, frisbee->coor.y);
        LCDDat(frisbee->shape);
    }
    return;

     
}

void InitInterrupts(){

    byte x = PORTB;
    PORTB = 0xFF;
    TRISB = 0xFF;
    INTCONbits.GIE = 1;
    INTCONbits.PEIE = 1;
    //PORTB <7:4>
    ADCON1 = 0x0F;
    x = PORTB;
    INTCONbits.RBIF = 0; //clear flag
    PORTB = 0x00;
    INTCONbits.RBIE = 1; //enable
    //RB0
    INTCONbits.INT0IF = 0; //clear flag
    INTCONbits.INT0E = 1; //enable
    INTCON2bits.INTEDG0 = 1; //rising edge
    INTCON2bits.RBPU = 1;
    //RB1
    INTCON3bits.INT1F = 0; //clear flag
    INTCON3bits.INT1E = 1; //enable
    INTCON2bits.INTEDG1 = 0; //rising edge
    
    T0CONbits.TMR0ON = 0;   // Turn off Timer0 initially
    T0CONbits.T08BIT = 0;   // Configure Timer0 as a 16-bit timer
    T0CONbits.T0CS = 0;     // Select internal instruction cycle clock (Fosc/4) as the clock source
    T0CONbits.PSA = 0;      // Assign prescaler to Timer0
    T0CONbits.T0PS2 = 0;    // Set the prescaler value to 1:64
    T0CONbits.T0PS1 = 1;
    T0CONbits.T0PS0 = 1;
    
    TMR1ON = 1;                 // Enable Timer1
    T1CONbits.TMR1CS = 0;       // Internal clock (Fosc/4)
    T1CONbits.T1CKPS = 0b00;    // 1:8 prescaler
    T1CONbits.RD16 = 1;
    TMR1 = 0x00;               // Clear Timer1 high byte
                   // Clear Timer1 low byte
    

    // Calculate the Timer0 initial value based on desired time period
    // For a 400ms interrupt with a 1:64 prescaler and 10 MHz clock frequency, the initial value is:
    TMR0 = 6800;

    // Enable Timer0 overflow interrupt
    INTCONbits.TMR0IE = 1;  // Enable Timer0 overflow interrupt

    // Configure and enable global interrupts

    // Start Timer0
    
            ADCON1bits.PCFG3 = 1; // RA0 = Analog, RA1=1 Analog, RA2 = Analog
        ADCON1bits.PCFG2 = 1;
        ADCON1bits.PCFG1 = 0;
        ADCON1bits.PCFG0 = 0;
        
        ADCON1bits.VCFG0 = 0; // Vref+=5.0, Vref=0
        ADCON1bits.VCFG1 = 0;
        
        TRISAbits.RA0 = 1;
        TRISAbits.RA1 = 1;
        TRISAbits.RA2 = 0;
        
        // For 40MHZ -> Tosc = 1/40 us
        // Tad options (2xTosc, 4xTosc, 8xTosc, 16xTosc, 32xTosc, 64xTosc)
        // min Tad 0.7 us - max Tad 25 us (Keep as short as possible)
        // The closest one to min Tad (32xTosc) hence Tad = 32xTosc = 0.8 us (ADCS2:ADCS0=010)
        // Acquisition time options (0xTad, 2xTad, 4xTad, 6xTad, 8xTad, 12xTad, 16xTad, 20xTad)
        // Min acquisition time = 2.4 us (the closest acquisition time we can set 4xTad = 3.2us) (ACQT2:ACQT0=010)
        
        ADCON2bits.ADCS2 = 0; // Tad (32xTOSC) -> 0.8us
        ADCON2bits.ADCS1 = 1;
        ADCON2bits.ADCS0 = 0;
        
        ADCON2bits.ACQT2 = 0; // Acquisition time (4xTad) = 3.2 us
        ADCON2bits.ACQT1 = 1;
        ADCON2bits.ACQT0 = 0;
        
        ADCON2bits.ADFM = 1; // Right justified...
                
        ADCON0bits.ADON = 1; // ADC module is enabled....

    
    
}

unsigned short readADCChannel(unsigned char channel)
    {
        // 0b 0101 -> 5th chanel 
        ADCON0bits.CHS0 =  channel & 0x1; // Select channel..
        ADCON0bits.CHS1 = (channel >> 1) & 0x1;
        ADCON0bits.CHS2 = (channel >> 2) & 0x1;
        ADCON0bits.CHS3 = (channel >> 3) & 0x1;
        
        
        
        ADCON0bits.GODONE = 1; //Start convertion
        while(ADCON0bits.GODONE == 1); //Wait the conversion to finish
        
        
        
        PIR1bits.ADIF = 0; // Clear interrupt flag...

        return (unsigned short)((ADRESH << 8)+ADRESL);
}

unsigned short setGameSpeed(unsigned short adcVal){
    if (adcVal > 0 && adcVal < 256){
        return 4;
    }
    if (adcVal > 255 && adcVal < 512){
        return 8;
    }
    if (adcVal > 511 && adcVal < 768){
        return 12;
    }
    if (adcVal > 767 && adcVal < 1024){
        return 16;
    }
}
/*
void displayDigit(unsigned char digit, unsigned char display)
{
       // Segment patterns for each digit (common cathode)
    const unsigned char digitPatterns[10] = {
        0b00111111, // 0
        0b00000110, // 1
        0b01011011, // 2
        0b01001111, // 3
        0b01100110, // 4
        0b01101101, // 5
        0b01111101, // 6
        0b00000111, // 7
        0b01111111, // 8
        0b01101111  // 9
    };

    // Activate the corresponding segments for the given digit
    SEGMENT_A = (digitPatterns[digit] & 0x01);
    SEGMENT_B = (digitPatterns[digit] & 0x02) >> 1;
    SEGMENT_C = (digitPatterns[digit] & 0x04) >> 2;
    SEGMENT_D = (digitPatterns[digit] & 0x08) >> 3;
    SEGMENT_E = (digitPatterns[digit] & 0x10) >> 4;
    SEGMENT_F = (digitPatterns[digit] & 0x20) >> 5;
    SEGMENT_G = (digitPatterns[digit] & 0x40) >> 6;
    
    // Activate the selected display
    DIGIT_1 = (display == 1) ? 1 : 0;
    DIGIT_2 = (display == 2) ? 1 : 0;
    DIGIT_3 = (display == 3) ? 1 : 0;
    DIGIT_4 = (display == 4) ? 1 : 0;
}*/

void main(void) {
    TRISD = 0x00;

    initializePlayers(players);
    initializeFrisbee(&realFrisbee, &targetFrisbee);
    InitLCD();
    InitInterrupts();
    initSpecialCharacters();

    drawToLCD(&players[0], NULL );
    drawToLCD(&players[1], NULL );
    drawToLCD(&players[2], NULL );
    drawToLCD(&players[3], NULL );
    drawToLCD(NULL, &realFrisbee );
    char values[10] = {0};
    
    unsigned short convertion = 0;
    const unsigned char digitPatterns[10] = {
        0b00111111, // 0
        0b00000110, // 1
        0b01011011, // 2
        0b01001111, // 3
        0b01100110, // 4
        0b01101101, // 5
        0b01111101, // 6
        0b00000111, // 7
        0b01111111, // 8
        0b01101111  // 9
    };
    while (1){
        if(CONVERT == 1)
        {
            convertion = readADCChannel(0);
            game_speed = setGameSpeed(convertion);
                   
            CONVERT = 0;
        }        
        
        PORTBbits.RB0 = 1;
        PORTBbits.RB1 = 0;
        PORTBbits.RB2 = 1;
        PORTBbits.RB3 = 1;
        
        PORTD = 0x66;
        __delay_ms(1000);  //add delay of one second

     
    }
    
   
    return;
}