找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

181

积分

0

好友

23

主题
发表于 前天 03:54 | 查看: 8| 回复: 0

本文通过STM32F103C8T6微控制器驱动0.96寸OLED显示屏,实现了一个完整的贪吃蛇游戏。项目同样适用于STM32F103RCT6等型号,只需调整启动文件、芯片类型和宏定义即可。

硬件介绍

0.96寸OLED显示屏

本项目采用四线IIC接口的0.96寸OLED显示屏,具有高对比度和低功耗特性。

OLED显示屏

STM32F103C8T6微控制器

STM32F103C8T6是一款广泛使用的微控制器,基于ARM Cortex-M3内核,具有丰富的外设资源和较高的性价比。

STM32开发板

硬件连接配置

  • B5 → OLED SDA
  • B6 → OLED SCL
  • B8 → 左按键 + 3.3V
  • B9 → 右按键 + 3.3V
  • B10 → 下按键 + 3.3V
  • B11 → 上按键 + 3.3V
  • B12 → 结束按键 + 3.3V
  • R → 复位按键
  • GND → 复位按键

核心代码实现

屏幕点操作函数

实现OLED屏幕上单个像素点的绘制与清除功能,数据暂存于OLED_GRAM中,最后统一刷新显示。

void OLED_DrawPoint(u8 x,u8 y){
    u8 pos,bx,temp=0;
    if(x>127||y>63)return;
    pos=7-y/8;
    bx=y%8;
    temp=1<<(7-bx);
    OLED_GRAM[x][pos]|=temp;
}

void OLED_DrawNoPoint(u8 x,u8 y){
    u8 pos,bx,temp=0;
    if(x>127||y>63)return;
    pos=7-y/8;
    bx=y%8;
    temp=1<<(7-bx);
    OLED_GRAM[x][pos]&=~temp;
}

游戏数据结构定义

考虑到0.96寸OLED分辨率为128×64,将每2×2像素点定义为游戏中的一个单元,地图尺寸设置为32×12。

#define MAXLENGTH 100
int map[32][12] = {0};
int score;
bool eated = false;
u8 KeyValue = 0;

struct {
    int snake_Grid[MAXLENGTH][2];
    int length;
    int direction;
} snake;

int tailX, tailY;
int FoodX, FoodY;

游戏画面渲染函数

void Creat_map() {
    int i,j;
    for(i=0;i<12;i++) {
        for(j=0;j<32;j++) {
            if(i==0||i==11) map[j][i]=-2;
            if(j==0||j==31) map[j][i]=-2;
        }
    }
}

void Paint_Map(int x,int y) {
    int i,j;
    for(i=4*y;i<4*y+4;i++) {
        for(j=4*x;j<4*x+4;j++) {
            OLED_DrawPoint(j,i+16);
        }
    }
}

// 其他绘制函数实现...

界面刷新机制

通过遍历地图数组,统一更新游戏界面所有元素显示状态。

void GUI_Refresh() {
    int i,j,temp;
    for(i=0;i<32;i++) {
        for(j=0;j<12;j++) {
            temp=map[i][j];
            switch(temp) {
                case 2: Paint_Body(i,j); break;
                case 1: Paint_Head(i,j); break;
                case -2: Paint_Map(i,j); break;
                case -1: Paint_Food(i,j); break;
                case 0: Paint_Clean(i,j); break;
            }
        }
    }
}

游戏初始化设置

void Snake_Init() {
    int i;
    snake.length=5;
    snake.direction=RIGHT;
    score=0;
    snake.snake_Grid[0][0]=7;
    snake.snake_Grid[0][1]=5;
    tailX = snake.snake_Grid[snake.length-1][0];
    tailY = snake.snake_Grid[snake.length-1][1];

    for(i=1;i<snake.length;i++) {
        snake.snake_Grid[i][0]=snake.snake_Grid[0][0]-i;
        snake.snake_Grid[i][1]=snake.snake_Grid[0][1];
    }
    Creat_map();
}

方向控制与中断处理

方向定义:

#define RIGHT 1
#define LEFT 2
#define DOWN 3
#define UP 4

按键处理函数通过外部中断获取输入值,控制蛇的移动方向。游戏逻辑涉及算法与数据结构的基础应用。

void Get_Command() {
    u8 key=KeyValue;
    switch(key) {
        case 1: if(snake.direction!=RIGHT) snake.direction=LEFT; break;
        case 2: if(snake.direction!=LEFT) snake.direction=RIGHT; break;
        case 3: if(snake.direction!=DOWN) snake.direction=UP; break;
        case 4: if(snake.direction!=UP) snake.direction=DOWN; break;
    }
}

蛇移动算法实现

void Move() {
    int i;
    int headX = snake.snake_Grid[0][0];
    int headY = snake.snake_Grid[0][1];
    tailX = snake.snake_Grid[snake.length-1][0];
    tailY = snake.snake_Grid[snake.length-1][1];

    if(headX==FoodX && headY==FoodY) {
        snake.length++;
        eated = true;
        score += 1;
        Food();
    } else {
        map[tailX][tailY] = 0;
    }

    for(i=snake.length-1;i>0;i--) {
        snake.snake_Grid[i][0] = snake.snake_Grid[i-1][0];
        snake.snake_Grid[i][1] = snake.snake_Grid[i-1][1];
    }

    switch(snake.direction) {
        case UP: snake.snake_Grid[0][1]--; break;
        case DOWN: snake.snake_Grid[0][1]++; break;
        case LEFT: snake.snake_Grid[0][0]--; break;
        case RIGHT: snake.snake_Grid[0][0]++; break;
    }
    drawSnake();
}

食物生成逻辑

int Chek(int i,int j) {
    return (map[i][j]==0) ? 1 : 0;
}

void Food() {
    int i,j;
    do {
        i=(rand()%30)+1;
        j=(rand()%10)+1;
    } while(Chek(i,j)==0);
    map[i][j]=-1;
}

游戏状态检测

bool GameOver() {
    bool isGameOver=false;
    int sx=snake.snake_Grid[0][0],sy=snake.snake_Grid[0][1],i;

    for(i=1;i<snake.length;i++) {
        if(snake.snake_Grid[i][0]==sx&&snake.snake_Grid[i][1]==sy)
            isGameOver=true;
    }

    if(snake.snake_Grid[0][0]==31||snake.snake_Grid[0][0]==0||
       snake.snake_Grid[0][1]==11||snake.snake_Grid[0][1]==0)
        isGameOver=true;

    return isGameOver;
}

分数显示功能

void Show_Score() {
    OLED_ShowString(30,6,"Score:",16);
    OLED_ShowNum(80,6,score,2,16);
}

实际运行效果

游戏界面1 游戏界面2

本项目完整展示了嵌入式系统开发中硬件驱动、图形显示和游戏逻辑的集成实现,为初学者提供了很好的实践参考。

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

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-1 17:05 , Processed in 0.065780 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

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