当前位置: 首页 > news >正文

【51单片机】【protues仿真】基于51单片机贪吃蛇游戏系统

目录

一、主要功能

二、使用步骤

三、硬件资源

四、软件设计

五、实验现象

一、主要功能

1、LCD12864液晶显示
2、按键控制移动方向,开始暂停​
3、小蛇撞墙、吃到自己游戏结束,自动跳转到等待状态
4、显示得分,LED灯显示对应方向

二、使用步骤

本项目采用STC89C52RC作为主控芯片,搭配LCD12864显示屏,通过独立键盘实现方向控制。使用LCD12864可显示更复杂的游戏界面,包括得分统计和暂停功能,需定义显示缓冲区数组管理像素数据。使用定时器中断(如10ms周期)替代延时函数,避免主循环阻塞导致的屏幕闪烁。方向键检测需配合消抖处理,通常采用定时中断扫描按键状态。同时需判断蛇头是否触碰墙壁(坐标边界)或自身身体坐标。

三、硬件资源

1、51单片机核心模块
2、按键模块
3、蜂鸣器模块
4、LED等模块
5、LCD12864显示模块

四、软件设计

#include <LCD12864.h>
#include <reg52.h>
#include <stdlib.h>
#include <intrins.h>
#include <zifu.h>


uint8 code image1[]=
{0x00,0x00,0x80,0xC0,0xE0,0xE0,0xE0,0xE0,0xE6,0xEE,0xFE,0xFC,0xF8,0xE0,0xE0,0xE0,
0xE0,0xE0,0xF8,0xFC,0xFE,0xEE,0xE6,0xE0,0xE0,0xE0,0xE0,0xC0,0x80,0x00,0x00,0x00,
0x00,0xFF,0xFF,0xFF,0xFF,0x01,0xC1,0xC1,0xE1,0xE1,0xE1,0xE1,0xE1,0x01,0x01,0x01,
0x01,0x01,0xE1,0xE1,0xE1,0xE1,0xE1,0xC1,0xC1,0x01,0xFF,0xFF,0xFF,0xFE,0x00,0x00,
0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x01,0x01,0x01,0x01,0x00,0x10,0x70,0x60,0x70,0x38,
0x60,0x60,0x30,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x03,0x0F,0x1F,0x1F,0x3E,0x3E,0x7C,0x7C,0x7C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,
0x3C,0x3C,0x3C,0x3C,0x3C,0x7C,0x7C,0x7C,0x3C,0x3E,0x1F,0x1F,0x0F,0x03,0x00,0x00};

uint8 dat;uint16 i,j;
uint8 snake_head[2], snake_tail[2], snake_len; //蛇头蛇尾坐标,蛇身长度
uint8 head_step, tail_step;        //蛇头蛇尾步数
uint8 tailtrun_step[20], tailtrun_direction[20];        //蛇尾转向步数&方向循环列表
uint8 rear, front;        //蛇尾转向循坏列表指针
uint8 direction, direction_tail;     //蛇头蛇尾方向
uint8 rand_x, rand_y;    //随机食物坐标
uint8 pause_flag;     //暂停标志位
uint8 victory_line;     //游戏胜利随机行
   uint8 start_line, start_column; //2×2点起始坐标
int bitTo16(uint8);
void start();
void over();
void delay();
void creat_food();
void Key_Scan();
void show_p(uint8,uint8,uint8);
void show_bp(uint8,uint8,uint8);
void out_bp(uint8,uint8,uint8);
void Display();
void snake_forward(uint8);
void snake_lose(uint8);
void InitGame();
void hit_block(uint8,uint8);
void bord();
void defen();
void show_number(uint8,uint8);
void score(uint8);
void pause();
void victory();
void judge_victory();
void hit_wall();
/****************************   主函数   ****************************/
void main()
{
    InitLCD();
    ClearScreen(0);
    Set_line(0);
    InitGame();

    while(1)
    {
        Display();
        Key_Scan();
    }
}
/****************************   自定义函数   ****************************/

void InitGame(){
    start();    //游戏开始
    bord();        //画页面
    pause_flag = 0;    //暂停标志
    victory_line = 3 + rand() % 27;        //游戏胜利随机行
    direction = 4;direction_tail = 4;    //初始蛇头蛇尾方向向右
    head_step = 3; tail_step = 1;        //初始蛇头步数3,蛇尾步数1
  for (i = 0;i < 20;i++) {    //循环队列步数&方向初始化
      tailtrun_step[i] = 0;    
      tailtrun_direction[i] = 0;    
  }
    rear=front=0;        //循环队列指针初始化
    snake_len=3;        //初始蛇身长度3
    snake_head[0]=5;snake_head[1]=3;    //蛇头第一个点
    snake_tail[0]=5;snake_tail[1]=1;    //蛇尾第一个点
    creat_food();        //创建食物
    score(3);    //初始得分03->长度
}

