|
一年前做的小玩意了,硬件丟失了,程序還在,以前都是寫在一個文件內(nèi),翻出來分成幾個文件,程序注釋寫的很詳細,希望對初入單片機的師兄有所幫助
1.png (264.72 KB, 下載次數(shù): 79)
下載附件
2020-1-21 20:09 上傳
單片機源程序如下:
- //=========================================================================================================================================
- //軟件功能:俄羅斯方塊
- //硬件描述:最小系統(tǒng)+4x(8x8點陣)+ (1x(HC154)+3x(74HC14D)) + 1x(HC595)
- //程序描述:74595.c中有串進并出程序
- // delay.c中有延遲函數(shù)
- // dispaly.c中有開始畫面顯示函數(shù)、點陣顯示函數(shù)、數(shù)碼管顯示函數(shù)
- // random.c中有隨機圖案緩存函數(shù)
- // anjian.c中按鍵函數(shù)、圖案觸底函數(shù)、消行函數(shù)、旋轉(zhuǎn)圖案數(shù)據(jù)改變函數(shù)、顯示清除函數(shù)
- // timinit.c中中斷初始化函數(shù)
- //功能概括描述:16x16點陣用于顯示、5個按鍵有旋轉(zhuǎn)按鍵、上、下、左、右按鍵、數(shù)碼管用于顯示得分
- // 上按鍵用于開始游戲鍵、下按鍵用于圖案加速下落鍵、左、右按鍵用于圖案左右移動
- // 有圖案觸底判斷、圖案左右碰壁判斷、消行判斷
- //=========================================================================================================================================
- #include "reg52.h" //52頭文件
- #include "stdlib.h" //隨機函數(shù)rand()調(diào)用頭文件
- #include "74595.h" //74HC595使用所需
- #include "delay.h"
- #include "display.h"
- #include "random.h"
- #include "anjian.h"
- #include "timinit.h"
- #define uchar unsigned char
- #define uint unsigned int
- sbit KS=P3^4; //下鍵
- //sbit BEEP=P2^7; //蜂鳴器
- uchar code DUANMA[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //數(shù)碼管顯示0~9,0xff不顯示;
- uint code KAITOU[3][8]={{0x3c10,0x2820,0x3bfc,0x2480,0x2520,0x3bfc,0x2020,0x20a8}, //陳發(fā)兩字;
- {0x2124,0x2020,0x2060,0x2020,0x0000,0x0000,0x0210,0x0428},
- {0x0844,0x1080,0x3ffc,0x03f0,0x04a0,0x0840,0x10a0,0x2110}};
- uint HUANCUN[16],CUN[16],XZA[4],KKK; //顯示數(shù)組HUANCUN[16],存儲隨機圖案數(shù)組CUN[16]
- uchar q,n,k,m=1,x=0,t=0,JILV=1,a=0,ZUOJIA=7,G=7,XUANZUAN=0,R=0; //ZUOJIA對應(yīng)16*16的豎,左到右編號為0~15
- //=========================================================================================================================================
- void main() //主函數(shù)
- {
- init(); //初始化
- KT(); //開頭顯示啟動游戲界面
- while(1)
- {
- a=rand()%6; //隨機數(shù)0~5
- XIANSI(); //點陣顯示函數(shù)
- if(TR0==0){ //判斷定時器是否關(guān)著
- SMG(); //數(shù)碼管顯示函數(shù)
- if(KEY==0){ //如果開始鍵按下
- QC_HC(); //清除緩存顯示函數(shù)
- KKK=0; //分數(shù)清零
- TR0=1; //啟動定時器
- }
- }
- }
- }
- //=========================================================================================================================================
- //變量說明:t:用于計時,配合向下按鍵的判斷,來決定圖案的下落速度
- // CBN:圖案下落速度變量
- // x,m,JILV:初始狀態(tài)m=JILV=1,x=0(x是HUANCUN[]里的數(shù)據(jù)編號,從0開始)
- //程序描述:先忽略按鍵部分,理順開始按鍵(KEY)按下后的整個流程
- // 判斷定時時間CBN與t的值是否相等,到時間先判斷圖案還能不能下落,既觸底(m=JILV),如果沒觸底清除當(dāng)前圖案,顯示下落一行后的圖案
- // 初始狀態(tài)是m=JILV=1,會先運行一次XH();和AJ_PD();
- // 添加按鍵功能,首先調(diào)用按鍵函數(shù)ANJIAN();
- // 如果按鍵有變化那么ZUOJIA和XUANZUAN都將發(fā)生改變,此時不管t為何值都要執(zhí)行相應(yīng)程序
- // 根據(jù)ZUOJIA的改變來變動CUN[]的圖案數(shù)據(jù)
- // 如果CUN[]改變,要從新調(diào)用AJ_PD();求JILV的值
- // 如果旋轉(zhuǎn)按鍵狀態(tài)XUANZUAN改變,變動CUN[]里的數(shù)據(jù),判斷此時的圖案會不會與原來的“積木”重疊,如果重疊,CUN[]變回原來的數(shù)據(jù),AJ_PD();重新調(diào)用
- //=========================================================================================================================================
- void timer() interrupt 1
- {
- static uchar CBN; //定義變量CBN用于控制圖案下落的速度
- TH0=(65536-5000)/256; //定時器初始化
- TL0=(65536-5000)%256;
- t++; //計時(t)累加
- ANJIAN(); //調(diào)用按鍵子程序
- if(KS==0){ //判斷向下按鍵(KS)有沒有按
- if(t>30)t=0; //如果計時(t)大于30,t清零重新開始計時
- CBN=20; //減短圖案下落的時間
- }else
- CBN=80; //圖案平時下落速度
- /*----------------------------------------------------------------------------------------------------------------------------------------*/
- if((t==CBN)||(ZUOJIA!=G)||(XUANZUAN!=R)){ //計時(t)到了所設(shè)定的時間“或”左右和旋轉(zhuǎn)按鍵三鍵中的一個按了一下
- if(m==JILV){ //如果圖案下落到預(yù)先掃描的指定行
- x=0; //各種變量初始化
- m=1;
- G=7;
- R=0;
- JILV=1;
- ZUOJIA=7;
- XUANZUAN=0;
- XIAOHAN(); //調(diào)用消行子程序
- /*---------------------------------------------------------------------------------*/
- if(HUANCUN[0]!=0x0000){ //點陣頂部是否亮起,如果亮起表示該結(jié)束了
- QC_HC(); //清除緩存
- HUANCUN[2]=0x0ff0; //結(jié)束顯示笑臉圖案
- HUANCUN[3]=0x1008;
- HUANCUN[4]=0x2424;
- HUANCUN[5]=0x2a54;
- HUANCUN[6]=0x2004;
- HUANCUN[7]=0x2004;
- HUANCUN[8]=0x2004;
- HUANCUN[9]=0x2004;
- HUANCUN[10]=0x2244;
- HUANCUN[11]=0x2184;
- HUANCUN[12]=0x1008;
- HUANCUN[13]=0x0ff0;
- TR0=0; //定時器關(guān)閉
- return; //跳出中斷
- }
- /*---------------------------------------------------------------------------------*/
- XH(); //圖案對應(yīng)數(shù)組
- AJ_PD(); //從上至下行掃描得到指定行變量(JILV)
- }else{ //如果圖案還在下落
- m--; //變量(m)控制圖案數(shù)組與緩存數(shù)組的數(shù)據(jù)運算
- x=m-1; //緩存變量(x)返回上個圖案值
- for(n=0;n<m;n++){
- HUANCUN[x]&=(~CUN[n]); //上個圖案清除
- x--;
- }
- x=m; //緩存變量(x)加一為下個圖案顯示做準備
- m++;
- }
- /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
- if(ZUOJIA!=G){ //如果左右鍵狀態(tài)發(fā)生一次改變
- for(n=0;n<16;n++){
- if(ZUOJIA>G){ //如果是右鍵發(fā)生的變動
- CUN[n]>>=1;
- }else
- CUN[n]<<=1;
- }
- AJ_PD(); //重新掃描求JILV
- x--;
- m--;
- G=ZUOJIA;
- }
- if(XUANZUAN!=R){ //旋轉(zhuǎn)鍵狀態(tài)改變一次
- x--;
- m--;
- XH(); //調(diào)用XH()子程序,為了顯示旋轉(zhuǎn)后的圖案,注意:這時圖案是在正中間,即ZUOJIA=7的位置
- HPP(); //調(diào)用旋轉(zhuǎn)子程序
- for(n=0;n<m;n++){
- if(CUN[n]!=0){
- if((HUANCUN[x]&CUN[n])!=0){ //如果旋轉(zhuǎn)后的圖案會和已存在圖案重合
- if(XUANZUAN==0)XUANZUAN=4; //4種旋轉(zhuǎn)圖案對應(yīng)狀態(tài)值改回未變圖案前的狀態(tài)
- else XUANZUAN--;
- for(n=0;n<4;n++){ //圖案也要變回去
- CUN[n]=XZA[n];
- }
- break;
- }
- }
- x--;
- }
- AJ_PD(); //調(diào)用掃描子程序,求新的JILV
- x=m-1;
- R=XUANZUAN; //把旋轉(zhuǎn)圖案狀態(tài)值賦值給變量R,只有旋轉(zhuǎn)按鈕再次按下,才會再進來
- }
- /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
- for(n=0;n<m;n++){
- HUANCUN[x]|=CUN[n]; //把將要顯示的圖案對應(yīng)的數(shù)組送入緩存數(shù)組
- x--;
- }
- m++;
- t=0; //計時變量清零
- }
- }
- //=========================================================================================================================================
復(fù)制代碼- #include "anjian.h"
- //=========================================================================================================================================
- extern uchar XUANZUAN,ZUOJIA,JILV,m,n,x,k,G;
- extern uint HUANCUN[16],CUN[16],XZA[4],KKK;
- //=========================================================================================================================================
- //程序描述:判斷右鍵(YOU)按下否?
- // 先把圖案對應(yīng)豎位置的狀態(tài)變量ZUOJIA改變,再判斷圖案可不可以移動,如果不可以ZUOJIA改回來
- // m,x確實有點繞
- // 左鍵同上
- // 旋轉(zhuǎn)按鍵按下,改變圖案狀態(tài)變量XUANZUAN,保存當(dāng)前圖案CUN[]到XZA[]
- //=========================================================================================================================================
- void ANJIAN() //按鍵子程序
- {
- static uchar i=1,s=1,j=1; //定義三個靜態(tài)變量i,s,j表示右,左,旋轉(zhuǎn)按鍵的狀態(tài)值
- if(YOU!=s){ //如果右鍵狀態(tài)值發(fā)生改變
- if(s!=0){ //判斷狀態(tài)值是否為0,如果不是,說明右鍵按下了
- ZUOJIA++; //圖案未動,圖案對應(yīng)豎的狀態(tài)值先加一
- m--; //x,m數(shù)組間交換變化所定義的變量
- x=m-1;
- for(n=0;n<m;n++){
- if(CUN[n]!=0){ //如果CUN[n]為0,就不用浪費時間判斷什么了
- if(((HUANCUN[x]&((CUN[n]|(CUN[n]/2))-CUN[n]))!=0)||((CUN[n]&0x0001)!=0)){ //CUN[n]/2右移一位
- m++; //CUN[n]|(CUN[n]/2)右移一位后和之前的數(shù)或,(CUN[n]|(CUN[n]/2))-CUN[n]或了的數(shù)再減去最開始的數(shù),就是右移后的圖案
- ZUOJIA--; //HUANCUN[x]&((CUN[n]|(CUN[n]/2))-CUN[n])!=0上面的數(shù)再和顯示數(shù)組里的數(shù)與,判斷運算后的數(shù)是否為0
- s=YOU; //上面的運算就是判斷”圖案向右移動是否會碰到已經(jīng)存在的圖案“
- return; //(CUN[n]&0x0001)!=0這句判斷圖案有沒有碰到右邊的邊界
- } //m++;ZUOJIA--;進入if說明圖案不能變,那么前面改變的值都要改回來,s=YOU;既然程序要跳出來了,按鍵的狀態(tài)值也要改變的,防止又進來了
- }
- x--;
- }
- x=m;
- m++;
- }
- s=YOU;
- }
- if(ZUO!=i){ //左鍵類同右鍵
- if(i!=0){
- ZUOJIA--;
- m--;
- x=m-1;
- for(n=0;n<m;n++){
- if(CUN[n]!=0){
- if(((HUANCUN[x]&((CUN[n]|(CUN[n]<<1))-CUN[n]))!=0)||(CUN[n]>=0x8000)){
- m++;
- ZUOJIA++;
- i=ZUO;
- return;
- }
- }
- x--;
- }
- x=n;
- m++;
- }
- i=ZUO;
- }
- if(XZ!=j){ //旋轉(zhuǎn)按鍵
- if(j!=0){
- XUANZUAN=(XUANZUAN+1)%4; //如果旋轉(zhuǎn)按鍵按下了,這里4種圖案是按逆時針變化
- for(n=0;n<4;n++){
- XZA[n]=CUN[n]; //圖案先保存在數(shù)組XZA[]中
- }
- }
- j=XZ;
- }
- }
- //=========================================================================================================================================
- //思維說明:在XH()程序中知道圖案細分成15種,目的是要寫一個程序讓這15種圖案下落后碰到下面的"積木"停下來(記下這一行的編號存在變量JILV里)
- //程序描述:圖案保存在數(shù)組CUN[]中,CUN[0]是圖案的底部,CUN[1]是圖案中部,CUN[2]是圖案上部,CUN[3]可以不作考慮
- // 16x16點陣有16行,以圖案當(dāng)前在點陣處在的位置開始與點陣已經(jīng)存在“積木”做運算,判斷再下落是否會重疊
- // 首先,判斷CUN[0]是否觸底了,即,(HUANCUN[n]&CUN[0])!=0
- // 其次,判斷CUN[1]是否觸底了,(CUN[1]|CUN[0])-CUN[0]這是取CUN[1]和CUN[0]在垂直方向上沒有重合的部分
- // 最后,判斷CUN[2]是否觸底了,這種情況只有一種圖案會發(fā)生
- // 總結(jié),一種圖案出現(xiàn)改變也好,都要調(diào)用這個函數(shù)找出觸底位置
- // 當(dāng)n>1后,運行一次for就判斷一個圖案分成3段的觸底情況
- //=========================================================================================================================================
- void AJ_PD() //從上至下行掃描得到指定行變量(JILV)子程序
- {
- for(n=m-1;n<16;n++){ //掃描緩存數(shù)組
- if((HUANCUN[n]&CUN[0])!=0) break; //如果圖案底層觸底,跳出掃描
- else
- if((n>0)&&((HUANCUN[n-1]&((CUN[1]|CUN[0])-CUN[0]))!=0)) break; //否則,圖案底層上面層觸底,跳出掃描
- if((n>1)&&((HUANCUN[n-2]&((CUN[2]|CUN[1])-CUN[1]))!=0)) break; //圖案底層上面層的上面層觸底,跳出掃描
- }
- JILV=n+1; //記錄JILV
- }
- //=========================================================================================================================================
- //我看到一個教程里說不要在for(i=0;i<6;i++)里面改變變量(i)的值,但我不知道會出什么問題
- //程序描述:從點陣的最下行向上開始判斷
- //=========================================================================================================================================
- void XIAOHAN()
- { //消行子程序
- uint i;
- uchar u;
- i=KKK;
- for(n=16;n>0;n--){ //掃描16行
- if(HUANCUN[n-1]==0xffff){ //如果某行全亮
- for(u=n;u>1;u--){
- HUANCUN[u-1]=HUANCUN[u-2]; //上面一行覆蓋下面一行
- }
- HUANCUN[0]=0x0000;
- n++;
- KKK++;
- } //最上面一行清零
- } //16行全掃描后,結(jié)束子程序
- if(KKK==(i+2))KKK+=2; //如果同時消除2行加4分
- else
- if(KKK==(i+3))KKK+=6; //如果同時消除3行加9分
- else
- if(KKK==(i+4))KKK+=12; //如果同時消除4行加16分
- else
- if(KKK>(i+4))KKK+=20; //如果同時消除5行加25分
- }
- //=========================================================================================================================================
- //思維說明:XH();中CUN[]只存改變后的圖案,位置是在ZUOJIA=7,現(xiàn)在要寫段程序根據(jù)ZUOJIA的值改變CUN[]的數(shù)據(jù),即左右移動后的圖案數(shù)據(jù)CUN[]
- //程序描述:比如當(dāng)ZUOJIA=6時,CUN[]前4位數(shù)據(jù)(圖案只用到前4位)都左移1位
- // 如果圖案碰到了邊界,重新調(diào)用XH();函數(shù)一次,CUN[]數(shù)據(jù)移動到能移動的最遠位置
- //=========================================================================================================================================
- void HPP() //旋轉(zhuǎn)子程序一部分
- {
- if(ZUOJIA<=7){ //如果圖案在點陣的左半邊
- for(k=0;k<(7-ZUOJIA);k++){ //7-ZUOJIA表示圖案需要移動的位數(shù)
- for(n=0;n<4;n++){ //圖案左移一位
- CUN[n]<<=1;
- if(CUN[n]>=0x8000){ //在該圖案左移的過程中,判斷有沒有碰到點陣左邊的邊界
- XH(); //調(diào)用XH()子程序,該圖案在ZUOJIA=7的位置;
- for(n=0;n<4;n++){ //該圖案左移k+1個位,因為是k=0圖案開始一位位左移,所以是k+1
- CUN[n]<<=k+1;
- }
- ZUOJIA=6-k; //圖案對應(yīng)豎變量也要跟著變化,6-k即7-(k+1)
- G=6-k; //圖案的豎位置變了,左右按鍵的狀態(tài)變量也要隨之改變
- return; //跳出子程序
- }
- }
- }
- }else{ //否則圖案在點陣右半邊
- for(k=0;k<(ZUOJIA-7);k++){ //以下類同上面
- for(n=0;n<4;n++){
- CUN[n]>>=1;
- if((CUN[n]&0x0001)!=0){
- XH();
- for(n=0;n<4;n++){
- CUN[n]>>=k+1;
- }
- ZUOJIA=8+k;
- G=8+k;
- return;
- }
- }
- }
- }
- }
- //=========================================================================================================================================
- void QC_HC() //緩存(顯示)數(shù)組清零
- {
- for(n=0;n<16;n++){
- HUANCUN[n]=0x0000;
- }
- }
- //=========================================================================================================================================
復(fù)制代碼
所有資料51hei提供下載:
俄羅斯方塊.rar
(73.91 KB, 下載次數(shù): 51)
2020-1-21 20:10 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|
|