the3
unknown
plain_text
3 years ago
18 kB
9
Indexable
/*
* 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;
}Editor is loading...