新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > mcu音樂程序的設計與實驗

        mcu音樂程序的設計與實驗

        作者: 時間:2016-11-27 來源:網絡 收藏
        利用單片機(或單板機)奏樂大概是無線電愛好者感興趣的問題之一。本文從單片機的基本發間實驗出發,談談音樂程序的設計原理,并給出具體實例,以供參考。

        1.單片機的基本發音實驗

        本文引用地址:http://www.104case.com/article/201611/322391.htm

        我們知道,聲音的頻譜范圍約在幾十到幾千赫茲,若能利用程序來控制單處機某個口線的“高”電平或低電平,則在該口線上就能產生一定頻率的矩形波,接上喇叭就能發出一定頻率的聲音,若再利用延時程序控制“高”“低”電平的持續時間,就能改變輸出頻率,從而改變音調。

        例如,要產生200HZ的音頻信號,按圖1接入喇叭(若屬臨時實驗,也可將喇叭直接接在P1口線上),實驗程序為:

        其中子程序DEL為延時子程序,當R3為1時,延時時間約為20us,R3中存放延時常數,對200HZ音頻,其周期為1/200秒,即5ms。這樣,當P1.4的高電平或低電平的持續時間為2.5ms,即R3的時間常數取2500/20=125(7DH)時,就能發出200HZ的音調。將上述程序鍵入學習機,并不斷修改R3的常數可以感到音調的變化。

        樂曲中,每一音符對應著確定的頻率,表1給出C調時各音符頻率及其相應的時間常數。

        讀者可以根據表1所提供的常數,將其16進制代碼送入R3,反復練習體會。根據表1可以奏出音符。僅這還不夠,要準確奏出一首曲子,必須準確地控制樂曲節奏,即一音符的持續時間。

        音符的節拍我們可以用定時器T0來控制,送入不同的初值,就可以產生不同的定時時間。便如某歌曲的節奏為每分鐘94拍,即一拍為0.64秒。其它節拍與時間的對應關系見表2。

        但時,由于T0的最大定時時間只能為131毫秒,因此不可能直接用改變T0的時間初值來實現不同節拍。我們可以用T0來產生10毫秒的時間基準,然后設置一個中斷計數器,通過判別中斷計數器的值來控制節拍時間的長短。表2中也給出了各種節拍所對應的時間常數。例如對1/4拍音符,定時時間為0.16秒,相應的時間常數為16(即10H);對3拍音符,定時時間為1.92秒,相應時間長數為192(即C0H)。

        我們將每一音符的時間常數和其相應的節拍常數作為一組,按順序將樂曲中的所有常數排列成一個表,然后由查表程序依次取出,產生音符并控制節奏,就可以實現演奏效果。

        此外,結束符和體止符可以分別用代碼00H和FFH來表示,若查表結果為00H,則表示曲子終了;若查表結果為FFH,則產生相應的停頓效果。

        為了產生手彈的節奏感,在某些音符(例如兩個相同音符)音插入一個時間單位的頻率略有不同的音符。

        程序框圖如圖2所示。

        可直接在TD-III型學習機上演奏,對其它不同型號的學習機,只需相應地改變一下地址即可。本程序演奏的是民歌“八月桂花遍地開”,C調,節奏為94拍/分。讀者也可以自行找出一首歌,按表1和表2給定的常數,將樂曲翻譯成碼表輸入機器,而程序不變。本實驗方法簡便,即使不懂音樂的人,將一首陌生的曲子翻譯成代碼也是易事,和著機器的演奏學唱一首歌曲,其趣味無窮。

        from:http://www.c51.cn/mcu/mcs51yy/200604/mcu_20060422123021_4081.html

        下面這個例子是我在網上找的簡單易懂,只不過是用C編寫的,而且基本思想跟上面講的相同。

        #i nclude
        #i nclude
        //本例采用89C52, 晶振為11.0592MHZ
        //關于如何編制音樂代碼, 其實十分簡單,各位可以看以下代碼.
        //頻率常數即音樂術語中的音調,而節拍常數即音樂術語中的多少拍;
        //所以拿出譜子, 試探編吧!


        unsigned char n=0;//n為節拍常數變量
        unsigned char code music_tab[] ={
        0x18, 0x30, 0x1C , 0x10, //格式為: 頻率常數, 節拍常數, 頻率常數, 節拍常數,
        0x20, 0x40, 0x1C , 0x10,
        0x18, 0x10, 0x20 , 0x10,
        0x1C, 0x10, 0x18 , 0x40,
        0x1C, 0x20, 0x20 , 0x20,
        0x1C, 0x20, 0x18 , 0x20,
        0x20, 0x80, 0xFF , 0x20,
        0x30, 0x1C, 0x10 , 0x18,
        0x20, 0x15, 0x20 , 0x1C,
        0x20, 0x20, 0x20 , 0x26,
        0x40, 0x20, 0x20 , 0x2B,
        0x20, 0x26, 0x20 , 0x20,
        0x20, 0x30, 0x80 , 0xFF,
        0x20, 0x20, 0x1C , 0x10,
        0x18, 0x10, 0x20 , 0x20,
        0x26, 0x20, 0x2B , 0x20,
        0x30, 0x20, 0x2B , 0x40,
        0x20, 0x20, 0x1C , 0x10,
        0x18, 0x10, 0x20 , 0x20,
        0x26, 0x20, 0x2B , 0x20,
        0x30, 0x20, 0x2B , 0x40,
        0x20, 0x30, 0x1C , 0x10,
        0x18, 0x20, 0x15 , 0x20,
        0x1C, 0x20, 0x20 , 0x20,
        0x26, 0x40, 0x20 , 0x20,
        0x2B, 0x20, 0x26 , 0x20,
        0x20, 0x20, 0x30 , 0x80,
        0x20, 0x30, 0x1C , 0x10,
        0x20, 0x10, 0x1C , 0x10,
        0x20, 0x20, 0x26 , 0x20,
        0x2B, 0x20, 0x30 , 0x20,
        0x2B, 0x40, 0x20 , 0x15,
        0x1F, 0x05, 0x20 , 0x10,
        0x1C, 0x10, 0x20 , 0x20,
        0x26, 0x20, 0x2B , 0x20,
        0x30, 0x20, 0x2B , 0x40,
        0x20, 0x30, 0x1C , 0x10,
        0x18, 0x20, 0x15 , 0x20,
        0x1C, 0x20, 0x20 , 0x20,
        0x26, 0x40, 0x20 , 0x20,
        0x2B, 0x20, 0x26 , 0x20,
        0x20, 0x20, 0x30 , 0x30,
        0x20, 0x30, 0x1C , 0x10,
        0x18, 0x40, 0x1C , 0x20,
        0x20, 0x20, 0x26 , 0x40,
        0x13, 0x60, 0x18 , 0x20,
        0x15, 0x40, 0x13 , 0x40,
        0x18, 0x80, 0x00
        };

        void int0()interrupt 1//采用中斷0 控制節拍
        {TH0=0xd8;
        TL0=0xef;
        n--;
        }

        void delay (unsigned char m)//控制頻率延時
        {
        unsigned i=3*m;
        while(--i);
        }

        void delayms(unsigned char a)//豪秒延時子程序
        {
        while(--a);//采用while(--a) 不要采用while(a--); 各位可編譯一下看看匯編結果就知道了!
        }

        void main()
        { unsigned char p,m;//m為頻率常數變量
        unsigned char i=0;
        TMOD&=0x0f;
        TMOD =0x01;
        TH0=0xd8;TL0=0xef;
        IE=0x82;
        play:
        while(1)
        {
        a: p=music_tab[i];
        if(p==0x00){ i=0, delayms(1000); goto play;}//如果碰到結束符,延時1秒,回到開始再來一遍
        else if(p==0xff){ i=i+1;delayms(100),TR0=0; goto a;}//若碰到休止符,延時100ms,繼續取下一音符
        else{m=music_tab[i++], n=music_tab[i++];}//取頻率常數 和 節拍常數
        TR0=1;//開定時器1
        while(n!=0) P1=~P1,delay(m);//等待節拍完成, 通過P1口輸出音頻(可多聲道哦!)
        TR0=0;//關定時器1
        }
        }




        關鍵詞: mcu音樂程

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 西平县| 布尔津县| 柳江县| 文山县| 桃源县| 镇赉县| 深圳市| 渝中区| 青河县| 广汉市| 仪陇县| 麻江县| 白朗县| 探索| 崇信县| 凉城县| 获嘉县| 繁峙县| 永春县| 通化县| 商洛市| 平果县| 富裕县| 离岛区| 大理市| 寿宁县| 禄丰县| 岳西县| 中卫市| 新龙县| 长子县| 盐城市| 简阳市| 特克斯县| 象山县| 周宁县| 松阳县| 汕尾市| 呈贡县| 酉阳| 且末县|