void delay(){
    i = 10000;
    while (i--);
}
// 创造食物
void creat_food(){
    while(1){
        i = rand();
        srand(i);
        rand_x = 3 + rand() % 27; // 3-29
        rand_y = 3 + rand() % 27;
        dat = read_LCD_data(rand_x * 2 / 8, rand_y * 2);
        if ((dat & bitTo16(rand_x * 2 % 8)) == 0x00) {
            show_bp(2, rand_x, rand_y);
            break;
        }
    }
}
// 按键扫描
void Key_Scan(void){
    
    if(KEY1 == 1)
        REDL1 = 1;
    if(KEY2 == 1)
        REDL2 = 1;
  if(KEY3 == 1)
        REDL3 = 1;
  if(KEY4 == 1)
        REDL4 = 1;
    
    if (KEY0 == 0)
        pause();
    else if (KEY1 == 0) {
        REDL1 = 0;
        if (direction != 2) { //蛇不能直接掉头
            direction = 1;
            tailtrun_step[rear] = head_step;
            tailtrun_direction[rear] = 1;
            rear = (rear + 1) % 20;
        }
    }
    else if (KEY2 == 0) {
            REDL2 = 0;
        if (direction != 1) {
            direction = 2;
            tailtrun_step[rear] = head_step;
            tailtrun_direction[rear] = 2;
            rear = (rear + 1) % 20;
        }
    }
    else if (KEY3 == 0) {
        REDL3 = 0;
        if (direction != 4) {
            direction = 3;
            tailtrun_step[rear] = head_step;
            tailtrun_direction[rear] = 3;
            rear = (rear + 1) % 20;
        }
    }
    else if (KEY4 == 0) {
        REDL4 = 0;
        if (direction != 3) {
            direction = 4;
            tailtrun_step[rear] = head_step;
            tailtrun_direction[rear] = 4;
            rear = (rear + 1) % 20;
        }
    }
}

// 2×2合并为一个点
void show_bp(uint8 screen,uint8 line,uint8 column){
    SelectScreen(screen);
    
    start_line = line * 2;start_column = column * 2;
    for(j=0;j<2;j++){
        dat = read_LCD_data(start_line / 8, start_column + j);
        write_LCD_data(dat | bitTo16(start_line % 8));
        dat = read_LCD_data(start_line / 8, start_column + j);
        write_LCD_data(dat | bitTo16(start_line % 8 + 1));
    }
    Set_page(start_line / 8);    //前面设置完会自动+1,需重新设置回来
    Set_column(start_column + 1);
}
void out_bp(uint8 screen,uint8 line,uint8 column){
    SelectScreen(screen);
    
    start_line = line * 2;start_column = column * 2;
    for(j=0;j<2;j++){
        dat = read_LCD_data(start_line / 8, start_column + j);
        write_LCD_data(dat & ~( bitTo16(start_line % 8)));
        dat = read_LCD_data(start_line / 8, start_column + j);
        write_LCD_data(dat & ~( bitTo16(start_line % 8 + 1)));
    }
    Set_page(start_line / 8);    //前面设置完会自动+1,需重新设置回来
    Set_column(start_column + 1);
}

void show_p(uint8 screen, uint8 line, uint8 column) {
    SelectScreen(screen);
    
    dat = read_LCD_data(line / 8, column);
    Set_page(line/8);    
  Set_column(column);
    write_LCD_data(dat | bitTo16(line % 8));
}
// 熄灭一个点,行列
void out_p(uint8 screen, uint8 line, uint8 column) {
    SelectScreen(screen);
    
    dat = read_LCD_data(line / 8, column);
    Set_page(line/8);    
  Set_column(column);
    write_LCD_data(dat & ~(bitTo16(line % 8)));
}
// 画框
void bord(){
    for (i = 0;i < 32;i++) {
        show_bp(0, 0, i);
        show_bp(0, i, 31);
        show_bp(0, 31, 31 - i);
        show_bp(0, 31 - i, 0);
    }
    defen();
}

