|
给51黑电子论坛的朋友们分享一个很优秀的俄罗斯方块程序,lcd12864屏幕 是用普通的51单片机做的,P3.4口,短按就可以开始运行了。效果如下图所示:
完整的源码下载:
俄罗斯方块全部源码.zip
(147.88 KB, 下载次数: 599)
Tetris.c源程序文件内容:
- /*******************************************************
- * 文件名称:Tetris.c
- * 单 片 机:STC89C52RC
- * 简 述:使用LCD12864显示的俄罗斯方块程序
- * 功 能:计分,下一个方块预览,欢迎结束界面,长按连续左右移,暂停(按键Left+Turn)
- * 作 者:刘琦
- * 完成日期:4月21日
- * IO口设定:按键
- sbit key_sr_left=P3^7;
- sbit key_sr_turn=P3^6;
- sbit key_sr_right=P3^5;
- sbit key_sr_down=P3^4;
- LCD12864
- sbit RS_Port=P1^0;
- sbit RW_Port=P1^1;
- sbit E_Port=P2^5;
- sbit PSB_Port=P1^2;
- sbit RST_Port=P1^4;
- 数码管锁存器
- sbit dula=P2^6;
- sbit wela=P2^7;
-
- *******************************************************/
- /*****************************头文件区*****************************************************/
- #include<reg52.h>
- //#include"STC15F2K60S2.h"
- #include"task_key.h"
- #include"task_activation.h"
- #include"12864b.h"
- #include"TaskBlock.h"
- #include"Block.h"
- /*****************************宏定义区*****************************************************/
- //需要判断是否刷新的任务总数
- //1KeyLeft,2KeyTurn,3KeyRight,4KeyDown,5TaskGoingDown,6KeyPause
- #define NUM_TASK_FLAG 7
- //需要定时刷新的任务总数
- //1TaskGoingDown,2KeyService
- #define NUM_TASK_REFRESH 3
- //刷新频率
- #define TIME_PER_SEC 200 //每次进入中断的频率,200Hz
- #define TIME_CLOCK 11059200 //晶振频率
- #define TIME_KEY_SERVICE_50HZ TIME_PER_SEC/50 //按键服务频率,0.02s
- #define TIME_TASKGOINGDOWN_2HZ TIME_PER_SEC/2 //下落频率,0.5s
- /******************************子函数声明区***********************************************/
- void initial_myself(void);
- void initial_peripheral(void);
- void delay100ms(void);
- /******************************全局变量定义区***********************************************/
- unsigned char uc_state=1;//状态标示:1欢迎界面,2等待开始界面,3下落界面,4死亡界面,5暂停界面
- enum Block{S1,S2,Z1,Z2,L1,L2,L3,L4,J1,J2,J3,J4,I1,I2,O1,T_1,T_2,T_3,T_4}enumBlock;//方块编号
- unsigned char ucBlockNow=0;//当前方块
- unsigned char ucBlockNext=0;//下一个方块
- unsigned char ucFlagScreenChange=1;//界面变更标志,界面更改时置1,激活task_activation
- unsigned char ucCoordinate[2];//方块的旋转点坐标,横H,竖S
- unsigned char xdata ucxMap[10][20];//整张屏幕的标记地图,用来记录未消除方块位置,有方块则为1
- unsigned char ucxBlockPosition[4][2];//方块的4个小方块坐标,[0][0],[0][1]为旋转点坐标H,S
- unsigned int uc_delay_task_cnt[NUM_TASK_REFRESH];//任务刷新延迟
- unsigned char uc_flag_taskrefresh[NUM_TASK_FLAG];//任务刷新标志
- unsigned long int ucScore=0;//得分
- /******************************主函数开始***********************************************/
- void main(void)
- {
- unsigned char i=0;
- initial_myself();
- delay100ms();
- initial_peripheral();
- while(1)
- {
- if(ucFlagScreenChange==1)//界面变更标志为1时,进行任务激活,防止一直刷新界面
- {
- task_activation(uc_state);
- ucFlagScreenChange=0;
- }
- if(uc_delay_task_cnt[2]==0)//20HZ频率刷新key_service
- {
- task_key_service();
- ET0=0;//在中断中也有可能变化的变量在更改前时先关闭中断
- uc_delay_task_cnt[2]=TIME_KEY_SERVICE_50HZ;//延迟重置
- ET0=1;
- }
- if(uc_flag_taskrefresh[5]&&uc_delay_task_cnt[1]==0)//需要时,2HZ频率刷新TaskGoingDown
- {
- if(!TaskGoingDown())//下落失败
- {
- //将当前方块位置写入Map
- for(i=0;i<4;i++)
- {
- ucxMap[ ucxBlockPosition[i][0] ][ ucxBlockPosition[i][1] ]=1;
- }
- //调用消除方块函数
- TaskClear();
- }
- ET0=0;//在中断中也有可能变化的变量在更改前时先关闭中断
- uc_delay_task_cnt[1]=TIME_TASKGOINGDOWN_2HZ;//延迟重置
- ET0=1;
- }
- }
- }
- //中断函数
- void timer0(void) interrupt 1
- {
- unsigned char i;
- TR0=0;
- TH0=255-TIME_CLOCK/TIME_PER_SEC/12/256;
- TL0=255-TIME_CLOCK/TIME_PER_SEC/12%256;
- //task_delay[]减到0时,相应的函数准备就绪
- for(i=0;i<NUM_TASK_REFRESH;i++)
- {
- if(uc_delay_task_cnt[i]!=0)//延迟不为0时才减
- {uc_delay_task_cnt[i]--;};
- }
- task_key_scan();//按键扫描函数,放在中断中,保证准时扫描
- TR0=1;
- }
- //初始化区
- void initial_myself(void)//第一区 初始化单片机
- {
- unsigned char i;
- for(i=0;i<NUM_TASK_REFRESH;i++)uc_delay_task_cnt[i]=0;//初始化让所有任务就绪
- TMOD=0X21; //定时器0为16位不自动重装,用来定时;定时器1为8位自动重装,用来产生随机数
- TH0=255-TIME_CLOCK/TIME_PER_SEC/12/256;
- TL0=255-TIME_CLOCK/TIME_PER_SEC/12%256;
- TH1=0;
- TL1=0;
- }
- void initial_peripheral(void) //第二区 初始化外围
- {
- Lcd_Init();//初始化12864
- EA=1; //开总中断
- ET0=1; //允许定时器0中断,定时器1无需开启中断
- TR0=1; //启动定时器0
- TR1=1; //启动定时器1
- }
- void delay100ms(void) //@11.0592MHz
- {
- unsigned char i, j, k;
- ;
- ;
- i = 5;
- j = 52;
- k = 195;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
复制代码- /*******************************************************
- * 文件名称:task_activation.c
- * 单 片 机:STC89C52RC
- * 简 述:任务激活子程序,uc_state:1欢迎界面,2等待界面,3下落界面,4死亡界面
- * 作 者:刘琦
- * 完成日期:2015年5月1日
- *******************************************************/
- #include"reg52.h"
- #include"12864b.h"
- #include"tetris.h"
- #include"TaskBlock.h"
- #include"Score.h"
- //#include"STC15F2K60S2.h"
- #define xchar unsigned char code
- //欢迎词
- xchar CorpInf[]=
- {
- "来玩俄罗斯方块!"
- };
- //死亡词
- xchar CorpInf1[]=
- {
- "不好意思你死了!"
- };
- void task_activation(unsigned char state)
- {
- unsigned char i=0,j=0;
- switch(state)
- {
- case 1: //欢迎界面
- DisGBStr(CorpInf); //写入欢迎词
- //当前界面需要刷新的任务
- //1KeyLeft,2KeyTurn,3KeyRight,4KeyDown,5TaskGoingDown,6KeyPause
- uc_flag_taskrefresh[1]=0;
- uc_flag_taskrefresh[2]=0;
- uc_flag_taskrefresh[3]=0;
- uc_flag_taskrefresh[4]=1;
- uc_flag_taskrefresh[5]=0;
- uc_flag_taskrefresh[6]=0;
- break;
- case 2: //等待界面
- //清空所有显示
- Cram_Off(); //清空文本显示
- Clr_GDRAM(); //清空绘图显示
- //画出边框
- DrawLineY(7,1,62,1);
- DrawLineX(7,127,1,1);
- DrawLineX(7,127,62,1);
- //将地图数据清空
- for(i=0;i<10;i++)
- {
- for(j=0;j<20;j++)
- {
- ucxMap[i][j]=0;
- }
- }
- ucScore=0;//计分清0
- //当前界面需要刷新的任务
- //1KeyLeft,2KeyTurn,3KeyRight,4KeyDown,5TaskGoingDown,6KeyPause
- uc_flag_taskrefresh[1]=0;
- uc_flag_taskrefresh[2]=0;
- uc_flag_taskrefresh[3]=0;
- uc_flag_taskrefresh[4]=1;
- uc_flag_taskrefresh[5]=0;
- uc_flag_taskrefresh[6]=0;
- break;
- case 3: //下落界面
- TaskScore (); //写分,刷新最开始的0000000
- TaskComingNew(); //出新方块
- //当前界面需要刷新的任务
- //1KeyLeft,2KeyTurn,3KeyRight,4KeyDown,5TaskGoingDown,6KeyPause
- uc_flag_taskrefresh[1]=1;
- uc_flag_taskrefresh[2]=1;
- uc_flag_taskrefresh[3]=1;
- uc_flag_taskrefresh[4]=1;
- uc_flag_taskrefresh[5]=1;
- uc_flag_taskrefresh[6]=1;
- break;
- case 4: //死亡界面
- Cram_Off(); //清空文本显示
- Clr_GDRAM(); //清空绘图显示
- DisGBStr(CorpInf1);
- //当前界面需要刷新的任务
- //1KeyLeft,2KeyTurn,3KeyRight,4KeyDown,5TaskGoingDown,6KeyPause
- uc_flag_taskrefresh[1]=0;
- uc_flag_taskrefresh[2]=0;
- uc_flag_taskrefresh[3]=0;
- uc_flag_taskrefresh[4]=1;
- uc_flag_taskrefresh[5]=0;
- uc_flag_taskrefresh[6]=0;
- break;
- case 5: //暂停界面
- //当前界面需要刷新的任务
- //1KeyLeft,2KeyTurn,3KeyRight,4KeyDown,5TaskGoingDown,6KeyPause
- uc_flag_taskrefresh[1]=0;
- uc_flag_taskrefresh[2]=0;
- uc_flag_taskrefresh[3]=0;
- uc_flag_taskrefresh[4]=1;
- uc_flag_taskrefresh[5]=0;
- uc_flag_taskrefresh[6]=0;
- break;
- default:
- break;
- }
- }
复制代码- #include"reg52.h"
- //#include"STC15F2K60S2.h"
- #include"tetris.h"
- #include"Block.h"
- #include"TaskBlock.h"
- #define CONST_KEY_TIME 10 //按键去抖动延时的时间
- //#define const_time_0_25s 111 //0.25秒钟的时间需要的定时中断次数
- //#define const_time_0_5s 222 //0.5秒钟的时间需要的定时中断次数
- #define const_time_0_25s 60 //0.125秒钟的时间需要的定时中断次数
- #define const_time_0_5s 60 //0.125秒钟的时间需要的定时中断次数
- sbit key_sr_left=P3^7;
- sbit key_sr_turn=P3^6;
- sbit key_sr_right=P3^5;
- sbit key_sr_down=P3^4;
- unsigned char ucKeySec=0; //被触发的按键编号
- unsigned int uiKeyTimeCnt_left=0; //按键去抖动延时计数器
- unsigned int uiKeyCtntyCnt_left=0; //按键连续触发的间隔延时计数器
- unsigned char ucKeyLock_left=0; //按键触发后自锁的变量标志
- unsigned int uiKeyTimeCnt_turn=0; //按键去抖动延时计数器
- //unsigned int uiKeyCtntyCnt_turn=0; //按键连续触发的间隔延时计数器
- unsigned char ucKeyLock_turn=0; //按键触发后自锁的变量标志
- unsigned int uiKeyTimeCnt_right=0; //按键去抖动延时计数器
- unsigned int uiKeyCtntyCnt_right=0; //按键连续触发的间隔延时计数器
- unsigned char ucKeyLock_right=0; //按键触发后自锁的变量标志
- unsigned int uiKeyTimeCnt_down=0; //按键去抖动延时计数器
- unsigned char ucKeyLock_down=0; //按键触发后自锁的变量标志
- unsigned int uiKeyTimeCnt_pause=0; //按键去抖动延时计数器
- unsigned char ucKeyLock_pause=0; //按键触发后自锁的变量标志
- //放在中断中,其中的每个按键的标志位为1时才刷新
- void task_key_scan(void)
- {
- if(uc_flag_taskrefresh[1])
- {
- if(key_sr_left==1)//left
- {
- ucKeyLock_left=0;
- uiKeyTimeCnt_left=0;
- uiKeyCtntyCnt_left=0;
- }
- else if(ucKeyLock_left==0)
- {
- uiKeyTimeCnt_left++;
- if(uiKeyTimeCnt_left>CONST_KEY_TIME)
- {
- uiKeyTimeCnt_left=0;
- ucKeyLock_left=1;
- ucKeySec=1; //触发1号键,left
- }
- }
- else if(uiKeyTimeCnt_left<const_time_0_5s)
- {
- uiKeyTimeCnt_left++;
- }
- else
- {
- uiKeyCtntyCnt_left++;
- if(uiKeyCtntyCnt_left>const_time_0_25s)
- {
- uiKeyCtntyCnt_left=0;
- ucKeySec=1; //触发1号键,left
- }
- }
- }
- if(uc_flag_taskrefresh[2])
- {
- if(key_sr_turn==1)//turn
- {
- ucKeyLock_turn=0;
- uiKeyTimeCnt_turn=0;
- // uiKeyCtntyCnt_turn=0;
- }
- else if(ucKeyLock_turn==0)
- {
- uiKeyTimeCnt_turn++;
- if(uiKeyTimeCnt_turn>CONST_KEY_TIME)
- {
- uiKeyTimeCnt_turn=0;
- ucKeyLock_turn=1;
- ucKeySec=2; //触发2号键,turn
- }
- }
- }
- if(uc_flag_taskrefresh[3])
- {
- if(key_sr_right==1)//right
- {
- ucKeyLock_right=0;
- uiKeyTimeCnt_right=0;
- uiKeyCtntyCnt_right=0;
- }
- else if(ucKeyLock_right==0)
- {
- uiKeyTimeCnt_right++;
- if(uiKeyTimeCnt_right>CONST_KEY_TIME)
- {
- uiKeyTimeCnt_right=0;
- ucKeyLock_right=1;
- ucKeySec=3; //触发3号键,right
- }
- }
- else if(uiKeyTimeCnt_right<const_time_0_5s)
- {
- uiKeyTimeCnt_right++;
- }
- else
- {
- uiKeyCtntyCnt_right++;
- if(uiKeyCtntyCnt_right>const_time_0_25s)
- {
- uiKeyCtntyCnt_right=0;
- ucKeySec=3; //触发3号键,right
- }
- }
- }
- if(uc_flag_taskrefresh[4])
- {
- if(key_sr_down==1)//down
- {
- ucKeyLock_down=0; //按键自锁标志清零
- uiKeyTimeCnt_down=0;//按键去抖动延时计数器清零
- }
- else if(ucKeyLock_down==0)//有按键按下,且是第一次被按下,并且当前界面支持这个按键
- {
- uiKeyTimeCnt_down++; //累加定时中断次数
- if(uiKeyTimeCnt_down>CONST_KEY_TIME)
- {
- uiKeyTimeCnt_down=0;
- ucKeyLock_down=1; //自锁按键置位,避免一直触发
- ucKeySec=4; //触发4号键,down
- }
- }
- }
- if(uc_flag_taskrefresh[6])
- {
- if(key_sr_left==1||key_sr_turn==1)//pause,按键左和按键旋转未同时按下
- {
- ucKeyLock_pause=0; //按键自锁标志清零
- uiKeyTimeCnt_pause=0;//按键去抖动延时计数器清零
- }
- else if(ucKeyLock_pause==0)//有按键按下,且是第一次被按下
- {
- uiKeyTimeCnt_pause++; //累加定时中断次数
- if(uiKeyTimeCnt_pause>CONST_KEY_TIME)
- {
- uiKeyTimeCnt_pause=0;
- ucKeyLock_pause=1; //自锁按键置位,避免一直触发
- ucKeySec=6; //触发6号键,暂停
- }
- }
- }
- }
- //按键服务函数
- void task_key_service(void)
- {
- unsigned char ucCheck=0;
- unsigned char ucOldEnum=0;
- unsigned char ucNewEnum=0;
- unsigned char i=0;
- switch(ucKeySec) //按键服务状态切换
- {
- case 1:// 1号键,left
- ucCoordinate[0]++; //旋转点坐标H+1
- WriteBlockCoordinate(); //写入其他3个方块坐标
- ucCheck=TaskCheck(); //检测碰撞
- if(ucCheck) //未碰撞,则左移
- {
- ucCoordinate[0]--;
- ChangeBlock(0);
- ucCoordinate[0]++;
- ChangeBlock(1);
- }
- else //碰撞,不变
- {
- ucCoordinate[0]--;
- WriteBlockCoordinate();
- }
- break;
- case 2:// 2号键,turn
- ucOldEnum=enumBlock;
- switch(enumBlock) //旋转后改变方块编号
- {
- case S1:
- enumBlock=S2;
- break;
- case S2:
- enumBlock=S1;
- break;
- case Z1:
- enumBlock=Z2;
- break;
- case Z2:
- enumBlock=Z1;
- break;
- case L1:
- enumBlock=L2;
- break;
- case L2:
- enumBlock=L3;
- break;
- case L3:
- enumBlock=L4;
- break;
- case L4:
- enumBlock=L1;
- break;
- case J1:
- enumBlock=J2;
- break;
- case J2:
- enumBlock=J3;
- break;
- case J3:
- enumBlock=J4;
- break;
- case J4:
- enumBlock=J1;
- break;
- case I1:
- enumBlock=I2;
- break;
- case I2:
- enumBlock=I1;
- break;
- case O1:
- enumBlock=O1;
- break;
- case T_1:
- enumBlock=T_2;
- break;
- case T_2:
- enumBlock=T_3;
- break;
- case T_3:
- enumBlock=T_4;
- break;
- case T_4:
- enumBlock=T_1;
- break;
- default:
- break;
- }
- WriteBlockCoordinate();
- ucCheck=TaskCheck();
- if(ucCheck)
- {
- ucNewEnum=enumBlock;
- enumBlock=ucOldEnum;
- ChangeBlock(0);
- enumBlock=ucNewEnum;
- ChangeBlock(1);
- }
- else
- {
- enumBlock=ucOldEnum;
- WriteBlockCoordinate();
- }
- break;
- case 3:// 3号键,right
- ucCoordinate[0]--;
- WriteBlockCoordinate();
- ucCheck=TaskCheck();
- if(ucCheck)
- {
- ucCoordinate[0]++;
- ChangeBlock(0);
- ucCoordinate[0]--;
- ChangeBlock(1);
- }
- else
- {
- ucCoordinate[0]++;
- WriteBlockCoordinate();
- }
- break;
- case 4:// 4号键,down
- //根据所处界面不同,按键down的功能不同
- switch(uc_state)
- {
- case 1:
- ucBlockNow=TL1%7; //准备进入等待界面,就先产生当前随机方块
- uc_state=2; //进入等待界面
- ucFlagScreenChange=1; //激活界面变更
- break;
- case 2:
- uc_state=3; //进入下落界面
- ucFlagScreenChange=1;
- break;
- case 3: //在下落界面下,down为直接下落到底
- ET0=0;//关闭计时器0,出新后开启,防止直接下落
- ChangeBlock(0); //先清除当前的图形
- do //循环模拟下落并检测,直到失败
- {
- ucCoordinate[1]++;
- WriteBlockCoordinate();
- ucCheck=TaskCheck();
- }
- while(ucCheck);
- ucCoordinate[1]--; //恢复到最后一次成功的坐标
- WriteBlockCoordinate();
- ChangeBlock(1); //画方块
- //立即写入,并消除,防止到底后还可以移动
- //写入Map
- for(i=0;i<4;i++)
- {
- ucxMap[ ucxBlockPosition[i][0] ][ ucxBlockPosition[i][1] ]=1;
- }
- //调用消除
- TaskClear();
- //刷新下落延迟,防止出新后,直接下落
- ET0=1;
- break;
- case 4: //死亡界面
- ucBlockNow=TL1%7; //准备进入等待界面,就先产生当前随机方块
- uc_state=2; //进入等待界面
- ucFlagScreenChange=1;
- break;
- case 5: //暂停界面
- uc_state=3; //进入下落界面
- //开启下落界面时的相关任务
- uc_flag_taskrefresh[1]=1;
- uc_flag_taskrefresh[2]=1;
- uc_flag_taskrefresh[3]=1;
- uc_flag_taskrefresh[4]=1;
- uc_flag_taskrefresh[5]=1;
- uc_flag_taskrefresh[6]=1;
- break;
- }
- break;
- case 6:// 6号键,pause
- uc_state=5;
- ucFlagScreenChange=1;
- break;
- default:
- break;
- }
- ucKeySec=0;
- }
复制代码
|
评分
-
查看全部评分
|