代碼: 選擇全部
#include <Adafruit_NeoPixel.h>
/*<1>紅色按鈕-外部中斷腳位PB2(INT0):具照明及警示作用
<2>綠色按鈕-PB3內含上拉電阻:遊戲鍵\開始及設定鍵
<3>環燈訊號腳-PB0
<4>無源蜂鳴器-PB1
----------------------------------------------------------------
*/
//--------------------------------------------------------
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈
#define LED_PIN 0 //環號串列訊號腳位PB0
#define KEY_PUSH 3//按鈕控制腳位(內建上拉電阻,平時為HIGH)
#define NUMLEDS 16//環燈=總顆數
#define BRIGHTNESS 250//燈亮度在15~50即可,最大亮度為255
#define buzzerPin 1 //無源蜂鳴器訊號腳位PB1
int period = 1000; //計時器延時週期
int Int_period = 700;//中斷延時週期
int GameState = 0; //遊戲初始狀態=0 1(第1關-3燈) 2(第2關-2燈) 3(第3關-1燈)
byte RingSpeed[] = {110, 100, 60, 40}; //共有4個等級的遊戲
byte Speed=0;//速度盒編號 RingSpeed陣列編號
byte Set_Led[]={0, 0, 0};//用陣列設定號燈(3燈=3個陣列.2燈2個陣列.1燈1個陣列)
byte led_run_at = 0; //跑馬燈號現在位置(led跑到那個位置)
byte Setting_Led = 0; //燈號設定點(亂數值存放)
byte LEVEL=0;//關卡
byte Score=0;//計分用
unsigned long Time_Get = 0;//擷取時間點,開機55天會溢位(歸0)
unsigned long IntTime_Get = 0;//中斷擷取時間點
boolean Go_Play = false;//遊戲處於等待狀態(布林值)
volatile byte Int_state = 0; //定義輸入狀態
//宣告環燈 顆數 腳位
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
//--------------------------------------------------------
//-----重置函式
void(* resetFunc)(void)=0;
//-----環燈初始化動作
void setup() {
RingLED.begin(); //初始化(環燈)
RingLED.setBrightness(BRIGHTNESS); //環燈亮度
Time_Get = millis();//擷取開機時間
pinMode(KEY_PUSH, INPUT_PULLUP);//按鈕輸入腳3(KEY_PUSH),內建上拉電阻
pinMode(buzzerPin, OUTPUT);//
// Serial.begin(9600);//串列傳輸啟動
randomSeed(analogRead(KEY_PUSH));//(擷取亂數因子)解決亂數不亂的問題
//######以下是將GIMSK中斷暫存器的INT0啟用,MCUCR控制暫存器設為負緣觸發
pinMode(2, INPUT_PULLUP);//紅色按鈕,外部中斷腳位
sei(); //enabling global interrupt
GIMSK |= (1<<INT0); // INT0啟用
MCUCR |= (1<<ISC01); // MCUCR控制暫存器設為負緣觸發
}
//--------------------------------------------------------
//------無窮迴圈
void loop() {
if (GameState == 0){
//Go_Play == false等待按鈕被按下去,則往下做3關,每關4種變速
if (digitalRead(KEY_PUSH) == LOW && Go_Play == false) {
delay(1000);//除火花,延遲 1000 毫秒,也就是 1 秒鐘。
PlayStar();//奏音樂
led_run_at = 0;//跑馬燈現在位置
Go_Play = true;//變數為true,可以取設定點(亂數)
//Serial.print("!");//※判斷按鈕準不準
GameState=1; //開始玩第1關
}
Z_Random();//亂數顯示燈號(等待綠鍵被按!)
}
if (GameState == 1){Level_1();}//往第1關開始遊戲(每關4種變速)
if (GameState == 2){Level_2();}//往第2關開始遊戲(每關4種變速)
if (GameState == 3){Level_3();}//往第3關開始遊戲(每關4種變速)
}
//--------------------------------------------------------
//-----第1關(3顆設定燈):------
void Level_1(){
RingLED.clear();//清除燈號
led_run_at=0;//跑馬燈歸零
while (GameState == 1) {
period = RingSpeed[Speed]; //[0][1][2][3]存放不同速度值
//=====取亂數置入設定點-->再延伸成3個設定燈=====
if (millis()-Time_Get > period){ //延時 (亮燈週期過了,再重設週期)
Time_Get = millis(); // 擷取當下時間放入Time_Get
if(Go_Play==true){ //Go_Play為true,可以取設定點(亂數)
Setting_Led = random(NUMLEDS); //隨機-取設定點
Go_Play = false; //隨機設定號燈完畢,等待按鈕!
}
//----設定3個點---------------------------------
//以下亮3個號燈(跨14-15-0)
Set_Led[0]=Setting_Led; //陣列0=放入亂數值
if(Setting_Led == (NUMLEDS-2)){ //第14顆:(若16顆為例)
Set_Led[1]=(NUMLEDS-1);//第15顆
Set_Led[2]=0;}//第0顆
//以下亮3個號燈(跨15-0-1)
else if(Setting_Led == (NUMLEDS-1)){
Set_Led[1]=0;
Set_Led[2]=1;}
else{
Set_Led[1]=Set_Led[0]+1;
Set_Led[2]=Set_Led[0]+2;}
//---點亮3個燈[][][]---
RingLED.setPixelColor(Set_Led[0], 0, 255, 0);//(綠)
RingLED.setPixelColor(Set_Led[1], 0, 255, 0);//(綠)
RingLED.setPixelColor(Set_Led[2], 0, 255, 0);//(綠)
RingLED.show();
LED_Runing();//呼叫跑馬燈
Check_Push(GameState);//檢查按鈕是否被按下?
}
}
}
//---------------------------------------------------------------
//-----第2關(2顆設定燈):------
void Level_2(){
RingLED.clear();//清除燈號
led_run_at=0;//跑馬燈歸零
while (GameState == 2) {
period = RingSpeed[Speed]; //(陣列中的數字愈大愈慢)
//=====取亂數置入設定點-->再延伸成2個設定燈=====
if (millis()-Time_Get > period){ //延時 (亮燈週期過了,再重設週期)
Time_Get = millis(); // 擷取當下時間放入Time_Get
//====亂數設定OK了嗎? Yes(改false)
if(Go_Play==true){ //Go_Play為true,可以取設定點(亂數)
Setting_Led = random(NUMLEDS);
Go_Play = false; //隨機設定號燈完畢,等待按鈕!
}
//---設定2個點---------------------------------
//====以下亮2個號燈(跨15-0)====
Set_Led[0]=Setting_Led; //陣列0=放入亂數值
if(Setting_Led==(NUMLEDS-1)){Set_Led[1]=0;}
else{Set_Led[1]=Set_Led[0]+1;}
RingLED.setPixelColor(Set_Led[0], 0, 255, 0);//(綠)
RingLED.setPixelColor(Set_Led[1], 0, 255, 0);//(綠)
RingLED.show();
LED_Runing();//呼叫跑馬燈
Check_Push(GameState);//檢查按鈕是否被按下?
}
}
}
//---------------------------------------------------------------
//-----第3關(1顆設定燈):------
void Level_3(){
RingLED.clear();//清除燈號
led_run_at=0;//跑馬燈歸零
while (GameState == 3) {
period = RingSpeed[Speed]; //(陣列中的數字愈大愈慢)
//=====取亂數置入設定點=====
if (millis()-Time_Get > period){ //延時 (亮燈週期過了,再重設週期)
Time_Get = millis(); // 擷取當下時間放入Time_Get
//====亂數設定OK了嗎? Yes(改false)
if(Go_Play==true){ //Go_Play為true,可以取設定點(亂數)
Setting_Led = random(NUMLEDS);
Go_Play = false; //隨機設定號燈完畢,回歸,等待按鈕!
}
//-------------------------------------------
//====以下亮1個號燈====
Set_Led[0]=Setting_Led;
RingLED.setPixelColor(Set_Led[0], 0, 255, 0);//(綠)
RingLED.show();
LED_Runing();//呼叫跑馬燈
Check_Push(GameState);//檢查按鈕是否被按下?
}
}
}
//---------------------------------------------------------------
//---------------------------------------------------------------
//----跑馬燈----
void LED_Runing(){
led_run_at++; //循環燈...往下累加
if (led_run_at >= NUMLEDS) { //如果循環紅點位置=60符合則歸零
RingLED.setPixelColor(led_run_at-1, 0, 0, 0);//最後一顆歸0
led_run_at = 0;//歸零
}
RingLED.setPixelColor(led_run_at, 255, 0, 0);//亮燈
RingLED.setPixelColor(led_run_at-1, 0, 0, 0);//往後關燈
RingLED.show();
}
//-----------------------------------------------------------
//----壓下去(檢查是否得分?)-------
void Check_Push(byte LV){ //Go_Play == false為等待的意思
if (digitalRead(KEY_PUSH) == LOW && Go_Play == false ) { //按鈕被按下去,往下做
delay(1000);
Go_Play=true;
//Serial.print("S");//判斷按鈕準不準
//-----------------------------------------------------------
//----得分-------
if(LV==1){
if (Set_Led[0]==led_run_at || Set_Led[1]==led_run_at || Set_Led[2]==led_run_at) {
Score++;
ScreLed(Score,550);//呼叫計分燈號函式(累計得分,高音頻)
}
else{ScreLed(Score,150);}//呼叫計分燈號函式(不累計,低音頻)
}
else if(LV==2){
if (Set_Led[0]==led_run_at || Set_Led[1]==led_run_at) {
Score++;
ScreLed(Score,550);//呼叫計分燈號函式(累計得分,高音頻)
}
else{ScreLed(Score,150);}//呼叫計分燈號函式(不累計,低音頻)
}
else if(LV==3){
if (Set_Led[0]==led_run_at) {
Score++;
ScreLed(Score,550);//呼叫計分燈號函式(累計得分,高音頻)
}
else{ScreLed(Score,150);}//呼叫計分燈號函式(不累計,低音頻)
}
//---換速度檔次--------
Speed++; //換下個速度檔次
//Serial.print(Speed);//查看勝利或失敗 */
//Serial.print(">");
//若4種檔次完成,換第二關
if(Speed==4){
//Serial.println("-");
GameState++;//下一大關
if(GameState==4){GameState=0; Go_Play=false;Score=0;}//3大關全部完成
Speed=0;
PlayFamily();
}
}
}
//-----------------------------------------------------------
//----計分燈號+鳴----
void ScreLed(byte Gain,int Freq){//接收得分值,及音頻
RingLED.clear();//清除燈號
for(byte i=0;i<Gain;i++){RingLED.setPixelColor(i, 255 , 255, 0);}
RingLED.show();
//--鳴--
for (byte j = 0; j <2; j++){
tinyTone(Freq, 400);}
delay(450);
RingLED.clear();//清除燈號
}
//-----------------------------------------------------------
//----亂數顯示燈號----
void Z_Random(){
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i, random(0, 255), random(0, 255), random(0, 255));//黃色
delay(15);
RingLED.show();
}
}
//-----------------------------------------------------------
//----星際爭霸----
void PlayStar(){
int Star[] = {440,440,440,349,523,440,349,523,440,659,659,659,698,523,415,349,523,440};
int StarDur[] = {400, 400, 400, 250, 50, 400, 250, 50, 900, 400, 400, 400, 250, 50, 400, 250, 50, 900};
for (int thisNote = 0; thisNote < 18; thisNote++) {//18個音符
tinyTone(Star[thisNote],StarDur[thisNote]);
delay(30);// 音符之間的間隔
}
}
//-----------------------------------------------------------
//----全家音樂----
void PlayFamily(){
int FamilyMusic[]={330, 262, 196, 262, 294, 392, 0, 0, 294, 330,0, 294, 196, 262,0};
for (int thisNote = 0; thisNote < 15; thisNote++) {//14個音符
tinyTone(FamilyMusic[thisNote],200);
delay(30);// 音符之間的間隔
}
}
//-----------------------------------------------------------
//----中斷函式----(處理第一次中斷無效問題)
ISR (INT0_vect){
if ( millis() - IntTime_Get > Int_period ){
IntTime_Get = millis();
Int_state++;//累計按下次數
//Serial.print(Int_state);
while(Int_state==1){ //按1次-->手電筒模式
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,255,255,255);//白色
RingLED.setBrightness(180); //環燈亮度
RingLED.show();
}
}
while(Int_state==2){ //按2次-->閃白光模式
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,255,255,255);//白色
RingLED.setBrightness(180); //環燈亮度
RingLED.show();
}
delay(400);
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,0,0,0);//黑色
RingLED.show();
}
delay(400);
}
while(Int_state==3){ //按3次-->閃紅光模式
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,255,0,0);//紅色
RingLED.setBrightness(180); //環燈亮度
RingLED.show();
}
delay(400);
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,0,0,0);//黑色
RingLED.show();
}
delay(400);
}
while(Int_state==4){ //按4次-->閃紅光+警示音模式
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,255,0,0);//紅色
RingLED.setBrightness(180); //環燈亮度
RingLED.show();
}
tinyTone(650, 200);
delay(300);
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,0,0,0);//黑色
RingLED.show();
}
tinyTone(900, 200);
delay(300);
}
if(Int_state==5){ //按5次-->重置模式
Int_state=0;
resetFunc();
}
}
}
//-----------------------------------------------------------
//----音樂播放函式(傳音符[頻率],聲音長度)
void tinyTone(int frequency, int length){
unsigned long period;
unsigned long n;
period=1000000/frequency;
n=1000*(long)length/period;
for(int j=1;j<n;j++){
digitalWrite(buzzerPin,HIGH);
delayMicroseconds(period/2);
digitalWrite(buzzerPin,LOW);
delayMicroseconds(period/2);
}
}