commit 08904b4b75860820a1ed73c6317464b50a7f4dc8 Author: Andrey Danyliuk Date: Sun May 31 15:51:36 2026 +0200 uploaded files diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9783d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +# User-specific uVision files +*.opt +*.uvopt +*.uvoptx +*.uvgui +*.uvgui.* +*.uvguix.* + +# Listing files +*.cod +*.htm +*.i +*.lst +*.map +*.m51 +*.m66 +# define exception below if needed +*.scr + +# Object and HEX files +*.axf +*.b[0-3][0-9] +*.hex +*.d +*.crf +*.elf +*.hex +*.h86 +*.lib +*.obj +*.o +*.sbr + +# Build files +# define exception below if needed +*.bat +*._ia +*.__i +*._ii + +# Generated output files +/output/ + +# Debugger files +# define exception below if needed +*.ini + +# Other files +*.build_log.htm +*.cdb +*.dep +*.ic +*.lin +*.lnp +*.orc +# define exception below if needed +*.pack +# define exception below if needed +*.pdsc +*.plg +# define exception below if needed +*.sct +*.sfd +*.sfr + +# Miscellaneous +*.tra +*.bin +*.fed +*.l1p +*.l2p +*.iex + +# backups +*.bak diff --git a/Gamebox.uvproj b/Gamebox.uvproj new file mode 100644 index 0000000..090c5c4 --- /dev/null +++ b/Gamebox.uvproj @@ -0,0 +1,440 @@ + + + + 1.1 + +
### uVision Project, (C) Keil Software
+ + + + Target 1 + 0x0 + MCS-51 + 8 + + + STC15F2K60S2 + STC + IRAM(0-0xFF) XRAM(0-0x6FF) IROM(0-0xEFF8) CLOCK(35000000) MODP2 + + "LIB\STARTUP.A51" ("Standard 8051 Startup Code") + + 62472 + STC15F2K60S2.H + + + + + + + + + + + 0 + 0 + C:\Program Files\SDCC\BIN\ + + + + STC\ + + 0 + 0 + 0 + 0 + 1 + + .\output\ + Gamebox + 1 + 0 + 1 + 1 + 1 + .\output\ + 0 + 0 + 0 + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 0 + 0 + + + 0 + 0 + 0 + 0 + + 0 + + + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + + + 1 + 65535 + + + S8051.DLL + + DP51.DLL + -pDP8051 + S8051.DLL + + TP51.DLL + -p51 + + + + 0 + 0 + 0 + 0 + 16 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + + + 0 + 1 + 0 + 1 + 1 + 1 + 0 + 1 + 0 + 1 + + 0 + -1 + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + 0 + 0 + -1 + + 0 + + "" () + + + + + 0 + + + + 2 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0x0 + 0xffff + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 1 + 0x0 + 0xeff9 + + + 0 + 0x0 + 0x100 + + + 0 + 0x0 + 0x700 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + + + 0 + 0 + 1 + 0 + 1 + 3 + 8 + 2 + 1 + 1 + 0 + 0 + + + + + + + + + 0 + 1 + 0 + 0 + + + + + + + + + 0 + 0 + 1 + 0 + 2 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Source Group 1 + + + STARTUP.A51 + 2 + .\STARTUP.A51 + + + Delay.c + 1 + .\src\Delay.c + + + Display_Drives.c + 1 + .\src\Display_Drives.c + + + GUI.c + 1 + .\src\GUI.c + + + Main.c + 1 + .\src\Main.c + + + RAC.c + 1 + .\src\RAC.c + + + Shot.c + 1 + .\src\Shot.c + + + snake.c + 1 + .\src\snake.c + + + Sound_Drives.c + 1 + .\src\Sound_Drives.c + + + Tetris.c + 1 + .\src\Tetris.c + + + Sound_date.c + 1 + .\src\Sound_date.c + + + + + + + +
diff --git a/PCB_BOM.CSV b/PCB_BOM.CSV new file mode 100644 index 0000000..fce33e7 --- /dev/null +++ b/PCB_BOM.CSV @@ -0,0 +1,18 @@ +"Bill of Material for GameBox_PCB.PrjPcb" +"On 2014/10/27 at 13:57:28" + +"Comment","Pattern","Quantity","Components" + +"104","0805","1","C1","" +"1K","0805","1","R2","" +"330","0805","1","R3","" +"BEEP","BEEP","1","BEEP1","" +"BUTTON","BTN8.5*8.5","1","KP1","" +"Cap2","RB.1/.2","1","C2","Capacitor" +"IAP15F2K60S2_QFP44","LQFP44","1","U1","" +"KEY_M","KEY_M","5","K_DOWN, K_LEFT, K_RIGHT, K_UP, OK","" +"LED-8X8","LED8*8-3.0mm","2","DD1, DD2","" +"RTX1","HDR1X4","1","P1","Header, 4-Pin" +"S8550","SOT-23R","1","Q1","8550/BCW68" +"SMG_3W_0.25","SMG_3W_0.25","1","SEG","" +"USB","Micro_USB","1","USB_1","" diff --git a/STARTUP.A51 b/STARTUP.A51 new file mode 100644 index 0000000..ec99b9e --- /dev/null +++ b/STARTUP.A51 @@ -0,0 +1,198 @@ +$NOMOD51 +;------------------------------------------------------------------------------ +; This file is part of the C51 Compiler package +; Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc. +; Version 8.01 +; +; *** <<< Use Configuration Wizard in Context Menu >>> *** +;------------------------------------------------------------------------------ +; STARTUP.A51: This code is executed after processor reset. +; +; To translate this file use A51 with the following invocation: +; +; A51 STARTUP.A51 +; +; To link the modified STARTUP.OBJ file to your application use the following +; Lx51 invocation: +; +; Lx51 your object file list, STARTUP.OBJ controls +; +;------------------------------------------------------------------------------ +; +; User-defined Power-On Initialization of Memory +; +; With the following EQU statements the initialization of memory +; at processor reset can be defined: +; +; IDATALEN: IDATA memory size <0x0-0x100> +; Note: The absolute start-address of IDATA memory is always 0 +; The IDATA space overlaps physically the DATA and BIT areas. +IDATALEN EQU 80H +; +; XDATASTART: XDATA memory start address <0x0-0xFFFF> +; The absolute start address of XDATA memory +XDATASTART EQU 0 +; +; XDATALEN: XDATA memory size <0x0-0xFFFF> +; The length of XDATA memory in bytes. +XDATALEN EQU 0 +; +; PDATASTART: PDATA memory start address <0x0-0xFFFF> +; The absolute start address of PDATA memory +PDATASTART EQU 0H +; +; PDATALEN: PDATA memory size <0x0-0xFF> +; The length of PDATA memory in bytes. +PDATALEN EQU 0H +; +; +;------------------------------------------------------------------------------ +; +; Reentrant Stack Initialization +; +; The following EQU statements define the stack pointer for reentrant +; functions and initialized it: +; +; Stack Space for reentrant functions in the SMALL model. +; IBPSTACK: Enable SMALL model reentrant stack +; Stack space for reentrant functions in the SMALL model. +IBPSTACK EQU 0 ; set to 1 if small reentrant is used. +; IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF> +; Set the top of the stack to the highest location. +IBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1 +; +; +; Stack Space for reentrant functions in the LARGE model. +; XBPSTACK: Enable LARGE model reentrant stack +; Stack space for reentrant functions in the LARGE model. +XBPSTACK EQU 0 ; set to 1 if large reentrant is used. +; XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF> +; Set the top of the stack to the highest location. +XBPSTACKTOP EQU 0xFFFF +1 ; default 0FFFFH+1 +; +; +; Stack Space for reentrant functions in the COMPACT model. +; PBPSTACK: Enable COMPACT model reentrant stack +; Stack space for reentrant functions in the COMPACT model. +PBPSTACK EQU 0 ; set to 1 if compact reentrant is used. +; +; PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF> +; Set the top of the stack to the highest location. +PBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1 +; +; +;------------------------------------------------------------------------------ +; +; Memory Page for Using the Compact Model with 64 KByte xdata RAM +; Compact Model Page Definition +; +; Define the XDATA page used for PDATA variables. +; PPAGE must conform with the PPAGE set in the linker invocation. +; +; Enable pdata memory page initalization +PPAGEENABLE EQU 0 ; set to 1 if pdata object are used. +; +; PPAGE number <0x0-0xFF> +; uppermost 256-byte address of the page used for PDATA variables. +PPAGE EQU 0 +; +; SFR address which supplies uppermost address byte <0x0-0xFF> +; most 8051 variants use P2 as uppermost address byte +PPAGE_SFR DATA 0A0H +; +; +;------------------------------------------------------------------------------ + +; Standard SFR Symbols +ACC DATA 0E0H +B DATA 0F0H +SP DATA 81H +DPL DATA 82H +DPH DATA 83H + + NAME ?C_STARTUP + + +?C_C51STARTUP SEGMENT CODE +?STACK SEGMENT IDATA + + RSEG ?STACK + DS 1 + + EXTRN CODE (?C_START) + PUBLIC ?C_STARTUP + + CSEG AT 0 +?C_STARTUP: LJMP STARTUP1 + + RSEG ?C_C51STARTUP + +STARTUP1: + +IF IDATALEN <> 0 + MOV R0,#IDATALEN - 1 + CLR A +IDATALOOP: MOV @R0,A + DJNZ R0,IDATALOOP +ENDIF + +IF XDATALEN <> 0 + MOV DPTR,#XDATASTART + MOV R7,#LOW (XDATALEN) + IF (LOW (XDATALEN)) <> 0 + MOV R6,#(HIGH (XDATALEN)) +1 + ELSE + MOV R6,#HIGH (XDATALEN) + ENDIF + CLR A +XDATALOOP: MOVX @DPTR,A + INC DPTR + DJNZ R7,XDATALOOP + DJNZ R6,XDATALOOP +ENDIF + +IF PPAGEENABLE <> 0 + MOV PPAGE_SFR,#PPAGE +ENDIF + +IF PDATALEN <> 0 + MOV R0,#LOW (PDATASTART) + MOV R7,#LOW (PDATALEN) + CLR A +PDATALOOP: MOVX @R0,A + INC R0 + DJNZ R7,PDATALOOP +ENDIF + +IF IBPSTACK <> 0 +EXTRN DATA (?C_IBP) + + MOV ?C_IBP,#LOW IBPSTACKTOP +ENDIF + +IF XBPSTACK <> 0 +EXTRN DATA (?C_XBP) + + MOV ?C_XBP,#HIGH XBPSTACKTOP + MOV ?C_XBP+1,#LOW XBPSTACKTOP +ENDIF + +IF PBPSTACK <> 0 +EXTRN DATA (?C_PBP) + MOV ?C_PBP,#LOW PBPSTACKTOP +ENDIF + + MOV SP,#?STACK-1 + +; This code is required if you use L51_BANK.A51 with Banking Mode 4 +; Code Banking +; Select Bank 0 for L51_BANK.A51 Mode 4 +#if 0 +; Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4. +EXTRN CODE (?B_SWITCH0) + CALL ?B_SWITCH0 ; init bank mechanism to code bank 0 +#endif +; + LJMP ?C_START + + END diff --git a/src/Delay.c b/src/Delay.c new file mode 100644 index 0000000..9b81764 --- /dev/null +++ b/src/Delay.c @@ -0,0 +1,33 @@ +#include "config.h" + +static void Delay1us() //@33.000MHz +{ + unsigned char i; + + _nop_(); + _nop_(); + _nop_(); + i = 5; + while (--i); +} +static void Delay1ms() //@33.000MHz +{ + unsigned char i, j; + + i = 33; + j = 22; + do + { + while (--j); + } while (--i); +} + +void delayus(unsigned int n) +{ + while(n--) Delay1us(); +} + +void delayms(unsigned int n) +{ + while(n--) Delay1ms(); +} \ No newline at end of file diff --git a/src/Delay.h b/src/Delay.h new file mode 100644 index 0000000..e5c9f59 --- /dev/null +++ b/src/Delay.h @@ -0,0 +1,7 @@ +#ifndef __DELAY_H_ +#define __DELAY_H_ + +extern void delayus(unsigned int n); //@33.000MHz +extern void delayms(unsigned int n); //@33.000MHz + +#endif \ No newline at end of file diff --git a/src/Display_Drives.c b/src/Display_Drives.c new file mode 100644 index 0000000..91a506c --- /dev/null +++ b/src/Display_Drives.c @@ -0,0 +1,154 @@ +#include "config.h" + + +#define A 0 +#define B 1 +#define ON 1 // common yin +void Data_CLR(bit ab) // Due to hardware limitations, the dot matrix display uses a common anode, while the digital tube uses a common cathode, hence the parameter requirement. +{ + LED_D0 = ab;LED_D1 = ab;LED_D2 = ab;LED_D3 = ab; + LED_D4 = ab;LED_D5 = ab;LED_D6 = ab;LED_D7 = ab; +} + +void ROW_data(uint8 rdata)// Row selection module +{ + switch (rdata) + { + case 0 :LED_R16 = 0; LED_R1 = 1; break; + case 1 :LED_R1 = 0; LED_R2 = 1; break; + case 2 :LED_R2 = 0; LED_R3 = 1; break; + case 3 :LED_R3 = 0; LED_R4 = 1; break; + case 4 :LED_R4 = 0; LED_R5 = 1; break; + case 5 :LED_R5 = 0; LED_R6 = 1; break; + case 6 :LED_R6 = 0; LED_R7 = 1; break; + case 7 :LED_R7 = 0; LED_R8 = 1; break; + + case 8 :LED_R8 = 0; LED_R9 = 1; break; + case 9 :LED_R9 = 0; LED_R10= 1; break; + case 10:LED_R10 = 0; LED_R11= 1; break; + case 11:LED_R11 = 0; LED_R12= 1; break; + case 12:LED_R12 = 0; LED_R13= 1; break; + case 13:LED_R13 = 0; LED_R14= 1; break; + case 14:LED_R14 = 0; LED_R15= 1; break; + case 15:LED_R15 = 0; LED_R16= 1; break; + + case 0xff: LED_R1 = 1;LED_R2 = 1;LED_R3 = 1;LED_R4 = 1; + LED_R5 = 1;LED_R6 = 1;LED_R7 = 1;LED_R8 = 1; + LED_R9 = 1;LED_R10= 1;LED_R11= 1;LED_R12= 1; + LED_R13= 1;LED_R14= 1;LED_R15= 1;LED_R16= 1; + break; // 0xff Select All Mode + default: LED_R1 = 0;LED_R2 = 0;LED_R3 = 0;LED_R4 = 0; + LED_R5 = 0;LED_R6 = 0;LED_R7 = 0;LED_R8 = 0; + LED_R9 = 0;LED_R10= 0;LED_R11= 0;LED_R12= 0; + LED_R13= 0;LED_R14= 0;LED_R15= 0;LED_R16= 0; + break; // Other options are closed, so select all. + } +} + +void DisPoint(uint8 x,uint8 y) +{ + #define L_ON 0 + ROW_data(88); // Clear + Data_CLR(B); + + ROW_data(y); // Row selection + switch (x) + { + case 0: LED_D0 = L_ON; break; + case 1: LED_D1 = L_ON; break; + case 2: LED_D2 = L_ON; break; + case 3: LED_D3 = L_ON; break; + case 4: LED_D4 = L_ON; break; + case 5: LED_D5 = L_ON; break; + case 6: LED_D6 = L_ON; break; + case 7: LED_D7 = L_ON; break; + } +} + +void Tns(uint8 n)// Brief delay +{ + while(n--); +} + +void MatxDisp(uint8 *buf,uint8 duty) +{ + uint8 p,i; + bit b; + SMG_S1 = 1; SMG_S2 = 1; SMG_S3 = 1; + Data_CLR(B); + #define LED_OFF 1; + for(p=0;p<16;p++) + { + ROW_data(p); + for(i=0;i<8;i++) + { + b = ~(bit)(buf[p] & bitman[i]);// Common positive reversal + switch (i) + { + case 0: LED_D7 = LED_OFF; Tns(100-duty); LED_D0 = b; break; + case 1: LED_D0 = LED_OFF; Tns(100-duty); LED_D1 = b; break; + case 2: LED_D1 = LED_OFF; Tns(100-duty); LED_D2 = b; break; + case 3: LED_D2 = LED_OFF; Tns(100-duty); LED_D3 = b; break; + case 4: LED_D3 = LED_OFF; Tns(100-duty); LED_D4 = b; break; + case 5: LED_D4 = LED_OFF; Tns(100-duty); LED_D5 = b; break; + case 6: LED_D5 = LED_OFF; Tns(100-duty); LED_D6 = b; break; + case 7: LED_D6 = LED_OFF; Tns(100-duty); LED_D7 = b; break; + default: break; + } + Tns(duty); + } + LED_D7 = 1; + } +} + +void SMG_Num(uint8 n) // Digital tube segment code +{ + switch (n) + { + case 0: SMG_A = ON; SMG_B = ON; SMG_C = ON; SMG_D = ON; SMG_E = ON; SMG_F = ON; + break; + case 1: SMG_B = ON; SMG_C = ON; + break; + case 2: SMG_A = ON; SMG_B = ON; SMG_D = ON; SMG_E = ON; SMG_G = ON; + break; + case 3: SMG_A = ON; SMG_B = ON; SMG_C = ON; SMG_D = ON; SMG_G = ON; + break; + case 4: SMG_B = ON; SMG_C = ON; SMG_F = ON; SMG_G = ON; + break; + case 5: SMG_A = ON; SMG_C = ON; SMG_D = ON; SMG_F = ON; SMG_G = ON; + break; + case 6: SMG_A = ON; SMG_C = ON; SMG_D = ON; SMG_E = ON; SMG_F = ON; SMG_G = ON; + break; + case 7: SMG_A = ON; SMG_B = ON; SMG_C = ON; + break; + case 8: SMG_A = ON; SMG_B = ON; SMG_C = ON; SMG_D = ON; SMG_E = ON; SMG_F = ON; SMG_G = ON; + break; + case 9: SMG_A = ON; SMG_B = ON; SMG_C = ON; SMG_D = ON; SMG_F = ON; SMG_G = ON; + break; + } +} +void SMG_Display(uint16 goal,uint8 duty) +{ + + ROW_data(88);// Shielding dot matrix + + Data_CLR(A); + Tns(100-duty); + SMG_S1 = 0; + SMG_Num(goal/100); + Tns(duty); + + Data_CLR(A); + Tns(100-duty); + SMG_S1 = 1; SMG_S2 = 0; + SMG_Num(goal/10%10); + Tns(duty); + + Data_CLR(A); + Tns(100-duty); + SMG_S2 = 1; SMG_S3 = 0; + SMG_Num(goal%10); + Tns(duty); + + SMG_S3 = 1; +} diff --git a/src/Display_Drives.h b/src/Display_Drives.h new file mode 100644 index 0000000..eedb8e0 --- /dev/null +++ b/src/Display_Drives.h @@ -0,0 +1,15 @@ +#ifndef __DISPLAY_DRIVES_H__ +#define __DISPLAY_DRIVES_H__ + +#include "typedef.h" +#define cdata P0 // Line data port +#define IORow_A P1 // Column Selection +#define IORow_B P2 + +extern void ROW_data(uint8 rdata); // Row selection module +extern void DisPoint(uint8 x,uint8 y); // Display pointer +extern void MatxDisp(uint8 *buf,uint8 duty);// Refresh display +extern void SMG_Display(uint16 goal,uint8 duty); + +#endif + diff --git a/src/GUI.c b/src/GUI.c new file mode 100644 index 0000000..5cfae25 --- /dev/null +++ b/src/GUI.c @@ -0,0 +1,216 @@ +#include "config.h" + +/****************Game preview animation, 4 frames in total**************************/ +uint8 code tetris_mod[4][8]= +{ + {0x08,0x0C,0x08,0x00,0x00,0x91,0xB3,0xB7}, + {0x00,0x00,0x00,0x00,0x00,0x99,0xBF,0xBF}, + {0x60,0x40,0x40,0x00,0x00,0x99,0xBF,0xBF}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF9}, +}; +uint8 code snake_mod[4][8]= +{ + {0x00,0x00,0x00,0x00,0x00,0x00,0x2E,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00}, + {0x20,0x00,0x00,0x20,0x20,0x20,0x30,0x00}, + {0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00}, +}; +uint8 code RAC_mod[4][8]= +{ + {0x8F,0x85,0x0A,0x81,0xA1,0x70,0xA1,0xD1}, + {0x00,0x85,0x8F,0x04,0xAB,0xF1,0x20,0xD1}, + {0x81,0x00,0x81,0x85,0x2E,0xF5,0xAB,0x50}, + {0x00,0x81,0x81,0x00,0xA1,0xF1,0x20,0xD1}, +}; +uint8 code shot_mod[4][8]= +{ + {0xBB,0xFB,0x00,0x00,0x00,0x00,0x04,0x0E}, + {0xF6,0xBB,0xFB,0x00,0x10,0x00,0x10,0x38}, + {0xF6,0xBB,0xEB,0x00,0x00,0x00,0x10,0x38}, + {0xCF,0xF6,0xBB,0xEB,0x00,0x00,0x10,0x38}, +}; + + +/***************************************************/ + + +static void GUI_Light_ADJ() +{ + uint8 i; + uint8 code light[2]={0x42,0x24}; + uint8 code tu[2]={0x3c,0x24}; + DispRAM[0]=tu[0]; + DispRAM[1]=tu[1]; + DispRAM[10]=tu[1]; + DispRAM[11]=tu[0]; + DispRAM[12]=0x00; + DispRAM[13]=0x00; + DispRAM[14]=light[0]; + DispRAM[15]=light[1]; + + for(i=2;i<10;i++){ // Brightness bar display + DispRAM[i] = ((i+1)>(duty/10) ? 0x00:0x18); + } +} + +static void GUI_Sound_SET() +{ + code uint8 S_Logo[8]={0x00,0x19,0x2A,0xC8,0x8B,0xC8,0x2A,0x19}; + code uint8 S_ON[8]={0x00,0x00,0x42,0x62,0x52,0x4A,0x46,0x42};/*ON*/ + code uint8 S_OFF[8]={0x00,0x00,0x3C,0x20,0x20,0x3C,0x20,0x20};/*OFF*/ + int8 i; + for(i=15;i>7;i--) + DispRAM[i] = S_Logo[15-i]; + + if(sound_ON) + { + for(i=7;i>-1;i--) + DispRAM[i] = S_ON[7-i]; + } + else + { + for(i=7;i>-1;i--) + DispRAM[i] = S_OFF[7-i]; + } +} + +void Flash_Screen_Clear()// Screen refresh animation +{ + int8 i,p,n; + code uint8 bitman[8]={1,2,4,8,16,32,64,128}; + for(p=0;p<8;p++) + for(i=0;i<8;i++) + { + n=2; + DispRAM[p] |= bitman[i]; + DispRAM[15-p] |= bitman[7-i]; + while(n--) MatxDisp(DispRAM,duty); + } + for(p=7;p>=0;p--) + for(i=7;i>=0;i--) + { + n=2; + DispRAM[p] &= ~bitman[i]; + DispRAM[15-p] &= ~bitman[7-i]; + while(n--) MatxDisp(DispRAM,duty); + } +} + + +void GUI_Game_Preview(uint8 s, uint16 fps, uint8 (*mod)[8]) +{ + uint8 i = 0; + if((tms/fps) > 3) tms=0;// Animation frame rate control + while(i<8) + { + DispRAM[i] = mod[tms/fps][7-i];// Animation loading + i++; + } + for(i=0;i<5;i++)// Game selection screen sequence display processing + { + DispRAM[14-i] = (num[s][i]<<2); + } + DispRAM[15] = 0x00; + DispRAM[9] = 0x00; + DispRAM[8] = 0x00; +} + +void GUI_Preview_Load(uint8 n) // Load game preview animation data +{ + switch (n) + { + case 1: GUI_Game_Preview(n,VIEW_FPS,tetris_mod); + break; + case 2: GUI_Game_Preview(n,VIEW_FPS,snake_mod); + break; + case 3: GUI_Game_Preview(n,VIEW_FPS,RAC_mod); + break; + case 4: GUI_Game_Preview(n,VIEW_FPS,shot_mod); + break; + case 5: GUI_Light_ADJ(); + break; + case 6: GUI_Sound_SET(); + break; + } +} + +//void Copier(uint8 *cpy,uint8 *dat)// Data copying is used to cache the current data. +//{ +// while(*cpy++ = *dat++);//I heard that using pointers like this looks cool. +//} + +void GUI_ScreenTransl(uint8 n,uint8 xfps)//Pan +{ + static s_ls = 1;// Used for left and right movement judgment + uint8 i,j,b; + uint8 tmpram[16]; + for(i=0;i<16;i++) + { + tmpram[i] = DispRAM[i];// Transfer data to prepare for panning the image. + } + GUI_Preview_Load(n); + for(j=0;j<8;j++) + { + for(i=0;i<16;i++) + { + if(n < s_ls)// Shift left + { + if(DispRAM[i]&0x01) b=0x80; + else b=0; + tmpram[i]=(tmpram[i]>>1) | b; + DispRAM[i] = DispRAM[i]>>1; + } + else // Move right + { + if(DispRAM[i]&0x80) b=1; + else b=0; + tmpram[i]=(tmpram[i]<<1) | b; + DispRAM[i]=DispRAM[i]<<1; + } + } + tms=0; + while(tms < xfps) MatxDisp(tmpram,duty);// Screen panning speed + } + s_ls = n;// Remember the current index to determine whether to shift left or right. + keypad = K_NULL;// The translation animation process takes time, which can cause a bug due to the button debounce time, resulting in continuous button triggering. Therefore, the button state needs to be adjusted to eliminate the bug. +} + +uint8 GUI_Main() +{ + static uint8 s = 1; + uint8 k = K_NULL; + while(1) + { + switch (Get_Kvuale(150)) + { + case K_NULL: + break; + case K_UP: if(s==5) if(duty<100) duty+=10; + break; + case K_DOWN:if(s==5) if(duty>=10) duty-=10; + break; + case K_LEFT:if(s>1) + { + s--; + GUI_ScreenTransl(s,SMOVE_SPEED); + } + break; + case K_RIGHT:if(s<6) + { + s++; + GUI_ScreenTransl(s,SMOVE_SPEED); + } + break; + case K_OK: if(s==6) + { + sound_ON = ~sound_ON; + Play_Music(sound_up); + } + else if(s<5) return s;// Return to the game selection number + break; + } + + GUI_Preview_Load(s); + MatxDisp(DispRAM,duty); + }//while +} \ No newline at end of file diff --git a/src/GUI.h b/src/GUI.h new file mode 100644 index 0000000..b79a6b4 --- /dev/null +++ b/src/GUI.h @@ -0,0 +1,9 @@ +#ifndef _GUI_H_ +#define _GUI_H_ + +extern void Flash_Screen_Clear(); +//void GUI_Game_Preview(uint8 s, uint16 fps, uint8 (*mod)[8]); +//void GUI_ScreenTransl(uint8 n,uint8 xfps);// Pan +extern uint8 GUI_Main(); + +#endif \ No newline at end of file diff --git a/src/Main.c b/src/Main.c new file mode 100644 index 0000000..5c6461d --- /dev/null +++ b/src/Main.c @@ -0,0 +1,221 @@ +/* +// 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; +} + + diff --git a/src/RAC.c b/src/RAC.c new file mode 100644 index 0000000..21da48a --- /dev/null +++ b/src/RAC.c @@ -0,0 +1,96 @@ +#include "config.h" + +#define ASPEED 28 // Speed ​​after pressing the acceleration button +uint8 ucar=1; // Your car, 1. Keep to the right, 2. Keep to the left + +static void keyscan() +{ + static bit r = 0; + int8 k = Get_Kvuale(30); + if(KEY_OK==0) { + speeds = ASPEED; + if(!sound_cnt_time | r) Sound_Tone(sound_ON,6,255); + r=0; + } + else{ // As the score increases, the game speed gradually increases. + speeds = 200 - scores/10; + if(!sound_cnt_time | !r) Sound_Tone(sound_ON,1,255); + r=1; + } + if(k==K_LEFT) ucar=1; + if(k==K_RIGHT) ucar=2; +} +void RAC_Game() +{ + int8 xcar[4][2]={0}; // [2] 0: Left/Right/None; 1: Y-axis position of the vehicle + uint8 code carport[3][4]={{0,0,0,0},{0x50,0x20,0x70,0x20},{0x0a,0x04,0x0e,0x04}}; + uint8 code track[5]={0x81,0x81,0x81,0x00,0x00}; + uint8 carid=0,lastid=0,stp=0; + uint8 p,i; + Glife=1; + speeds = 200; + scores = 0; + for(i=0;i<4;i++){ + xcar[i][1]=i*5;// Inter-race spacing between other race cars is a crucial aspect! + xcar[i][0]=0; + } + /******************Initialization complete, start the game.***********************/ + while(Glife){ +// Layered scanning divides the track and race cars on both sides of the image into two separate scans, creating contrast between the track and the cars. +// uint8 xtmp[16]; +// for(p=0;p<16;p++)// Refresh the track +// DispRAM[p]=track[(p+stp)%5];// Dynamic runway algorithm +// for(p=0;p<16;p++){ +// xtmp[p]=0x00; +// for(i=0;i<4;i++) // Refresh other racing cars +// if((0<=(p-xcar[i][1])) && (p-xcar[i][1])<4) +// xtmp[p] = carport[xcar[i][0]][p-(xcar[i][1])]; +// if(p<4) +// if(xtmp[p] & carport[ucar][p])// Determine if your race car has collided with other race cars. +// Glife=0; +// else +// xtmp[p] |= carport[ucar][p]; +// } + + // Synchronous scanning + for(p=0;p<16;p++)// Refresh the track + { + DispRAM[p]=0x00; + DispRAM[p]=track[(p+stp)%5];// Dynamic runway algorithm + + for(i=0;i<4;i++)// Refresh other racing cars + if((0<=(p-xcar[i][1])) && (p-xcar[i][1])<4) + DispRAM[p] |= carport[xcar[i][0]][p-(xcar[i][1])]; + if(p<4) + { + if(DispRAM[p] & carport[ucar][p])// Determine if your race car has collided with other race cars. + Glife=0; + else DispRAM[p] |= carport[ucar][p]; + } + } + if(tms > speeds)// Game Speed ​​Beat + { + stp++; + if(stp==5) stp=0;// Runway dynamic algorithm marker bits + for(i=0;i<4;i++) + { + xcar[i][1]--; // Other cars followed the runway down. + if(xcar[i][1]== -4){ + xcar[i][1]=15; + if(lastid>0) // The game rules state that if the previous parking space was not empty, then an empty parking space will be generated this time. + carid=0; + else + carid=rand()%3;// Randomly generate a car + lastid = carid; + xcar[i][0]=carid; + scores ++; + } + } + tms=0; + } + keyscan(); + MatxDisp(DispRAM,duty); + SMG_Display(scores,duty); + } + TR2_OFF; +} diff --git a/src/RAC.h b/src/RAC.h new file mode 100644 index 0000000..065ebb6 --- /dev/null +++ b/src/RAC.h @@ -0,0 +1,5 @@ +#ifndef _RAC_H_ +#define _RAC_H_ + +extern void RAC_Game(void); +#endif \ No newline at end of file diff --git a/src/STC15F2K60S2.H b/src/STC15F2K60S2.H new file mode 100644 index 0000000..951be0d --- /dev/null +++ b/src/STC15F2K60S2.H @@ -0,0 +1,236 @@ +#ifndef __STC15F2K60S2_H_ +#define __STC15F2K60S2_H_ + +///////////////////////////////////////////////// + +// After including this header file, it is not necessary to include "REG51.H" separately + +// Core Special Function Registers // Reset Value Description +sfr ACC = 0xE0; // 0000,0000 Accumulator +sfr B = 0xF0; // 0000,0000 B Register +sfr PSW = 0xD0; // 0000,0000 Program Status Word +sbit CY = PSW^7; +sbit AC = PSW^6; +sbit F0 = PSW^5; +sbit RS1 = PSW^4; +sbit RS0 = PSW^3; +sbit OV = PSW^2; +sbit P = PSW^0; +sfr SP = 0x81; // 0000,0111 Stack Pointer +sfr DPL = 0x82; // 0000,0000 Data Pointer Low Byte +sfr DPH = 0x83; // 0000,0000 Data Pointer High Byte + +// I/O Port Special Function Registers +sfr P0 = 0x80; // 1111,1111 Port 0 +sbit P00 = P0^0; +sbit P01 = P0^1; +sbit P02 = P0^2; +sbit P03 = P0^3; +sbit P04 = P0^4; +sbit P05 = P0^5; +sbit P06 = P0^6; +sbit P07 = P0^7; +sfr P1 = 0x90; // 1111,1111 Port 1 +sbit P10 = P1^0; +sbit P11 = P1^1; +sbit P12 = P1^2; +sbit P13 = P1^3; +sbit P14 = P1^4; +sbit P15 = P1^5; +sbit P16 = P1^6; +sbit P17 = P1^7; +sfr P2 = 0xA0; // 1111,1111 Port 2 +sbit P20 = P2^0; +sbit P21 = P2^1; +sbit P22 = P2^2; +sbit P23 = P2^3; +sbit P24 = P2^4; +sbit P25 = P2^5; +sbit P26 = P2^6; +sbit P27 = P2^7; +sfr P3 = 0xB0; // 1111,1111 Port 3 +sbit P30 = P3^0; +sbit P31 = P3^1; +sbit P32 = P3^2; +sbit P33 = P3^3; +sbit P34 = P3^4; +sbit P35 = P3^5; +sbit P36 = P3^6; +sbit P37 = P3^7; +sfr P4 = 0xC0; // 1111,1111 Port 4 +sbit P40 = P4^0; +sbit P41 = P4^1; +sbit P42 = P4^2; +sbit P43 = P4^3; +sbit P44 = P4^4; +sbit P45 = P4^5; +sbit P46 = P4^6; +sbit P47 = P4^7; +sfr P5 = 0xC8; // xxxx,1111 Port 5 +sbit P50 = P5^0; +sbit P51 = P5^1; +sbit P52 = P5^2; +sbit P53 = P5^3; +sbit P54 = P5^4; +sbit P55 = P5^5; +sbit P56 = P5^6; +sbit P57 = P5^7; +sfr P6 = 0xE8; // 0000,0000 Port 6 +sbit P60 = P6^0; +sbit P61 = P6^1; +sbit P62 = P6^2; +sbit P63 = P6^3; +sbit P64 = P6^4; +sbit P65 = P6^5; +sbit P66 = P6^6; +sbit P67 = P6^7; +sfr P7 = 0xF8; // 0000,0000 Port 7 +sbit P70 = P7^0; +sbit P71 = P7^1; +sbit P72 = P7^2; +sbit P73 = P7^3; +sbit P74 = P7^4; +sbit P75 = P7^5; +sbit P76 = P7^6; +sbit P77 = P7^7; +sfr P0M0 = 0x94; // 0000,0000 Port 0 Mode Register 0 +sfr P0M1 = 0x93; // 0000,0000 Port 0 Mode Register 1 +sfr P1M0 = 0x92; // 0000,0000 Port 1 Mode Register 0 +sfr P1M1 = 0x91; // 0000,0000 Port 1 Mode Register 1 +sfr P2M0 = 0x96; // 0000,0000 Port 2 Mode Register 0 +sfr P2M1 = 0x95; // 0000,0000 Port 2 Mode Register 1 +sfr P3M0 = 0xB2; // 0000,0000 Port 3 Mode Register 0 +sfr P3M1 = 0xB1; // 0000,0000 Port 3 Mode Register 1 +sfr P4M0 = 0xB4; // 0000,0000 Port 4 Mode Register 0 +sfr P4M1 = 0xB3; // 0000,0000 Port 4 Mode Register 1 +sfr P5M0 = 0xCA; // 0000,0000 Port 5 Mode Register 0 +sfr P5M1 = 0xC9; // 0000,0000 Port 5 Mode Register 1 +sfr P6M0 = 0xCC; // 0000,0000 Port 6 Mode Register 0 +sfr P6M1 = 0xCB; // 0000,0000 Port 6 Mode Register 1 +sfr P7M0 = 0xE2; // 0000,0000 Port 7 Mode Register 0 +sfr P7M1 = 0xE1; // 0000,0000 Port 7 Mode Register 1 + +// System Management Special Function Registers +sfr PCON = 0x87; // 0001,0000 Power Control Register +sfr AUXR = 0x8E; // 0000,0000 Auxiliary Register +sfr AUXR1 = 0xA2; // 0000,0000 Auxiliary Register 1 +sfr P_SW1 = 0xA2; // 0000,0000 Peripheral Port Switch Register 1 +sfr CLK_DIV = 0x97; // 0000,0000 Clock Divider Control Register +sfr BUS_SPEED = 0xA1; // xx10,x011 Bus Speed Control Register +sfr P1ASF = 0x9D; // 0000,0000 Port 1 Analog Function Config Register +sfr P_SW2 = 0xBA; // xxxx,x000 Peripheral Port Switch Register 2 + +// Interrupt Special Function Registers +sfr IE = 0xA8; // 0000,0000 Interrupt Control Register +sbit EA = IE^7; +sbit ELVD = IE^6; +sbit EADC = IE^5; +sbit ES = IE^4; +sbit ET1 = IE^3; +sbit EX1 = IE^2; +sbit ET0 = IE^1; +sbit EX0 = IE^0; +sfr IP = 0xB8; // 0000,0000 Interrupt Priority Register +sbit PPCA = IP^7; +sbit PLVD = IP^6; +sbit PADC = IP^5; +sbit PS = IP^4; +sbit PT1 = IP^3; +sbit PX1 = IP^2; +sbit PT0 = IP^1; +sbit PX0 = IP^0; +sfr IE2 = 0xAF; // 0000,0000 Interrupt Control Register 2 +sfr IP2 = 0xB5; // xxxx,xx00 Interrupt Priority Register 2 +sfr INT_CLKO = 0x8F; // 0000,0000 External Interrupt and Clock Output Control Register + +// Timer Special Function Registers +sfr TCON = 0x88; // 0000,0000 T0/T1 Control Register +sbit TF1 = TCON^7; +sbit TR1 = TCON^6; +sbit TF0 = TCON^5; +sbit TR0 = TCON^4; +sbit IE1 = TCON^3; +sbit IT1 = TCON^2; +sbit IE0 = TCON^1; +sbit IT0 = TCON^0; +sfr TMOD = 0x89; // 0000,0000 T0/T1 Mode Register +sfr TL0 = 0x8A; // 0000,0000 T0 Low Byte +sfr TL1 = 0x8B; // 0000,0000 T1 Low Byte +sfr TH0 = 0x8C; // 0000,0000 T0 High Byte +sfr TH1 = 0x8D; // 0000,0000 T1 High Byte +sfr T4T3M = 0xD1; // 0000,0000 T3/T4 Mode Register +sfr T3T4M = 0xD1; // 0000,0000 T3/T4 Mode Register +sfr T4H = 0xD2; // 0000,0000 T4 High Byte +sfr T4L = 0xD3; // 0000,0000 T4 Low Byte +sfr T3H = 0xD4; // 0000,0000 T3 High Byte +sfr T3L = 0xD5; // 0000,0000 T3 Low Byte +sfr T2H = 0xD6; // 0000,0000 T2 High Byte +sfr T2L = 0xD7; // 0000,0000 T2 Low Byte +sfr WKTCL = 0xAA; // 0000,0000 Power-down Wake-up Timer Low Byte +sfr WKTCH = 0xAB; // 0000,0000 Power-down Wake-up Timer High Byte +sfr WDT_CONTR = 0xC1; // 0000,0000 Watchdog Timer Control Register + +// Serial Port Special Function Registers +sfr SCON = 0x98; // 0000,0000 Serial Port 1 Control Register +sbit SM0 = SCON^7; +sbit SM1 = SCON^6; +sbit SM2 = SCON^5; +sbit REN = SCON^4; +sbit TB8 = SCON^3; +sbit RB8 = SCON^2; +sbit TI = SCON^1; +sbit RI = SCON^0; +sfr SBUF = 0x99; // xxxx,xxxx Serial Port 1 Data Register +sfr S2CON = 0x9A; // 0000,0000 Serial Port 2 Control Register +sfr S2BUF = 0x9B; // xxxx,xxxx Serial Port 2 Data Register +sfr S3CON = 0xAC; // 0000,0000 Serial Port 3 Control Register +sfr S3BUF = 0xAD; // xxxx,xxxx Serial Port 3 Data Register +sfr S4CON = 0x84; // 0000,0000 Serial Port 4 Control Register +sfr S4BUF = 0x85; // xxxx,xxxx Serial Port 4 Data Register +sfr SADDR = 0xA9; // 0000,0000 Slave Address Register +sfr SADEN = 0xB9; // 0000,0000 Slave Address Mask Register + +// ADC Special Function Registers +sfr ADC_CONTR = 0xBC; // 0000,0000 A/D Conversion Control Register +sfr ADC_RES = 0xBD; // 0000,0000 A/D Conversion Result High 8 Bits +sfr ADC_RESL = 0xBE; // 0000,0000 A/D Conversion Result Low 2 Bits + +// SPI Special Function Registers +sfr SPSTAT = 0xCD; // 00xx,xxxx SPI Status Register +sfr SPCTL = 0xCE; // 0000,0100 SPI Control Register +sfr SPDAT = 0xCF; // 0000,0000 SPI Data Register + +// IAP/ISP Special Function Registers +sfr IAP_DATA = 0xC2; // 0000,0000 EEPROM Data Register +sfr IAP_ADDRH = 0xC3; // 0000,0000 EEPROM Address High Byte +sfr IAP_ADDRL = 0xC4; // 0000,0000 EEPROM Address Low Byte +sfr IAP_CMD = 0xC5; // xxxx,xx00 EEPROM Command Register +sfr IAP_TRIG = 0xC6; // 0000,0000 EEPROM Command Trigger Register +sfr IAP_CONTR = 0xC7; // 0000,x000 EEPROM Control Register + +// PCA/PWM Special Function Registers +sfr CCON = 0xD8; // 00xx,xx00 PCA Control Register +sbit CF = CCON^7; +sbit CR = CCON^6; +sbit CCF2 = CCON^2; +sbit CCF1 = CCON^1; +sbit CCF0 = CCON^0; +sfr CMOD = 0xD9; // 0xxx,x000 PCA Work Mode Register +sfr CL = 0xE9; // 0000,0000 PCA Counter Low Byte +sfr CH = 0xF9; // 0000,0000 PCA Counter High Byte +sfr CCAPM0 = 0xDA; // 0000,0000 PCA Module 0 PWM Register +sfr CCAPM1 = 0xDB; // 0000,0000 PCA Module 1 PWM Register +sfr CCAPM2 = 0xDC; // 0000,0000 PCA Module 2 PWM Register +sfr CCAP0L = 0xEA; // 0000,0000 PCA Module 0 Capture/Compare Register Low Byte +sfr CCAP1L = 0xEB; // 0000,0000 PCA Module 1 Capture/Compare Register Low Byte +sfr CCAP2L = 0xEC; // 0000,0000 PCA Module 2 Capture/Compare Register Low Byte +sfr PCA_PWM0 = 0xF2; // xxxx,xx00 PCA Module 0 PWM Register +sfr PCA_PWM1 = 0xF3; // xxxx,xx00 PCA Module 1 PWM Register +sfr PCA_PWM2 = 0xF4; // xxxx,xx00 PCA Module 2 PWM Register +sfr CCAP0H = 0xFA; // 0000,0000 PCA Module 0 Capture/Compare Register High Byte +sfr CCAP1H = 0xFB; // 0000,0000 PCA Module 1 Capture/Compare Register High Byte +sfr CCAP2H = 0xFC; // 0000,0000 PCA Module 2 Capture/Compare Register High Byte + +///////////////////////////////////////////////// + +#endif \ No newline at end of file diff --git a/src/STC_ISP.H b/src/STC_ISP.H new file mode 100644 index 0000000..de408cb --- /dev/null +++ b/src/STC_ISP.H @@ -0,0 +1,24 @@ + + /********************************************************* + STC_12C5A60S2Ãâ¶ÏµçÉÕ¼³ÌÐò + *********************************************************/ + + + #ifndef _STC_ISP_H_ + #define _STC_ISP_H_ +// sfr IAP_CONTR = 0xC7; //IAP Control Register + + sbit IN_OFF=P3^0;//´®¿Ú½ÓÊÕ¶Ë + //************************************************** + + void STC_ISP() + { + + IN_OFF=1; //¡ª¡ª2 + + if(!IN_OFF){IAP_CONTR=0x60;} //Åжϴ®¿ÚÊÇ·ñÓÐÊý¾Ý¹ýÀ´ + + } + + +#endif \ No newline at end of file diff --git a/src/Shot.c b/src/Shot.c new file mode 100644 index 0000000..bc3d09b --- /dev/null +++ b/src/Shot.c @@ -0,0 +1,101 @@ +#include "config.h" + +uint8 site; +uint8 bullet = 0; +uint8 aim_layer = 1; +uint8 plane[2]; +uint8 block[16]; +static void Shot_One(); + +static void Shot_One() +{ + if(bullet>15){ + bullet=1; + return; + } + if(bitman[site] & block[bullet]) + { + block[bullet] &= (~bitman[site]);// Eliminate the shot block + bullet=1; + scores++; +// Sound_Tone(1,site+1,5); + } + else + { + ++bullet; + Sound_Tone(sound_ON,bullet,1); + DisPoint(site,bullet); // Iterative generation of ballistics + delayus(300); + Shot_One(); // Recursive elimination + } +} + +static void Block_Down() +{ + uint8 i; + for(i=0;i<15;i++) + { + block[i] = block[i+1]; + } + block[15] = rand()%256; +} +static void Key_Control() +{ + int8 k = Get_Kvuale(150); + switch (k) + { + case K_LEFT: if(site < 7) site++; + break; + case K_RIGHT:if(site > 0) site--; + break; + case K_OK: Shot_One(); return; + break; + default: break; + } + if(!(tms%20)) if(!KEY_OK) Shot_One(); +} + +static void Shot_Game_Init() +{ + uint8 i; + Glife=1; + site=3; + scores=0; + bullet=0; + speeds = 1000; + plane[1] = bitman[site]; // Draw the shape of an airplane + plane[0] = plane[1]<<1 | plane[1] | plane[1]>>1; + + for(i=0;i<16;i++) block[i]=0x00; // Clear data + block[15] = rand()%256; // Let's start with one. +} +static void Shot_GameDisp() +{ +// Copier(DispRAM,block); + uint8 i; + for(i=0;i<16;i++) + { + DispRAM[i] = block[i]; + } + DispRAM[0] |= plane[0]; + DispRAM[1] |= plane[1]; + MatxDisp(DispRAM,duty); +} +void Shot_Game() +{ + Shot_Game_Init(); + while(Glife) + { + Key_Control(); + plane[1] = bitman[site]; + plane[0] = plane[1]<<1 | plane[1] | plane[1]>>1; + if(tms > (speeds-scores)) + { + tms = 0; + Block_Down(); + if(block[0] | (block[1]&plane[1])) Glife=0; + } + Shot_GameDisp(); + SMG_Display(scores,duty); + } +} diff --git a/src/Shot.h b/src/Shot.h new file mode 100644 index 0000000..2b3e03e --- /dev/null +++ b/src/Shot.h @@ -0,0 +1,6 @@ +#ifndef _SHOT_H_ +#define _SHOT_H_ + +extern void Shot_Game(void); + +#endif \ No newline at end of file diff --git a/src/Sound_Drives.c b/src/Sound_Drives.c new file mode 100644 index 0000000..d4b979b --- /dev/null +++ b/src/Sound_Drives.c @@ -0,0 +1,64 @@ +#include "config.h" + +uint8 freq_load[16][2]; +uint16 data sound_cnt_time = 0; +uint8 (*music_p)[2] = 0; +uint8 s_p=0;// Music pointer + +void Sound_Freq_Init() // Calculate the timer load value at the current crystal oscillator frequency based on the original frequency data upon power-on. +{ + // Raw frequency data + code uint16 prime_freq[16]= + { + 0xffff, + /*M*/523,587,659,698,784,880,988, + /*H*/1046,1175,1318,1397,1568,1760,1967, + 0 + }; + uint16 load_vaule = 0; + uint8 i = 0; + do + { + load_vaule = (65536-(FOSC/prime_freq[i]));// Initialize timer value + freq_load[i][0] = load_vaule; + freq_load[i][1] = load_vaule >>8; + }while(prime_freq[++i]); +} + +void Sound_Init(void) //@24.000MHz +{ + AUXR |= 0x04; // Timer 2 is in 1T mode +// AUXR &= ~0x04; // Timer 2 is in 12T mode +// T2L = T1MS; // Initialize timer value +// T2H = T1MS >> 8; +// AUXR |= 0x10; // Timer 2 starts counting + IE2 |= 0x04; // Enable Timer 2 interrupt + EA = 1; + beep = 1; // Turn off the buzzer. + sound_cnt_time=0; + (*music_p)[2] = 0; + TR2_OFF; + Sound_Freq_Init(); +} + +void Sound_Tone(bit ON_OFF,uint8 freq,uint8 s_tms) //freqx>367 +{ + if(ON_OFF) + { + T2L = freq_load[freq][0]; + T2H = freq_load[freq][1]; + if(s_tms == 0xff) sound_cnt_time = 0xffff; + else sound_cnt_time = (uint16)s_tms*10; + TR2_NO; + } +} + +void Play_Music(uint8 (*sound)[2]) +{ + if(sound_ON){ + s_p=0; + sound_cnt_time = 0; + music_p = sound; + TR2_NO; + } +} diff --git a/src/Sound_Drives.h b/src/Sound_Drives.h new file mode 100644 index 0000000..f463872 --- /dev/null +++ b/src/Sound_Drives.h @@ -0,0 +1,46 @@ +#ifndef _SOUND_DRIVES_H__ +#define _SOUND_DRIVES_H__ + +/*************Tone_Freq_HZ*******************/ +#define L_1D0 262 +#define L_2RE 294 +#define L_3MI 330 +#define L_4FA 349 +#define L_5SO 392 +#define L_6LA 440 +#define L_7XI 494 +#define M_1DO 523 +#define M_2RE 587 +#define M_3MI 659 +#define M_4FA 698 +#define M_5SO 784 +#define M_6LA 880 +#define M_7XI 988 +#define H_1DO 1046 +#define H_2RE 1175 +#define H_3MI 1318 +#define H_4FA 1397 +#define H_5SO 1568 +#define H_6LA 1760 +#define H_7XI 1967 +/*********************************************/ +#define TR2_NO AUXR |= 0x10 // Timer 2 turned on +#define TR2_OFF AUXR &= 0xEF // closure +#define PIN_TR2 (AUXR & 0x10) // Determine if TR2 is on + +extern uint8 code sound_up[][2]; +extern uint8 code sound_down[8][2]; +extern uint8 code sound_game_start[][2]; +extern uint8 code sound_game_over[][2]; +extern uint8 code sound_korobelniki[][2]; +extern uint8 code sound_canon[][2]; + +extern uint16 data sound_cnt_time; +extern uint8 (*music_p)[2]; +extern uint8 s_p; + +void Sound_Init(void); +void Sound_Tone(bit ON_OFF,uint8 freq,uint8 s_tms); //freq>367 +void Play_Music(uint8 (*sound)[2]); + +#endif \ No newline at end of file diff --git a/src/Sound_date.c b/src/Sound_date.c new file mode 100644 index 0000000..483ca1d --- /dev/null +++ b/src/Sound_date.c @@ -0,0 +1,147 @@ +#include "config.h" + +uint8 code sound_up[8][2]= +{ + {8,8},{9,8},{10,8},{11,8},{12,8},{13,8},{14,8},{0,0} +}; + +uint8 code sound_down[8][2]= +{ + {7,8},{6,8},{5,8},{4,8},{3,8},{2,8},{1,8},{0,0} +}; + +uint8 code sound_game_start[][2]= +{ + {1,15}, + {1,15}, + {3,15}, + + {1,10}, + {1,10}, + {3,20}, + {0,0} +}; + +uint8 code sound_game_over[5][2]= +{ + {6,15}, + {4,15}, + {3,15}, + {1,30}, + {0,0} +}; + +uint8 code sound_korobelniki[][2]= +{ + {6,28}, + {3,18}, + {4,18}, + {5,18}, + + {4,18}, + {3,18}, + {2,20}, + +{0,1}, + + {2,20}, + {4,20}, + {6,28}, + +{0,1}, + + {5,18}, + {4,22}, + {3,22}, + +{0,1}, + + {4,22}, + {5,22}, + {6,22}, + +{0,1}, + + {4,22}, + + {2,22}, + {0,2}, + {2,28}, + +{0,12}, + + {5,30}, + {6,25}, + {7+2,22}, + + {7+1,22}, + {6,28}, + + {4,18}, + {6,20}, + + {5,18}, + {4,18}, + {3,28}, + + {4,18}, + {5,28}, + + {6,20}, + {4,20}, + {2,20}, + {0,1}, + {2,25}, + {0,0}, +}; + +uint8 code sound_canon[][2]= +{ + {7+3,35},{7+2,40},{7+1,35},{7,40}, + + {6,35},{5,40}, + + {6,35},{7,40}, + + {7+1,35},{7,40}, + + {6,35},{5,40}, + + {4,35},{3,40}, + + {4,35},{2,40}, + + {7+1,20},{7,20},{7+1,20},{1,20}, + + {7,20},{5,20},{2,20},{3,20}, + + {1,20},{7+1,20},{7,20},{6,20}, + + {7,20},{7+3,20},{7+5,20},{7+6,20}, + + {7+4,20},{7+3,20},{7+2,20},{7+4,20}, + + {7+4,20},{7+3,20},{7+1,20},{7,20}, + + {6,20},{5,20},{4,20},{3,20}, + + {2,20},{4,20},{3,20},{2,20}, + + {1,20},{2,20},{3,20},{4,20}, + + {5,20},{2,20},{5,20},{4,20}, + + {3,20},{6,20},{5,20},{4,20}, + + {5,20},{4,20},{3,20},{2,20}, + + {1,20},{6,20},{6,20},{7,20}, + + {7+1,20},{7,20},{6,20},{5,20}, + + {4,20},{3,20},{2,20},{6,20}, + + {5,20},{6,20},{5,20},{4,20}, + + {0,0}, +}; diff --git a/src/Tetris.c b/src/Tetris.c new file mode 100644 index 0000000..0366ac7 --- /dev/null +++ b/src/Tetris.c @@ -0,0 +1,332 @@ +#include "config.h" + +#define NORSPEED 500 // Normal game speed +#define MAXSPEED 28 // Press the DOWN button to speed up the game. +#define KEYSET 50 // Button Delay Detection + +static char x=0,y=15; // The position marker of the dynamic block +static uint8 boxID; // When the block number is in front +static uint8 showbox[4]; // Dynamic block caching +static uint8 sblock[16]; // Static block cache + +uint8 code getscore[5] = {0,1,3,7,15}; // Score for eliminating rows in one go +uint8 code rotlist[19]={0,2,1,4,3,6,5,8,9,10,7,12,13,14,11,16,17,18,15};// Block Rotating Linked List +uint8 code blocks[19][4]= +{ + {0x00,0x00,0x18,0x18}, // Square shape 0 + {0x10,0x10,0x10,0x10}, // Vertical line 1 + {0x00,0x00,0x00,0x3c}, // Horizontal line 2 + {0x00,0x08,0x18,0x10}, // Right-leaning 3 + {0x00,0x00,0x30,0x18}, // Z-shape 1 4 + {0x00,0x10,0x18,0x08}, // Shape 5 5 + {0x00,0x00,0x18,0x30}, // Z-shape 2 6 + {0x00,0x08,0x08,0x18}, // Corner shape 1 7 + {0x00,0x00,0x38,0x08}, // Shape 8 8 + {0x00,0x18,0x10,0x10}, // Shape 9 9 + {0x00,0x00,0x20,0x38}, // Shape 10 10 + {0x00,0x10,0x10,0x18}, // L-shape 11 + {0x00,0x00,0x08,0x38}, // Shape 12 12 + {0x00,0x18,0x08,0x08}, // Shape 13 13 + {0x00,0x00,0x38,0x20}, // Shape 14 14 + {0x00,0x00,0x10,0x38}, // T-shape (convex) 15 + {0x00,0x08,0x18,0x08}, // Shape 16 16 + {0x00,0x00,0x38,0x10}, // Shape 17 17 + {0x00,0x10,0x18,0x10}, // Shape 18 18 +}; + +static void RandBox() // Randomly load a block +{ + uint8 i; + boxID = rand() % 19; + if(KEY_LEFT == 0 && KEY_RIGHT == 0) boxID = 2; // Game back-door, you know what I mean! ^.^ + for(i=0;i<4;i++) // Load the block + { + showbox[i] = blocks[boxID][3-i]; // Due to hardware layout, load in reverse order for easier dot matrix operation + } +} + +static char Check_LR(uint8 lr) // 0: left, 1: right; returns 1 if movable, 0 if blocked +{ + uint8 i; + if(lr) + { + for(i=0;i<4;i++) + { + // Check boundary and existing static blocks + if ((showbox[i] & 0x01) || (showbox[i] >> 1 & sblock[i+y])) + return 0; // Exit if boundary or obstacle detected + } + return 1; + } + else + { + for(i=0;i<4;i++) + { + // Check boundary and existing static blocks + if((showbox[i] & 0x80) || (showbox[i] << 1 & sblock[i+y])) + return 0; // Exit if boundary or obstacle detected + } + return 1; + } +} + +static void moveone(bit lr, uint8 *buf) +{ + uint8 i; + if(lr) + { + for(i=0;i<4;i++) + { + buf[i] = buf[i]>>1; + } + } + else + { + for(i=0;i<4;i++) + { + buf[i] = buf[i]<<1; + } + } +} + +static char BoxMover(char lr,uint8 *buf) +{ + char i,j; + if(lr>0) + { + for(j=0;j>1; + + if(j+1 == (-lr)) + if(buf[i] & sblock[i+y]) + return 0; + } + } + return 1; + } + return 1; +} + +static void SpinBox() +{ + uint8 i,tmpid,tmpbuf[4]={0}; + tmpid = rotlist[boxID]; + for(i=0;i<4;i++) + tmpbuf[i] = blocks[tmpid][3-i];// Transform the next image based on the linked list. + + if(x > 0) + { + if(BoxMover(x,tmpbuf)) + { + boxID = tmpid; + for(i=0;i<4;i++) + showbox[i] = tmpbuf[i]; + } + } + + else if(x < 0) + { + if(BoxMover(x,tmpbuf)) + { + boxID = tmpid; + for(i=0;i<4;i++) + showbox[i] = tmpbuf[i]; + } + } + + else + { + bit f = 1; + for(i=0;i<4;i++) + { + if(tmpbuf[i] & sblock[i+y]) + { + f = 0; + break; + } + } + if( f ) + { + for(i=0;i<4;i++) + showbox[i] = tmpbuf[i]; + boxID = tmpid; + } + } +} +static char Check_Down() // Detect whether the falling block overlaps with a static block. +{ + if((sblock[15] & showbox[0]) | (sblock[15] & showbox[1])) + return -1; + + if(y==0) return 1; + if(sblock[y-1] & showbox[0]) return 1; + if(sblock[y] & showbox[1]) return 1; + if(y<15) + if(sblock[y+1] & showbox[2]) return 1; + if(y<14) + if(sblock[y+2] & showbox[3]) return 1; + + return 0; +} + +static void TetrisDisp() // 0: Scan only static images 1: Scan both static and dynamic images simultaneously +{ + uint p; + for(p=0;p<16;p++) + DispRAM[p] = sblock[p]; + + for(p=y;p tms) + { + MatxDisp(sblock,duty); + SMG_Display(scores,duty); + } + } + for(k=p;k<15;k++) + { + sblock[k] = sblock[k+1]; + if(sblock[k] == 0x00) + break; + } + p--; + } + } + scores += getscore[tmps]; +} + +static void Tetris_Keyscan() // +{ + int8 k = Get_Kvuale(150); + + switch (k) + { + case K_NULL:break; + + case K_LEFT:if(Check_LR(0)) + { + moveone(0, showbox); + x++; + } + break; + case K_RIGHT:if(Check_LR(1)) + { + moveone(1, showbox); + x--; + } + break; + case K_OK: + Sound_Tone(sound_ON & !(AUXR & 0x10),2,8); + SpinBox(); + break; + } + + if(KEY_DOWN==0) + speeds = MAXSPEED;// When down is pressed, it switches to the maximum speed block fall. + else speeds = NORSPEED;// The speed did not return to normal on time. +} +static void Tetris_Init() +{ + uint i; + for(i=0;i<16;i++) // Clear static memory + sblock[i]=0x00; + scores=0; + keycont=0; + keypad=0; + tms=0; + speeds = NORSPEED; + RandBox(); // Randomly load a block + Glife=1; +} + +void Tetris_Game() +{ + Tetris_Init(); + Play_Music(sound_korobelniki); + while(Glife) + { + Tetris_Keyscan(); + if(tms > speeds) // Game Speed Beat + { + tms=0; + if(Check_Down() == 1) // Check if the dynamic block can no longer descend. + { + sblock[y] |= showbox[0]; // Combining dynamic blocks with static images + if(y<15) sblock[y+1] |= showbox[1]; + if(y<14) sblock[y+2] |= showbox[2]; + if(y<13) sblock[y+3] |= showbox[3]; + + RowFull(); // Check if there are rows that are full and perform the necessary processing. + RandBox(); // A new block is generated randomly. + x=0; + y=15; // Return the dynamic block coordinates to their original positions to prepare for the next new block. + } + else if(Check_Down() == -1)// The blocks have been detected to have reached their maximum capacity. + { + Glife = 0;// End game + } + else + { + y--; // The block moves down one space. + } + } + TetrisDisp();// Refresh game graphics + SMG_Display(scores,duty); + } + TR2_OFF; +} + + + + + + + diff --git a/src/Tetris.h b/src/Tetris.h new file mode 100644 index 0000000..413bebb --- /dev/null +++ b/src/Tetris.h @@ -0,0 +1,6 @@ +#ifndef _TETRIS_H_ +#define _TETRIS_H_ + +extern void Tetris_Game(); + +#endif \ No newline at end of file diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..52838d2 --- /dev/null +++ b/src/config.h @@ -0,0 +1,99 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#define FOSC 24000000L +#define T1MS (65536-FOSC/1000) // 1T mode +/*******************include*********************/ +#include +#include "intrins.h" + +#include "STC15F2K60S2.H" +#include "typedef.h" +//#include "common.h" +#include "delay.h" + +#include "Display_Drives.h" +#include "Sound_Drives.h" +#include "GUI.h" + +#include "Tetris.h" +#include "snake.h" +#include "RAC.h" +#include "Shot.h" + +/*******************PIN_CONFIG*********************/ +// passive buzzer +sbit beep = P3^4; +/*******keyborad******/ +sbit KEY_UP =P3^2; +sbit KEY_DOWN =P3^6; +sbit KEY_LEFT =P3^0; +sbit KEY_RIGHT =P3^3; +sbit KEY_OK =P3^7; +//exint, which external interrupt number each button is connected to. +#define K_UP 0 +#define K_DOWN 2 +#define K_RIGHT 1 +#define K_LEFT 4 +#define K_OK 3 +#define K_NULL 255 //Untriggered value +/*******Digital tube pin configuration********/ +sbit SMG_S1 = P2^3; // Digital tube position selection +sbit SMG_S2 = P2^5; +sbit SMG_S3 = P4^2; + +sbit SMG_A = P4^1; +sbit SMG_B = P2^4; +sbit SMG_C = P2^1; +sbit SMG_D = P2^0; +sbit SMG_E = P4^4; +sbit SMG_F = P2^2; +sbit SMG_G = P1^4; +/*********Dot matrix pin configuration*********/ +// Dot matrix data port +sbit LED_D0 = P1^5; +sbit LED_D1 = P4^1; +sbit LED_D2 = P2^2; +sbit LED_D3 = P1^4; +sbit LED_D4 = P2^1; +sbit LED_D5 = P4^4; +sbit LED_D6 = P2^0; +sbit LED_D7 = P2^4; +// Dot matrix row selection +sbit LED_R16= P2^6; +sbit LED_R15= P4^5; +sbit LED_R14= P0^4; +sbit LED_R13= P2^7; +sbit LED_R12= P0^0; +sbit LED_R11= P0^3; +sbit LED_R10= P0^1; +sbit LED_R9 = P0^2; +sbit LED_R8 = P0^5; +sbit LED_R7 = P0^7; +sbit LED_R6 = P1^3; +sbit LED_R5 = P0^6; +sbit LED_R4 = P1^0; +sbit LED_R3 = P1^2; +sbit LED_R2 = P1^1; +sbit LED_R1 = P1^6; +/******************general global variables*******************/ +#define VIEW_FPS 600 // Game selection frame interval time +#define SMOVE_SPEED 28 // Game selection screen panning speed + +extern volatile uint8 data keypad; // Keyboard status +extern volatile uint16 data scores; // Game scoring +extern volatile uint8 data keycont; // Keyboard detection debounce timer +extern uint16 data tms; // 1ms T0 timer +extern uint16 data speeds; // Game speed +extern uint8 data duty; // Display duty cycle +extern bit sound_ON; // sound switch +extern bit Glife; // Game Life +extern uint8 data DispRAM[16]; // Show cache area +extern uint8 code bitman[8]; // Used for digital positioning +extern uint8 code num[10][5]; + +void ShowScore(uint score); +//void Copier(uint8 *dat,uint8 *cpy); +uint8 Get_Kvuale(uint8 key_delay); + +#endif \ No newline at end of file diff --git a/src/snake.c b/src/snake.c new file mode 100644 index 0000000..bbc498d --- /dev/null +++ b/src/snake.c @@ -0,0 +1,170 @@ +/* + 2014-1-26 00:00:00 :Complete the Snake game model + 2014-3-8 23:27:05 :The game speed increases as more food is consumed. + 2014-3-15 20:06:15 :Physical hardware testing showed it was running well, but the snake game's structure consumed too much RAM and will be optimized. +*/ +#include "config.h" + +#define NORSPEED 360 +#define ASPEED 100 +#define WIDTH 8 // Game screen width +#define LENGTH 16 // Game screen length + +static struct Food +{ + uint8 x;// x-axis of food + uint8 y;// y-axis of food +}food; + +struct Snake snake; + +enum direc{up, down, left, right};// snake's direction of movement + +static void Snake_Init(); // Initialize the game +static void Snake_Disp(); // Game display +static void Snake_Run(); // The snake took a step forward. +static void Create_Food(); // Randomly generated food + +static void Create_Food() +{ + uint8 i; + food.x = rand() % WIDTH; // Range 1-16; + food.y = rand() % LENGTH; // Get the random number seed; // Use a counter as a random number generator + for(i=1;i<(snake.node);i++)// Detect whether the generated food overlaps with the snake itself. + { + if((food.x==snake.x[i])&&(food.y==snake.y[i])) + Create_Food(); // Overlapping will lead to regeneration + } +} + +static void Snake_Init() +{ + uint8 c; + for(c=0;c < MAX_SNAKE;c++)// Clear memory data + { + snake.x[c]=-1; + snake.y[c]=-1; + } + snake.life = 1; // Give life to snakes + snake.node = 3; // Default length 3 sections + snake.direc = up;// Initial direction + snake.x[0]=4; + snake.y[0]=5; + snake.x[1]=4; + snake.y[1]=4; + snake.x[2]=4; + snake.y[2]=3; + speeds = NORSPEED; //Game speed + tms = 0; + scores = 0; + Create_Food(); //Generate the first food +} + +static void Snake_Run() //Snake crawling algorithm +{ + uint8 i; + for(i=(snake.node-1);i>0;i--) // The snakehead serves as a guide for progress, with the new generation surpassing the old. + { + snake.y[i]=snake.y[i-1]; + snake.x[i]=snake.x[i-1]; + } + switch (snake.direc) // Follow the direction of the snake. + { + case up: snake.y[0]+=1; break; + case down: snake.y[0]-=1; break; + case left: snake.x[0]-=1; break; + case right: snake.x[0]+=1; break; + } +} + +static void Snake_Disp() // Game screen display +{ + uint8 p = 16; +// for(p=0;p> (snake.x[p]); + } +// DispRAM[food.y] |= 0x80 >> (food.x); + + MatxDisp(DispRAM,duty); + DisPoint(7-food.x,food.y); + delayus(duty); +} + +void Snake_Game() // Game Process +{ + Snake_Init(); // Initialize the game + Play_Music(sound_canon); + while(snake.life) // If there is life, then there is play. + { + uint8 i; + switch(keypad)// Snake game directly reads key-value pairs; no debouncing is needed. + { + case K_UP: if((snake.direc==left)||(snake.direc==right)) snake.direc=up; + // When the UP button is pressed, the snake can only change direction when it is in a horizontal position. + break; + case K_DOWN:if((snake.direc==left)||(snake.direc==right)) snake.direc=down; + // When the DOWN key is pressed, the snake can only be changed when it is in a horizontal position. + break; + case K_LEFT:if((snake.direc==up)||(snake.direc==down)) snake.direc=left; + // When the left key is pressed, the snake can only be changed when it is in a vertical direction. + break; + case K_RIGHT:if((snake.direc==up)||(snake.direc==down)) snake.direc=right; + // When the right key is pressed, the snake can only be changed when it is in a vertical direction. + break; + default : + break; + } + + if(KEY_OK==0) speeds = ASPEED;// Acceleration key + else speeds = NORSPEED; + keypad = K_NULL; + + if(tms > speeds) // Advance one square every half second + { + tms=0; + Snake_Run(); // A boring walk + } + if((snake.x[0]==food.x) && (snake.y[0]==food.y))// Did you eat any food? + { + Sound_Tone(sound_ON,4,5); +// getfood=1;// Increasing the snake length directly here will create a copy of the original data in the next scan, so lengthening it is necessary to... + snake.node++; +// game_speed-=10; // Each food item consumed increases speed by 10 points. + Create_Food(); // Producing new foods + } + if((snake.x[0]>WIDTH-1)||(snake.x[0]<0)||(snake.y[0]>LENGTH-1)||(snake.y[0]<0))// Have you hit a wall? + { + snake.life=0; // The snake died after hitting the wall. + } + for(i=3;i