① 簡易8按鍵電子琴設計實驗
簡易電子琴的設計
摘 要 隨著基於CPLD的EDA技術的發展和應用領域的擴大與深入,EDA技術在電子信息、通信、自動控制用計算機等領域的重要性日益突出。作為一個學電子信息專業的學生,我們必須不斷地了解更多的新產品信息,這就更加要求我們對EDA有個全面的認識。本程序設計的是簡易電子琴的設計。採用EDA作為開發工具,VHDL語言為硬體描述語言,MAX + PLUS II作為程序運行平台,所開發的程序通過調試運行、波形模擬驗證,初步實現了設計目標。本程序使用的硬體描述語言VHDL,可以大大降低了硬體數字系統設計的入門級別,讓人感覺就是C語言的近親。通過老師的指導和自己的學習完成了預想的功能。
關鍵詞 電子琴;課程設計;EDA;VHDL
1 引言
1.1 課程設計胡配陪的目的
鞏固和運用所學課程,理論聯系實際,提高分析、解決計算機技術實際問題的獨立工作能力,通過對一個簡易的八音符電子琴的設計,進一步加深對計算機原理以及數字電路應用技術方面的了解與認識,進一步熟悉數字電路系統設計、製作與調試的方法和步驟。鞏固所學課堂知識,理論聯系實際,提高分析、解決計算機技術實際問題的獨立工作能力。為了進一步了解計算機組成原理與系統結構,深入學習EDA技術,用VHDL語言去控制將會使我們對本專業知識可以更好地掌握。
1.2 課程設計的內容
(1)設計一個簡易的八音符電子琴,它可通過按鍵輸入來控制音響。
(2)演奏時可以選擇是手動演奏(由鍵盤輸入)還是自動演奏已存入的樂曲。
(3)能夠自動演奏多首樂曲,且每首樂曲可重復演奏。
2 開發工具簡介
2.1 EDA技術
EDA是電子設計自動化(Electronic Design Automation)縮寫,是90年代初從CAD(計算機輔助設計)、CAM(計算機輔助製造)、CAT(計算機輔助測試)和CAE(計算機輔助工程)的概念發展而來的。EDA技術是以計算機為工具,根據硬體描述語言HDL( Hardware Description language)完成的設計文件,自動地完成邏輯編譯、化簡、分割、綜合及優化、布局布線、模擬以及對於特定目標晶元的適配編譯和編程褲蠢下載等工作。典型的EDA工具中必須包含兩個特殊的軟體包,即綜合器和適配器。綜合器的功能就是將設計者在EDA平台上完成的針對某個系統項目的HDL、原理圖或狀態圖形描述,針對給定的硬體系統組件,進行編譯、優化、轉換和綜合,最終獲得我們欲實現功能的描述文件。綜合器在工作前,必須給定所要實現的硬體結構參數,它的功能就是將軟體描述與給定的硬體結構用一定的方式聯系起來。也就是說,綜合器是軟體描述與硬體實現的一座橋梁。綜合過程就是將電路的高級語言描述轉換低級的、可與目標器件FPGA/CPLD相映射的網表文件。
適配器的功能是將由綜合器產生的王表文件配置與指定的目標器件中,產生最終的下載文件,如JED文件。適配所選定的目標器件(FPGA/CPLD晶元)必須屬於在綜合器中已指定的目標器件系列。
硬體描述語言HDL是相對於一般的計算機軟體語言,如:C、PASCAL而言的。HDL語言使用與設計硬體電子系統的計算機語言,它能描述電子系統的邏輯功能、電路結構和連接方式。設計者可利用HDL程序來描述所希望的電路系統,規定器件結構特徵和電路的行為方式;然後利用綜合器和適配器將此程序編程能控制FPGA和CPLD內部結構,並實現相應邏輯功能的的門級或更底層的結構網表文件或下載文件。目前,就FPGA/CPLD開發來說,比較常用和流行的HDL主要有ABEL-HDL、AHDL和VHDL。
2.2硬體描述語言—VHDL
VHDL的英文全名是Very-High-Speed Integrated Circuit Hardware Description Language,誕生於1982年。1987年底,VHDL被IEEE和美國國防部確認為標准硬體描述語言 。自IEEE公布了VHDL的標准版本,IEEE-1076(簡稱87版)之後,各EDA公司相繼推出了自己的VHDL設計環境,或宣布自己的設計工賣弊具可以和VHDL介面。此後VHDL在電子設計領域得到了廣泛的接受,並逐步取代了原有的非標準的硬體描述語言。1993年,IEEE對VHDL進行了修訂,從更高的抽象層次和系統描述能力上擴展VHDL的內容,公布了新版本的VHDL,即IEEE標準的1076-1993版本,(簡稱93版)。現在,VHDL和Verilog作為IEEE的工業標准硬體描述語言,又得到眾多EDA公司的支持,在電子工程領域,已成為事實上的通用硬體描述語言。有專家認為,在新的世紀中,VHDL於Verilog語言將承擔起大部分的數字系統設計任務。
VHDL主要用於描述數字系統的結構,行為,功能和介面。除了含有許多具有硬體特徵的語句外,VHDL的語言形式和描述風格與句法是十分類似於一般的計算機高級語言。VHDL的程序結構特點是將一項工程設計,或稱設計實體(可以是一個元件,一個電路模塊或一個系統)分成外部(或稱可是部分,及埠)和內部(或稱不可視部分),既涉及實體的內部功能和演算法完成部分。在對一個設計實體定義了外部界面後,一旦其內部開發完成後,其他的設計就可以直接調用這個實體。這種將設計實體分成內外部分的概念是VHDL系統設計的基本點。應用VHDL進行工程設計的優點是多方面的。
(1) 與其他的硬體描述語言相比,VHDL具有更強的行為描述能力,從而決定了他成為系統設計領域最佳的硬體描述語言。強大的行為描述能力是避開具體的器件結構,從邏輯行為上描述和設計大規模電子系統的重要保證。
(2) VHDL豐富的模擬語句和庫函數,使得在任何大系統的設計早期就能查驗設計系統的功能可行性,隨時可對設計進行模擬模擬。
(3) VHDL語句的行為描述能力和程序結構決定了他具有支持大規模設計的分解和已有設計的再利用功能。符合市場需求的大規模系統高效,高速的完成必須有多人甚至多個代發組共同並行工作才能實現。(4)對於用VHDL完成的一個確定的設計,可以利用EDA工具進行邏輯綜合和優化,並自動的把VHDL描述設計轉變成門級網表。
(4) VHDL對設計的描述具有相對獨立性,設計者可以不懂硬體的結構,也不必管理最終設計實現的目標器件是什麼,而進行獨立的設計。
2.3 VHDL的設計流程:
(1) 設計輸入根據電路設計所提出的要求,將程序輸入到VHDL編輯器中去編輯。
(2) 功能級模擬用VHDL,模擬器對編輯後的程序進行模擬,如果達不到設計要求,則可以重新修改程序,直到通過功能模擬。
(3) 邏輯綜合與優化 將通過功能模擬的程序放到VHDL編譯器中,進行邏輯綜合與優化。
(4) 門級模擬對電路用VHDL。模擬器模擬。可對門級電路的延時、定時狀態、驅動能力等進行模擬。如不符合要求,可重復步驟(3),再門級模擬,直到符合要求止。
(5) 版圖生成 用相應的軟體處理後,就可以拿去製版。
設計過程
3.1設計規劃
根據系統設計要求,系統設計採用自頂向下的設計方法,系統的整體組裝設計原理圖如圖3-1所示,它由樂曲自動演奏模塊、音調發生模塊和數控分頻模塊三部分組成。
圖3-1 系統的整體組裝設計原理圖
3.2 各模塊的原理及其程序
(1)樂曲自動演奏模塊
樂曲自動演奏模塊(AUTO.VHD)的作用是產生8位發聲控制輸入信號/當進行自動演奏時,由存儲在此模塊中的8位二進制數作為發聲控制輸入,從而自動演奏樂曲。
VHDL源程序(AUTO.VHD)
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY AUTO IS
PORT ( CLK : IN STD_LOGIC;
AUTO : IN STD_LOGIC;
CLK2 : BUFFER STD_LOGIC;
INDEX2 : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
INDEX0 : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END AUTO;
ARCHITECTURE BEHAVIORAL OF AUTO IS
SIGNAL COUNT0: INTEGER RANGE 0 TO 31;
BEGIN
PULSE0 :PROCESS(CLK,AUTO)
VARIABLE COUNT :INTEGER RANGE 0 TO 8;
BEGIN
IF AUTO ='1' THEN
COUNT := 0;CLK2<='0';
ELSIF(CLK'EVENT AND CLK ='1')THEN
COUNT :=COUNT +1;
IF COUNT =4 THEN
CLK2 <='1';
ELSIF COUNT =8 THEN
CLK2<='0'; COUNT:=0;
END IF ;
END IF ;
END PROCESS;
MUSIC:PROCESS(CLK2)
BEGIN
IF (CLK2'EVENT AND CLK2='1')THEN
IF (COUNT0=31)THEN
COUNT0<=0;
ELSE
COUNT0<=COUNT0+1;
END IF ;
END IF ;
END PROCESS;
COM1:PROCESS(COUNT0,AUTO,INDEX2)
BEGIN
IF AUTO ='0' THEN
CASE COUNT0 IS
WHEN 0=>INDEX0<="00000100"; --3
WHEN 1=>INDEX0<="00000100"; --3
WHEN 2=>INDEX0<="00000100"; --3
WHEN 3=>INDEX0<="00000100"; --3
WHEN 4=>INDEX0<="00010000"; --5
WHEN 5=>INDEX0<="00010000"; --5
WHEN 6=>INDEX0<="00010000"; --5
WHEN 7=>INDEX0<="00100000"; --6
WHEN 8=>INDEX0<="10000000"; --8
WHEN 9=>INDEX0<="10000000"; --8
WHEN 10=>INDEX0<="10000000"; --8
WHEN 11=>INDEX0<="00000100"; --3
WHEN 12=>INDEX0<="00000010"; --2
WHEN 13=>INDEX0<="00000010"; --2
WHEN 14=>INDEX0<="00000001"; --1
WHEN 15=>INDEX0<="00000001"; --1
WHEN 16=>INDEX0<="00010000"; --5
WHEN 17=>INDEX0<="00010000"; --5
WHEN 18=>INDEX0<="00001000"; --4
WHEN 19=>INDEX0<="00001000"; --4
WHEN 20=>INDEX0<="00001000"; --4
WHEN 21=>INDEX0<="00000100"; --3
WHEN 22=>INDEX0<="00000010"; --2
WHEN 23=>INDEX0<="00000010"; --2
WHEN 24=>INDEX0<="00010000"; --5
WHEN 25=>INDEX0<="00010000"; --5
WHEN 26=>INDEX0<="00001000"; --4
WHEN 27=>INDEX0<="00001000"; --4
WHEN 28=>INDEX0<="00000100"; --3
WHEN 29=>INDEX0<="00000100"; --3
WHEN 30=>INDEX0<="00000010"; --2
WHEN 31=>INDEX0<="00000010"; --2
WHEN OTHERS =>NULL;
END CASE;
ELSE INDEX0<=INDEX2;
END IF;
END PROCESS;
END BEHAVIORAL;
(2) 音調發生模塊
音調發生模塊的作用是產生音階的分頻預置值。當8位發聲控制輸入信號中的某一位為高電平時,則對應某一音節的數值將輸出,該數值即為該音階的分頻預置值,分頻預置值控制數控分頻模塊進行分頻,由此可得到每個音階對應的頻率。
VHDL源程序(TONE.VHD)
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY TONE IS
PORT (INDEX: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
CODE: OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
HIGH: OUT STD_LOGIC;
TONE0: OUT INTEGER RANGE 0 TO 2047);
END TONE;
ARCHITECTURE ART OF TONE IS
BEGIN
SEARCH : PROCESS(INDEX)
BEGIN
CASE INDEX IS
WHEN "00000001"=>TONE0 <=773;CODE<="1001111";HIGH<='1';
WHEN "00000010"=>TONE0 <=912;CODE<="0010010";HIGH<='1';
WHEN "00000100"=>TONE0 <=1036;CODE<="0000110";HIGH<='1';
WHEN "00001000"=>TONE0 <=1116;CODE<="1001100";HIGH<='1';
WHEN "00010000"=>TONE0 <=1197;CODE<="0100100";HIGH<='1';
WHEN "00100000"=>TONE0 <=1290;CODE<="0100000";HIGH<='0';
WHEN "01000000"=>TONE0 <=1372;CODE<="0001111";HIGH<='0';
WHEN "10000000"=>TONE0 <=1410;CODE<="0000000";HIGH<='0';
WHEN OTHERS =>TONE0<=2047;CODE<="0000001";HIGH<='0';
END CASE;
END PROCESS;
END ART;
(3) 數控分頻模塊
數控分頻模塊是對時基脈沖進行分頻,得到與1、2、3、4、5、6、7七個音符相對應的頻率。
VHDL源程序(FENPIN.VHD)
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY FENPIN IS
PORT(CLK1: IN STD_LOGIC;
TONE1: IN INTEGER RANGE 0 TO 2047;
SPKS: OUT STD_LOGIC);
END ENTITY FENPIN;
ARCHITECTURE ART OF FENPIN IS
SIGNAL PRECLK:STD_LOGIC;
SIGNAL FULLSPKS:STD_LOGIC;
BEGIN
PROCESS(CLK1)
VARIABLE COUNT:INTEGER RANGE 0 TO 8;
BEGIN
IF (CLK1'EVENT AND CLK1='1')THEN
COUNT:=COUNT +1;
IF COUNT=2 THEN
PRECLK<='1';
ELSIF COUNT =4 THEN
PRECLK<='0';COUNT:=0;
END IF ;
END IF ;
END PROCESS;
PROCESS(PRECLK,TONE1)
VARIABLE COUNT11:INTEGER RANGE 0 TO 2047;
BEGIN
IF (PRECLK'EVENT AND PRECLK='1')THEN
IF COUNT11<TONE1 THEN
COUNT11:=COUNT11+1;FULLSPKS<='1';
ELSE
COUNT11:=0;FULLSPKS<='0';
END IF ;
END IF ;
END PROCESS;
PROCESS(FULLSPKS)
VARIABLE COUNT2 :STD_LOGIC:='0';
BEGIN
IF (FULLSPKS'EVENT AND FULLSPKS='1')THEN
COUNT2:=NOT COUNT2;
IF COUNT2='1'THEN
SPKS<='1';
ELSE
SPKS<='0';
END IF ;
END IF;
END PROCESS;
END ART;
(4) 頂層設計
VHDL源程序(DIANZIQIN.VHD)
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DIANZIQIN IS
PORT(CLK32MHZ: IN STD_LOGIC;
HANDTOAUTO:IN STD_LOGIC;
CODE1: OUT STD_LOGIC_VECTOR(6 DOWNTO 0);--音符顯示信號
INDEX1: IN STD_LOGIC_VECTOR(7 DOWNTO 0);--鍵盤輸入信號
HIGH1: OUT STD_LOGIC;--高低音節信號
SPKOUT: OUT STD_LOGIC);--音頻信號
END;
ARCHITECTURE ART OF DIANZIQIN IS
COMPONENT AUTO
PORT(CLK: IN STD_LOGIC;
AUTO: IN STD_LOGIC;
INDEX2: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
INDEX0: OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END COMPONENT;
COMPONENT TONE
PORT(INDEX: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
CODE: OUT STD_LOGIC_VECTOR(6 DOWNTO 0);
HIGH: OUT STD_LOGIC;
TONE0: OUT INTEGER RANGE 0 TO 2047);
END COMPONENT;
COMPONENT FENPIN
PORT(CLK1: IN STD_LOGIC;
TONE1:IN INTEGER RANGE 0 TO 2047;
SPKS: OUT STD_LOGIC);
END COMPONENT;
SIGNAL TONE2:INTEGER RANGE 0 TO 2047;
SIGNAL INDX:STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
U0:AUTOPORTMAP(CLK=>CLK32MHZ,INDEX2=>INDEX1,INDEX0=>INDX,AUTO=>HANDTOAUTO);
U1:TONEPORTMAP(INDEX=>INDX,TONE0=>TONE2,CODE=>CODE1,HIGH=>HIGH1);
U2:FENPIN PORT MAP(CLK1=>CLK32MHZ,TONE1=>TONE2,SPKS=>SPKOUT);
END ART;
4 波形模擬
(1)樂曲自動演奏模塊的模擬(如圖4-1所示)
圖4-1樂曲自動演奏模塊的模擬圖
(2)音調發生模塊的模擬(如圖4-2)
圖4-2 音調發生模塊的模擬圖
(3)數控分頻模塊的模擬(如圖4-3)
圖4-3數控分頻模塊模擬圖
(4)簡易電子琴整個系統的模擬(如圖4-4)
圖4-4簡易電子琴整個系統的模擬圖
5 結束語
經過努力,簡易電子琴的設計基本上完成了。在整個設計過程中,包括前期中期和後期,我都有著許多不同的體會:
1) 這個設計的基本是接觸一門新的語言並加以應用,對於我來說,沒有想到的是入手的速度比我的預料快,在以前編程的基礎上,從接觸到開始動手編程的時間得到了很大的縮短。知識的接收速度在很大的程度上決定了動手的時間。
2) VHDL的編程與C語言的編程有著本質的不同,然而以往形成的舊編程習慣在VHDL編程中依然起著很大的作用。一通百通,不是沒有道理的。對於學習新的知識並予以應用的信心,顯得更足了。
3) VHDL的設計關鍵是電路邏輯設計,而一個程序的關鍵是總體設計。對於硬體設計接觸不多的我們清楚這一點也許不無好處。
4)通過這個程序設計讓我學會一種新的語言,對數字系統結構也有了更進一步的了解和認識,對我以後的學習有很大的幫助。希望其他人在看再做類似設計時有所借鑒。
通過幾天的課程設計,我對資料庫軟體EDA技術、VHDL、等系列知識都有了一定的了解。使用EDA技術開發頁面的能力也有了很大提高。
在整個設計過程中,有很多人對任務的完成給予了重要的支持和幫助。感謝老師給了我本次設計的機會並提供指導;感謝許多同學在我此課程設計遇到問題時給我的幫助使我能夠順利地進行設計的工作;論壇中有很多認識不認識的朋友也都為我的設計提出了很寶貴的建議,同樣在這里感謝他們。
參考文獻
《VHDL與數字電路設計》.盧毅,賴傑.科學出版社
《VHDL語言100例詳解——北京理工大學ASIC研究所》.北京理工大學ASIC研究所.清華大學出版社
《VHDL程序設計》(第二版). 曾繁泰等.清華大學出版社
《VHDL入門與應用》陳雪松,滕立中.人民郵電出版社
《VHDL簡明教程》.王小軍.清華大學出版社
② 單片機簡易電子琴程序
22. 電子琴
1. 實驗任務
(1. 由4X4組成16個按鈕矩陣,設計成16個音。
(2. 可隨意彈奏想要表達的音樂。
2. 電路原理圖
圖4.22.1
3. 系統板硬體連線
(1. 把「單片機系統」區域中的P1.0埠用導線連接到「音頻放大模塊」區域中的SPK IN埠上;
(2. 把「單片機系統「區域中的P3.0-P3.7埠用8芯排線連接到「4X4行列式鍵盤」區域中的C1-C4 R1-R4埠上;
4. 相關程序內容
(1. 4X4行列式鍵盤識別;
(2. 音樂產生的方法;
一首音樂是許多不同的音階組成的,而每個音階對應著不同的頻率,這樣我們就可以利用不同的頻率的組合,即可構成我們所想要的音樂了,當然對於單片機來產生不同的頻率非常方便,我們可以利用單片機的定時/計數器T0來產生這樣方波頻率信號,因此,我們只要把一首歌曲的音階對應頻率關系弄正確即可。現在以單片機12MHZ晶振為例,例出高中低音符與單片機計數T0相關的計數值如下表所示
音符 頻率(HZ) 簡譜碼(T值) 音符 頻率(HZ) 簡譜碼(T值)
低1 DO 262 63628 # 4 FA# 740 64860
#1 DO# 277 63731 中 5 SO 784 64898
低2 RE 294 63835 # 5 SO# 831 64934
#2 RE# 311 63928 中 6 LA 880 64968
低 3 M 330 64021 # 6 932 64994
低 4 FA 349 64103 中 7 SI 988 65030
# 4 FA# 370 64185 高 1 DO 1046 65058
低 5 SO 392 64260 # 1 DO# 1109 65085
# 5 SO# 415 64331 高 2 RE 1175 65110
低 6 LA 440 64400 # 2 RE# 1245 65134
# 6 466 64463 高 3 M 1318 65157
低 7 SI 494 64524 高 4 FA 1397 65178
中 1 DO 523 64580 # 4 FA# 1480 65198
# 1 DO# 554 64633 高 5 SO 1568 65217
中 2 RE 587 64684 # 5 SO# 1661 65235
# 2 RE# 622 64732 高 6 LA 1760 65252
中 3 M 659 64777 # 6 1865 65268
中 4 FA 698 64820 高 7 SI 1967 65283
下面我們要為這個音符建立一個表格,有助於單片機通過查表的方式來獲得相應的數據
低音0-19之間,中音在20-39之間,高音在40-59之間
TABLE: DW 0,63628,63835,64021,64103,64260,64400,64524,0,0
DW 0,63731,63928,0,64185,64331,64463,0,0,0
DW 0,64580,64684,64777,64820,64898,64968,65030,0,0
DW 0,64633,64732,0,64860,64934,64994,0,0,0
DW 0,65058,65110,65157,65178,65217,65252,65283,0,0
DW 0,65085,65134,0,65198,65235,65268,0,0,0
DW 0
2、音樂的音拍,一個節拍為單位(C調)
曲調值 DELAY 曲調值 DELAY
調4/4 125ms 調4/4 62ms
調3/4 187ms 調3/4 94ms
調2/4 250ms 調2/4 125ms
對於不同的曲調我們也可以用單片機的另外一個定時/計數器來完成。
下面就用AT89S51單片機產生一首「生日快樂」歌曲來說明單片機如何產生的。
在這個程序中用到了兩個定時/計數器來完成的。其中T0用來產生音符頻率,T1用來產生音拍。
5. 程序框圖
貼不了.
7. C語言源程序
#include <AT89X51.H>
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
unsigned char temp;
unsigned char key;
unsigned char i,j;
unsigned char STH0;
unsigned char STL0;
unsigned int code tab[]={64021,64103,64260,64400,
64524,64580,64684,64777,
64820,64898,64968,65030,
65058,65110,65157,65178};
void main(void)
{
TMOD=0x01;
ET0=1;
EA=1;
while(1)
{
P3=0xff;
P3_4=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=0;
break;
case 0x0d:
key=1;
break;
case 0x0b:
key=2;
break;
case 0x07:
key=3;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_5=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=4;
break;
case 0x0d:
key=5;
break;
case 0x0b:
key=6;
break;
case 0x07:
key=7;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_6=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=8;
break;
case 0x0d:
key=9;
break;
case 0x0b:
key=10;
break;
case 0x07:
key=11;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
P3=0xff;
P3_7=0;
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P3;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
switch(temp)
{
case 0x0e:
key=12;
break;
case 0x0d:
key=13;
break;
case 0x0b:
key=14;
break;
case 0x07:
key=15;
break;
}
temp=P3;
P1_0=~P1_0;
P0=table[key];
STH0=tab[key]/256;
STL0=tab[key]%256;
TR0=1;
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P3;
temp=temp & 0x0f;
}
TR0=0;
}
}
}
}
void t0(void) interrupt 1 using 0
{
TH0=STH0;
TL0=STL0;
P1_0=~P1_0;
}
根據自己的情況稍微改改就好了
③ 用單片機做電子琴,復音(合音)怎麼實現
解析MIDI電子琴的設計用單片機是如何實現的
摘要:用單片機控制通用MIDI音源模塊製作製作出的電子琴,結構簡單,可靠性高,並且價格低廉,具有實用的價值。這種電子琴能夠支持單音和復音彈奏,如果與高品質的音源晶元連接,音質更可與高檔電子琴相媲美。我們在實驗過程中,也曾採用手機中通用的音樂晶元構成音源模塊,效果不錯,價格更低廉,如韓國產的QS6400 等,這些晶元的驅動要復雜一些,需要對晶元進行初始化設置,詳細內容可參看國防工業出版社出版的《MIDI原理與開發應用》一書中的相關章節。
關鍵字:電子琴,單片機,音源板,MD2064
1、電子琴的硬體設計方案
本電子琴包含48個按鍵鍵盤,即具有4個8度的音域,單片機AT89C51通過對所彈按鍵的識別,產生相應的MIDI消息。它支持單音彈奏和最多16個復音彈奏。電子琴結構示意圖和電路原理圖分別如圖1和圖2所示。AT89C51作為主控晶元,它使得鍵盤矩陣模塊、通道和音色選擇以及串口發送等各功能模塊協調工作。48按鍵行列式鍵盤矩陣構成MIDI電子琴的鍵盤掃描輸入端,由於89C51的P0口內部沒有上拉電阻,故這里採用電阻R14——R21將列線拉至高電平,與六條行線組合完成48個琴鍵的掃描識別,在圖1中,單片機與鍵盤矩陣間的雙箭頭線表示單片機在掃描鍵盤矩陣時,P0口和P2口分別作為輸入/輸出口使用。人機介面電路則利用了單片機P1口的大部分口線,並通過或門向INT0發出中斷請求,該部分電路主要完成MIDI電子琴的通道設置和音色選擇等人機交互功能。鍵盤的彈奏信息以及通道、音色信息經CPU處理後,由串口將標準的MIDI數據發送給MIDI音源及放大器,推動揚聲器發聲。
圖1:MIDI電子琴結構示意圖
圖2:MIDI電子琴電路圖
音源模塊採用MD2064 套板,如圖3所示。它是一種模塊化的MIDI音源產品,由得理電子公司開發,具有標准MIDI介面,該板能接受標准GM MIDI命令進行音樂播放,自帶3D, REVERB, CHORUS等效果處理。由於該套板的MIDI 介面採用了光耦合器,電流驅動,故設計了由Q1、Q2等器件組成的驅動電路,使單片機串口數據得以正常傳輸。在模塊的耳機輸出端取得信號後,經小功率放大即可推動揚聲器發聲。
2、電子琴的軟體設計特點
該電子琴軟體採用模塊化設計方法,程序也較簡單。軟體中各功能模塊都由相應的子程序完成,主要包含通道選擇模塊,音色選擇模塊,48按鍵鍵盤掃描模塊,串口發送模塊等,其中為了及時完成用戶命令,音色選擇模塊採用了中斷服務子程序,可以在演奏中快速響應使用者的請求。
主程序在完成串口初始化、相關變數的初始化以及設置通道後,即進入鍵盤掃描、發送音符消息流程,為了使按鍵識別准確可靠,還設置了兩個緩沖區BUFF1和BUFF2保存鍵盤掃描值。主程序流程圖如圖3。
圖3:MIDI電子琴程序的流程圖
以下是部分功能模塊的程序設計介紹。
2.1 音色選擇模塊的設計
該模塊的功能是使MIDI電子琴能按要求快速改變音色,所以採用了中斷服務子程序。當某個音色選擇按鍵壓下時,通過或門向單片機的INT0發出中斷請求,CPU響應後進入該中斷服務子程序。MIDI技術規范規定,標准MIDI含有128種音色,它們的編號范圍是0~127,為了能夠快速找到所需音色,硬體中設置3個按鍵,其中2個用於音色編號的單步增加和減小,每次增加或減小1個音色編號,另外一個鍵用於音色快進,當快進鍵有效時,每次增加8個音色編號,選擇增加8個音色的原因是:標准MIDI的128種音色是按每8個音色一組編排的,共包含16個樂器組。電子琴開機時默認的音色編號是0,即大鋼琴音色。
單片機的P1.2口線連接著音色增加按鍵,P1.3則連接音色減小按鍵,P1.4連接音色快進鍵。低電平時按鍵有效,這三個按鍵通過與門連接外部中斷INT0,以便實時響應音色設置。該外部中斷0的中斷服務子程序流程圖見圖4,(圖中省去了按鍵延時去抖動部分):
圖4:音色改變子程序流程圖
在該子程序中,變數TAMBER中存放當前音色,其值可在0~127間循環,當TAMBER是最大值127時,加1後又變為0;而當TAMBER為0時,減1則變為127;在邊界范圍加8取模後,剛好為其對應的音色值。
2.2 串口發送模塊
串口發送模塊主要用於發送產生的MIDI消息,串口採用的模式1,發送的波特率是31.25KBPS。串口通過驅動電路連接MIDI音源,發送MIDI消息。通道號存放在變數CHANNEL中,通過與90H相與,所得值就是當前所設置的通道號。
2.3 鍵盤掃描模塊
本電子琴提供了48個MIDI按鍵,即4個8度音的音域范圍,當按下單個鍵時,產生一條MIDI消息,當按下多個鍵值時產生對應鍵值的多條MIDI音符開消息,當某個鍵值被釋放時,發送對應的音符關消息。這些MIDI消息通過串口發送給MIDI音源,產生MIDI音樂。音樂的時值由按鍵的時間長度控制,當按鍵被釋放,實時產生MIDI消息,關閉被釋放的鍵值音。
由P0口和P2口的P2.0~P2.5構成行列式鍵盤,也可繼續擴展鍵盤,例如改為常用的49鍵或64鍵。因為支持復音按鍵,鍵盤掃描程序必須掃描到行列式鍵盤的每個鍵值,掃描所得的鍵值存放在緩沖區BUFF1或BUFF2中。鍵盤掃描程序獲得的鍵盤編號范圍是0~47,還需將這個鍵盤編號值轉換為MIDI設備能夠識別的鋼琴鍵盤編號,這個功能由一個子程序來完成,限於篇幅本文不再詳述。鍵盤掃描子程序流程如圖5。
圖5:鍵盤掃描子程序
④ 求89c51單片機製作簡易電子琴的c程序及源代碼
#include
#include
#include
#include
#include
#define uchar unsigned char
typedef unsigned char uint8; // 無符號8位整型變數
typedef signed char int8; // 有符號8位整型變數
typedef unsigned short uint16; // 無符號16位整型變數
typedef signed short int16; // 有符號16位整型變數
typedef unsigned int uint32; // 無符號32位整型變數
typedef signed int int32; // 有符號32位整型變數
typedef float fp32; // 單精度浮點數(32位長度)
typedef double fp64; // 雙精度浮點數(64位長度)
sbit row1 = P1 ^ 0;
sbit row2 = P1 ^ 1;
sbit row3 = P1 ^ 2;
sbit col1 = P0 ^ 1;
sbit col2 = P0 ^ 2;
sbit col3 = P0 ^ 3;
sbit col4 = P0 ^ 4;
sbit col5 = P0 ^ 5;
sbit col6 = P0 ^ 6;
sbit col7 = P0 ^ 7;
#define uint unsigned int
uchar STH0; //定時器計數初值
uchar STL0;
bit FY=0; //放樂曲時FY=1, 電子琴彈奏時FY=0
uchar Song_Index=0,Tone_Index=0; //放音樂的參數
uchar k, key;
sbit SPK=P3^7;
sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P3^4;
sbit LED4=P3^5;
sbit LED5=P3^6;
void Delay(uint16 count)
{
uint8 i;
while(--count != 0)
{
for(i = 0; i < 125; i++); // ";" 表示空語句,CPU空轉。
} // i 從0加到125,在12M晶體下CPU大概耗時1毫秒
}
uint8 KeyDown(void)
{
col1=0; col2=0; col3=0; col4=0; col5=0; col6=0; col7=0; // 列線全部置低
if((row1==0) || (row2==0) || (row3==0)) // 若有任一行線讀回狀態為低
{
Delay(80); // 延時消抖
if((row1==0) || (row2==0) || (row3==0)) // 再次讀行線狀態,若有任一行線讀回狀態為低
return 1; // 返回1,表明有鍵盤按下
else
return 0; // 返回0,表明無鍵盤按下
}
else
return 0;
}
uint8 KeyUp(void)
{
col1=0; col2=0; col3=0; col4=0; col5=0; col6=0; col7=0;
if((row1==1) && (row2==1) && (row3==1))
{
Delay(80);
if((row1==1) && (row2==1) && (row3==1))
return 1;
else
return 0;
}
else
return 0;
}
uint8 KeyNum(void)
{
uint8 KeyTemp;
KeyTemp=0;
if(KeyDown()==1)
{
col1=0; col2=1; col3=1; col4=1; col5=1; col6=1; col7=1; // 將列線1置低,其他列線置高
if (row1==0) KeyTemp=1; // 若行線1讀回狀態為低,則表明按鍵1被按下
if (row2==0) KeyTemp=8; // 若行線2讀回狀態為低,則表明按鍵8被按下
if (row3==0) KeyTemp=15; // 若行線3讀回狀態為低,則表明按鍵15被按下
col1=1; col2=0; col3=1; col4=1; col5=1; col6=1; col7=1;
if (row1==0) KeyTemp=2;
if (row2==0) KeyTemp=9;
if (row3==0) KeyTemp=16;
col1=1; col2=1; col3=0; col4=1; col5=1; col6=1; col7=1;
if (row1==0) KeyTemp=3;
if (row2==0) KeyTemp=10;
if (row3==0) KeyTemp=17;
col1=1; col2=1; col3=1; col4=0; col5=1; col6=1; col7=1;
if (row1==0) KeyTemp=4;
if (row2==0) KeyTemp=11;
if (row3==0) KeyTemp=18;
col1=1; col2=1; col3=1; col4=1; col5=0; col6=1; col7=1;
if (row1==0) KeyTemp=5;
if (row2==0) KeyTemp=12;
if (row3==0) KeyTemp=19;
col1=1; col2=1; col3=1; col4=1; col5=1; col6=0; col7=1;
if (row1==0) KeyTemp=6;
if (row2==0) KeyTemp=13;
if (row3==0) KeyTemp=20;
col1=1; col2=1; col3=1; col4=1; col5=1; col6=1; col7=0;
if (row1==0) KeyTemp=7;
if (row2==0) KeyTemp=14;
if (row3==0) KeyTemp=21;
return KeyTemp;
}
else
return 0; //無按鍵按下
}
uchar code DSY_CODE[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,0x06};
uchar code GE_CODE[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71};
uchar code Song[][100]= //任意選幾首音樂的旋律
{
{5,3,5,3,5,3,1,2,4,3,2,5,5,3,5,3,5,3,1,2,4,3,2,1,2,2,4,4,3,1,5,2,4,3,2,5,5,3,5,3,5,3,1,2,4,3,2,1,-1}, //《粉刷匠》
{1,2,3,4,5,3,1,8,6,4,5,5,3,1,2,3,4,5,3,2,1,2,3,2,5,1,2,3,4,5,3,1,8,6,4,5,3,1,2,3,4,5,3,2,1,2,3,1,1,8,6,4,5,5,1,8,6,4,5,3,1,2,3,4,5,3,2,1,2,3,1,1,-1},//《小紅帽》
{1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,4,3,1,5,6,5,4,3,1,1,5,1,1,5,1,-1}, //《兩只老虎》
{5,8,6,8,5,3,5,2,3,5,0,3,5,6,8,5,6,5,3,5,1,3,2,0,3,2,1,2,3,6,5,3,5,6,0,5,8,6,5,3,5,2,5,2,3,2,1,-1}, //《一分錢》
{5,3,5,3,5,3,2,3,5,5,5,3,6,5,3,5,3,2,1,2,3,5,3,2,1,2,3,6,5,6,5,2,3,5,6,5,6,5,2,3,1,-1}, //《丟手絹》
{5,3,5,3,5,6,5,3,6,5,1,1,2,3,5,3,2,0,3,5,5,5,6,5,3,5,5,6,5,8,6,5,1,5,3,2,1,2,3,5,5,2,3,1,10,9,8,6,5,5,6,6,5,6,8,10,8,9,0,5,10,9,8,6,5,5,6,6,5,6,10,9,9,10,9,8,6,5,5,8,6,5,3,2,1,0,2,3,5,5,0,5,6,8,-1}, //《七子之歌-澳門》
{5,6,5,6,5,6,5,5,8,7,6,5,3,5,5,3,4,5,5,3,1,4,3,2,1,2,1,-1}, //《找朋友》
{5,10,9,10,3,8,7,6,6,9,8,9,6,8,9,9,9,9,8,10,10,9,9,5,10,9,10,3,8,7,6,5,6,8,8,8,9,10,9,8,7,8,8,-1},//《感恩的心》
{3,3,4,5,5,4,3,2,1,1,2,3,3,2,2,3,3,4,5,5,4,3,2,1,1,2,3,2,1,1,2,2,3,1,2,3,4,3,1,2,3,4,3,2,1,2,1,3,3,3,4,5,5,4,3,4,2,1,1,2,3,2,1,1,-1}, //《歡樂頌》
{5,8,5,4,3,2,1,1,1,2,3,3,1,3,4,5,5,5,8,5,4,3,5,2,4,3,2,6,5,2,3,1,1,0,5,3,6,8,7,6,7,5,3,9,9,9,8,7,6,8,5,5,5,3,6,8,7,6,7,8,9,5,6,7,8,9,5,8,8,-1}, //《我愛北京天安門》
{3,5,8,5,6,0,6,5,3,3,5,5,3,5,6,8,9,8,5,3,2,5,3,3,3,3,5,8,5,6,0,8,9,8,5,3,5,7,6,0,3,2,3,5,10,9,7,8,3,5,8,3,5,8,5,6,0,8,9,8,5,3,5,7,6,0,3,2,3,5,10,9,7,8,3,5,2,3,5,10,9,9,9,7,8,-1},//《北京歡迎你》
{1,2,3,1,5,6,6,8,6,5,6,6,8,5,6,5,6,5,3,5,3,1,2,3,1,-1}, //《上學歌》
{10,9,9,10,8,0,3,8,6,5,3,5,0,5,5,6,8,8,8,6,8,3,5,5,6,5,3,2,2,0,10,9,9,10,8,0,3,8,6,5,3,5,0,5,5,6,8,8,6,5,6,3,0,3,10,10,10,10,9,6,8,-1},//《當兵的人》
{3,3,5,6,8,8,6,5,5,6,5,3,3,5,6,8,8,6,5,5,6,5,5,5,5,3,5,6,6,5,3,2,3,5,3,2,1,1,2,1,-1},//《茉莉花》
{3,1,3,3,1,3,3,5,6,5,0,6,6,5,5,4,4,4,2,3,2,1,2,0,3,1,0,3,1,0,3,3,5,6,6,0,8,5,5,6,3,2,1,2,3,5,8,5,5,6,3,2,1,2,3,1,-1},//《數鴨子》
{1,1,3,4,5,5,5,3,4,4,4,2,1,3,5,0,1,1,3,4,5,5,5,3,4,4,4,2,1,3,1,0,6,6,4,5,5,5,5,3,4,4,4,2,1,3,5,0,6,6,4,5,5,5,5,3,4,4,4,2,1,3,1,0,-1},//《洋娃娃和小熊跳舞》
};
uchar code Len[][100]= //上面幾首音樂的旋律每個音符對應的節拍
{
{2,2,2,2,2,2,4,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,4,2,2,2,2,2,2,4,2,2,2,2,4,-1}, //《粉刷匠》
{2,2,2,2,4,2,2,4,2,2,2,2,4,2,2,2,2,2,2,2,2,4,4,4,4,2,2,2,2,4,2,2,4,2,2,4,4,2,2,2,2,2,2,2,2,4,4,4,4,4,2,2,2,2,4,4,2,2,4,4,2,2,2,2,2,2,2,2,4,4,4,4,-1}, //《小紅帽》
{2,2,2,2,2,2,2,2,2,2,4,2,2,4,2,2,2,2,4,4,2,2,2,2,4,4,2,2,4,2,2,4,2,2,4,-1}, //《兩只老虎》
{4,4,2,2,4,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,4,2,4,4,2,2,2,2,8,2,2,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,8,-1}, //《一分錢》
{6,2,6,2,2,2,2,2,8,2,4,2,4,4,2,2,2,2,4,4,4,4,2,2,2,2,8,2,2,2,2,2,2,4,2,2,2,2,4,4,8,-1}, //《丟手絹》
{4,2,2,2,6,2,2,2,2,8,4,2,2,4,2,2,4,2,2,8,2,2,2,2,2,4,2,2,2,2,2,8,4,2,2,2,2,4,2,6,2,2,4,16,4,2,1,2,2,4,2,4,2,2,1,2,2,12,2,2,4,2,1,2,2,4,2,4,2,4,2,2,16,4,2,1,2,2,4,4,2,2,2,2,4,4,2,2,8,8,4,2,2,16,-1}, //《七子之歌-澳門》
{2,2,2,2,2,2,4,2,2,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,2,2,4,-1}, //《找朋友》
{2,4,2,6,2,4,2,6,2,4,2,5,1,1,2,1,1,2,1,1,2,2,4,2,4,2,6,2,4,2,6,2,2,1,1,2,2,2,4,2,2,2,8,-1},//《感恩的心》
{4,4,4,4,4,4,4,4,4,4,4,4,5,2,6,4,4,4,4,4,4,4,4,4,4,4,4,5,2,6,4,4,4,4,4,2,2,4,4,4,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,4,4,4,4,5,2,6,-1},//《歡樂頌》
{2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,6,6,2,2,2,2,2,2,4,2,2,2,2,4,2,2,6,4,4,5,2,4,4,4,2,2,4,4,2,2,2,2,4,2,2,6,6,5,2,4,4,2,2,2,2,6,2,2,2,2,4,4,6,4,-1},//《我愛北京天安門》
{4,4,2,2,4,2,2,2,2,2,2,6,2,2,2,2,2,2,2,2,2,2,2,2,6,2,2,2,2,4,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,5,2,8,2,2,8,2,2,2,2,4,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,5,2,8,2,2,2,2,2,2,6,10,8,4,10,-1},//《北京歡迎你》
{2,2,2,2,6,2,2,2,2,6,2,2,4,2,2,4,2,2,2,2,2,2,2,2,6,-1},//《上學歌》
{6,4,3,2,8,4,4,4,2,2,4,8,4,4,2,2,4,3,2,4,4,6,4,2,2,4,2,2,8,4,6,4,3,2,8,4,4,4,2,2,4,8,4,2,4,2,4,4,4,2,2,4,2,2,2,4,2,4,2,2,8,4,-1},//《當兵的人》
{4,2,2,2,2,2,2,4,2,2,6,4,2,2,2,2,2,2,4,2,2,6,4,4,4,2,2,4,4,6,4,2,2,4,2,2,4,2,2,8,-1},//《茉莉花》
{4,4,2,2,4,2,2,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,4,4,4,2,2,4,2,2,2,2,2,2,4,4,4,2,2,4,4,2,2,2,2,6,4,2,2,4,4,2,2,2,2,6,-1},//《數鴨子》
{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,-1},//《洋娃娃和小熊跳舞》
};
uint code tab[]=
{
0,63628,63835,64021,64103,64260,64400,64524,
64580,64684,64777,64820,64898,64968,65030,
65058,65110,65157,65178,65217,65252,65283
};
void delay1(uint ms) //播放歌曲時實現節拍的延時函數
{
uchar t;
while(ms--) for (t=0;t<120;t++);
}
void delay(void)
{
uchar i;
for (i=300;i>0;i--);
}
void EX0_INT() interrupt 0
{
FY=0; LED1=0; LED2=1; STL0=STL0;
}
void EX1_INT() interrupt 2
{
FY=1; LED1=1; LED2=0;LED3=1;LED4=1;LED5=1;P2=0xff; Tone_Index=-1;Tone_Index++;
STH0=(tab[Song[k][Tone_Index]])/256;
STL0=(tab[Song[k][Tone_Index]])%6;
}
void time0_int(void) interrupt 1 using 0
{
TH0 = STH0;
TL0 = STL0;
SPK=!SPK; // 反相,產生輸出脈沖
if(FY==0)
{P2=~DSY_CODE[k] ;}
else {if(FY==1) {P2=~GE_CODE[k];}}
}
void main(void)
{ LED1=0;
LED2=1;
LED3=1;LED4=1;LED5=1;
P2=0xff;
IE=0x87;
TMOD=0x01;
IT0=1;
IT1=1;
while(1)
{
if (KeyDown())
{
k = KeyNum(); // 調用鍵盤掃描函數
if(FY==0)
{
STH0 = tab[k]/256;
STL0 = tab[k]%6;
TR0 = 1; // 開始計數
while (KeyUp()==0); // 若沒有松開按鍵,則等待,等待期間彈奏該音符
TR0 = 0; // 若按鍵松開,則停止計數,不產生脈沖輸出
}
else
{
while (FY==1)
{
if (Song[k][Tone_Index]==-1)
Tone_Index=0;
STH0=(tab[Song[k][Tone_Index]])/256;
STL0=(tab[Song[k][Tone_Index]])%6;
P2=~GE_CODE[Song[k][Tone_Index]] ;
TR0 = 1;
delay1(150*Len[k][Tone_Index]);
Tone_Index++;
TR0 = 0;
}
}
if(k>=1&&(k<=7)){LED3=0;LED4=1;LED5=1;}
else
{if(k>=8&&(k<=14)){LED3=1;LED4=0;LED5=1;}
else
{if (k==0){LED3=1;LED4=1;LED5=1;}
else
{LED3=1;LED4=1;LED5=0;}} }
}
}
}