找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7703|回复: 15
收起左侧

51单片机+LCD12864俄罗斯方块游戏程序+PCB+Proteus仿真

  [复制链接]
ID:577864 发表于 2019-7-4 16:43 | 显示全部楼层 |阅读模式
Altium Designer画的基于51单片机的俄罗斯方块电路原理图和PCB图如下:(51hei附件中可下载工程文件)
0.png 0.png 0.png

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.png 0.png 0.png

                                               俄罗斯方块元件清单        
元件编号    参数    数量
R11    10K电阻    1
C2    10uF电解电容    1
Y1    12M晶振    1
C1, C3    30pf瓷片电容    2
VR1    103滑动变阻器    1
P4    4针插针    1
LCD1    LCD12864液晶    1
U1    STC89C51单片机    1
K1, K2, K3, K4, K5, K6    大按键    6
K7    小轻触按键    1
J1    电源接口    1
SW1    自锁开关    1

单片机源程序如下:
  1. #include <REGX52.H>
  2. #include"pic.c"
  3. #include <intrins.h>
  4. #define LCD_DATA P2
  5. #define button_delay 150  //按键延时
  6. #define button_acceleration 65  //按键加速度阈值
  7. #define GAME_LOCATION 30
  8. sbit button_a = P3^4;         //变形
  9. sbit button_b = P3^5;        //开始
  10. sbit up = P3^2;           //暂停开始
  11. sbit down = P3^0;
  12. sbit left = P3^1;
  13. sbit right = P3^3;
  14. sbit speaker=P3^6;

  15. sbit LCD_RS=P1^0;
  16. sbit LCD_RW=P1^1;
  17. sbit LCD_E=P1^2;
  18. sbit LCD_CS2=P1^4;                //右屏选择(左右屏有时候相反)
  19. sbit LCD_CS1=P1^3;                //左屏选择
  20. sbit LCD_RST=P3^7;

  21. unsigned int up_reg=button_delay;       //按键up累加器
  22. unsigned int down_reg=button_delay;     //按键down累加器
  23. unsigned int left_reg=button_delay;     //按键left累加器
  24. unsigned int right_reg=button_delay;    //按键right累加器
  25. unsigned int button_a_reg=button_delay; //按键button_a累加器
  26. unsigned int button_b_reg=button_delay; //按键button_b累加器
  27. unsigned int right_acceleration=0;                //按键right加速度寄存器
  28. unsigned int left_acceleration=0;                //按键left加速度寄存器

  29. unsigned int idata Box_Ram[19];//定义游戏点阵缓存10*16
  30. unsigned char box_down_reg;//定义方块下落累加寄存器
  31. unsigned char time0_reg;//定义定时器0累加寄存器
  32. unsigned char next_mode;//定义下一个方块的类型
  33. unsigned char next_shape;//定义下一个方块的形状
  34. unsigned int destroy_row_num=0;//定义所消的行数
  35. unsigned char speed_num=0;//定义游戏速度等级
  36. unsigned char level_num;//定义游戏难度等级
  37. bit game_over_flag;//游戏结束标志位置0表示游戏未结束
  38. bit pause_game_flag;//游戏暂停标志位置0表示游戏未暂停

  39. struct
  40. {
  41.         unsigned char mode;//类型
  42.         unsigned char shape;//形状
  43.         unsigned char x;//x坐标
  44.         unsigned char y;//y坐标
  45.         unsigned int box;//定义方块缓存
  46. }s_box;        //定义方块结构体
  47. //LCD检测忙状态函数
  48. void LCD_check_busy()
  49. {
  50.         unsigned char temp;
  51.         LCD_RS=0;
  52.         LCD_RW=1;
  53.         do
  54.         {
  55.                 LCD_DATA=0xff;
  56.                 LCD_E=1;
  57.                 temp=LCD_DATA;
  58.                 LCD_E=0;
  59.         }while((temp&0x80)==0x80);               
  60. }
  61. //写指令代码(cs为0选左屏,cs为1选右屏)
  62. void LCD_W_code(unsigned char tpcode,bit cs)
  63. {
  64.         LCD_RS=0;
  65.         LCD_RW=0;
  66.         LCD_CS2=~cs;
  67.         LCD_CS1=cs;
  68.         LCD_DATA=tpcode;
  69.         LCD_E=1;
  70.         _nop_();
  71.         LCD_E=0;
  72. }
  73. //写显示数据(cs为0选左屏,cs为1选右屏)
  74. void LCD_W_data(unsigned char tpdata,bit cs)
  75. {
  76.         LCD_check_busy();
  77.         LCD_RS=1;
  78.         LCD_RW=0;
  79.         LCD_CS2=~cs;
  80.         LCD_CS1=cs;       
  81.         LCD_DATA=tpdata;
  82.         LCD_E=1;       
  83.         _nop_();
  84.         LCD_E=0;
  85. }

  86. //LCD初始化函数
  87. void LCD_initialize()
  88. {
  89.         LCD_RST=0;
  90.         _nop_();
  91.         _nop_();
  92.         LCD_RST=1;
  93.         LCD_W_code(0x3f,0);                //开显示设置       
  94.         LCD_W_code(0xc0,0);                //设置显示起始行为第一行       
  95.         LCD_W_code(0xb8,0);                //页面地址设置       
  96.         LCD_W_code(0x40,0);                //列地址设为0
  97.         LCD_W_code(0x3f,1);
  98.         LCD_W_code(0xc0,1);       
  99.         LCD_W_code(0xb8,1);
  100.         LCD_W_code(0x40,1);
  101. }
  102. //LCD清屏函数
  103. void LCD_clear()
  104. {
  105.         unsigned char i,j;
  106.         for(j=0;j<8;j++)
  107.         {
  108.                 LCD_W_code(0xb8+j,0);
  109.                 LCD_W_code(0x40,0);
  110.                 LCD_W_code(0xb8+j,1);
  111.                 LCD_W_code(0x40,1);
  112.                 for(i=0;i<64;i++)
  113.                         {       
  114.                                 LCD_W_data(0x00,0);       
  115.                                 LCD_W_data(0x00,1);
  116.                         }
  117.         }
  118. }
  119. //LCD显示字符串函数(word表示要显示的字符串,
  120. //length表示要显示的字符串宽度,
  121. //x表示首字符所在行数,
  122. //y表示首字符所在列数)
  123. void LCD_display_word(unsigned char word[],
  124.                       unsigned int length,
  125.                                           unsigned char x,
  126.                                           unsigned char y)
  127. {
  128.         unsigned char i;
  129.         for(i=0;i<length;i++)
  130.         {
  131.                
  132.                 LCD_W_code(0xb8+x,0);
  133.                 LCD_W_code(0xb8+x,1);
  134.                 if(y+i<64)
  135.                 {
  136.                         LCD_W_code(0x40+y+i,0);       
  137.                         LCD_W_data(word[i],0);
  138.                 }
  139.                 else
  140.                 {
  141.                         LCD_W_code(y+i,1);       
  142.                         LCD_W_data(word[i],1);
  143.                 }
  144.         }
  145. }
  146. //LCD画全屏函数
  147. void LCD_full_draw(unsigned char word[])
  148. {
  149.         unsigned char i,j;
  150.         for(i=0;i<8;i++)
  151.         {
  152.                 LCD_W_code(0xb8+i,0);
  153.                 LCD_W_code(0x40,0);       
  154.                 for(j=0;j<64;j++)
  155.                 {
  156.                         LCD_W_data(word[i*128+j],0);
  157.                 }
  158.                 LCD_W_code(0xb8+i,1);
  159.                 LCD_W_code(0x40,1);       
  160.                 for(j=0;j<64;j++)
  161.                 {
  162.                         LCD_W_data(word[i*128+64+j],1);
  163.                 }                       
  164.         }
  165. }
  166. //LCD显示一个字节函数(
  167.   //x表示x坐标,
  168.   //y表示y坐标,
  169.   //tpdata表示要显示的数据)
  170. void LCD_display_byte(unsigned char x,
  171.                                           unsigned char y,
  172.                                           unsigned char tpdata)
  173. {
  174.         if(x<64)
  175.         {
  176.                 LCD_W_code(0xb8+y,0);
  177.                 LCD_W_code(0x40+x,0);
  178.                 LCD_W_data(tpdata,0);       
  179.         }
  180.         else
  181.         {
  182.                 LCD_W_code(0xb8+y,1);
  183.                 LCD_W_code(x,1);
  184.                 LCD_W_data(tpdata,1);       
  185.         }
  186. }

  187. void LCD_draw(unsigned char word[])
  188. {
  189.   unsigned char i,j;
  190.   for(i=0;i<8;i++)
  191.   {
  192.     LCD_W_code(0xb8+i,1);
  193.         LCD_W_code(0x40+20,1);
  194.         for(j=0;j<44;j++)
  195.         {
  196.           LCD_W_data(word[i*44+j],1);
  197.         }
  198.   }
  199. }
  200. //基本界面显示函数
  201. void display_basic()
  202. {
  203.         unsigned char i;
  204.         for(i=0;i<8;i++)
  205.         {
  206.                 LCD_display_byte(GAME_LOCATION,i,0xff);
  207.                 LCD_display_byte(GAME_LOCATION+41,i,0xff);
  208.         }
  209. }
  210. //刷新游戏区域函数
  211. void refurbish_display()
  212. {
  213.         unsigned char i,j,tpdata;
  214.         for(i=0;i<8;i++)
  215.         {
  216.                 for(j=0;j<10;j++)
  217.                 {
  218.                         tpdata=0x00;
  219.                         if(  (Box_Ram[2*i]>>(12-j))&0x0001==1  )
  220.                         {
  221.                                 tpdata=0x0f;
  222.                         }
  223.                         if(  (Box_Ram[2*i+1]>>(12-j))&0x0001==1  )
  224.                         {
  225.                                 tpdata|=0xf0;
  226.                         }
  227.                         LCD_display_byte(GAME_LOCATION+1+j*4,i,tpdata);
  228.                         LCD_display_byte(GAME_LOCATION+2+j*4,i,0xbb&tpdata);
  229.                         LCD_display_byte(GAME_LOCATION+3+j*4,i,0xdd&tpdata);
  230.                         LCD_display_byte(GAME_LOCATION+4+j*4,i,tpdata);
  231.                 }
  232.         }
  233. }
  234. //基本按键程序(返回0表示没按键被按下,返回1表示down被按下,返回2表示up被按下,返回3表示button_a被按下,返回4表示left被按下,返回5表示right被按下)
  235. //游戏中按键识别程序(有优先级,从高到低依次是button_a_reg>down>left>right>up)
  236. unsigned char basic_button()
  237. {
  238.         unsigned char tpflag=0;
  239.         if(button_b==0)
  240.         {
  241.             if(button_b_reg<button_delay*8)
  242.                 {
  243.                   button_b_reg++;
  244.                 }
  245.                 else
  246.                 {
  247.                   button_b_reg=0;
  248.                   tpflag=6;
  249.                 }
  250.         }
  251.         else
  252.         {
  253.                 button_b_reg=button_delay*8;
  254.         }
  255.         if(down==0)
  256.         {
  257.                 if(down_reg<button_delay)//按键一直被按下时设置时间间隔触发
  258.                 {
  259.                         down_reg++;
  260.                 }
  261.                 else
  262.                 {
  263.                         down_reg=0;
  264.                         tpflag=1;//返回1表示down被按下
  265.                 }               
  266.         }
  267.         else
  268.         {
  269.                 down_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
  270.         }
  271.         if(up==0)
  272.         {
  273.                 if(up_reg<button_delay)//按键一直被按下时设置时间间隔触发
  274.                 {
  275.                         up_reg++;
  276.                 }
  277.                 else
  278.                 {
  279.                         up_reg=0;
  280.                         tpflag=2;//返回2表示up被按下
  281.                 }               
  282.         }
  283.         else
  284.         {
  285.                 up_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
  286.         }
  287.         if(button_a==0)
  288.         {
  289.                 if(button_a_reg<button_delay*8)//按键一直被按下时设置时间间隔触发
  290.                 {
  291.                         button_a_reg++;
  292.                 }
  293.                 else
  294.                 {
  295.                         button_a_reg=0;
  296.                         tpflag=3;//返回3表示button_a被按下
  297.                 }               
  298.         }
  299.         else
  300.         {
  301.                 button_a_reg=button_delay*8;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
  302.         }
  303.         if(left==0)
  304.         {
  305.                 if(left_reg<(button_delay))//按键一直被按下时设置时间间隔触发
  306.                 {
  307.                         left_reg++;
  308.                 }
  309.                 else
  310.                 {
  311.                         left_reg=left_acceleration*button_acceleration;
  312.                         if(left_acceleration<2)left_acceleration++;
  313.                         tpflag=4;//返回4表示left被按下
  314.                 }               
  315.         }
  316.         else
  317.         {
  318.                 left_acceleration=0;
  319.                 left_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
  320.         }
  321.         if(right==0)
  322.         {
  323.                 if(right_reg<(button_delay))//按键一直被按下时设置时间间隔触发
  324.                 {
  325.                         right_reg++;
  326.                 }
  327.                 else
  328.                 {
  329.                         right_reg=right_acceleration*button_acceleration;
  330.                         if(right_acceleration<2)right_acceleration++;
  331.                         tpflag=5;//返回5表示right被按下
  332.                 }               
  333.         }
  334.         else
  335.         {
  336.                 right_acceleration=0;
  337.                 right_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
  338.         }
  339.         return(tpflag);
  340. }
  341. //检查覆盖函数(检查此时带入的参数所确定的方块是否会覆盖原有图形,不会覆盖返回1,覆盖返回0)
  342. bit check_cover(unsigned char tpx,unsigned char tpy,unsigned int tpbox)
  343. {
  344.         unsigned char i;
  345.         bit tpflag=1;
  346.         unsigned int temp;
  347.         temp=s_box.box;
  348.         for(i=0;i<4;i++)
  349.         {
  350.                 Box_Ram[3-i+s_box.y]&=(~((temp&0x000f)<<(9-s_box.x)));
  351.                 temp=temp>>4;
  352.         }//先将现有的方块从游戏点阵缓存中删除
  353.         temp=tpbox;
  354.         for(i=0;i<4;i++)
  355.         {
  356.                 if((((temp&0x000f)<<(9-tpx))&Box_Ram[3-i+tpy])!=0x0000)
  357.                 {
  358.                         tpflag=0;
  359.                 }
  360.                 temp=temp>>4;
  361.         }//检查方块是否和原有图形重叠,重叠置标志位tpflag为0,不重叠不置标志位,即tpflag为1
  362.         temp=s_box.box;
  363.         for(i=0;i<4;i++)
  364.         {
  365.                 Box_Ram[3-i+s_box.y]|=((temp&0x000f)<<(9-s_box.x));
  366.                 temp=temp>>4;
  367.         }//在游戏点阵缓存中恢复原有方块
  368.         return(tpflag);
  369. }
  370. //方块缓存数据函数(输入方块类型和形状即可获得方块缓存数据)
  371. unsigned int box_read_data(unsigned char tpmode,unsigned char tpshape)
  372. {
  373.         unsigned int tpbox;
  374.         switch(tpmode)
  375.         {
  376.                 case 0: switch(tpshape)
  377.                                 {
  378.                                         case 0: tpbox=0xf000;break;
  379.                                         case 1: tpbox=0x4444;break;
  380.                                         case 2: tpbox=0xf000;break;
  381.                                         case 3: tpbox=0x4444;break;
  382.                                         default:;
  383.                                 }break;       
  384.                 case 1: switch(tpshape)
  385.                                 {
  386.                                         case 0: tpbox=0xe800;break;
  387.                                         case 1: tpbox=0xc440;break;
  388.                                         case 2: tpbox=0x2e00;break;
  389.                                         case 3: tpbox=0x88c0;break;
  390.                                         default:;
  391.                                 }break;       
  392.                 case 2: switch(tpshape)
  393.                                 {
  394.                                         case 0: tpbox=0xe200;break;
  395.                                         case 1: tpbox=0x44c0;break;
  396.                                         case 2: tpbox=0x8e00;break;
  397.                                         case 3: tpbox=0xc880;break;
  398.                                         default:;
  399.                                 }break;       
  400.                 case 3: switch(tpshape)
  401.                                 {
  402.                                         case 0: tpbox=0xcc00;break;
  403.                                         case 1: tpbox=0xcc00;break;
  404.                                         case 2: tpbox=0xcc00;break;
  405.                                         case 3: tpbox=0xcc00;break;
  406.                                         default:;
  407.                                 }break;       
  408.                 case 4: switch(tpshape)
  409.                                 {
  410.                                         case 0: tpbox=0xc600;break;
  411.                                         case 1: tpbox=0x4c80;break;
  412.                                         case 2: tpbox=0xc600;break;
  413.                                         case 3: tpbox=0x4c80;break;
  414.                                         default:;
  415.                                 }break;       
  416.                 case 5: switch(tpshape)
  417.                                 {
  418.                                         case 0: tpbox=0x6c00;break;
  419.                                         case 1: tpbox=0x8c40;break;
  420.                                         case 2: tpbox=0x6c00;break;
  421.                                         case 3: tpbox=0x8c40;break;
  422.                                         default:;
  423.                                 }break;
  424.                 case 6: switch(tpshape)
  425.                                 {
  426.                                         case 0: tpbox=0x4e00;break;
  427.                                         case 1: tpbox=0x8c80;break;
  428.                                         case 2: tpbox=0xe400;break;
  429.                                         case 3: tpbox=0x4c40;break;
  430.                                         default:;
  431.                                 }break;
  432.                 default:;
  433.         }
  434.         return(tpbox);
  435. }
  436. //方块载入函数
  437. void box_load()
  438. {
  439.         s_box.box=box_read_data(s_box.mode,s_box.shape);
  440. }
  441. //方块映射游戏点阵缓存函数(参数是原来方块的位置、缓存,先消去原有位置的方块)
  442. void box_to_Box_Ram(unsigned char tpx,unsigned char tpy,unsigned int tpbox)
  443. {
  444.         unsigned char i;
  445.         unsigned int temp;
  446.         temp=tpbox;
  447.         for(i=0;i<4;i++)
  448.         {
  449.                 Box_Ram[3-i+tpy]=Box_Ram[3-i+tpy]&(~((temp&0x000f)<<(9-tpx)));
  450.                 temp=temp>>4;
  451.         }//从游戏点阵缓存中删除以前的方块
  452.         temp=s_box.box;
  453.         for(i=0;i<4;i++)
  454.         {
  455.                 Box_Ram[3-i+s_box.y]=((temp&0x000f)<<(9-s_box.x))|Box_Ram[3-i+s_box.y];
  456.                 temp=temp>>4;
  457.         }//在游戏点阵缓存中加入新的方块
  458. }
  459. //显示数字函数(
  460.   //x表示x坐标,
  461.   //y表示y坐标,
  462.   //tpdata表示要显示的数字)
  463. //显示速度函数
  464. void show_num(unsigned char x,
  465.                                           unsigned char y,
  466.                                           unsigned char tpdata)
  467. {
  468.         unsigned char i;
  469.         for(i=0;i<4;i++)
  470.         {
  471.                 LCD_display_byte(x+i,y,num_data[tpdata*4+i]);       
  472.         }
  473. }
  474. void show_speed_num(unsigned char x,unsigned char y)
  475. {
  476.         show_num(x,y,speed_num);
  477. }
  478. //显示得分函数
  479. void show_score_num(unsigned char x,unsigned char y)
  480. {
  481.         show_num(x,y,destroy_row_num/10000);
  482.         show_num(x+=5,y,(destroy_row_num%10000)/1000);
  483.         show_num(x+=5,y,(destroy_row_num%1000)/100);
  484.         show_num(x+=5,y,(destroy_row_num%100)/10);
  485.         show_num(x+=5,y,destroy_row_num%10);
  486. }
  487. //消行函数
  488. void destroy_row()
  489. {
  490.         unsigned char i,j=0;
  491.         unsigned char tpflag[4]={0,0,0,0};//最多一次只能消四行,所以设置四个标志位即可,初值为0
  492.         for(i=0;i<16;i++)
  493.         {
  494.                 if((Box_Ram[i]&0x3ffc)==0x3ffc)
  495.                 {
  496.                         tpflag[j]=i+1;//tpflag为0表示不标志,1表示第0行缓存为0xffff,n表示第n+1行缓存为0xffff
  497.                         destroy_row_num++;//消除的行数加一
  498.                         /*如不把Box_Ram[19]定义成idata类型的话加入这段代码显示数据区就溢出了*/
  499.                         if(destroy_row_num%30==0&&speed_num!=9)
  500.                         {
  501.                                 speed_num++;//消够三十行游戏速度加一
  502.                                 show_speed_num(13,4);//调用显示游戏速度函数
  503.                         }
  504.                         /*如不把Box_Ram[19]定义成idata类型的话加入这段代码显示数据区就溢出了*/
  505.                         j++;
  506.                         if(j==4)
  507.                         {
  508.                                 break;
  509.                         }//检查完有四行要消除则退出检查循环
  510.                 }
  511.         }//依次检测是否有行缓存为0xffff,如果是则标志tpflag为此行的行号
  512.         for(j=0;j<4;j++)
  513.         {
  514.                 if(tpflag[j]!=0)
  515.                 {
  516.                         for(i=tpflag[j]-1;i>0;i--)
  517.                         {
  518.                         Box_Ram[i]=Box_Ram[i-1];
  519.                         Box_Ram[0]=0x2004;
  520.                         }
  521.                 }
  522.         }//被标志的行依次被上一行所取代,即被消去
  523.         show_score_num(3,1);
  524. }
  525. //显示下一个方块函数
  526. void show_next_box()
  527. {
  528.         unsigned char i,tpdata;
  529.         unsigned int temp;
  530.         temp=box_read_data(next_mode,next_shape);
  531.         for(i=0;i<4;i++)
  532.         {
  533.                 tpdata=0x00;
  534.                 if(  ((temp>>(15-i))&0x0001)==1  )
  535.                 {
  536.                         tpdata=0x0f;
  537.                 }
  538.                 if(  ((temp>>(11-i))&0x0001)==1  )
  539.                 {
  540.                         tpdata|=0xf0;
  541.                 }
  542.                 LCD_display_byte(7+i*4,6,tpdata);
  543.                 LCD_display_byte(8+i*4,6,0xbb&tpdata);
  544.                 LCD_display_byte(9+i*4,6,0xdd&tpdata);
  545.                 LCD_display_byte(10+i*4,6,tpdata);       
  546.                 tpdata=0x00;
  547.                 if(  ((temp>>(7-i))&0x0001)==1  )
  548.                 {
  549.                         tpdata=0x0f;
  550.                 }
  551.                 if(  ((temp>>(3-i))&0x0001)==1  )
  552.                 {
  553.                         tpdata|=0xf0;
  554.                 }
  555.                 LCD_display_byte(7+i*4,7,tpdata);
  556.                 LCD_display_byte(8+i*4,7,0xbb&tpdata);
  557.                 LCD_display_byte(9+i*4,7,0xdd&tpdata);
  558.                 LCD_display_byte(10+i*4,7,tpdata);               
  559.         }
  560. }
  561. //方块生成函数
  562. void box_build()
  563. {
  564.         s_box.mode=next_mode;
  565.         s_box.shape=next_shape;
  566.         s_box.x=3;
  567.         s_box.y=0;
  568.         next_mode=TL0%7;//产生随机数,但是是伪随机的
  569.         next_shape=TL0%4;//产生随机数,但是是伪随机的
  570.         show_next_box();//放到game_execute()函数中不知道为什么就是不正常显示
  571. }
  572. void game_button()
  573. {
  574.        
  575.     switch(basic_button())
  576.     {
  577.         case 3: if(s_box.y!=0)//3表示button_a被按下
  578.                 {
  579.                     EA=0;//关中断,如果不关的话可能引起游戏显示混乱
  580.                     speaker=0;
  581.                     if(s_box.shape==3&&check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,0)))
  582.                     {
  583.                                                        
  584.                         s_box.shape=0;
  585.                         box_load();
  586.                         box_to_Box_Ram(s_box.x,s_box.y,box_read_data(s_box.mode,3));
  587.                     }
  588.                     else if(check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,0)))
  589.                     {        if(check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,s_box.shape+1)))
  590.                                                         {       
  591.                                                                 s_box.shape++;
  592.                                                                 box_load();
  593.                                                                 box_to_Box_Ram(s_box.x,s_box.y,box_read_data(s_box.mode,s_box.shape-1));
  594.                                                         }
  595.                      }
  596.                     EA=1;//开中断
  597.                     speaker=1;
  598.                                         }break;
  599.         case 1: if(s_box.y!=0)//1表示down被按下
  600.         {
  601.             EA=0;//关中断,如果不关的话可能引起游戏显示混乱
  602.             speaker=0;
  603.             while(check_cover(s_box.x,s_box.y+1,s_box.box))//检测是否能下降,指导不能再下降为止
  604.             {
  605.                 s_box.y++;
  606.                 box_to_Box_Ram(s_box.x,s_box.y-1,s_box.box);
  607.             }
  608.             destroy_row();
  609.             box_build();
  610.             box_load();
  611.                                         //        game_over_flag=check_game_over();//游戏结束标志位置1表示游戏结束
  612.                                         //        next_box();
  613.             box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
  614.             EA=1;//开中断
  615.             speaker=1;
  616.             }break;
  617.         case 4: if(s_box.y!=0)//4表示left被按下
  618.         {
  619.             EA=0;//关中断,如果不关的话可能引起游戏显示混乱
  620.             speaker=0;
  621.             if(check_cover(s_box.x-1,s_box.y,s_box.box))
  622.             {
  623.                 s_box.x--;
  624.                 box_to_Box_Ram(s_box.x+1,s_box.y,s_box.box);
  625.             }
  626.             EA=1;//开中断
  627.             speaker=1;
  628.         }break;
  629.         case 5: if(s_box.y!=0)//5表示right被按下
  630.                 {
  631.                     EA=0;//关中断,如果不关的话可能引起游戏显示混乱
  632.                     speaker=0;
  633.                     if(check_cover(s_box.x+1,s_box.y,s_box.box))
  634.                     {
  635.                         s_box.x++;
  636.                         box_to_Box_Ram(s_box.x-1,s_box.y,s_box.box);
  637.                     }
  638.                                                 EA=1;//开中断
  639.                                                 speaker=1;
  640.                                         }break;
  641.         case 2: //2表示up被按下
  642.             speaker=0;
  643.             pause_game_flag=~pause_game_flag;//游戏暂停标志取反
  644.             while(up==0);
  645.             speaker=1;
  646.             break;
  647.         default:;
  648.     }       
  649. }
  650. //检查游戏结束函数(游戏结束返回1,游戏没有结束返回0)
  651. bit check_game_over()
  652. {
  653.         unsigned char i;
  654.         bit tpflag=0;
  655.         unsigned int temp;
  656.         temp=s_box.box;
  657.         for(i=0;i<4;i++)
  658.         {
  659.                 if((((temp&0x000f)<<(9-s_box.x))&Box_Ram[3-i+s_box.y])!=0x0000)
  660.                 {
  661.                         tpflag=1;
  662.                 }
  663.                 temp=temp>>4;
  664.         }//检查新建方块是否和原有图形重叠,重叠置标志位tpflag为1,不重叠不置标志位,即tpflag为0
  665.         return(tpflag);
  666. }
  667. //游戏执行函数(控制方块下落,检测是否到底,如果到底调用消行函数)
  668. void game_execute()
  669. {
  670.         if(box_down_reg<20-(speed_num<<1))
  671.         {                                  
  672.                 box_down_reg++;
  673.         }
  674.         else
  675.         {
  676.                 box_down_reg=0;
  677.                 if(check_cover(s_box.x,s_box.y+1,s_box.box))
  678.                 {
  679.                         s_box.y++;
  680.                         box_to_Box_Ram(s_box.x,s_box.y-1,s_box.box);
  681.                 }//检测是否还可以下降,如果还能下降则继续下降
  682.                 else
  683.                 {
  684.                         destroy_row();
  685.                         box_build();
  686.                         box_load();
  687.                         game_over_flag=check_game_over();//游戏结束标志位置1表示游戏结束
  688.                         box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
  689.                         box_down_reg=(20-(speed_num<<1)-1);//为了使方块一出现就能变换形状,所以需要尽快使得方块下降一行,不知道为什么最高行不能变换形状
  690.                 }//如果不能下降则调用消行函数检查是否可以消行,之后重新建立方块
  691.         }       
  692. }
  693. //选择游戏速度函数
  694. void select_speed()
  695. {
  696.         unsigned char i;
  697.         bit tpflag=1;//置循环标志位为1
  698.         LCD_clear();
  699.         for(i=0;i<128;i++)
  700.         {
  701.                 LCD_display_byte(i,0,0xff);
  702.                 LCD_display_byte(i,7,0xff);
  703.         }
  704.         LCD_display_byte(60,4,0x7f);
  705.         LCD_display_byte(59,4,0x3e);
  706.         LCD_display_byte(58,4,0x1c);
  707.         LCD_display_byte(57,4,0x08);
  708.         LCD_display_byte(67,4,0x7f);
  709.         LCD_display_byte(68,4,0x3e);
  710.         LCD_display_byte(69,4,0x1c);
  711.         LCD_display_byte(70,4,0x08);
  712.         LCD_display_word(speed_data,24,3,52);
  713.         show_speed_num(62,4);
  714.         while(tpflag)
  715.         {
  716.                 switch(basic_button())
  717.                 {
  718.                         case 4: if(speed_num!=0)
  719.                                         {
  720.                                                 speaker=0;
  721.                                                 speed_num--;
  722.                                                 show_speed_num(62,4);
  723.                                                 speaker=1;
  724.                                         }
  725.                                         while(left==0);
  726.                                         break;
  727.                         case 5: if(speed_num!=9)
  728.                                         {
  729.                                             speaker=0;
  730.                                                 speed_num++;
  731.                                                 show_speed_num(62,4);
  732.                                                 speaker=1;
  733.                                         }
  734.                                         while(right==0);
  735.                                         break;
  736.                         case 6: tpflag=0;
  737.                                  speaker=0;
  738.                                         while(button_b==0);
  739.                                         speaker=1;
  740.                                         break;
  741.                         default:;
  742.                 }
  743.         }//选择游戏速度循环
  744. }
  745. //游戏开始显示画面
  746. void game_start_show()
  747. {
  748.         bit tpflag=1;//置循环标志位为1
  749.         LCD_full_draw(start_pic);
  750.         while(tpflag)
  751.         {
  752.                 switch(basic_button())
  753.                 {
  754.                         case 6: tpflag=0;
  755.                                 speaker=0;
  756.                                         while(button_b==0);
  757.                                         speaker=1;
  758.                                         break;
  759.                         default:;
  760.                 }
  761.         }//game_start_show循环
  762. }
  763. //游戏初始化函数
  764. void game_initialize()
  765. {
  766.         box_down_reg=0;
  767.         next_mode=6;
  768.         next_shape=2;
  769.         destroy_row_num=0;
  770.         game_over_flag=0;
  771.         pause_game_flag=0;
  772.         LCD_clear();
  773.         time0_reg=0;
  774.         display_basic();       
  775.         LCD_display_word(score_data,24,0,3);
  776.         LCD_display_word(speed_data,24,3,3);
  777.         show_score_num(3,1);
  778.         show_speed_num(13,4);
  779. }
  780. //定时器0初始化函数
  781. void time0_initialize()
  782. {
  783.         TMOD=0x03;//定时器0,16位工作方式
  784.         TR0=1; //启动定时器
  785.         ET0=1; //打开定时器0中断
  786.                         //默认中断优先级为低
  787.         EA=1; //打开总中断
  788. }
  789. //俄罗斯方块游戏主函数
  790. void Tetris_main()
  791. {
  792.         unsigned char i;
  793.         for(i=0;i<19;i++)
  794.         {
  795.                 Box_Ram[i]=Box_Ram_data[i];
  796.         };//载入游戏初始显示画面
  797.         LCD_draw(mpic);
  798.         game_over_flag=0;//游戏结束标志位置0表示游戏未结束
  799.         box_build();
  800.         box_load();
  801. //        next_box();
  802.         box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
  803.         box_down_reg=(20-(speed_num<<1)-1);//为了使方块一出现就能变换形状,所以需要尽快使得方块下降一行,不知道为什么最高行不能变换形状
  804.         time0_initialize();
  805.         while(!game_over_flag)//如果游戏结束标志位置1,表示游戏结束,打破循环,调用游戏结束画面显示函数
  806.         {
  807.                 game_button();
  808.         }
  809.         EA=0;//游戏结束后关中断
  810. }
  811. //游戏结束画面显示函数
  812. void game_over_show()
  813. {
  814.         unsigned char i;
  815.         bit tpflag=1;//置循环标志位为1
  816.         LCD_full_draw(over_pic);
  817.         while(button_a==0);
  818.         while(tpflag)
  819. ……………………

  820. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
0.png

所有资料51hei提供下载:
俄罗斯方块完整资料.7z (1.25 MB, 下载次数: 380)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:590216 发表于 2019-7-25 14:43 | 显示全部楼层
哇这个看起来很清楚,想试一试
回复

使用道具 举报

ID:275030 发表于 2019-7-25 17:13 | 显示全部楼层
下载学习一下LCD使用方法,谢谢分享
回复

使用道具 举报

ID:407535 发表于 2019-7-25 17:30 | 显示全部楼层
膜拜大佬!
回复

使用道具 举报

ID:712698 发表于 2020-3-21 09:54 | 显示全部楼层
代码报错
回复

使用道具 举报

ID:562148 发表于 2020-3-27 15:40 | 显示全部楼层
看起来不错
回复

使用道具 举报

ID:619259 发表于 2020-3-29 19:15 | 显示全部楼层
大神
回复

使用道具 举报

ID:718740 发表于 2020-3-30 13:46 | 显示全部楼层
膜拜大佬!
回复

使用道具 举报

ID:187521 发表于 2021-2-22 22:59 | 显示全部楼层
精彩的比赛
回复

使用道具 举报

ID:800711 发表于 2021-2-23 13:40 | 显示全部楼层
好家伙,刚好拿来学习。
回复

使用道具 举报

ID:884588 发表于 2021-2-26 10:47 | 显示全部楼层
牛逼!!!!
回复

使用道具 举报

ID:652804 发表于 2021-3-2 19:16 | 显示全部楼层
下载学习一下LCD使用方法,谢谢分享。
回复

使用道具 举报

ID:369562 发表于 2021-3-6 12:38 | 显示全部楼层
取模方式是啥
回复

使用道具 举报

ID:582255 发表于 2021-3-6 22:01 | 显示全部楼层
对我来说不可实现。。。
回复

使用道具 举报

ID:949285 发表于 2021-7-7 15:18 | 显示全部楼层
膜拜大佬
回复

使用道具 举报

ID:982529 发表于 2021-11-23 10:50 来自手机 | 显示全部楼层
实物LCD12864,,好像不显示图案,不知道是不是接错脚了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表