Files
stc-gamebox/src/Main.c
Andrey Danyliuk 08904b4b75 uploaded files
2026-05-31 15:51:36 +02:00

222 lines
6.7 KiB
C

/*
// 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;
}