Proteus仿真51單片機生日快樂音樂播放器

實驗名稱:基於51單片機音樂播放器

實驗目的:

聲音的音調不同是因爲聲音的頻率不同造成的。那麼,就可以通過單片機發送不同頻率的脈衝信號給蜂鳴器,來達到讓蜂鳴器發出不同音調聲音的目的。不同頻率的脈衝信號就意外着每個脈衝之間必須有着不一樣的時差,這可以通過延時或者定時計數器定時的方式來實現。

我們便是通過這個目的,去通過對於單片機的操作,蜂鳴器變調,使蜂鳴器完成對於歌曲樂譜的播放,再通過LCD1602把我們想顯示的漢字顯示在液晶屏幕上。製作成一個建議的基於單片機的音樂播放器。

實驗環境:

Keil4編寫代碼,Proteus仿真程序

LCD1602液晶顯示漢字:

這個程序代碼關聯性不強,所以我分成3個模塊爲大家講解程序,首先爲大家講解比較重要的1602。1602是一種工業字符型液晶,全稱LCD1602,能夠同時顯示16x02即32個字符。LCD1602液晶顯示的原理是利用液晶的物理特性,通過電壓對其顯示區域進行控制,有電就有顯示,這樣即可以顯示出圖形。
對其編程需要看時序圖,根據時序圖寫出與1602通信代碼。我們先來看1602引腳定義:
第1腳:VSS爲電源地
第2腳:VCC接5V電源正極
第3腳:V0爲液晶顯示器對比度調整端,接正電源時對比度最弱,接地電源時對比度最高(對比度過高時會 產生“鬼影”,使用時可以通過一個10K的電位器調整對比度)。
第4腳:RS爲寄存器選擇,高電平1時選擇數據寄存器、低電平0時選擇指令寄存器。
第5腳:RW爲讀寫信號線,高電平(1)時進行讀操作,低電平(0)時進行寫操作。
第6腳:E(或EN)端爲使能(enable)端,高電平(1)時讀取信息,負跳變時執行指令。
第7~14腳:D0~D7爲8位雙向數據端。
第15~16腳:空腳或背燈電源。15腳背光正極,16腳背光負極
我們可以看到除了雙向數據端,我們需要用到的有三個,RS(4),RW(5),E(6)這三個。
下面我們上時序圖,我們來看寫時序:
在這裏插入圖片描述
通過時序圖,我們可以看出需要進行寫操作時,我們RW引腳要爲低(0),RS引腳選擇是寫數據還是寫命令(0/1),E引腳的下降沿即完成程序寫入操作,上程序:

void write_command(uchar com)
{
	check_busy();
	E=0;
	RS=0;
	RW=0;
	out=com;
	E=1;
	delay(2);
	E=0;
	delay(2);
}

void write_date(uchar dat)
{
	check_busy();
	E=0;
	RS=1;
	RW=0;
	out=dat;
	E=1;
	delay(2);
	E=0;
	delay(2);
}

Out即爲整個雙向數據端,根據我們每個人的接線去操作即可。完成了寫函數以後,我們就可以根據指令集對1602進行初始化,這裏我們不在對指令集和初始化進行介紹。

對於1602寫漢字我們需要下一番功夫,因爲1602內置的CGROM裏存儲了常見的192個字符,但是沒有中文,我們想顯示中文就必須字節創建一個字庫。查看1602數據手冊,我們可以看到1602有一個CGRAM區,作爲用戶自定義區,大小爲64字節,每8個字節爲一組顯示一個字符,總共可以顯示8種自定義字符。每種字符顯示都有自己的顯示編碼從第一種字符到第八個字符,依次是:{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}。

現在的問題就是建字庫,我查看數據手冊發現1602其內部數據矩陣並非是8 * 8的,而是5 * 8的只用右邊區域進行顯示,知道這點我們就直接上字模提取軟件,且只用右邊位置即可。
在這裏插入圖片描述
總得來說,就是我們先建一個字庫,然後設定好一個顯示地址,然後在每個地址寫入每個字符的顯示編碼,即可在對應的區域顯示我們的字符了。
我們這裏放個字庫截圖吧:
在這裏插入圖片描述
table2就是我們建的字庫,table3是每個字庫顯示編碼,table4即直接用了CGROM的字符。想知道我們建的庫長啥樣,見文末。。
顯示函數我們列一下:

