// ============================ // // Do not edit this part!!!! // // ============================ // // 0x300001 - CONFIG1H #pragma config OSC = HSPLL // Oscillator Selection bits (HS oscillator, // PLL enabled (Clock Frequency = 4 x FOSC1)) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit // (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover bit // (Oscillator Switchover mode disabled) // 0x300002 - CONFIG2L #pragma config PWRT = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out // Reset disabled in hardware and software) // 0x300003 - CONFIG1H #pragma config WDT = OFF // Watchdog Timer Enable bit // (WDT disabled (control is placed on the SWDTEN bit)) // 0x300004 - CONFIG3L // 0x300005 - CONFIG3H #pragma config LPT1OSC = OFF // Low-Power Timer1 Oscillator Enable bit // (Timer1 configured for higher power operation) #pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; // RE3 input pin disabled) // 0x300006 - CONFIG4L #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply // ICSP disabled) #pragma config XINST = OFF // Extended Instruction Set Enable bit // (Instruction set extension and Indexed // Addressing mode disabled (Legacy mode)) #pragma config DEBUG = OFF // Disable In-Circuit Debugger #define KHZ 1000UL #define MHZ (KHZ * KHZ) #define _XTAL_FREQ (40UL * MHZ) // ============================ // // End // // ============================ // #include #include #include #define T_PRELOAD_LOW 0x6A // BLINK 250MS #define T_PRELOAD_HIGH 0x67 // Add a structure for pieces struct current_piece { uint8_t horizontal_port; // 0.C, 1.D, 2.E, 3.F uint8_t vertical_port; // A binary number to represent the vertical port e.g 10000000 uint8_t type; // 0.dot, 1.square, 2.l_piece }; // ============================ // // Global variables // // ============================ // // Assign initial piece as a dot: struct current_piece current_piece = {2, 0b00010000, 0}; struct current_piece anti_piece = {0, 0b00000010, 0}; // Needed for interrupt on PORTB to work volatile uint8_t prevB; // Anti piece rotate state: // XX -> 0, OX -> 1, XO -> 2, XX -> 3 // OX XX XX XO // Represents the empty block position for the current piece if it is an l-piece: uint8_t rotate_state = 0; // Submitted lanes for pieces: uint8_t c_lane = 0b00000000; uint8_t d_lane = 0b00000000; uint8_t e_lane = 0b00000000; uint8_t f_lane = 0b00000000; // Flags for buttons: uint8_t right_button = 0; uint8_t up_button = 0; uint8_t down_button = 0; uint8_t left_button = 0; // Temp uint8_t x; uint8_t y; uint8_t z; uint8_t t; // ============================ // // Initialize the system // // ============================ // void init() { // 2.2 INPUTS // Port G is set as input: // RA0: Right // RA1: Up // RA2: Down // RA3: Left ADCON1 = 0b00001111; LATG = 0x00; PORTG = 0x00; TRISG = 0x0F; LATG = 0x00; PORTG = 0x00; // Port B is also set as input: // RB5: Rotate // RB6: Submit LATB = 0x00; PORTB = 0x00; TRISB = 0x60; // 2.3 OUTPUTS // C TO F FOR GAME AREA // C LATC = 0x00; PORTC = 0x00; TRISC = 0x00; // D LATD = 0x00; PORTD = 0x00; TRISD = 0x00; // E LATE = 0x00; PORTE = 0x00; TRISE = 0x00; // F LATF = 0x00; PORTF = 0x00; TRISF = 0x00; // H AND J ? S-10 // Initialize the 7-segment display ports TRISJ = 0x00; // Set PORTJ to output LATJ = 0x00; // Clear segments (assumes common cathode display) TRISH = 0x00; // Set PORTH to output LATH = 0x00; // Disable all 7-segment displays // Enable the first 7-segment display and set it to show '0' LATJ = 0x3F; // '0' on a common cathode 7-segment display } void initialize_timer_and_interrupts() { // Enable pre-scalar // Full pre-scale // we also need to do in-code scaling T0CON = 0x00; T0CONbits.TMR0ON = 1; T0CONbits.T0PS2 = 1; T0CONbits.T0PS1 = 0; T0CONbits.T0PS0 = 1; // Pre-load the value TMR0H = T_PRELOAD_HIGH; TMR0L = T_PRELOAD_LOW; RCONbits.IPEN = 0; INTCON = 0x00; INTCONbits.TMR0IE = 1; INTCONbits.RBIE = 1; INTCONbits.GIE = 1; INTCONbits.PEIE = 1; } // ============================ // // Piece related functions // // ============================ // void create_piece() { if (current_piece.type == 0) { // Last piece was a dot. // Create a square and assign it to alive_piece: current_piece.horizontal_port = 0; current_piece.vertical_port = 0b00000011; current_piece.type = 1; } else if (current_piece.type == 1) { // Last piece was a square. // Create an l-piece and assign it to alive_piece: current_piece.horizontal_port = 0; current_piece.vertical_port = 0b00000011; // Same as square, we already add anti_piece current_piece.type = 2; anti_piece.horizontal_port = 0; anti_piece.vertical_port = 0b00000010; anti_piece.type = 0; rotate_state = 0; } else if (current_piece.type == 2) { // Last piece was an l-piece. // Create a dot and assign it to alive_piece: current_piece.horizontal_port = 0; current_piece.vertical_port = 0b00000001; current_piece.type = 0; } } void submit_piece() { // TODO: Add square and l-piece cases switch (current_piece.horizontal_port) { case 0: if (!(c_lane & current_piece.vertical_port)) { c_lane = c_lane | current_piece.vertical_port; } break; case 1: if (!(d_lane & current_piece.vertical_port)) { d_lane = d_lane | current_piece.vertical_port; } break; case 2: if (!(e_lane & current_piece.vertical_port)) { e_lane = e_lane | current_piece.vertical_port; } break; case 3: if (!(f_lane & current_piece.vertical_port)) { f_lane = f_lane | current_piece.vertical_port; } break; default: break; } } // ============================ // // Interrupt related functions // // ============================ // __interrupt(high_priority) void handle_interrupt() { if (INTCONbits.RBIF) { // Read the value to satisfy the interrupt prevB = PORTB; // Submit current piece and create a new one submit_piece(); create_piece(); INTCONbits.RBIF = 0; } INTCONbits.GIE = 1; } // ============================ // // Button related functions // // ============================ // void move_current_piece_left() { if (current_piece.horizontal_port > 0) { current_piece.horizontal_port--; // Move the anti_piece as well, regardless of the type of the current piece anti_piece.horizontal_port--; } } void move_current_piece_right() { if (current_piece.type == 0) { if (current_piece.horizontal_port < 3) { current_piece.horizontal_port++; } } else { if (current_piece.horizontal_port < 2) { current_piece.horizontal_port++; anti_piece.horizontal_port++; } } } void move_current_piece_down() { if (current_piece.type == 0) { if (current_piece.vertical_port < 64) { // If 7th bit is not 1, then move down current_piece.vertical_port = current_piece.vertical_port << 1; } } else { // If 7th and 6th bits are not 1, then move down if (!(current_piece.vertical_port & 0b11000000)) { current_piece.vertical_port = current_piece.vertical_port << 1; anti_piece.vertical_port = anti_piece.vertical_port << 1; } } } void move_current_piece_up() { if (current_piece.type == 0) { if (current_piece.vertical_port > 1) { // If 0th bit is not 1, then move up current_piece.vertical_port = current_piece.vertical_port >> 1; } } else { // If 0th and 1st bits are not 1, then move up if (!(current_piece.vertical_port & 0b00000011)) { current_piece.vertical_port = current_piece.vertical_port >> 1; anti_piece.vertical_port = anti_piece.vertical_port >> 1; } } } // ============================ // // Polling functions // // ============================ // void right_button_task() { if (PORTGbits.RG0 == 1) { right_button = 1; } else { if (right_button == 1) { move_current_piece_right(); right_button = 0; } } } void up_button_task() { if (PORTGbits.RG1 == 1) { up_button = 1; } else { if (up_button == 1) { move_current_piece_up(); up_button = 0; } } } void down_button_task() { if (PORTGbits.RG2 == 1) { down_button = 1; } else { if (down_button == 1) { move_current_piece_down(); down_button = 0; } } } void left_button_task() { if (PORTGbits.RG3 == 1) { left_button = 1; } else { if (left_button == 1) { move_current_piece_left(); submit_piece(); left_button = 0; } } } // ============================ // // Rendering functions // // ============================ // void render() { if (current_piece.horizontal_port == 0) { LATC = c_lane | current_piece.vertical_port; if (current_piece.type != 0) { // Whether it is square or l-piece, we need to render right lane as well LATD = d_lane | current_piece.vertical_port; } if (current_piece.type == 2) { // XX -> 0, OX -> 1, XO -> 2, XX -> 3 // OX XX XX XO // Depending on anti_piece position, remove the anti_piece block by subtracting it from the lane switch (rotate_state) { case 0: LATC = LATC - anti_piece.vertical_port; break; case 1: LATC = LATC - anti_piece.vertical_port; break; case 2: LATD = LATD - anti_piece.vertical_port; break; case 3: LATD = LATD - anti_piece.vertical_port; break; default: break; } } } else if (current_piece.horizontal_port == 1) { LATD = d_lane | current_piece.vertical_port; if (current_piece.type != 0) { // Whether it is square or l-piece, we need to render right lane as well LATE = e_lane | current_piece.vertical_port; } if (current_piece.type == 2) { // XX -> 0, OX -> 1, XO -> 2, XX -> 3 // OX XX XX XO // Depending on anti_piece position, remove the anti_piece block by subtracting it from the lane switch (rotate_state) { case 0: LATD = LATD - anti_piece.vertical_port; break; case 1: LATD = LATD - anti_piece.vertical_port; break; case 2: LATE = LATE - anti_piece.vertical_port; break; case 3: LATE = LATE - anti_piece.vertical_port; break; default: break; } } } else if (current_piece.horizontal_port == 2) { LATE = e_lane | current_piece.vertical_port; if (current_piece.type != 0) { // Whether it is square or l-piece, we need to render right lane as well LATF = f_lane | current_piece.vertical_port; } if (current_piece.type == 2) { // XX -> 0, OX -> 1, XO -> 2, XX -> 3 // OX XX XX XO // Depending on anti_piece position, remove the anti_piece block by subtracting it from the lane switch (rotate_state) { case 0: LATE = LATE - anti_piece.vertical_port; break; case 1: LATE = LATE - anti_piece.vertical_port; break; case 2: LATF = LATF - anti_piece.vertical_port; break; case 3: LATF = LATF - anti_piece.vertical_port; break; default: break; } } } else if (current_piece.horizontal_port == 3) { LATF = f_lane | current_piece.vertical_port; } } // ============================ // // Main function // // ============================ // void main() { init(); initialize_timer_and_interrupts(); prevB = PORTB; __delay_ms(100); while (1) { left_button_task(); up_button_task(); down_button_task(); right_button_task(); render(); } }