void hit_block(uint8 line, uint8 column) {
    dat = read_LCD_data(line * 2 / 8, column * 2);
    
    Set_page(line * 2 /8);    
    Set_column(column * 2);
    if ((dat & bitTo16(line * 2 % 8)) != 0)
        over();
}
// 撞墙
void hit_wall(){
    if(snake_head[0] <2)
        over();
    if(snake_head[0] >29)
        over();
    if(snake_head[1] <2)
        over();
    if(snake_head[1] >29)
        if(snake_head[0] != victory_line)
            over();
}
// 显示
void Display(){
    snake_forward(direction);
    // 判断是否吃到食物
    if ((snake_head[0] == rand_x) && (snake_head[1] == rand_y)) {
        score(snake_len + 1);
        snake_len++;
        creat_food();
    }
    else {
        snake_lose(direction_tail);
    }
    // 判断蛇尾是否转向
    if (tail_step == tailtrun_step[front]) {
        direction_tail = tailtrun_direction[front];
        tailtrun_direction[front] = 0;
        front = (front + 1) % 20;
    }
    judge_victory();
    hit_wall();
}
// 蛇向前一格
void snake_forward(uint8 direction){
    switch(direction){
        case 1:{
            if (((snake_head[0] - 1) != rand_x) && (snake_head[1] != rand_y)) // 如果不是食物再判断是否碰到蛇身
                hit_block(snake_head[0] - 1, snake_head[1]); 
            show_bp(2, --snake_head[0], snake_head[1]);    // 点亮前一个点
            break;
        }
        case 2:{
            if (((snake_head[0] + 1) != rand_x) && (snake_head[1] != rand_y)) // 如果不是食物再判断是否碰到蛇身
                hit_block(snake_head[0] + 1, snake_head[1]); 
            show_bp(2, ++snake_head[0], snake_head[1]);
            break;
        }
        case 3:{
            if ((snake_head[0] != rand_x) && ((snake_head[1] - 1) != rand_y)) // 如果不是食物再判断是否碰到蛇身
                hit_block(snake_head[0], snake_head[1] - 1);
            show_bp(2, snake_head[0], --snake_head[1]); 
            break;
        }
        case 4:{
            if ((snake_head[0] != rand_x) && ((snake_head[1] + 1) != rand_y)) // 如果不是食物再判断是否碰到蛇身
                hit_block(snake_head[0], snake_head[1] + 1); 
            show_bp(2, snake_head[0], ++snake_head[1]);
            break;
        }
    }
    head_step++;
}
// 蛇消失一格
void snake_lose(uint8 direction_tail){
    switch(direction_tail){
        case 1:{
            out_bp(2, snake_tail[0]--, snake_tail[1]);
            break;
        }
        case 2:{
            out_bp(2, snake_tail[0]++, snake_tail[1]);
            break;
        }
        case 3:{
            out_bp(2, snake_tail[0], snake_tail[1]--);
            break;
        }
        case 4:{
            out_bp(2, snake_tail[0], snake_tail[1]++);
            break;
        }
    }
    delay();
    tail_step++;
}
// 游戏胜利
void judge_victory() {
    if (snake_len >= 17) {
        out_bp(2, victory_line, 31);
        if (snake_head[1] >= 31)
            victory();
    }
}
// 暂停函数
void pause() {
    pause_flag = 1;
    delay();delay();
    while (pause_flag == 1) {
        if (KEY0 == 0) {
            pause_flag = 0;
            delay();delay();
        }
    }
}
// 位转16进制
int bitTo16(uint8 wei){
    switch (wei){
        case 0:return 0x01;break;
        case 1:return 0x02;break;
        case 2:return 0x04;break;
        case 3:return 0x08;break;
        case 4:return 0x10;break;
        case 5:return 0x20;break;
        case 6:return 0x40;break;
        case 7:return 0x80;break;
        //default:return 0x00;break;
    }
}
// 游戏开始界面
void start(){
    BEEP = 1;
    show_im(1, 2, 0 * 16, image1);
    show_ch(1, 4, 2 * 16, ch + 32 * 0);
    show_ch(1, 4, 3 * 16, ch + 32 * 1);
    show_ch(2, 4, 0 * 16, ch + 32 * 2);
    show_ch(2, 4, 1 * 16, ch + 32 * 3);
    show_ch(2, 4, 2 * 16, ch + 32 * 6);
    show_ch(2, 4, 3 * 16, ch + 32 * 6);
    pause();
    ClearScreen(0);
}
// 游戏结束界面
void over(){
    BEEP = 0;
    ClearScreen(0);
    show_im(1, 2, 0 * 16, image1);
    show_ch(1, 4, 2 * 16, ch + 32 * 0);
    show_ch(1, 4, 3 * 16, ch + 32 * 1);
    show_ch(2, 4, 0 * 16, ch + 32 * 4);
    show_ch(2, 4, 1 * 16, ch + 32 * 5);
    show_ch(2, 4, 2 * 16, ch + 32 * 6);
    show_ch(2, 4, 3 * 16, ch + 32 * 6);
    pause();InitGame();
}
// 游戏胜利界面
void victory() {
    BEEP = 0;
    ClearScreen(0);
    show_im(1, 2, 0 * 16, image1);
    show_ch(1, 4, 2 * 16, ch + 32 * 0);
    show_ch(1, 4, 3 * 16, ch + 32 * 1);
    show_ch(2, 4, 0 * 16, ch + 32 * 9);
    show_ch(2, 4, 1 * 16, ch + 32 * 10);
    show_ch(2, 4, 2 * 16, ch + 32 * 6);
    show_ch(2, 4, 3 * 16, ch + 32 * 6);
    pause();InitGame();
}
// 得分
void defen(){
    show_ch(1, 2, 1 * 16, ch + 32 * 7);
    show_ch(1, 2, 2 * 16, ch + 32 * 8);
}
// 分数
void show_number(uint8 num, uint8 colume) {
    switch(num){
        case 0:{
            show_num(1, 4, colume, number + 16 * 0);
            break;
        }
        case 1:{    
            show_num(1, 4, colume, number + 16 * 1);
            break;
        }
        case 2:{    
            show_num(1, 4, colume, number + 16 * 2);
            break;
        }
        case 3:{    
            show_num(1, 4, colume, number + 16 * 3);
            break;
        }
        case 4:{    
            show_num(1, 4, colume, number + 16 * 4);
            break;
        }
        case 5:{
            show_num(1, 4, colume, number + 16 * 5);
            break;
        }
        case 6:{    
            show_num(1, 4, colume, number + 16 * 6);
            break;
        }
        case 7:{
            show_num(1, 4, colume, number + 16 * 7);
            break;
        }
        case 8:{
            show_num(1, 4, colume, number + 16 * 8);
            break;
        }
        case 9:{    
            show_num(1, 4, colume, number + 16 * 9);
            break;
        }
    }
}

