目錄
一、創(chuàng)作背景
二、實現(xiàn)過程
1.一些聲明與定義
2.鍵盤掃描
3.定時器中斷
5.蛇的初始化
6.蛇體的移動
7.食物的創(chuàng)建
8.食物的檢測和身體的增長
9.檢測死亡
10.總代碼
總結(jié)
一、創(chuàng)作背景
由于大一的一個小作業(yè),花了10天完成了這個小項目,中途克服了很多困難,發(fā)此文章以作紀念。
二、實現(xiàn)過程
1.一些聲明與定義
這些后面會講到。
#include <reg52.h>
#include <stdlib.h>
#define uint unsigned int
#define uchar unsigned char
#include <intrins.h>
sbit DIO = P3 ^ 4;
sbit S_CLK = P3 ^ 5;
sbit R_CLK = P3 ^ 6;
sbit key_s2 = P3 ^ 0;//獨立鍵盤4個按鍵
sbit key_s3 = P3 ^ 1;
sbit key_s4 = P3 ^ 2;
sbit key_s5 = P3 ^ 3;
uchar coorx[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };
uchar coory[8] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };
uchar snakex[20];//蛇體x坐標
uchar snakey[20];//蛇體y坐標
uchar m = 0;
uchar len = 1;//蛇體長度
uchar foodx, foody;//食物x, y坐標
uchar d, xx, yy;
2.鍵盤掃描
這里我用的是獨立鍵盤,由于點陣屏的IO口和矩陣鍵盤的IO口沖突導(dǎo)致顯示的內(nèi)容不對(個人能力有限,暫時沒辦法解決這個沖突問題,只好避開),所以采用了獨立鍵盤。同時也是因為這個原因我沒有采用掃描的方式,而是一個一個判斷。如果開發(fā)板不沖突可以選擇矩陣鍵盤。
char key = 0;
void delay(uint z)
{
uint x, y;
for (x = z; x > 0; x--)
for (y = 114; y > 0; y--);
}
void keyscan()
{
if (key_s2 == 0)
{
delay(10);
if (key_s2 == 0)
{
if (key != 4)
key = 1;
}
}
if (key_s3 == 0)
{
delay(10);
if (key_s3 == 0)
{
if (key != 3)
key = 2;
}
}
if (key_s4 == 0)
{
delay(10);
if (key_s4 == 0)
{
if (key != 2)
key = 3;
}
}
if (key_s5 == 0)
{
delay(10);
if (key_s5 == 0)
{
if (key != 1)
key = 4;
}
}
}
3.定時器中斷
這里是相關(guān)寄存器的配置,定時為5ms,用處是為了控制蛇的移動速度已經(jīng)鍵盤的判斷。
void timer0Init()
{
EA = 1;
ET0 = 1;
TR0 = 1;
TMOD = 0X01;
TH0 = 0XED;
TL0 = 0XFF;
}
void SendByte(uchar x, uchar y)//用來接收行列值,這里x和y是坐標,點陣屏左下角為坐標原點
{
uchar i, j, dat1, dat2;
dat1 = coorx[x - 1];//這里通過前面定義的兩個數(shù)組將坐標轉(zhuǎn)化為了行列的十六進制數(shù)
dat2 = coory[y - 1];
for (i = 0; i < 8; i++)
{
if (dat1 & 0x01)
DIO = 1;
else
DIO = 0;
S_CLK = 1;//穿行輸入
S_CLK = 0;
dat1 >>= 1;
}
for (j = 0; j < 8; j++)
{
if (dat2 & 0x01)
DIO = 1;
else
DIO = 0;
S_CLK = 1;//串行輸入
S_CLK = 0;
dat2 >>= 1;
}
R_CLK = 1;//并行輸出
R_CLK = 0;
}
5.蛇的初始化
main函數(shù)主要內(nèi)容
void main()
{
timer0Init();//定時器0初始化
snakex[0] = 5;//蛇體初始x坐標
snakey[0] = 5;//蛇初始y坐標
creat_food();
while (1)
{
snakemove();
FoodAnd();
}
}
void timer0() interrupt 1
{
TH0 = 0XED;
TL0 = 0XFF;
m++;//每加到一百蛇體移動一次,速度可以自己調(diào)
keyscan();//鍵盤掃描
for (d = 0; d < len; d++)
{
SendByte(snakex[d], snakey[d]);//將蛇體顯示在點陣屏上,參數(shù)是xy坐標
}
SendByte(foodx, foody);//顯示食物
CheckDead();//檢驗是否死亡
}
6.蛇體的移動
void left()//上下左右都是一個道理
{
uchar i, x1, x2, y1, y2;
x1 = snakex[0];//保留上一結(jié)點的x軸狀態(tài)
snakex[0]--;//坐標減1
if (snakex[0] == 0)//這里是判定是否碰到邊界了,這里設(shè)定的是可以從另一邊出來,當然也可以設(shè)定為碰到就死
snakex[0] = 8;
y1 = snakey[0];//保留上一結(jié)點的y軸狀態(tài)
for (i = 1; i < len; i++)
{
y2 = snakey[i];//進行各個結(jié)點的狀態(tài)移動,形成蛇運動的效果
snakey[i] = y1;
y1 = y2;
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
}
}
void up()
{
uchar i, x1, x2, y1, y2;
y1 = snakey[0];
snakey[0]--;
if (snakey[0] == 0)
snakey[0] = 8;
x1 = snakex[0];
for (i = 1; i < len; i++)
{
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
y2 = snakey[i];
snakey[i] = y1;
y1 = y2;
}
}
void down()
{
uchar i, x1, x2, y1, y2;
y1 = snakey[0];
snakey[0]++;
if (snakey[0] == 9)
snakey[0] = 1;
x1 = snakex[0];
for (i = 1; i < len; i++)
{
y2 = snakey[i];
snakey[i] = y1;
y1 = y2;
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
}
}
void right()
{
uchar i, x1, x2, y1, y2;
x1 = snakex[0];
snakex[0]++;
if (snakex[0] == 9)
snakex[0] = 1;
y1 = snakey[0];
for (i = 1; i < len; i++)
{
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
y2 = snakey[i];
snakey[i] = y1;
y1 = y2;
}
}
void snakemove()
{
if (key == 1 && m == 100)//這里是判斷按鍵值并且m要達到100,也就是500ms移動一次
{
left();
m = 0;//要清一下零
}
if (key == 2 && m == 100)
{
up();
m = 0;
}
if (key == 3 && m == 100)
{
down();
m = 0;
}
if (key == 4 && m == 100)
{
right();
m = 0;
}
}
7.食物的創(chuàng)建
這一部分本來以為使用c語言里面srand(unsigned seed)(這個函數(shù)只要種子的值是變化的生成的就是某種意義上隨機數(shù))函數(shù)加上一個一直變化的時間戳就可以生成隨機數(shù)的,但是后來發(fā)現(xiàn)keil里面沒有time.h這個頭文件,導(dǎo)致沒法實現(xiàn)真正意義的隨機數(shù)。這個問題暫留
uchar CheckFood()//檢驗食物有沒有和蛇體重合
{
uchar i;
for (i = 0; i < len; i++)
{
if (foodx == snakex[i] && foody == snakey[i])
{
return 1;
}
}
return 0;
}
void creat_food()
{
do
{
foodx = (uchar)(rand() % 8 + 1);
foody = (uchar)(rand() % 8 + 1);
} while (CheckFood() != 0);
}
8.食物的檢測和身體的增長
void FoodAnd()//檢驗食物有沒有被吃掉
{
if (foodx == snakex[0] && foody == snakey[0])
{
if (len < 20)
{
snakex[len] = snakex[len - 1];//和之前一樣,把上一個結(jié)點的狀態(tài)賦給下一個結(jié)點,用來增加長度
snakey[len] = snakey[len - 1];
len++;
}
creat_food();//被吃掉重新生成食物
}
}
9.檢測死亡
這里i = 2是因為等于1的時候會在吃食物的時候沖突,而蛇頭不可能碰到碰到第二節(jié),所以初值設(shè)定為2文章來源:http://www.zghlxwxcb.cn/news/detail-721764.html
void CheckDead()
{
uchar i;
for (i = 2; i < len; i++)
{
if (snakex[0] == snakex[i] && snakey[0] == snakey[i])
{
while (1);
}
}
}
10.總代碼
#include <reg52.h>
#include <stdlib.h>
#define uint unsigned int
#define uchar unsigned char
#include <intrins.h>
sbit DIO = P3 ^ 4;
sbit S_CLK = P3 ^ 5;
sbit R_CLK = P3 ^ 6;
sbit key_s2 = P3 ^ 0;
sbit key_s3 = P3 ^ 1;
sbit key_s4 = P3 ^ 2;
sbit key_s5 = P3 ^ 3;
uchar coorx[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };
uchar coory[8] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };
uchar snakex[20];
uchar snakey[20];
uchar m = 0;
uchar len = 1;
uchar foodx, foody;
uchar d, xx, yy;
char key = 0;
void delay(uint z)
{
uint x, y;
for (x = z; x > 0; x--)
for (y = 114; y > 0; y--);
}
void keyscan()
{
if (key_s2 == 0)
{
delay(10);
if (key_s2 == 0)
{
if (key != 4)
key = 1;
}
}
if (key_s3 == 0)
{
delay(10);
if (key_s3 == 0)
{
if (key != 3)
key = 2;
}
}
if (key_s4 == 0)
{
delay(10);
if (key_s4 == 0)
{
if (key != 2)
key = 3;
}
}
if (key_s5 == 0)
{
delay(10);
if (key_s5 == 0)
{
if (key != 1)
key = 4;
}
}
}
void SendByte(uchar x, uchar y)//用來接收行列值,這里x和y是坐標,點陣屏左下角為坐標原點
{
uchar i, j, dat1, dat2;
dat1 = coorx[x - 1];//這里通過前面定義的兩個數(shù)組將坐標轉(zhuǎn)化為了行列的十六進制數(shù)
dat2 = coory[y - 1];
for (i = 0; i < 8; i++)
{
if (dat1 & 0x01)
DIO = 1;
else
DIO = 0;
S_CLK = 1;//穿行輸入
S_CLK = 0;
dat1 >>= 1;
}
for (j = 0; j < 8; j++)
{
if (dat2 & 0x01)
DIO = 1;
else
DIO = 0;
S_CLK = 1;//串行輸入
S_CLK = 0;
dat2 >>= 1;
}
R_CLK = 1;//并行輸出
R_CLK = 0;
}
uchar CheckFood()//檢驗食物有沒有和蛇體重合
{
uchar i;
for (i = 0; i < len; i++)
{
if (foodx == snakex[i] && foody == snakey[i])
{
return 1;
}
}
return 0;
}
void creat_food()
{
do
{
foodx = (uchar)(rand() % 8 + 1);
foody = (uchar)(rand() % 8 + 1);
} while (CheckFood() != 0);
}
void FoodAnd()//檢驗食物有沒有被吃掉
{
if (foodx == snakex[0] && foody == snakey[0])
{
if (len < 20)
{
snakex[len] = snakex[len - 1];//和之前一樣,把上一個結(jié)點的狀態(tài)賦給下一個結(jié)點,用來增加長度
snakey[len] = snakey[len - 1];
len++;
}
creat_food();//被吃掉重新生成食物
}
}
void left()//上下左右都是一個道理
{
uchar i, x1, x2, y1, y2;
x1 = snakex[0];//保留上一結(jié)點的x軸狀態(tài)
snakex[0]--;//坐標減1
if (snakex[0] == 0)//這里是判定是否碰到邊界了,這里設(shè)定的是可以從另一邊出來,當然也可以設(shè)定為碰到就死
snakex[0] = 8;
y1 = snakey[0];//保留上一結(jié)點的y軸狀態(tài)
for (i = 1; i < len; i++)
{
y2 = snakey[i];//進行各個結(jié)點的狀態(tài)移動,形成蛇運動的效果
snakey[i] = y1;
y1 = y2;
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
}
}
void up()
{
uchar i, x1, x2, y1, y2;
y1 = snakey[0];
snakey[0]--;
if (snakey[0] == 0)
snakey[0] = 8;
x1 = snakex[0];
for (i = 1; i < len; i++)
{
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
y2 = snakey[i];
snakey[i] = y1;
y1 = y2;
}
}
void down()
{
uchar i, x1, x2, y1, y2;
y1 = snakey[0];
snakey[0]++;
if (snakey[0] == 9)
snakey[0] = 1;
x1 = snakex[0];
for (i = 1; i < len; i++)
{
y2 = snakey[i];
snakey[i] = y1;
y1 = y2;
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
}
}
void right()
{
uchar i, x1, x2, y1, y2;
x1 = snakex[0];
snakex[0]++;
if (snakex[0] == 9)
snakex[0] = 1;
y1 = snakey[0];
for (i = 1; i < len; i++)
{
x2 = snakex[i];
snakex[i] = x1;
x1 = x2;
y2 = snakey[i];
snakey[i] = y1;
y1 = y2;
}
}
void CheckDead()
{
uchar i;
for (i = 2; i < len; i++)
{
if (snakex[0] == snakex[i] && snakey[0] == snakey[i])
{
while (1);
}
}
}
void snakemove()
{
if (key == 1 && m == 100)//這里是判斷按鍵值并且m要達到100,也就是500ms移動一次
{
left();
m = 0;//要清一下零
}
if (key == 2 && m == 100)
{
up();
m = 0;
}
if (key == 3 && m == 100)
{
down();
m = 0;
}
if (key == 4 && m == 100)
{
right();
m = 0;
}
}
void timer0Init()
{
EA = 1;
ET0 = 1;
TR0 = 1;
TMOD = 0X01;
TH0 = 0XED;
TL0 = 0XFF;
}
void main()
{
timer0Init();//定時器0初始化
snakex[0] = 5;//蛇體初始x坐標
snakey[0] = 5;//蛇初始y坐標
creat_food();
while (1)
{
snakemove();
FoodAnd();
}
}
void timer0() interrupt 1
{
TH0 = 0XED;
TL0 = 0XFF;
m++;//每加到一百蛇體移動一次,速度可以自己調(diào)
keyscan();//鍵盤掃描
for (d = 0; d < len; d++)
{
SendByte(snakex[d], snakey[d]);//將蛇體顯示在點陣屏上,參數(shù)是xy坐標
}
SendByte(foodx, foody);//顯示食物
CheckDead();//檢驗是否死亡
}
總結(jié)
代碼由于本人實力問題還有部分不足之處希望支持。文章來源地址http://www.zghlxwxcb.cn/news/detail-721764.html
到了這里,關(guān)于51單片機實現(xiàn)貪吃蛇(清翔單片機)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!