利用AT89C52单片机和LCD12864实现贪吃蛇游戏的详细代码
时间: 2024-03-30 14:36:08 浏览: 17
好的,以下是一个完整的贪吃蛇游戏代码,它使用AT89C52单片机和LCD12864进行实现:
```C
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
// 定义 LCD12864 端口
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^2;
sbit CS1 = P3^6;
sbit CS2 = P3^7;
// 定义贪吃蛇和食物的坐标
#define SNAKE_MAX_LEN 20
uchar snake_x[SNAKE_MAX_LEN] = {0};
uchar snake_y[SNAKE_MAX_LEN] = {0};
uchar food_x = 0;
uchar food_y = 0;
// 定义贪吃蛇的长度和方向
uchar snake_len = 3;
uchar snake_dir = 0; // 0:向右,1:向上,2:向左,3:向下
// 定义 LCD12864 的显示缓存
uchar lcd_buf[64][128/8] = {0};
// 初始化 LCD12864
void init_lcd12864() {
RS = 0;
RW = 0;
EN = 0;
CS1 = 0;
CS2 = 0;
P2 = 0x30;
EN = 1;
EN = 0;
delay(2);
P2 = 0x0C;
EN = 1;
EN = 0;
delay(2);
P2 = 0x01;
EN = 1;
EN = 0;
delay(2);
P2 = 0x06;
EN = 1;
EN = 0;
delay(2);
}
// 刷新 LCD12864 显示
void refresh_lcd12864() {
for (int i = 0; i < 64; i++) {
CS1 = 0;
CS2 = 0;
RS = 0;
RW = 0;
P2 = 0xB8 + i;
EN = 1;
EN = 0;
RS = 1;
for (int j = 0; j < 128/8; j++) {
RW = 0;
P2 = lcd_buf[i][j];
EN = 1;
EN = 0;
}
}
}
// 画一个点
void draw_point(uchar x, uchar y) {
uchar row = y / 8;
uchar col = x;
uchar bit = y % 8;
lcd_buf[row][col] |= (1 << bit);
}
// 清除一个点
void clear_point(uchar x, uchar y) {
uchar row = y / 8;
uchar col = x;
uchar bit = y % 8;
lcd_buf[row][col] &= ~(1 << bit);
}
// 在 LCD12864 上画一个矩形
void draw_rect(uchar x, uchar y, uchar w, uchar h) {
for (int i = x; i < x+w; i++) {
for (int j = y; j < y+h; j++) {
draw_point(i, j);
}
}
}
// 清除 LCD12864 上的一个矩形
void clear_rect(uchar x, uchar y, uchar w, uchar h) {
for (int i = x; i < x+w; i++) {
for (int j = y; j < y+h; j++) {
clear_point(i, j);
}
}
}
// 在 LCD12864 上显示贪吃蛇
void draw_snake() {
for (int i = 0; i < snake_len; i++) {
draw_rect(snake_x[i], snake_y[i], 1, 1);
}
}
// 在 LCD12864 上显示食物
void draw_food() {
draw_rect(food_x, food_y, 1, 1);
}
// 清除 LCD12864 上的贪吃蛇
void clear_snake() {
for (int i = 0; i < snake_len; i++) {
clear_rect(snake_x[i], snake_y[i], 1, 1);
}
}
// 清除 LCD12864 上的食物
void clear_food() {
clear_rect(food_x, food_y, 1, 1);
}
// 在 LCD12864 上显示分数
void draw_score() {
uchar score_str[5];
sprintf(score_str, "%d", snake_len - 3);
RS = 0;
RW = 0;
EN = 0;
CS1 = 0;
CS2 = 0;
P2 = 0xB8 + 6;
EN = 1;
EN = 0;
RS = 1;
for (int i = 0; i < 3; i++) {
RW = 0;
P2 = ' ';
EN = 1;
EN = 0;
}
for (int i = 0; i < 2; i++) {
RW = 0;
P2 = score_str[i];
EN = 1;
EN = 0;
}
}
// 初始化贪吃蛇和食物的位置
void init_game() {
snake_len = 3;
snake_dir = 0;
snake_x[0] = 10;
snake_y[0] = 0;
snake_x[1] = 9;
snake_y[1] = 0;
snake_x[2] = 8;
snake_y[2] = 0;
food_x = 5;
food_y = 5;
}
// 处理贪吃蛇的移动和生长
void update_snake() {
// 根据方向移动贪吃蛇
for (int i = snake_len-1; i > 0; i--) {
snake_x[i] = snake_x[i-1];
snake_y[i] = snake_y[i-1];
}
switch (snake_dir) {
case 0:
snake_x[0]++;
break;
case 1:
snake_y[0]--;
break;
case 2:
snake_x[0]--;
break;
case 3:
snake_y[0]++;
break;
}
// 判断是否撞到边界
if (snake_x[0] < 0 || snake_x[0] >= 128 || snake_y[0] < 0 || snake_y[0] >= 64) {
while (1); // 游戏结束
}
// 判断是否吃到食物
if (snake_x[0] == food_x && snake_y[0] == food_y) {
snake_len++;
food_x = rand() % 128;
food_y = rand() % 64;
}
// 判断是否撞到自己的身体
for (int i = 1; i < snake_len; i++) {
if (snake_x[0] == snake_x[i] && snake_y[0] == snake_y[i]) {
while (1); // 游戏结束
}
}
}
// 处理按键输入
uchar read_key() {
uchar key_val = P0;
if (key_val == 0x7F) {
snake_dir = 1; // 上
} else if (key_val == 0xBF) {
snake_dir = 3; // 下
} else if (key_val == 0xDF) {
snake_dir = 2; // 左
} else if (key_val == 0xEF) {
snake_dir = 0; // 右
}
return key_val;
}
// 主程序循环
void main() {
init_lcd12864();
init_game();
while (1) {
uchar key = read_key();
if (key == 0xFF) {
continue;
}
clear_snake();
clear_food();
update_snake();
draw_snake();
draw_food();
draw_score();
refresh_lcd12864();
delay(100);
}
}
```
该代码使用了delay函数进行简单的时间控制,但是不够精确,可以使用定时器来提高精度。同时,该代码还有一些待完善的地方,例如按键输入的处理、游戏结束的处理等,您可以在此基础上进行优化和改进。