、**演奏原理
2、樂譜單位元組編碼方法
(1)定時器0/1產生各種音訊的方法
表1 為c調的發音頻率表,給出了各個音的頻率f,可以用定時器/計數器,定時產生對應頻率的方波訊號,將方波訊號送給喇叭,便可使喇叭發出同頻率的聲音。定時初值x與發聲頻率f的關係如下:
由公式 t=(2n - x)×tmc
式中 t=t/2、 t=1/f、 tmc=12/fosc
n取16表示用模式1定時,tmc為機器週期,fosc為晶振頻率,因此初值x為:
x=65536-(1/f/2)×fosc/12
如果fosc=12hz,則x=65536-500000/f
表1 c音調發音頻率表
c 調
5 6 7 1
2345
67ⅰⅱ
ⅲ頻率f(hz)
196220
247262
294330
349392
440494
523588
660其它各音的發聲頻率如圖1所示。
(2)樂譜單位元組編碼方法
位元組的高4位表示譜的音名,低4位表示音的長短(單位元組法最多只能表示15個音)。
音名表示方法:乙個樂譜中的最低音用
1表示,次低音用2表示
……,依次類推,休止符用
0表示。
音長短的表示方法:乙個樂譜中的最短音用
1表示,其它音的長度都是它的整數倍,是它的幾倍用幾表示。
(3)樂譜單位元組編碼舉例
樂譜:3 5 6 i6 5 | 2·3 6 5 | 1 — | 1 0 ||
音名編碼:該段樂譜的最低音5編碼1,其它音6、7……依次編碼為2、3……,休止符用0表示。其編碼對應關係如表2所示。
表2 編碼與音名對應關係
音 名0
5 6 7 1
2345
67ⅰⅱ
ⅲ編 碼01
2345
6789
abcd
編碼與音名的換算:
音長編碼:由於該段樂譜的最短音是1/4拍,因此將1/4拍編碼為1,其音長編碼如下:
1表示1/4拍、 2表示2/4拍、
3表示3/4拍、 4表示1拍、
6表示1.5拍、 8表示2拍、
c表示3拍……
上面一段樂譜的編碼為: 0x62,0x82,0x91,0xb1,0x91,0x81,0x53,0x61,0x22,0x12,0x4c,0x04,0。(最後的0表示樂譜結束)
節拍時間計算:
設某歌曲的演奏速度為p拍/分鐘,則每拍的時間間隔為:
分鐘/p=60000毫秒/p
若某歌曲的最短音為1/4拍,對應的延時為15000毫秒/p,則15000毫秒/p是該歌曲的基本延時單位。
如p=100,即每分鐘100拍,則乙個基本延時單位(1/4拍)的時間長度為150ms。
3、程式設計方法
需要編寫以下4個函式;建立歌曲編碼表和頻率表。
(1)建立歌曲編碼表和頻率表
樂譜編碼陣列mus[ ];
各音頻率陣列freq[ ]。
(2)主函式
主函式主要是對定時器、中斷做初始化設定。
(3)**演奏函式
順序從歌譜編碼陣列mus中讀取資料,分離出高4位和低4位。用高4位讀取陣列freq[ ]的頻率值,然後根據定時器初值與頻率的關係,計算出定時初值x;用低4位控制發聲延時,以上面所述的「15000毫秒/m」為基本延時單位,以低4位為倍數控制發聲時間。
(4)延時函式
x=x*150;
(5)定時器中斷函式
4、定時器2產生各種音訊的方法
對於定時器2,發聲頻率f與微控制器振盪頻率fosc的關係為:
f=fosc/(2 16 - x)/4 2 16-x= fosc/f/4 65536-x= fosc/f/4
因此初值x為:
x=65536-fosc/f/4
如果fosc=12hz,則x=65536-3000000/f
**演奏程式流程
讀取第i個音mus[i++]編碼
mus[i]為0結束
分離出高低4位給high和low
讀取freq[high]得到發聲頻率f
由f計算出定時初值x
x的高低8位分別送給全域性變數xh和xl及計數器thx和tlx
開定時器tx(trx=1)
呼叫延時函式delay(low)
關定時器tx(trx=0)
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
sbit buzz=p2^6;
uchar high=0;
uchar low=0;
uint x=0;
uint flag=0;
uchar code huadie=; //化蝶樂譜編碼表
uint code freq=; //頻率編碼表
void delay_ms(int x)
void tim0_init()
void compute_x()
}void tim0() interrupt 1
void main()
}
C51 通用 儲存器指標
c51編譯器支援用星號 進行指標宣告。你可以用指標完成在標準c語言中有的所有操作。另外,由於8051及其派生系列所具有的獨特結構,c51編譯器支援兩種不同型別的指標 儲存器指標和通用指標。通用指標 通用或未定型的指標的宣告和標準c語言中一樣。如 char s string ptr int numpt...
C51用巨集定義代替printf函式
有時候我們想用巨集定義來決定是編譯debug版本的 還是release的 dubug版本的 會通過printf列印除錯資訊,release版本的 則不會。我們總不能對每一條printf都這樣寫 if debug printf hello world endif這樣子實在是太麻煩了!萬一要各個地方都要...
c51為啥要巨集定義時鐘 c51時鐘
程式效果 時鐘,包括時間可調,定時到了鬧鐘響,用蜂鳴器,本程式已經除錯通過 喇叭接在p2.0上.埠均可自行更改.include 標頭檔案 include define uchar unsigned char 巨集定義 define uint unsigned int sbit key1 p3 5 位...