本文通过STM32F103C8T6微控制器驱动0.96寸OLED显示屏,实现了一个完整的贪吃蛇游戏。项目同样适用于STM32F103RCT6等型号,只需调整启动文件、芯片类型和宏定义即可。
硬件介绍
0.96寸OLED显示屏
本项目采用四线IIC接口的0.96寸OLED显示屏,具有高对比度和低功耗特性。

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

硬件连接配置
- 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);
}
实际运行效果

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