本人零基础在B站上学习完江科大的51单片机入门后做的一个实战项目
完整代码百度网盘链接:
链接:https://pan.baidu.com/s/1DZfGqGllyQu2fWCMP1eoIQ
提取码:tc99文末介绍了我所购OLED显示屏规格
main.c
#include <REGX52.H>
#include "oled.h"
#include "snack.h"
#include "MatrixKey.h"
#include "Timer0.h"
//游戏延时
unsigned char time= 500;
static unsigned char T0Count;
int main(void)
{
OLED_Init();
OLED_Clear();
Timer0_Init();
initSnake();
InitFood();
displaySnakeOnScreen();
while(1)
{ //检测按键按下
KeyDown();
//随机生成食物,随机因子T0Count
GenerateFood(T0Count);
//判断是否吃到食物
isGetFood();
//检测蛇的生存状态
CheckCollision();
//检测游戏胜利
GameSucess();
}
}
void Timer0() interrupt 1
{
TL0=0X18;
TH0=0XFC;
T0Count++;
if(T0Count == time)
{
T0Count=0;
moveSnake();
}
}
snake.c【各个函数的功能我已经在注释中写好了】
#include "oled.h"
#include "snack.h"
#include "Delay.h"
#include <REGX52.H>
#define OLED_WIDTH 16 //定义游戏画面宽度
#define OLED_HEIGHT 8 //定义游戏画面高度
//动画节点数据
unsigned char body[]={0xFF,0xFF,0xC3,0xC3,0xC3,0xC3,0xFF,0xFF};
//蛇身长度
unsigned char snake_length;
//控制上下左右的不同模式
unsigned char MODE;
//食物是否存在标志位
unsigned char flag=0;
//定义蛇的结构体
typedef struct {
unsigned char x;// 蛇身节点横坐标
unsigned char y;// 蛇身节点纵坐标
}Snake;
Snake snake[20];
//定义食物的结构体
typedef struct {
u8 x;//食物节点横坐标
u8 y;//食物节点纵坐标
} Food;
Food food;
// 显示动画节点
void ShowNode(unsigned char x,unsigned char y)
{
u8 t;
OLED_Set_Pos(x*8,y);
for(t=0;t<8;t++)
{
OLED_WR_Byte(body[t],OLED_DATA);
}
}
//覆盖动画节点
void OverrideTail(unsigned char x, unsigned char y)
{
u8 i;
OLED_Set_Pos(x*8,y);
for(i=0;i<8;i++)
{
OLED_WR_Byte(0x00,OLED_DATA);
}
}
// 初始化蛇
void initSnake() {
snake_length=3;
snake[0].x = 6;
snake[0].y = 3;
snake[1].x = 7;
snake[1].y = 3;
snake[2].x = 8;
snake[2].y = 3;
}
// 将蛇显示在屏幕上
void displaySnakeOnScreen() {
unsigned char i;
// 显示蛇身节点
for(i=0;i<snake_length;i++){
ShowNode(snake[i].x,snake[i].y);
}
}
//检测按键按下
void KeyDown(){
//定义局部静态变量KeyNum接受矩阵键盘的key值
static unsigned char KeyNum;
KeyNum = MatrixKey();
switch(KeyNum){
//上键3
case 3:
if( MODE!=1 && MODE!=2){
MODE=1;
}
break;
//下键11
case 11:
if( MODE!=1 && MODE!=2){
MODE=2;
}
break;
//左键6
case 6:
if( MODE!=3 && MODE!=4){
MODE=3;
}
break;
//右键8
case 8:
if( MODE!=3 && MODE!=4){
MODE=4;
}
break;
}
}
//显示游戏信息
void ShowMessage(u8 *message){
OLED_Clear();
OLED_ShowString( 0,3, message,16);
}
//检测蛇的生存状态
void CheckCollision() {
u8 i;
//检查蛇是否撞墙
if (snake[0].x <= 0 || snake[0].x >= OLED_WIDTH ||
snake[0].y <= 0 ||snake[0].y >= OLED_HEIGHT) {
//关闭定时器
TR0=0;
//显示失败信息
ShowMessage(" hit the wall!");
}
// 检查蛇是否撞到自身
for ( i = 1; i < snake_length; ++i) {
if (snake[0].x == snake[i].x &&
snake[0].y == snake[i].y) {
//关闭定时器
TR0=0;
//显示失败信息
ShowMessage("Snake hit itself!");
}
}
}
//初始化食物
void InitFood(){
food.x = 2;
food.y = 4;
ShowNode(food.x,food.y);
}
//食物被吃掉后,随机生成食物
void GenerateFood(unsigned char rand) {
u8 i;
if(flag==1){
do {
food.x = rand % (OLED_WIDTH);
food.y = rand % (OLED_HEIGHT);
// 检查食物的位置是否和身体重叠
for (i = 0; i < snake_length; i++) {
if (food.x == snake[i].x && food.y == snake[i].y) {
break; // 位置重叠,需要重新生成食物
}
}
} while (i != snake_length); //只有在生成食物位置不和蛇身体重叠时才跳出循环
snake_length++;
ShowNode(food.x, food.y);
}
}
//判断是否吃到食物
void isGetFood(){
if(snake[0].x == food.x&&snake[0].y==food.y){
flag=1;
} else{
flag=0;
}
}
//控制蛇的移动
void moveSnake() {
u8 i;
switch (MODE) {
case 1:
if(flag==0)
OverrideTail(snake[snake_length-1].x,snake[snake_length-1].y);
//控制蛇往上走
for ( i = snake_length - 1; i > 0; i--) {
snake[i].x = snake[i - 1].x;
snake[i].y = snake[i - 1].y;
}
snake[0].y -= 1;
ShowNode(snake[0].x,snake[0].y);
break;
case 2:
//控制蛇往下走
if(flag==0)//没吃到食物时消除蛇尾
OverrideTail(snake[snake_length-1].x,snake[snake_length-1].y);
for ( i = snake_length - 1; i > 0; i--) {
snake[i].x = snake[i - 1].x;
snake[i].y = snake[i - 1].y;
}
snake[0].y += 1;
ShowNode(snake[0].x,snake[0].y);
break;
case 3:
// 控制蛇往左走
if(flag==0)
OverrideTail(snake[snake_length-1].x,snake[snake_length-1].y);
for ( i = snake_length - 1; i > 0; i--) {
snake[i].x = snake[i - 1].x;
snake[i].y = snake[i - 1].y;
}
snake[0].x -= 1;
ShowNode(snake[0].x,snake[0].y);
break;
case 4:
//控制蛇往右走
if(flag==0)
OverrideTail(snake[snake_length-1].x,snake[snake_length-1].y);
for ( i = snake_length - 1; i > 0; i--) {
snake[i].x = snake[i - 1].x;
snake[i].y = snake[i - 1].y;
}
snake[0].x += 1;
ShowNode(snake[0].x,snake[0].y);
break;
default:
break;
}
}
//游戏胜利
void GameSucess(){
if(snake_length>=20){
ShowMessage("GAME SUCESS!");
}
}
为了游戏的操作方便,我采用了矩阵键盘作为操作键,但是由此带来的一些延迟也影响了按键的反映灵敏度,同时蛇吃到食物后的加长和食物的产生存在一些bug,希望后续改进
最后再介绍一下我的OLED显示屏规格,1.3寸,4针 已焊接,IIC通信,电源可接3.3v至5v
SCL线接的是P10引脚,SDA线 P11 引脚
希望能给到现在也在学习51单片机的伙伴们一些启发