单片机/MCU论坛
直播中

24不可说

8年用户 7954经验值
擅长:电源/新能源
私信 关注

51单片机项目实战---贪吃蛇(测试版)

本帖最后由 24不可说 于 2017-1-2 13:42 编辑

一、元器件
1、AT89C51单片机,随便网上一搜索就是一大堆的介绍。

2、8x8点阵
    点阵里面就是一些二极管,通过纵横交叉连接,横8竖8,每个交叉点都接一个二极管。通过高低电平控制二极管点亮和熄灭。点阵的实物图实例:

二、原理图
1.png
三、原理分析
2.png

3.png

1、首先定义一个结构体
    struct snake{
        unsigned char x[20];
        unsigned char y[20];
        unsigned char length;
        unsigned char direction;
    }snk;
    数组x,y分别存放每一个点的横纵坐标,length为蛇的长度,direction为蛇前进的方向

2、坐标系:点阵的左下角为点(0,0),横纵坐标都是正向增长,P2控制横坐标;P0控制纵坐标。通过坐标可以找到点阵中点的位置,然后将其点亮
    假设现在有第2个点的坐标x[2] = 1, y[2] = 2,那么点亮这个点的方式为
    P2 = 0x04;        //0000 0100
    P0 = 0xfb;        //1111 1011

3、按键产生外部中断,在中断里判断按下那个方向get_direction(),并且同时设置坐标set_location()

4、定时器每隔1s就应该更新位置,因为蛇要不停的前进。定时器不需要更新方向,因为方向只有按键才会改动,定时器用前一步的方向

5、关于点的位置更新方式
    1)、向上移动
        后面的点去覆盖前面的点,第一个点用新坐标表示x[0]不变,y[0]+1
    2)、向下移动
        后面的点去覆盖前面的点,第一个点用新坐标表示x[0]不变,y[0]-1
    3)、向左移动
        后面的点去覆盖前面的点,第一个点用新坐标表示x[0]-1,y[0]不变
    4)、向右移动
        后面的点去覆盖前面的点,第一个点用新坐标表示x[0]+1,y[0]不变

6、关于边界问题:
    1)、任何一个点的横坐标  0 <= x < 8
    2)、任何一个点的纵坐标  0 <= y < 8
    3)、第一个点在移动的时候不能和其他点重复,否则就自己追尾了

7、关于原理图按键的设计
    贪吃蛇要求系统能迅速响应按键,因此轮询的方式并不可取,只有靠外部中断。然而51只有2个外部中断,我们起码需要4个方向键,这样就不能一个按键配一个外部中断,通过使用4输入与门,将所有按键状态集合在一起,然后送给外部中断0。我们将4个按键都接在与门,只要有一个按下,那么与门的输出就会产生一个下降沿,从而产生外部中断。

