找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 4907|回復(fù): 2
收起左側(cè)

51單片機(jī)音樂游戲設(shè)計(jì)與制作 附程序源碼

[復(fù)制鏈接]
ID:432777 發(fā)表于 2018-11-25 11:52 | 顯示全部樓層 |閱讀模式
一、課程設(shè)計(jì)內(nèi)容
利用89c52單片機(jī)設(shè)計(jì)一款音樂游戲。
游戲說明:游戲基于單片機(jī)開發(fā)箱實(shí)現(xiàn)。游戲開始時(shí),會(huì)播放一首音樂,同時(shí)每隔一個(gè)音符,LED點(diǎn)陣中會(huì)從最上方下落一個(gè)小點(diǎn)。玩家需要根據(jù)音樂的節(jié)奏,在小點(diǎn)下降到LED點(diǎn)陣的底部時(shí),按下對(duì)應(yīng)的按鍵。其中,矩陣鍵盤第一行從左到右的四個(gè)鍵分別對(duì)應(yīng)LED點(diǎn)陣的1、3、5、7列。根據(jù)每個(gè)按鍵按下的時(shí)間,會(huì)有不同的得分,通過LED模塊的D1-D5亮起來代表獲得1-5分。如果沒有LED燈亮則代表得0分。當(dāng)整首歌播放完后,會(huì)在LED點(diǎn)陣上顯示整首歌的得分,得分為0-99分。

二、設(shè)計(jì)思路和方案選擇
在決定制作音樂游戲后,利用開發(fā)箱的哪幾個(gè)模塊來制作也是需要考慮的一個(gè)問題,最終我們決定利用現(xiàn)在的這個(gè)方案。其主要原因是LED點(diǎn)陣和蜂鳴器是游戲中的主體部分,因此無可替代。獨(dú)立鍵盤還是矩陣鍵盤的選擇上,經(jīng)過試驗(yàn)發(fā)現(xiàn)獨(dú)立鍵盤由于離LED點(diǎn)陣較遠(yuǎn),在實(shí)際游戲中經(jīng)常會(huì)有反應(yīng)不過來的情況。而矩陣鍵盤就在點(diǎn)陣的正下方,因此在操作上較為方便,所以選擇了矩陣鍵盤。而游戲得分的顯示,最初是想利用數(shù)碼管來實(shí)現(xiàn),后來發(fā)現(xiàn)數(shù)碼管和LED點(diǎn)陣都用到了單片機(jī)的P0口。在LED點(diǎn)陣無法被取代的情況下,只能退而求其次,選擇用LED模塊顯示得分。
程序的具體設(shè)計(jì)思路如下:
  • 實(shí)現(xiàn)音樂的播放效果            
  • 實(shí)現(xiàn)LED點(diǎn)陣的顯示下落效果
  • 實(shí)現(xiàn)音樂的節(jié)奏和LED點(diǎn)的下落同步
  • 實(shí)現(xiàn)按鍵得分功能
  • 實(shí)現(xiàn)顯示得分效果

三、硬件設(shè)計(jì)
本游戲的實(shí)現(xiàn)基于單片機(jī)開發(fā)試驗(yàn)儀,其主要用到的硬件電路有
89C52CPU模塊,LED點(diǎn)陣模塊,74HC595模塊,LED模塊,矩陣鍵盤模塊和蜂鳴器模塊。
四、軟件框圖及設(shè)計(jì)

程序流程圖:



五、實(shí)物照片及調(diào)試結(jié)果
游戲時(shí)照片:
結(jié)束顯示分?jǐn)?shù)照片:

