
如圖所示為原理圖,@小華同學畫的
測驗出的點陣相應引腳,很亂……

話不多說直接上代碼,添加了一些注釋
#include "reg52.h"
#include "stdlib.h"
typedef unsigned int u16; //對資料型別進行宣告定義
typedef unsigned char u8;
sbit KEY_IN_1 = P2^7; //上
sbit KEY_IN_2 = P2^4; //下
sbit KEY_IN_3 = P2^6; //左
sbit KEY_IN_4 = P2^5; //右
u8 T0RH = 0;
u8 T0RL = 0;
u8 keysta[4] = {1,1,1,1};
u8 FoodPosition[2] = {4,5}; //初始化果子
u8 snake_x[32] = {0},snake_y[32] = {0}; //蛇身最大長度
u8 snakelong = 3; //全域變數蛇長
u8 flag_x = 1; //初始化移動方向,共有四種情況 1,0 -1,0 0,1 0,-1
u8 flag_y = 0;
u8 flag_g = 1; //初始化果子標志位
u8 flag_c = 0; //吃到自己身體游戲結束
u8 flag_m = 1; //蛇身移動位
u8 score = 0;//吃果分數
u8 code mtable[10]={0x01,0xb7,0x42,0x12,0x34,0x18,0x08,0xb3,0x80,0x10};//控制數碼管顯示0-9
void ConfigTimer0(unsigned int ms)//定時器配置,設定成1ms進入一次中斷
{
unsigned long tmp;
tmp = 12000000/12;
tmp = (tmp*ms)/1000;
tmp = 65535 - tmp;
T0RH = (unsigned char)(tmp>>8);
T0RL = (unsigned char)tmp;
EA = 1;
TMOD &= 0XF0;
TMOD |=0x01;
TH0 = T0RH;
TL0 = T0RL;
ET0 = 1; //T0中斷使能
TR0 = 1;
}
void delay(u16 i)//沒有任何技術含量的延時函式
{
while(i)
{
i--;
}
}
//點陣坐標顯示,因為引腳太亂了只能如此,一共64個坐標
void leddot(u8 snake_x,u8 snake_y)
{
switch(snake_x){
case 1:
{
switch(snake_y){
case 1 :P1 = 0xea;P3 = 0x2c ;break;
case 2 :P1 = 0xe9;P3 = 0x2c ;break;
case 3 :P1 = 0xcb;P3 = 0x2c ;break;
case 4 :P1 = 0xeb;P3 = 0x0c ;break;
case 5 :P1 = 0xab;P3 = 0x2c ;break;
case 6 :P1 = 0xeb;P3 = 0x24 ;break;
case 7 :P1 = 0xeb;P3 = 0x28 ;break;
case 8 :P1 = 0xe3;P3 = 0x2c ;break;
default:break;
}
break;
}
case 2:
{
switch(snake_y){
case 1 :P1 = 0x6e;P3 = 0x2c ;break;
case 2 :P1 = 0x6d;P3 = 0x2c ;break;
case 3 :P1 = 0x4f;P3 = 0x2c ;break;
case 4 :P1 = 0x6f;P3 = 0x0c ;break;
case 5 :P1 = 0x2f;P3 = 0x2c ;break;
case 6 :P1 = 0x6f;P3 = 0x24 ;break;
case 7 :P1 = 0x6f;P3 = 0x28 ;break;
case 8 :P1 = 0x67;P3 = 0x2c ;break;
default:break;
}
break;
}
case 3:
{
switch(snake_y){
case 1 :P1 = 0x6a;P3 = 0xac ;break;
case 2 :P1 = 0x69;P3 = 0xac ;break;
case 3 :P1 = 0x4b;P3 = 0xac ;break;
case 4 :P1 = 0x6b;P3 = 0x8c ;break;
case 5 :P1 = 0x2b;P3 = 0xac ;break;
case 6 :P1 = 0x6b;P3 = 0xa4 ;break;
case 7 :P1 = 0x6b;P3 = 0xa8 ;break;
case 8 :P1 = 0x63;P3 = 0xac ;break;
default:break;
}
break;
}
case 4:
{
switch(snake_y){
case 1 :P1 = 0x7a;P3 = 0x2c ;break;
case 2 :P1 = 0x79;P3 = 0x2c ;break;
case 3 :P1 = 0x5b;P3 = 0x2c ;break;
case 4 :P1 = 0x7b;P3 = 0x0c ;break;
case 5 :P1 = 0x3b;P3 = 0x2c ;break;
case 6 :P1 = 0x7b;P3 = 0x24 ;break;
case 7 :P1 = 0x7b;P3 = 0x28 ;break;
case 8 :P1 = 0x73;P3 = 0x2c ;break;
default:break;
}
break;
}
case 5:
{
switch(snake_y){
case 1 :P1 = 0x6a;P3 = 0x2d ;break;
case 2 :P1 = 0x69;P3 = 0x2d ;break;
case 3 :P1 = 0x4b;P3 = 0x2d ;break;
case 4 :P1 = 0x6b;P3 = 0x0d ;break;
case 5 :P1 = 0x2b;P3 = 0x2d ;break;
case 6 :P1 = 0x6b;P3 = 0x25 ;break;
case 7 :P1 = 0x6b;P3 = 0x29 ;break;
case 8 :P1 = 0x63;P3 = 0x2d ;break;
default:break;
}
break;
}
case 6:
{
switch(snake_y){
case 1 :P1 = 0x6a;P3 = 0x6c ;break;
case 2 :P1 = 0x69;P3 = 0x6c ;break;
case 3 :P1 = 0x4b;P3 = 0x6c ;break;
case 4 :P1 = 0x6b;P3 = 0x4c ;break;
case 5 :P1 = 0x2b;P3 = 0x6c ;break;
case 6 :P1 = 0x6b;P3 = 0x64 ;break;
case 7 :P1 = 0x6b;P3 = 0x68 ;break;
case 8 :P1 = 0x63;P3 = 0x6c ;break;
default:break;
}
break;
}
case 7:
{
switch(snake_y){
case 1 :P1 = 0x6a;P3 = 0x2e ;break;
case 2 :P1 = 0x69;P3 = 0x2e ;break;
case 3 :P1 = 0x4b;P3 = 0x2e ;break;
case 4 :P1 = 0x6b;P3 = 0x0e ;break;
case 5 :P1 = 0x2b;P3 = 0x2e ;break;
case 6 :P1 = 0x6b;P3 = 0x26 ;break;
case 7 :P1 = 0x6b;P3 = 0x2a ;break;
case 8 :P1 = 0x63;P3 = 0x2e ;break;
default:break;
}
break;
}
case 8:
{
switch(snake_y){
case 1 :P1 = 0x6a;P3 = 0x3c ;break;
case 2 :P1 = 0x69;P3 = 0x3c ;break;
case 3 :P1 = 0x4b;P3 = 0x3c ;break;
case 4 :P1 = 0x6b;P3 = 0x1c ;break;
case 5 :P1 = 0x2b;P3 = 0x3c ;break;
case 6 :P1 = 0x6b;P3 = 0x34 ;break;
case 7 :P1 = 0x6b;P3 = 0x38 ;break;
case 8 :P1 = 0x63;P3 = 0x3c ;break;
default:break;
}
break;
}
default:break;
}
}
void appearsnake() //顯示蛇身
{
u8 i = 0;
for(i=0;i<snakelong;i++) //snakelong 是用來控制陣列的全域關鍵變數
{
if((snake_x[i] != 0)||(snake_y[i] != 0))
{
leddot(snake_x[i],snake_y[i]);
delay(300); //延時,一次只顯示一個點,利用視覺停留
P1 = 0x6b;
P3 = 0x2c;
}
}
}
void keyaction(u8 dat) //控制蛇頭上下左右移動
{
if(dat == 0) //上
{
if(flag_x != -1){
flag_x = 1;
flag_y = 0;
}
}
else if(dat == 1) //下
{
if(flag_x != 1){
flag_x = -1;
flag_y = 0;
}
}
else if(dat == 2) //左
{
if(flag_y != -1){
flag_x = 0;
flag_y = 1;
}
}
else if(dat == 3) //右
{
if(flag_y != 1){
flag_x = 0;
flag_y = -1;
}
}
}
void keydriver()
{
u8 i;
static u8 backup[4] = {1,1,1,1};
for(i = 0;i<4;i++)
{
if(keysta[i] != backup[i])
{
if(backup[i]!=0) //上一次是彈起狀態,則執行回應動作
keyaction(i);//這里才是執行動作的部分
backup[i] = keysta[i];//更新按鍵狀態
}
}
}
void KeyScan()//按鍵檢測函式,軟體消抖
{
u8 i = 0;
static u8 keybuf[4] = {0xFF,0xFF,0xFF,0xFF};
keybuf[0] = (keybuf[0]<<1)|KEY_IN_1;
keybuf[1] = (keybuf[1]<<1)|KEY_IN_2;
keybuf[2] = (keybuf[2]<<1)|KEY_IN_3;
keybuf[3] = (keybuf[3]<<1)|KEY_IN_4;
for(i=0;i<4;i++)
{
if(keybuf[i] == 0x00)
keysta[i] = 0; //按鍵按下
else if(keybuf[i] == 0xFF)
keysta[i] = 1; //按鍵彈起
}
}
void appearguo()
{
u8 i,m,n;
do{
flag_g = 0;
m = rand()%8+1; //顯示下一個果子
n = rand()%8+1;
for(i=0;i<snakelong;i++)
{
if((m == snake_x[i])&&(n == snake_y[i])) //如果果子和蛇身有重復,則flag_g置1,再生成一次
flag_g = 1;
}
}while(flag_g);
FoodPosition[0] = m;
FoodPosition[1] = n;
}
void move()//蛇移動,改變蛇的坐標
{
u8 i;
for(i = 0;i<snakelong-1;i++)
{
snake_x[i] = snake_x[i+1];
snake_y[i] = snake_y[i+1];
}
snake_x[i] += flag_x;
snake_y[i] += flag_y;
if(snake_x[snakelong-1]>8) //穿墻判斷
snake_x[snakelong-1] = 1;
else if(snake_x[snakelong-1]<1)
snake_x[snakelong-1] = 8;
if(snake_y[snakelong-1]>8)
snake_y[snakelong-1] = 1;
else if(snake_y[snakelong-1]<1)
snake_y[snakelong-1] = 8;
flag_m = 0;
}
void chiguo()
{
if((snake_x[snakelong-1]) == FoodPosition[0] && (snake_y[snakelong-1]) == FoodPosition[1])
{
TR0 = 0;
snakelong++;
score++;
P0 = mtable[score];
snake_x[snakelong-1] = FoodPosition[0]+flag_x;
snake_y[snakelong-1] = FoodPosition[1]+flag_y;
appearguo();
TR0 = 1;
}
}
void eatself()
{
u8 i;
for(i = 3;i<snakelong-1;i++)//判斷蛇是否吃到自己的身體
{
if(snake_x[snakelong-1] == snake_x[i]&&snake_y[snakelong-1] == snake_y[i])
{
flag_c = 1;
break;
}
}
}
int main()
{
snake_x[0] = 1;
snake_x[1] = 2;
snake_x[2] = 3;
snake_y[0] = 1;
snake_y[1] = 1;
snake_y[2] = 1;//初始化蛇身
P0 = mtable[0];
ConfigTimer0(1);//定時器0開始計時
while(1)
{
if(!flag_c) //蛇身移動位
{
appearsnake();
keydriver();
if(flag_m) //蛇身死亡位
{
move();
chiguo();
eatself();
delay(300);
}
}
}
}
void Timer0() interrupt 1 //重繪點陣,按鍵
{
static u16 index = 0;
static u16 count = 0;
TH0 = T0RH;
TL0 = T0RL;
KeyScan();
index++;
count++;
if( index >= 400)//蛇移動的速度
{
flag_m = 1;
index = 0;
}
if(!flag_c&&count>30)//果子顯示頻率
{
count = 0;
leddot(FoodPosition[0],FoodPosition[1]);
}
}

稍微簡單寫了點,建議學弟學妹們先去學習一下C語言,數碼管和點陣的顯示原理以及單片機的定時器等,然后能更好的理解程式,另外希望大家保持一顆熱愛的心,不管比賽結果如何,都能繼續繼續努力下去,唯有時間不會辜負你
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/375052.html
標籤:其他
上一篇:1000以內猜數游戲