void score(uint8 score){
    uint8 shi_wei, ge_wei;
    shi_wei = score / 10;
    ge_wei = score % 10;
    show_number(shi_wei, 20);
    show_number(ge_wei, 32);
}

五、实验现象

演示视频:

【51单片机-B054】【protues仿真】基于51单片机贪吃蛇游戏设计仿真

http://www.dtcms.com/a/454477.html

相关文章:

  • 昆明学校网站设计公司网页设计项目模板代码
  • 有没有做培养基的网站已备案网站想关闭
  • 【Canvas与旗帜】油管五常之印度旗恒河之眼版
  • 广州门户网站开发济南seo优化外包
  • 微网站样式wordpress 插件编写
  • Oracle数据库常见问题实战:从连接错误到自动清理空闲会话
  • 网站开发项目管理步骤如何做国外的网站
  • 建设银行潍坊支行网站wordpress博客二次元
  • html5网站开发特点wordpress导出导入
  • 个人博客网站总结全网营销解决方案
  • 域名注册好后怎么建设网站官网浏览器
  • Smac Planner与 NavFn Planner 的对比分析
  • 傅里叶变换·思考
  • 南部县网站建设怎样建单位的网站
  • 虹桥做网站WordPress的主题制作教程
  • 太仓高端网站制作甘肃省建设银行校园招聘网站
  • 人力资源网站建设方案安装wordpress中文包
  • 江苏省建设厅网站建造师强制注销有哪些网站的搜索引擎
  • wordpress 多语言网站网站配图尺寸
  • 站长工具在线免费观看网络营销推广网站
  • tdk标签影响网站权重广州现在算什么风险地区
  • AssemblyScript 入门教程(9):直接内存管理
  • 新的南宁网站建设公司WordPress中文空格
  • 手机网站设计小程序wordpress用什么系统
  • STIP开源股票技术指标回测分析平台产品深度分析
  • 什么网站可以接室内设计做建设人力资源网
  • 图文详解Transformer模型——解码器输入(shifted input)详解
  • 网站推广方案策划书2000杭州g20网站建设公司
  • 网站导航栏图标js 访问wordpress
  • 品牌宣传网站建设网站开发软件和工具ide和编辑器