六、心得體會(huì)
這次單片機(jī)的課程設(shè)計(jì),也是我們第一次自己完成一個(gè)由自己構(gòu)思并實(shí)現(xiàn)的作品。在選擇方案的時(shí)候,我們首先決定的是自己編寫一款游戲。在聽完老師講解蜂鳴器播放音樂和LED點(diǎn)陣的原理后,我想到了以前玩過的一款名為節(jié)奏大師的音樂游戲,我發(fā)現(xiàn)利用LED點(diǎn)陣和蜂鳴器結(jié)合,完全可以在單片機(jī)上實(shí)現(xiàn)它的主要框架。再配合按鍵的功能,就能用單片機(jī)來玩這一簡(jiǎn)易的音樂游戲了。于是,我們便初步?jīng)Q定了這個(gè)題目。
然而,在制作的過程中,我們遇到了許多事先沒有料想到的困難。比如LED顯示點(diǎn)的出現(xiàn)和對(duì)應(yīng)的音符的不同步,按鍵的不同得分判定難以實(shí)現(xiàn),用于顯示分?jǐn)?shù)的數(shù)碼管和LED點(diǎn)陣共用了一個(gè)端口等等。這些困難都給我們編寫程序造成了很大的困擾,甚至令我們一度想要放棄。但在我們的努力下,最終還是一個(gè)個(gè)解決了這些困難,實(shí)現(xiàn)了我們?cè)镜臉?gòu)想。這也讓我體會(huì)到實(shí)踐才是檢驗(yàn)問題最好的辦法。
通過這次課程設(shè)計(jì),我也對(duì)單片機(jī)的軟件、硬件有了進(jìn)一步的認(rèn)識(shí)。完成這一課程設(shè)計(jì),需要能熟練地運(yùn)用51單片機(jī)的C語言編程,以及單片機(jī)內(nèi)部的定時(shí)器、中斷等功能,也需要對(duì)LED、按鍵、蜂鳴器、數(shù)碼管等的原理進(jìn)行一定的了解。更重要的是,能夠?qū)⑦@兩者結(jié)合,才能讓各個(gè)模塊都能受我們控制,達(dá)到我們想要的效果。


這一次的實(shí)驗(yàn)作品的完成,讓我們充分體會(huì)到了學(xué)習(xí)是一個(gè)循序漸進(jìn)的過程。在課程開始之初,我們對(duì)于單片機(jī)一無所知,老師給與我們的開發(fā)箱也只不過是一個(gè)上課依葫蘆畫瓢,展現(xiàn)一下黑板上程序的工具。然而隨著課程的深入,我們可以不斷的運(yùn)用課本上新學(xué)到的知識(shí)已經(jīng)實(shí)驗(yàn)之中運(yùn)用過的程序和結(jié)構(gòu),來實(shí)現(xiàn)更多的功能以及想法。直到最后,我們?cè)陂_發(fā)箱上,依靠著這門課程給予我們的知識(shí)和技巧,完成了一個(gè)簡(jiǎn)易的音樂游戲。雖然游戲非常的簡(jiǎn)單,但是能夠設(shè)計(jì)出這樣一個(gè)游戲是我們?cè)陂_始完全沒有預(yù)想到的。
通過這門課程,我們第一次實(shí)際感受到了知識(shí)是如何運(yùn)用于實(shí)際的。在別的課程之中考核基本都是通過書面的考試,而這一次是讓我們自己在開發(fā)箱上創(chuàng)造自己的作品,讓我們受益匪淺。我們不僅僅需要用這一門課程上的知識(shí),許多之前學(xué)過的知識(shí)也再一次被我們從課本中找了回來,運(yùn)用于其中。在這一次的期末作業(yè)考核之中,我們真正認(rèn)識(shí)到了之前學(xué)過的許多知識(shí)的作用,例如微機(jī)原理、C語言等等,這些東西不再是課本上的知識(shí),而變成了我們的一種能力,這是我們?cè)陂_發(fā)箱創(chuàng)造作品的過程之中最大的收獲。
另外,通過這次的作品,讓我感受到了團(tuán)隊(duì)協(xié)作的真諦。團(tuán)隊(duì)成員通過配合來?yè)P(yáng)長(zhǎng)避短,兩個(gè)人的知識(shí)和想法融合在一起,來更好地完成這次考核。我們的作品也從最初的一直空白,變成了一個(gè)簡(jiǎn)易但是很完整的音樂游戲。我們都從這次的創(chuàng)作中受益匪淺。