void lcd1602xianshi(void)
{
			uchar i;
			init_1602();
	
			write_command(0x40);//向用戶自定義RAM區寫入我們定義好的字庫
			for(i=0;i<64;i++)
			{
				  write_date(table2[i]);
					delay(1);
			}
			write_command(0x80+0x03);//把填充好的字庫顯示在第一行第三個字符位置後面
			for(i=0;i<8;i++)
			{
					write_date(table3[i]);
					delay(100);
			}
			write_command(0xc0+0x02);//把happy birthday顯示到第二行第二個字符後面
			for(i=0;i<14;i++)
			{
					write_date(table4[i]);
					delay(100);
			}
	a=2;
}

很簡單的我們就完成了在1602上顯示漢字的騷操作了,效果見文末。

PWM控制揚聲器/蜂鳴器演奏音樂:

首先我們來看硬件連接,很簡單
在這裏插入圖片描述
我們在硬件上只是簡單的通過一個NPN三極管去做成了一個放大電路從而驅動有源蜂鳴器,在軟件上因爲89C51不像STM32有自己PWM硬件外設,所以我們只能去模擬PWM波形的產生,從而控制蜂鳴器的聲調。

模擬PWM其實很簡單,我們可以想象有一個單片機引腳PA0我們設置成輸出爲0,還有兩個數字a ,b, 這個a初始值爲0,b的初始值爲300,我們在定時器裏面設定每進一次定時器中斷,a就自增,a = b時,我們把PA0設置成輸出爲1,當a = 1000時,我們讓a = 0,PA0=0。這樣我們就輸出了佔空比爲70%的方波。驅動蜂鳴器也只是改變這個佔空比而以,換句話說就是改變b的值!

一首曲子肯定要有7個音調,哆來咪發嗦啦西,只有一個聲部肯定不夠,要分高聲部和低聲部,這樣我們就要設置14個音調,每個音調持續的時間也不一定,有的音持續時間長,有的音持續時間短。所以我們還需要一個可以標誌音持續時間的數字。

綜上所述,我們還是直接上截圖:

在這裏插入圖片描述
Sszymmh[]這個數組裏的數據每3個爲一組,前兩個數確定PWM佔空比,後一個確定佔空比持續時間。
我們這裏上一下音樂播放函數:

void t0int() interrupt 1
{
 TR0=0;
 speaker=!speaker;
 TH0=timer0h;
 TL0=timer0l;
 TR0=1;
}
void song()
{
 TH0=timer0h;
 TL0=timer0l;
 TR0=1;
 delayms(time);                       
 }

void music(void)
 {
	unsigned char k,i;
	TMOD=1; 
	EA=1;
	ET0=1;
	while(1)
        {
						i=0;  
						while(i<75){               
						k=sszymmh[i]+7*sszymmh[i+1]-1;
						timer0h=FREQH[k];
						timer0l=FREQL[k];
						time=sszymmh[i+2];
						i=i+3;
						song();
         }
      } 
			a=3;
 }

函數還是比較容易理解的,我們這裏就不囉嗦了。

8*8矩陣

我們在程序裏面加入了8*8矩陣作爲一個趣味性的元器件,這個矩陣會形成一個箭頭,逐漸往上,等到箭頭全部上升完畢,1602顯示內容,蜂鳴器播放音樂。
矩陣還是比較簡單的,雖然用的引腳好多。。就是8個引腳來掃描,8個引腳搞顯示,其實用74hc595會更省事兒,兩個引腳就能解決問題,懶得弄了。直接上程序把:

void juzhen()
{
	uint n,i;
	uint k;
	
			for(i=0;i<8;i++)		
			{ k=0;
				while(k<100)
					{for(n=0;n<8;n++)				
					{	
						P3=~table1[n];
						P1=table[n+i*8];
						delay(1);
					}
					k++;
				}
			}
	a=1;
}

實物效果展示

在這裏插入圖片描述
這是基本的電路設計,因爲是仿真,沒有加入晶振,復位等電路。
接下來看運行以後的程序:
在這裏插入圖片描述
在這裏插入圖片描述
至此,這個簡單的項目已經介紹完畢,感興趣的同學可以給個贊。下面放完整視頻:
B站 51音樂播放器

發佈了7 篇原創文章 · 獲贊 5 · 訪問量 2869
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章