代碼: 選擇全部
/*-----01-Arduino系列-Attiny85 遊戲及照明兩用---
<1>紅色按鈕PB2腳-外部中斷腳位PB2-外部中斷腳位(INT0):具照明及警示作用
<2>綠色按鈕PB3腳-內含上拉電阻:遊戲鍵\開始及設定鍵
<3>環燈訊號腳-PB0腳
<4>無源蜂鳴器-PB1腳
<5>可使用的腳位共6支,可再增加一個按鈕調亮度
*/
//----02-C語言外部宣告--------------------------
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈WS2812
#define LED_PIN 0 //環號WS2812訊號腳位接PB0
#define KEY_PUSH 3//按鈕(綠)控制腳位(內建上拉電阻,平時為HIGH)
#define NUMLEDS 16//依環燈WS2812顆數修正
#define BRIGHTNESS 250//燈亮度在15~50即可,最大亮度為255
#define buzzerPin 1 //無源蜂鳴器訊號腳位PB1
int period = 1000; //計時器延時週期
int Int_period = 700;//中斷延時週期
byte 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; //定義輸入狀態
//----03定義WS2812環燈: 顆數 腳位 頻率
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
//----04 重置函式 ------
void(* resetFunc)(void)=0; //如果有呼叫 resetFunc函式,則軟體重啟
//----05 程式開始-1.進行WS2812環燈初始化動作 2.按鈕宣告輸入 3.蜂鳴器宣告輸出 4.外部中斷腳位宣告
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控制暫存器設為負緣觸發
}
//----06 進入無窮迴圈 1.等待綠按鈕被觸發 2.執行"亂數燈(彩色燈)"-----
void loop() {
if (GameState == 0){ // 如果第0關-->等待按鈕(且)Go_Play == false遊戲等待中
if (digitalRead(KEY_PUSH) == LOW && Go_Play == false) {
delay(1000);//除火花,延遲 1000 毫秒,也就是 1 秒鐘。
PlayStar();//奏音樂
led_run_at = 0;//跑馬燈現在位置
Go_Play = true;//遊戲開始
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種變速)
}
//-----07 第Level=1關(3顆設定燈):------
void Level_1(){
RingLED.clear();//清除燈號
led_run_at=0;//跑馬燈歸零
//-----第1關遊戲迴圈
while (GameState == 1) {
period = RingSpeed[Speed]; //取速度值陣列內容
//---由燈數中,隨機取1顆--->再延伸左右各1形成3個燈
if (millis()-Time_Get > period){ //延時 (亮燈週期過了,再重設週期)
Time_Get = millis(); // 擷取當下時間放入Time_Get
if(Go_Play==true){ //遊戲中,可以取設定點(亂數)
Setting_Led = random(NUMLEDS); //隨機取設定點
Go_Play = false; //隨機設定號燈完畢,等待按鈕!
}
//----由隨機取1點,再延伸為3個點----------
//以下亮3個號燈(以16個燈為例:處理跨界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個號燈(以16個燈為例:處理跨界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);//檢查按鈕是否被按下?
}
}
}
//-----08 第Level=2關(2顆設定燈):------
void Level_2(){
RingLED.clear();//清除燈號
led_run_at=0;//跑馬燈歸零
//-----第2關遊戲迴圈
while (GameState == 2) {
period = RingSpeed[Speed]; //取速度值陣列內容
//---由燈數中,隨機取1顆--->再延伸左右各1形成2個燈
if (millis()-Time_Get > period){ //延時 (亮燈週期過了,再重設週期)
Time_Get = millis(); // 擷取當下時間放入Time_Get
if(Go_Play==true){ //Go_Play為true,可以取設定點(亂數)
Setting_Led = random(NUMLEDS);
Go_Play = false; //隨機設定號燈完畢,等待按鈕!
}
//---設定2個點[][]---------------------------------
//====以下亮2個號燈(以16個燈為例:處理跨界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);//檢查按鈕是否被按下?
}
}
}
//-----09 第Level=3關(1顆設定燈):------
void Level_3(){
RingLED.clear();//清除燈號
led_run_at=0;//跑馬燈歸零
//-----第3關遊戲迴圈
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; //隨機設定號燈完畢,回歸,等待按鈕!
}
//---設定2個點[][]---------------------------------
//====以下亮1個號燈====
Set_Led[0]=Setting_Led;
RingLED.setPixelColor(Set_Led[0], 0, 255, 0);//(綠)
RingLED.show();
LED_Runing();//呼叫跑馬燈
Check_Push(GameState);//檢查按鈕是否被按下?
}
}
}
//----10 跑馬燈函式 ----
void LED_Runing(){
led_run_at++; //循環燈...往下累加
if (led_run_at >= NUMLEDS) { //如果循環紅點位置=燈數(符合則歸零)
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();
}
//----11 檢查按鈕是被按(檢查是否得分?)-------
void Check_Push(byte LV){ //Go_Play == false為等待的意思
if (digitalRead(KEY_PUSH) == LOW && Go_Play == false ) { //按鈕被按下去,往下做
delay(1000);//延時
Go_Play=true;
//----得分-------
if(LV==1){ //第1關:3個燈選中其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){ //第2關:2個燈選中其1,則得分
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){ //第3關:1個燈選中,則得分
if (Set_Led[0]==led_run_at) {
Score++;
ScreLed(Score,550);//呼叫計分燈號函式(累計得分,高音頻)
}
else{ScreLed(Score,150);}//呼叫計分燈號函式(不累計,低音頻)
}
//---切換速度陣列[][][][]--------
Speed++; //換下個檔速
//若4種檔速完成,換下一關
if(Speed==4){
//Serial.println("-");
GameState++;//下一關
if(GameState==4){GameState=0; Go_Play=false;Score=0;}//3大關全部完成
Speed=0;
PlayFamily();
}
}
}
//----12 計分燈號(黃燈)+鳴(函式)----
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();//清除燈號
}
//-----------------------------------------------------------
//----13 秀"亂數燈(彩色燈)"----
void Z_Random(){
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i, random(0, 255), random(0, 255), random(0, 255));//0~255隨機取數
delay(15);
RingLED.show();
}
}
//----14 演奏"星際爭霸"音樂----
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);// 音符之間的間隔
}
}
//----15 演奏"全家音樂"----
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);// 音符之間的間隔
}
}
//----16 外部中斷PB2腳(紅)按鈕被觸發1.白光 2.閃白光 3.閃紅光 4.閃紅光+鳴 5.軟體重啟
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();
}
}
}
//----17 音樂播放函式(傳音符[頻率],聲音長度)
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);
}
}