單片機(jī)源程序如下:
  1. #include <REG52.H>   
  2. #include <INTRINS.H>
  3. #define COMMONPORTS              P0              //定義輸出端口                 
  4. sbit BeepIO=P1^5;                            //定義輸出管腳
  5. sbit SRCLK=P3^6;
  6. sbit RCLK1=P3^5;
  7. sbit SER=P3^4;
  8. sbit k1=P1^3;                                          //定義按鍵
  9. sbit k2=P1^2;
  10. sbit k3=P1^1;
  11. sbit k4=P1^0;
  12. sbit button=P1^7;

  13. unsigned char code music_tab[]={
  14. 33,16,4,33,8,2,34,8,2,39,16,4,26,8,2,29,8,2,33,8,2,33,8,2,33,8,2,34,8,2,
  15. 39,16,4,29,8,2,33,8,2,34,16,4,34,8,2,33,8,2,26,16,4,34,8,2,33,8,2,34,16,4,
  16. 11,8,2,26,8,2,29,16,4,26,8,2,29,8,2,33,16,4,33,8,2,34,8,2,39,16,4,44,8,2,
  17. 49,8,2,104,8,2,104,8,2,33,8,2,34,8,2,39,16,4,29,8,2,33,8,2,34,8,2,33,8,2,
  18. 34,8,2,104,8,2,104,16,4,29,8,2,33,8,2,34,8,2,33,8,2,34,8,2,117,8,2,
  19. 117,16,4,104,8,2,49,8,2,104,26,4,117,8,2,132,8,2,117,8,2,104,8,2,49,8,2,
  20. 104,26,4,104,8,2,49,8,2,39,8,2,39,8,2,26,8,2,44,26,4,44,8,2,39,8,2,26,8,2,
  21. 26,8,2,33,8,2,29,26,4,33,4,1,34,4,1,34,8,2,39,8,2,104,8,2,49,8,2,104,26,4,
  22. 117,8,2,132,8,2,117,8,2,104,8,2,49,8,2,104,26,4,104,8,2,49,8,2,39,8,2,
  23. 39,8,2,26,8,2,44,26,4,44,8,2,39,8,2,39,8,2,104,8,2,49,8,2,104,76,4,44,8,2,
  24. 44,8,2,44,8,2,49,8,2,49,8,2,44,8,2,39,8,2,39,16,4,33,8,2,26,5,5,26,8,2,
  25. 29,8,2,33,8,2,34,8,2,33,4,1,34,5,0,34,8,2,33,4,1,34,5,0,34,26,4,33,8,2,
  26. 34,8,2,33,8,2,34,8,2,117,8,2,117,16,4,104,8,2,49,8,2,104,26,4,117,8,2,
  27. 132,8,2,117,8,2,104,8,2,49,8,2,104,26,4,104,4,1,49,5,0,49,8,2,39,8,2,
  28. 39,8,2,26,8,2,44,26,4,44,8,2,39,8,2,26,8,2,26,8,2,33,8,2,29,26,4,33,4,1,
  29. 34,4,1,34,8,2,39,8,2,104,8,2,49,8,2,104,26,4,117,8,2,132,8,2,117,8,2,
  30. 104,8,2,49,8,2,104,26,4,104,8,2,49,8,2,39,8,2,39,8,2,26,8,2,44,26,4,
  31. 44,8,2,39,8,2,39,8,2,104,8,2,49,8,2,104,76,4,34,16,4,34,8,2,44,8,2,
  32. 39,10,0,26,8,2,26,16,4,34,26,4,29,16,4,33,16,4,26,76,4,0,0,0
  33. };              //歌曲格式為{音調(diào),發(fā)音長(zhǎng)度,不發(fā)音長(zhǎng)度,...,0,0,0}                                                                     
  34. unsigned char code P0TAB[8]  =
  35. {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};              //分別為選中點(diǎn)陣1-8列
  36. unsigned char code DIG_CODE[10][4]=
  37. {
  38. {0xf8,0x88,0xf8,0x00}, //0
  39. {0x00,0x00,0xf8,0x00}, //1
  40. {0xb8,0xa8,0xe8,0x00}, //2
  41. {0xa8,0xa8,0xf8,0x00}, //3
  42. {0xe0,0x20,0xf8,0x00}, //4
  43. {0xe8,0xa8,0xb8,0x00}, //5
  44. {0xf8,0xa8,0xb8,0x00}, //6
  45. {0x80,0x80,0xf8,0x00}, //7
  46. {0xf8,0xa8,0xf8,0x00}, //8
  47. {0xe8,0xa8,0xf8,0x00}, //9
  48. };                                         
  49. unsigned int Sound_Temp_TH0,Sound_Temp_TL0;              //音符定時(shí)器初值暫存
  50. unsigned int Sound_Temp_TH1,Sound_Temp_TL1;              //音長(zhǎng)定時(shí)器初值暫存
  51. void InitialSound(void);
  52. void Hc595SendByte(unsigned char dat);
  53. void Delay(unsigned int n);
  54. void Play(unsigned char *Sound);
  55. void ShowScore(unsigned int sum);
  56. unsigned int sum;

  57. void InitialSound(void)
  58. {
  59.               button = 0;
  60.               BeepIO = 0;
  61.               TMOD  |= 0x11;
  62.               Sound_Temp_TH1 = (65535-30000)/256;              //計(jì)算TL1應(yīng)裝入的初值
  63.               Sound_Temp_TL1 = (65535-30000)%256;              //計(jì)算TH1應(yīng)裝入的初值
  64.               ET0= 1;
  65.               ET1= 0;
  66.               TR0= 0;
  67.               TR1= 0;
  68.               EA= 1;
  69. }

  70. void ShowScore(unsigned int sum)               //顯示得分
  71. {
  72.               unsigned int tab,n;
  73.               while(1)
  74.               {
  75.                             for(tab=0;tab<8;tab++)
  76.                             {
  77.                             Hc595SendByte(0x00);              //消隱                                                      
  78.                             COMMONPORTS              = P0TAB[tab];              //輸出字碼
  79.                             if(tab<4)
  80.                             {
  81.                                           n=sum/10;            
  82.                                           Hc595SendByte(DIG_CODE[n][tab]);
  83.                             }
  84.                             else
  85.                             {
  86.                                           n=sum%10;
  87.                                           Hc595SendByte(DIG_CODE[n][tab-4]);
  88.                             }            
  89.                             Delay(1);                           
  90.                             }
  91. }
  92. }

  93. void Delay(unsigned int n)   //延時(shí)50us
  94. {
  95.               unsigned char a,b;
  96.               for(;n>0;n--)
  97.               {
  98.                                 for(b=1;b>0;b--)
  99.                                    for(a=22;a>0;a--);
  100.               }
  101. }

  102. void BeepTimer0(void) interrupt 1              //音符發(fā)生中斷
  103. {
  104.               BeepIO = !BeepIO;
  105.               TH0    = Sound_Temp_TH0;
  106.               TL0    = Sound_Temp_TL0;
  107. }

  108. void Hc595SendByte(unsigned char dat)     //向74H595發(fā)送一個(gè)字節(jié)的數(shù)據(jù)
  109. {
  110.               unsigned char a;
  111.               SRCLK=0;
  112.               RCLK1=0;
  113.               for(a=0;a<8;a++)
  114.               {
  115.                             SER=dat>>7;
  116.                             dat<<=1;
  117.                             SRCLK=1;
  118.                             _nop_();
  119.                             _nop_();
  120.                             SRCLK=0;            
  121.               }
  122.               RCLK1=1;
  123.               _nop_();
  124.               _nop_();
  125.               RCLK1=0;
  126. }

  127. void Play(unsigned char *Sound)                            //演奏子程序
  128. {
  129.               unsigned int HC595TAB[8]  = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  130.               unsigned char i;
  131.               unsigned int tab,j,k,Point_led,Point_sound,LDiv,LDiv1,LDiv2,LDiv16,
  132. LDiv16_temp,CurrentFre,LDiv1_sound,LDiv2_sound,LDiv1_temp,
  133. CurrentFre_sound,Fre_Temp,Temp_T,SoundLength,score,count;
  134.               unsigned int temp[4];                                                                                                               
  135.               SoundLength = 0;
  136.               LDiv16=5;                                                        //16分音符的長(zhǎng)度            
  137.               while(Sound[SoundLength] != 0x00)              //計(jì)算歌曲總長(zhǎng)度
  138.               {
  139.                             SoundLength+=3;
  140.               }
  141.               LDiv1_temp=0;
  142.               LDiv16_temp=0;
  143.               Point_led=0;
  144.               Point_sound=0;            
  145.               TR0=0;
  146.               TR1=1;
  147.               score=0;
  148.               sum=0;
  149.               j=1;
  150.               while(Point_sound < SoundLength)              //一個(gè)音符一個(gè)音符的來
  151.               {
  152.               CurrentFre  = Sound[Point_led];            
  153.               LDiv1 = Sound[Point_led+1];                           
  154.               LDiv1_sound = Sound[Point_sound+1]; //發(fā)音長(zhǎng)度                                          
  155.               LDiv2 = Sound[Point_led+2];
  156.               if(Sound[Point_led]!=0)                              
  157.                             LDiv=LDiv1+LDiv2;              //兩個(gè)LED燈之間的間隔長(zhǎng)度
  158.               else
  159.                             LDiv=5;
  160.               if (Point_led!=0)
  161.               {
  162. if (Fre_Temp>CurrentFre)              //頻率比上個(gè)音符大,LED顯示的點(diǎn)右移兩行,比上個(gè)音符小則左移兩行,移到最左或最右循環(huán)
  163.               {
  164.                             if(k==0)              k=6;
  165.                             else              k=k-2;
  166.               }
  167.               else if (Fre_Temp<CurrentFre)
  168.               {
  169.                             if(k==6)              k=0;
  170.                             else              k=k+2;
  171.                             }
  172.               }
  173.               Fre_Temp= CurrentFre;
  174.               if(Sound[Point_led]!=0)
  175.               HC595TAB[k]|=0x80;                            //顯示led燈在最上方
  176.               for(i=LDiv;i>0;i--)               //間隔規(guī)定長(zhǎng)度顯示下一個(gè)led燈
  177.               {
  178.                             LDiv16_temp++;
  179.                             count++;                                                      
  180.                             if(j!=1)                                                        //判斷得分
  181.                             {                                         
  182.                             if(temp[j/2]!=0)
  183.                             {
  184.                             if(count==1){              score=5;P2=239;}
  185.                             else if(count==2){score=4;P2=247;}
  186.                             else if(count==3){score=3;P2=251;}
  187.                             else if(count==4){score=2;P2=253;}
  188.                             else if(count==5){score=1;P2=254;}
  189.                             else{score=0;P2=255;}
  190.                             sum=sum+score;
  191.                             j=1;
  192.                             }
  193.               }                           
  194.               if(LDiv16_temp==LDiv16) //每隔1個(gè)16分音符的時(shí)間
  195.               {            
  196.               for(tab=0;tab<8;tab++)                           
  197.               {
  198.                             HC595TAB[tab]>>=1;              //led燈下降1格            
  199.                             if(HC595TAB[tab]&1 == 1)              //判斷l(xiāng)ed燈是否下降到底部            
  200.                             {                                                                                                
  201.                             CurrentFre_sound  = Sound[Point_sound];            
  202.                             LDiv1_sound = Sound[Point_sound+1];
  203.                             LDiv2_sound = Sound[Point_sound+2];
  204.                             LDiv1_temp=0;                                                                                                                                          
  205. Temp_T = 65536-(5000/CurrentFre_sound)*10; //計(jì)算計(jì)數(shù)器初值
  206.                             Sound_Temp_TH0 = Temp_T/256;
  207.                                           Sound_Temp_TL0 = Temp_T%256;
  208.                                           TH0 = Sound_Temp_TH0;
  209.                                           TL0 = Sound_Temp_TL0 + 12;
  210.                                           TR0=1;
  211.                                           temp[0]=temp[1]=temp[2]=temp[3]=0;
  212.                                           count=0;
  213.                                           P2=255;
  214.                                           j=tab;
  215.                                           Point_sound+=3;              //發(fā)下一個(gè)音
  216.                                           if(Sound[Point_sound]==0)
  217.                                           i=LDiv1_sound+LDiv2_sound;            
  218.                                           }                                                                                      
  219.                             }
  220.                             LDiv16_temp=0;
  221.               }                           
  222.               while(TF1==0)                                                                                                                             
  223.               {                                                      
  224. ……………………

  225. …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼

全部資料51hei下載地址:
基于51單片機(jī)的音樂游戲.docx (459.93 KB, 下載次數(shù): 47)


評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:543985 發(fā)表于 2019-5-21 17:07 來自觸屏版 | 顯示全部樓層
小白,有的部分看不懂,希望博主能回下,可以有償解釋
回復(fù)

使用道具 舉報(bào)

無效樓層,該帖已經(jīng)被刪除
無效樓層,該帖已經(jīng)被刪除
5#
無效樓層,該帖已經(jīng)被刪除
6#
無效樓層,該帖已經(jīng)被刪除
ID:1148086 發(fā)表于 2025-4-16 15:27 | 顯示全部樓層
我想要源碼呀
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表