/* // Function: Retro Handheld Tetris Game Console source code, including game GUI, // Tetris, Snake, Classic Racing, and Obstacle Shooting games. v1.0: 2014-7-26 00:00:00 : Completed the basic model for the Tetris game; 2014-7-28 02:12:03 : Changed the temporary delay-based keyboard scanning to external interrupt status detection; 2014-7-28 20:40:37 : Implemented Tetris scoring and score display functions; 2014-8-1 01:01:54 : Merged and integrated the previously completed Snake game code; 2014-8-2 17:04:25 : Organized temporary source code to standardize project files; 2014-8-3 23:50:49 : Built the basic model for the game selection screen and completed the screen transition effect; 2014-8-5 00:50:04 : Improved LED dot-matrix low-level driver, added software PWM to adjust screen brightness; 2014-8-7 00:53:35 : Completed the racing game; used PWM layered scanning for screen display to create contrast; 2014-8-8 02:16:44 : Completed the racing game preview screen and merged all three games; 2014-8-12 01:47:07 : Changed line-by-line scanning to point-by-point scanning for uniform display brightness; added brightness adjustment; 2014-9-9 00:32:40 : Modified and optimized several details; v1.1: 2014-9-18 0:57:23 : Re-laid out the circuit, corrected unreasonable design parts, and prepared for PCB production; 2014-9-19 22:02:36 : Added game sound effects with software-controlled mute switch; 2014-9-21 14:59:39 : Added three mini digital tubes to display the game score in real-time, sharing the parallel data port with the dot-matrix; ~~~~~~~~~~~ Note forgotten ~~~~~~~~~~~ 2014-10-20 21:30:15 : Added shooting game and modularized the GUI to simplify the workflow. */ #include "config.h" volatile uint8 data keypad = K_NULL; // Keypad status volatile uint8 data keycont = 0; // Keypad debounce timer volatile uint16 data tms = 0; // 1ms T0 timer bit key_state = 0; // Key state uint16 data speeds = 0; // Game speed uint16 data scores = 0; // Game score bit Glife = 1; // Game life status bit sound_ON = 1; // Sound effect switch uint8 data duty = 80; // PWM, default brightness uint8 data DispRAM[16]={0}; // Display RAM uint8 code bitman[8]={1,2,4,8,16,32,64,128}; // Bitmask for locating bits 0-7 uint8 code num[10][5]= // Yang code { {0x7,0x5,0x5,0x5,0x7}, {0x2,0x6,0x2,0x2,0x7}, {0x7,0x1,0x7,0x4,0x7}, {0x7,0x1,0x7,0x1,0x7}, {0x5,0x5,0x7,0x1,0x1}, {0x7,0x4,0x7,0x1,0x7}, {0x7,0x4,0x7,0x5,0x7}, {0x7,0x1,0x1,0x1,0x1}, {0x7,0x5,0x7,0x5,0x7}, {0x7,0x5,0x7,0x1,0x7} }; /*********************PORT_INIT********************/ void Port_Init() { P0M0 = 0Xff; P0M1 = 0X00; P1M0 = 0Xff; P1M1 = 0X00; P2M0 = 0Xff; P2M1 = 0X00; P3M0 = 0X00; P3M1 = 0X00; P4M0 = 0Xff; P4M1 = 0X00; P5M0 = 0Xff; P5M1 = 0X00; } void Init_Timer() { /****************** Timer 0 Interrupt Setup **********************/ AUXR |= 0x80; // Set Timer 0 to 1T mode TMOD = 0x00; // Set Timer 0 to Mode 0 (16-bit auto-reload) TL0 = T1MS; // Initialize timer value TH0 = T1MS >> 8; TR0 = 1; // Start Timer 0 ET0 = 1; // Enable Timer 0 interrupt /***************** External Interrupt Setup *************************/ IT0 = 1; // Set INT0 to falling edge trigger EX0 = 1; // Enable external interrupt INT0 IT1 = 1; // Set INT1 to falling edge trigger EX1 = 1; // Enable external interrupt INT1 INT_CLKO |= 0x70; // Enable INT2, INT3, INT4 (EX4 = 1, EX3 = 1, EX2 = 1) EA = 1; // Enable global interrupts } void Array_CLR(uint8 *p) { uint8 i=0; while(i!=16) { p[i] = 0x00; i++; } } void ShowScore(uint score) { uint8 i; uint8 qx,bx,sx,gx; qx = score /1000; bx = score %1000 /100; sx = score %100/10; gx = score %10; Array_CLR(DispRAM); for(i=0;i<5;i++) DispRAM[8-i] = (num[sx][i]<<4) | (num[gx][i]); for(i=0;i<5;i++) DispRAM[14-i] = (num[qx][i]<<5) | (num[bx][i]<<1); // MatxDisp(DispRAM,duty); } void main() { Port_Init(); Sound_Init(); Init_Timer(); Sound_Tone(1,14,5);// drop srand(TL0); delayms(100); Play_Music(sound_game_start); Flash_Screen_Clear(); while(1) { tms = 0; keypad = K_NULL;// Clear key status switch (GUI_Main()) // Enter the user game selection interface and return to the selected game. { case 1: Tetris_Game(); break; case 2: Snake_Game(); break; case 3: RAC_Game(); break; case 4: Shot_Game(); break; } Play_Music(sound_game_over); Flash_Screen_Clear(); ShowScore(scores); // Load the score into video memory delayms(300); keypad = K_NULL; while(keypad != K_UP) // Keep the score displayed when the OK button is not pressed. { MatxDisp(DispRAM,duty); SMG_Display(scores,duty); } } } /* Timer0 interrupt routine */ void T0_Timer_1ms_int() interrupt 1 using 1 { if(tms<0xfffe) tms++; // Prevent overflow if(key_state){ if(!--keycont) key_state=0;} if(PIN_TR2)// If TR2 is enabled, sound effects will begin playing. { if(!sound_cnt_time--) { TR2_OFF; beep = 1; if(music_p[s_p][1]) { Sound_Tone(sound_ON,music_p[s_p][0],music_p[s_p][1]); s_p++; // Automatically load the next note to achieve simultaneous sound effects and gameplay. } } } if(KEY_DOWN==0 & KEY_UP==0) IAP_CONTR=0x60;// Software reset download program } void T2_Timer_Sound_freq() interrupt 12 // Interrupt Entry { beep = ~beep; // Buzzer frequency vibration } uint8 Get_Kvuale(uint8 key_delay)// Key debouncing processing, parameter is sensitivity adjustment { uint8 kvuale = K_NULL; // The returned initial value is null. if(keypad != K_NULL) // When the key value is not NULL, it means that a key has been pressed. { if(!key_state) // When the button status bit (state) is 0, it indicates that the first trigger is valid; when it is 1, it indicates a repeated trigger. { key_state=1; // Set to 1 to prevent repeated triggering. kvuale = keypad;// Get Read Key Value keycont = key_delay;// Loading debouncing time } keypad = K_NULL; // Clear key value } return kvuale; } /********* External interrupt button area **********/ void exint0() interrupt 0 //INT0 { keypad = 0; } void exint1() interrupt 2 //INT1 { keypad = 1; } void exint2() interrupt 10 //INT2 { keypad = 2; } void exint3() interrupt 11 //INT3 { keypad = 3; } void exint4() interrupt 16 //INT4 { keypad = 4; }