#include <Wire.h> //載入I2C程式庫
#include "LiquidCrystal_I2C.h" //載入I2C_LCD模組程式庫
LiquidCrystal_I2C I2C_LCD(0x27,2,1,0,4,5,6,7,3,POSITIVE); //設定LCD位址及腳位
//LiquidCrystal_I2C(lcd_Addr,En,Rw,Rs,d4,d5,d6,d7,backlighPin,backlighPol)
#include <LedControl.h> //載入SPI_MAX7219_LED矩陣控制程式庫
LedControl LED_Matrix=LedControl(51,52,53,2); //LED陣列模組腳位
//LedControl(DIN[MOSI],CLK[SCK],CS[SS],LED_模組數),[]內為模組腳位名稱,[]內為SPI腳位名稱
int BZ=3; //蜂鳴器接腳
int Time=150; //預設每個音0.15s
String Song="1234567 CDEFGAB cdefgab"; //記錄歌曲之字串
int PitchM[]={262,294,330,349,392,440,494};//中音1(Do),2(Re),3(Mi),4(Fa),5(So),6(La),7(Ti)
int PitchL[]={131,147,165,175,196,220,247};//c(Do),d(Re),e(Mi),f(Fa),g(So),低音a(La),b(Ti)
int PitchH[]={523,587,659,698,784,880,988};//C(Do),D(Re),E(Mi),F(Fa),G(So),高音A(La),B(Ti)
const uint64_t P_LED0[7][2]={ //8*8_LED矩陣顯示音名
{0x00FE828244380000,0x007C8282827C0000},//DO
{0x00FE909894620000,0x00FE929292820000},//RE
{0x00FE403040FE0000,0x000082FE82000000},//MI
{0x00FE909090800000,0x007E8888887E0000},//FA
{0x00629292928C0000,0x007C8282827C0000},//SO
{0x00FE020202020000,0x007E8888887E0000},//LA
{0x008080FE80800000,0x000082FE82000000}};//TI
void PlaySong(){//播放歌曲副程式
Serial.print("歌曲音階="); //印字串,不換行
Serial.println(Song); //印出歌曲Song字串,換行
I2C_LCD.setCursor(0,1); //設定游標為第0行,第1列(左下)
for(int i=0;i<Song.length();i++){ //使i=0~歌曲字串長-1
if(i>15) //顯示超過16行(0-15)
I2C_LCD.autoscroll(); //LCD自動向左捲動
char ch=Song[i]; //讀出音階代號至ch
I2C_LCD.print(ch); //LCD印出正要播之音階
if(ch>='1' && ch<='7'){ //若為音階為1~7字元
ch=ch-'1'; //轉成音階陣列號0~6數字
tone(BZ,PitchM[ch]); //播放中音
DisplayP(ch); //在8*8_LED矩陣顯示音名
}//if(ch='1'~'7')結束
if(ch>='A' && ch <='G'){//若為音階為A~G
if(ch>='C') //若音階為C~G
ch=ch-'C'; //轉成音階陣列號0~4數字
else //否則,音階為A~B
ch=ch-'A'+5; //轉成音階陣列號5~6數字
tone(BZ,PitchH[ch]); //播放輸入之高音音階
DisplayP(ch); //在8*8_LED矩陣顯示音階名
}//else if(ch='A'~'G')結束
if(ch>='a' && ch<='g'){//若為音階為a~g
if(ch>='c') //若音階為c~g
ch=ch-'c'; //轉成音階陣列號0~4數字
else //否則,音階為a~b
ch=ch-'a'+5; //轉成音階陣列號5~6數字
tone(BZ,PitchL[ch]); //播放低音
DisplayP(ch); //在8*8_LED矩陣顯示音名
}//else if(ch='A'~'G')結束
delay(Time); //蜂鳴器發音時間
noTone(BZ);} //蜂鳴器關閉
I2C_LCD.noAutoscroll(); //LCD停止自動捲動
I2C_LCD.clear(); //LCD清除顯示器
} //PlaySong()結束
void DisplayP(char ch){ //在8*8_LED矩陣顯示音名
for (int i = 0; i<8; i++) { //使i=0~7,i為要顯示之列(row)
LED_Matrix.setRow(0,i,P_LED0[ch][0]>>(8*i)); //逐列顯示音名前面英文字母
LED_Matrix.setRow(1,i,P_LED0[ch][1]>>(8*i)); //逐列顯示音名後面英文字母後
}//for(i=0~7)結束
}//DisplayP()結束
void LEDOFF(int off){ //控制全部LED陣列是否關閉之副程式.off=0不關(即打開),off=1關
for(int i=0;i<2;i++){ //i=0~1,i為要控制的LED陣列號
LED_Matrix.shutdown(i,off); //第i個LED陣列是否關, off=0不關(即打開),off=1關
LED_Matrix.clearDisplay(i); //清除第i個LED陣列
}//for(i=0~1)結束
}//LEDOFF()結束
void setup() { //初始設定
LEDOFF(0); //LED陣列全部不關(即打開)
for(int i=0;i<8;i++){ //使i=0~7,i為要顯示之列(row)、行(Column)或亮度(Intensity)
LED_Matrix.setRow(0, i, 0xFF); // LED陣列0逐列亮
LED_Matrix.setIntensity(0,2*i); // LED陣列0亮度為2i
LED_Matrix.setColumn(1, i, 0xFF); // LED陣列1逐行亮
LED_Matrix.setIntensity(1,2*i); // LED陣列1亮度為2i
delay(500); //顯示下個狀態前延遲0.5s
}//for(i=0~7)結束
Serial.begin(9600); //開啟串列埠,速度為9600bps
I2C_LCD.begin(16,2); //設定為16行,2列(行編號0-15,列編號0-1)
I2C_LCD.backlight(); //打開背光
I2C_LCD.print("Tone Time=200ms");//LCD列出每個音為200ms
pinMode(BZ, OUTPUT); //蜂鳴器接腳設定為輸出
PlaySong(); //播放歌曲
}//setup()結束
void loop() {//重覆執行無窮迴圈
if(Serial.available()){ //若序列埠有輸入
LEDOFF(0); // LED陣列不關(即打開)
I2C_LCD.backlight(); //打開背光
char ch=Serial.read(); //讀入序列埠資料
switch(ch){
case '+': if(Time>50) { //按[+],若播放時間大於50ms
Time-=50;Serial.println("加速!");}break;//播放時間減50ms
case '-': Time+=50;Serial.println("減速!");break;//按[-],播放時間加50ms
case '*': PlaySong();break;//按[*],再播一次歌
case '/': Song="";Serial.println("刪歌!");break;//按[/],使歌曲song為空白
default: Song=Song+ch; //若非設定字元,有新加入音,加在原歌後面
while(Serial.available()){ //若序列埠仍有資料
ch=Serial.read(); //讀入序列埠資料
if(ch !=0x0A) //不是換行符號
Song=Song+ch; //加在原歌後面
}//while()結束
PlaySong();//讀完播放歌曲
}//switch(}結束
}//if(Serial.available())結束
I2C_LCD.home(); //LCD游標回左上
I2C_LCD.print("Tone Time=");I2C_LCD.print(Time);I2C_LCD.print("ms ");//印每音時間
I2C_LCD.noBacklight(); //LCD關閉背光
LEDOFF(1); //LED陣列關
}//loop()結束