四、源代码(main.c

  1. #include "snake.h"

  2. int error = 0;
  3. int time=0;

  4. void interrupt_init()
  5. {
  6.     EA = 0;             //关闭总中断
  7.     IT0 = 1;        //外部中断0方式 下降沿
  8.     EA = 1;         //开启总中断
  9.     EX0 = 1;        //开启外部中断
  10. }

  11. void timer_init()
  12. {
  13.     EA = 0;                //关总中断
  14.     ET0 = 1;            //开定时器0中断
  15.     TMOD = 0x02;        //定时器0工作方式2
  16.     TL0 = 6;            //定时250us
  17.     TH0 = 6;
  18.     EA = 1;             //开总中断
  19.     TR0 = 1;         //开始定时
  20. }
  21. int main()
  22. {
  23. //    unsigned char tempx, tempy;
  24. //    unsigned char i,j;

  25.     interrupt_init();
  26.     timer_init();
  27.     snk_init();

  28.     while(1)
  29.     {   
  30.         //如果位置错了就重新初始化蛇
  31.         if(error)
  32.             snk_init();
  33.         //点亮点阵
  34.         matrix();   
  35.     }
  36. }

  37. void inter0() interrupt 0
  38. {   
  39.     //按键产生外部中断,获取新的方向
  40.     get_direction();
  41.     //设置新的位置
  42.     error = set_location();   
  43. //    matrix();
  44. }
  45. void timer0() interrupt 1
  46. {   
  47.     time++;
  48.     //定时器为250us 积累4000次就是1s
  49.     if(time == 4000)
  50.     {
  51.         //每隔1s都需要重新设置位置,让蛇前进
  52.         error = set_location();   
  53.         time = 0;
  54.     }
  55. }
  56. snake.c
  57. 点击(此处)折叠或打开
  58. #include "snake.h"

  59. //蛇的结构体,x为横坐标,y为纵坐标,length为蛇的长度,direction为蛇的前进方向
  60. struct snake{
  61.     unsigned char x[20];
  62.     unsigned char y[20];
  63.     unsigned char length;
  64.     unsigned char direction;
  65. }snk;

  66. void matrix()
  67. {
  68.     unsigned char i;
  69.     int count=500;
  70.     //关闭所有的点
  71.     P2 = 0x00;
  72.     P0 = 0xff;

  73.     //根据蛇每一个点的坐标,将对应的点阵点亮
  74.     for(i=0; i
  75.     {
  76.         P2 = 1<
  77.         P0 = ~(1<
  78.     }
  79. }

  80. void snk_init()
  81. {
  82.     //初始化坐标,总共4个点(3,0) (2,0)    (1,0)     (1,0)
  83.     snk.x[0] = 3;
  84.     snk.y[0] = 0;
  85.     snk.x[1] = 2;
  86.     snk.y[1] = 0;
  87.     snk.x[2] = 1;
  88.     snk.y[2] = 0;
  89.     snk.x[3] = 0;
  90.     snk.y[3] = 0;

  91.     //初始长度4
  92.     snk.length = 4;
  93.     //初始移动方向 向右
  94.     snk.direction = RIGHT;
  95.     //点亮点阵
  96.     matrix();
  97. }



  98. void get_direction()
  99. {
  100.     //通过按键的状态获取方向
  101.     if(!up)
  102.         snk.direction = UP;

  103.     if(!down)
  104.         snk.direction = DOWN;
  105.             
  106.     if(!left)
  107.         snk.direction = LEFT;
  108.         
  109.     if(!right)
  110.         snk.direction = RIGHT;
  111. }

  112. int set_location()
  113. {
  114.     unsigned char i;
  115.     int err = 0;
  116.     if(snk.direction == UP)
  117.     {               
  118.         for(i=snk.length-1; i>0; i--)
  119.         {
  120.             snk.x[i] = snk.x[i-1];
  121.             snk.y[i] = snk.y[i-1];
  122.         }

  123.         //如果向上运动,第0个点的横坐标不变,纵坐标加1
  124.         snk.x[0] = snk.x[0];
  125.         snk.y[0] = snk.y[0] + 1;
  126.     }
  127.     else if(snk.direction == DOWN)
  128.     {
  129.         for(i=snk.length-1; i>0; i--)
  130.         {
  131.             snk.x[i] = snk.x[i-1];
  132.             snk.y[i] = snk.y[i-1];
  133.         }

  134.          //如果向下运动,第0个点的横坐标不变,纵坐标减1
  135.         snk.x[0] = snk.x[0];
  136.         snk.y[0] = snk.y[0] - 1;            
  137.     }
  138.     else if(snk.direction == LEFT)
  139.     {
  140.         for(i=snk.length-1; i>0; i--)
  141.         {
  142.             snk.x[i] = snk.x[i-1];
  143.             snk.y[i] = snk.y[i-1];
  144.         }

  145.          //如果向左运动,第0个点的横坐标减1,纵坐标不变
  146.         snk.x[0] = snk.x[0] - 1;
  147.         snk.y[0] = snk.y[0];            
  148.     }
  149.     else
  150.     {
  151.         for(i=snk.length-1; i>0; i--)
  152.         {
  153.             snk.x[i] = snk.x[i-1];
  154.             snk.y[i] = snk.y[i-1];
  155.         }

  156.         //如果向右运动,第0个点的横坐标加1,纵坐标不变
  157.         snk.x[0] = snk.x[0] + 1;
  158.         snk.y[0] = snk.y[0];        
  159.     }

  160.     err = is_location_error();
  161.     return err;
  162. }

  163. int is_location_error()
  164. {
  165.     unsigned char i;

  166.     //如果第0个点的坐标和其他任意一个点重复,那么蛇就自己撞自己,出错
  167.     for(i=1; i
  168.     {
  169.         if((snk.x[0]==snk.x[i]) && (snk.y[0]==snk.y[i]))
  170.             return 1;
  171.     }

  172.     //如果蛇的坐标超出范围,也出错
  173.     if(snk.x[0]>7 || snk.y[0]>7)
  174.         return 1;

  175.     return 0;
  176. }
  177. snake.h

  178. #include

  179. //定义四个方向按键
  180. ***it up = P3^4;
  181. ***it down = P3^5;
  182. ***it left = P3^6;
  183. ***it right = P3^7;
  184. //定义1个游戏级别按键
  185. ***it level = P3^0;
  186. //定义一个复位按键
  187. ***it reset = P3^1;

  188. //定义4个方向的值
  189. #define RIGHT 0
  190. #define    UP 1
  191. #define LEFT 2
  192. #define DOWN 3

  193. void delay_us();
  194. void delay_10us();
  195. void delay_ms();
  196. void delay_10ms();
  197. void delay_100ms();
  198. void delay_s();
  199. int is_location_error();
  200. void matrix();
  201. void snk_init();
  202. void set_direction();
  203. int get_location();
  204. int is_location_error();

打包好的程序:
main.c (4.53 KB)
(下载次数: 85, 2017-1-2 13:41 上传)


回帖(13)

笨笨DAO

2017-1-2 14:01:23
我还以为是上的液晶呢,原来是用的点阵来实现的,还是很巧妙的。
举报

尧建堂

2017-1-2 18:46:02
有空研究一下看看好不好玩?
举报

王栋春

2017-1-2 20:24:54
这个不错  感谢分享  改天DIY一下 看看效果
举报

24不可说

2017-1-3 10:28:04
引用: 王栋春 发表于 2017-1-2 20:24
这个不错  感谢分享  改天DIY一下 看看效果

在LCD上才好玩,
这个就比较简单的了
举报

曲终人散

2017-1-3 14:08:02
好玩
举报

王栋春

2017-1-3 19:38:14
引用: 24不可说 发表于 2017-1-3 10:28
在LCD上才好玩,
这个就比较简单的了

这个有12864的屏  改天试试看
举报

花不语怪风

2017-1-3 19:52:47
谢谢分享,进来学习了
举报

JASON

2017-1-7 20:07:40
学习了,谢谢!
举报

JASON

2017-1-7 20:07:44
学习了,谢谢!
举报

JASON

2017-1-7 20:07:50
学习了,谢谢!
举报

qinliuzhuang

2017-1-7 22:38:54
不错,想去试试
举报

UniqueMouse

2017-3-15 09:28:24
   前来学习
举报

老杨头儿

2018-12-14 12:22:40
楼主还是秀啊
举报

更多回帖

发帖
×
20
完善资料,
赚取积分