找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 716|回复: 0
收起左侧

基于51单片机的俄罗斯方块程序与Proteus仿真图

[复制链接]
ID:1084173 发表于 2023-6-16 16:45 | 显示全部楼层 |阅读模式
仿真在Proteus8.3运行正常,8.9不行
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
51hei.gif 1686905057198.jpg
部分代码
  1. #include <REG52.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 change = P3^4;
  9. sbit OK = 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(OK==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(change==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()函数中不知道为什么就是不正常显示(2015注释:程序可能重入了)
  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(OK==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(OK==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(change==0);
  818.     while(tpflag)
  819.     {
  820.         switch(basic_button())
  821.         {
  822.             case 6: tpflag=0;
  823.                     speaker=0;
  824.                     while(OK==0);
  825.                     speaker=1;
  826.                     break;
  827.             default:;
  828.         }
  829.     }//game over画面循环
  830.     LCD_clear();
  831.     for(i=0;i<128;i++)
  832.     {
  833.         LCD_display_byte(i,0,0xff);
  834.         LCD_display_byte(i,7,0xff);
  835.     }
  836.     LCD_display_word(score_data,24,3,52);
  837.     show_score_num(52,4);
  838.     tpflag=1;
  839.     while(tpflag)
  840.     {
  841.         switch(basic_button())
  842.         {
  843.             case 6: tpflag=0;
  844.                     speaker=0;
  845.                     while(OK==0);
  846.                     speaker=1;
  847.                     break;
  848.             default:;
  849.         }
  850.     }//游戏得分显示循环
  851. }

  852. void main()
  853. {
  854.     LCD_initialize();
  855.     LCD_clear();
  856.     while(1)
  857.     {
  858.         game_start_show();
  859.         select_speed();
  860.         game_initialize();//调用游戏初始化函数,初始化游戏所有变量以及在液晶屏上显示基本的信息
  861.         Tetris_main();
  862.         game_over_show();   
  863.     }   
  864. }
  865. //定时器0中断服务
  866. void timer0() interrupt 1
  867. {
  868.     TH0=0x00;
  869.     TL0=0x00;
  870.     if(time0_reg<10)
  871.     {                  
  872.         time0_reg++;
  873.     }
  874.     else
  875.     {
  876.         time0_reg=0;
  877.         if(pause_game_flag==0)
  878.         {
  879.             game_execute();
  880.             refurbish_display();
  881.         }
  882.     }
  883. }
复制代码

仿真在Proteus8.13 8.3运行正常,8.9不行
Keil代码与Proteus仿真下载: Proteus8.13仿真程序.7z (80.34 KB, 下载次数: 24)

评分

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

查看全部评分

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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