00.教學網站
===
https://reurl.cc/AM0WA8 上課資料網址

01.模擬器 & C語言程式
===
常用的電路模擬器Tinkercad(註冊/登入)
---
https://www.tinkercad.com/
支援3D列印、基礎電子電路、適合教育單位,進階功能無法滿足複雜需求!

電路模擬器Wokwi(註冊/登入)
---
https://wokwi.com/
介面陽春,適合測試複雜的設計和演算法! 隨著專案愈多,伺服器忙碌等待頻率愈高。
建議:一般電子電路或邏輯可以用,TinkerCad來模擬,比較接近實際狀況.

微處理器為何大多選用C語言
---
1.接近硬件: C語言是一種低階語言,它能直接與硬件互動。
2.高效性能: C語言的執行效率非常高,能夠生成接近機器碼的精簡程序。
3.靈活性與可移植性。
4.豐富的支持庫與工具。
02.Attiny85與Attiny85發展版介紹
===
1.ATtiny85 CMOS 8 位微控制器作為最小的 Arduino,最便宜的微型版本(單顆約60元)。
2.工作電壓:2.7V 至 5.5V
3.8支腳其中有6支引腳供設計者使用。PB0~PB5 簡化為 0~5

4.ATtiny85如何燒錄

5.ATtiny85應用:穿戴裝置、發光衣物、光劍、計時器...等。

6.Digispark Attiny85開發板腳位



03.Wokwi與Tinkercad簡易電路操作
===
3-1.Wokwi簡易操作
---
開新專案

Arduino系列-ATtiny85

void setup()必要條件,不能刪! 優先讀取
void loop()必要條件,不能刪! 無窮迴圈
**範例程式:39,61**

放零件\旋轉.鏡射\拉線\模擬
<註1>按鈕1.l-1.r或者1.a-1.b相通 ;2.l-2.r或者2.a-2.b相通
<註2>以下電路有2個錯誤!!

3-2.Tinkercad簡易操作
---


04.Wokwi與Tinkercad簡單程式toogle電路
===
4-1.示範toogle電路
---
https://www.youtube.com/watch?v=zdZ7ifLHgcM
{%youtube zdZ7ifLHgcM%}
4-2.toogle電路圖-wokwi
---
PB0 (0) 輸出端
PB3 (3) 按鈕(低電位)輸入端

4-3.C語言常用的變數宣告+toogle程式碼
---


讀取某腳位狀態:digitalRead(腳位) **範例程式:64,191**
輸出某腳位高.低值:digitalWrite(腳位,高電位/低電位) **範例程式:337,339**
```
boolean state=false; //布林代數狀態為0或false
#define KEY_PUSH 3//按鈕控制PB3腳位(內建上拉電阻,平時為HIGH)
#define LED_PIN 0 //LED腳位PB0
void setup() {
pinMode(KEY_PUSH, INPUT_PULLUP);//按鈕輸入腳3(KEY_PUSH),內建上拉電阻
pinMode(LED_PIN, OUTPUT);//PB0腳設為輸出
}
void loop() {
if (digitalRead(KEY_PUSH) == LOW) { //如果按鈕被按下
delay(200); //除火花
Led_State(); //呼叫Led_State函式
}
}
void Led_State(){ //Led_State函式
state=!state; //與上次狀態相反
digitalWrite(LED_PIN,state); //第PB0腳輸出
}
```
4-4.toogle程式碼轉貼入Tinkercad
---


4-5.除火花的各種寫法
---

```
boolean state=false; //布林代數狀態為0或false
#define KEY_PUSH 3//按鈕控制PB3腳位(內建上拉電阻,平時為HIGH)
#define LED_PIN 0 //LED腳位PB0
void setup() {
pinMode(KEY_PUSH, INPUT_PULLUP);//按鈕輸入腳3(KEY_PUSH),內建上拉電阻
pinMode(LED_PIN, OUTPUT);//PB0腳設為輸出
}
void loop() {
if (digitalRead(KEY_PUSH) == LOW) { //如果按鈕被按下
delay(100); //除火花
if (digitalRead(KEY_PUSH) == LOW) { //如果按鈕被再按
delay(50);//除火花
Led_State(); //呼叫Led_State函式
}
}
}
void Led_State(){ //Led_State函式
state=!state; //與上次狀態相反
digitalWrite(LED_PIN,state); //第PB0腳輸出
}
```
05.常用延時的兩種方法:delay()與millis()
===
Arduino 的 delay() 指令雖然簡單易用,但也有缺點:
當它在執行時,微控制器停止處理其他代碼。意味著在 delay() 的延遲期間,Arduino 將無法處理其他輸入或執行其他任務
1.多任務處理困難:由於 delay() 會阻塞代碼執行,因此在使用 delay() 時難以實現多任務處理。如果需要在延遲期間處理其他任務,建議使用 millis() 函數來創建非阻塞延遲,這樣可以讓程序在等待的同時繼續運行其他代碼。
2.精度限制:delay() 的精度可能會受到外部因素的影響,如晶體振盪器的精度,這可能會導致延遲時間略有偏差。如果需要非常高的時間精度,delay() 可能不適合。
millis()擷取此刻距開機時間值。**大約55天後數字會溢位-也就是會歸零**

**把delay();刪除,改用 millis()當延遲功能。**

**外部宣告 int period=1000;**

```
boolean state=false; //布林代數狀態為0或false
#define KEY_PUSH 3//按鈕控制PB3腳位(內建上拉電阻,平時為HIGH)
#define LED_PIN 0 //LED腳位PB0
unsigned long Time_Get=0;//擷取開機至今時間點
int period=500;//等待週期
void setup() {
pinMode(KEY_PUSH, INPUT_PULLUP);//按鈕輸入腳3(KEY_PUSH),內建上拉電阻
pinMode(LED_PIN, OUTPUT);//PB0腳設為輸出
}
void loop() {
if (digitalRead(KEY_PUSH) == LOW) { //如果按鈕被按下
Time_Get=millis();//擷取開機至今時間點
while( millis()-Time_Get <= period ){ } //空轉直至符合週期period時,往下做!
Led_State(); //呼叫Led_State函式
}
}
void Led_State(){ //Led_State函式
state=!state; //與上次狀態相反
digitalWrite(LED_PIN,state); //第PB0腳輸出
}
```
**◎範例程式第57,72,73,90,91,127,128,154,155,272,273行 millis()**
06.無源蜂鳴器模組電路
===
6-1.蜂鳴器模組影片(得分.失敗音效)+電路圖
---
**紅色按鈕撥放(失敗,低頻) 黑色按鈕撥放(得分,高頻)**
https://www.youtube.com/watch?v=vIYvefnqFmc
{%youtube vIYvefnqFmc %}
ATtiny85開發板不支援Arduino的tone()函式,必須自行撰寫函式
tinyTone( frequency頻率 , length長度 ) 使用時要傳2個值'頻率','音長'**

範例程式:第230─249行、第330─342行
```
#define KEY_PUSH 3//按鈕控制PB3腳位(內建上拉電阻,平時為HIGH)
#define KEY_PB2 2//按鈕控制PB2腳位(內建上拉電阻,平時為HIGH)
#define LED_PIN 0 //LED腳位PB0
#define buzzerPin 1 //無源蜂鳴器訊號腳位PB1
void setup() {
pinMode(KEY_PUSH, INPUT_PULLUP);//按鈕輸入腳3(KEY_PUSH),內建上拉電阻
pinMode(KEY_PB2, INPUT_PULLUP);//按鈕輸入腳2(KEY_PB2),內建上拉電阻
pinMode(buzzerPin, OUTPUT);//PB1腳設為音頻輸出
}
void loop() {
if (digitalRead(KEY_PUSH) == LOW) { //如果按鈕被按下
delay(300);
//--鳴-成功--
for (byte j = 0; j <2; j++){
tinyTone(550, 400);}
}
if (digitalRead(KEY_PB2) == LOW) { //如果按鈕被按下
delay(300);
//--鳴-失敗--
for (byte j = 0; j <2; j++){
tinyTone(150, 400);}
}
}
//----17 音樂播放函式(傳音符[頻率],聲音長度)
void tinyTone(int frequency, int length){
unsigned long period;//週期
unsigned long n;//方波週期
period=1000000/frequency;//計算方波週期,單位us
n=1000*(long)length/period; //計算方波週數
for(int j=1;j<n;j++){
digitalWrite(buzzerPin,HIGH);//輸出半週期高電位
delayMicroseconds(period/2);
digitalWrite(buzzerPin,LOW);//輸出半週期低電位
delayMicroseconds(period/2);
}
}
```
6-2.紅色鈕撥放(全家音樂)+黑色鈕撥放(星際爭霸音樂)
---

```
//----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);// 音符之間的間隔
}
}
```
**將上式貼至檔後,並註解掉不要的程式,加上呼叫函式**

https://www.youtube.com/watch?v=__4FtnFhQWY
{%youtube __4FtnFhQWY %}
07.認識WS2812B燈條及函式庫Adafruit_NeoPixel
===
7-1.WS2812B燈條
---


**本專題最終電路**

7-2.載入函式庫Adafruit_NeoPixel.h
---
```
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈
#define LED_PIN 0 //環號串列訊號腳位PB0
#define NUMLEDS 16//環燈=總顆數
//宣告環燈 顆數, 腳位,採用GRB,800KHZ通訊訊號的速率。
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup() { }
void loop() { }
```
A.上方程式貼上/模擬/
B.出現未載入第三方程式/點擊 INSTALL

C.點擊?問號

D.下載/下載Adafruit_NeoPixel-1.12.5.zip

E.解壓縮後,點擊/Library Manager/Upload files,指向Adafruit_NeoPixel.h

F.存檔關閉後,Adafruit_NeoPixel.h會不見,解決方法"另存新檔"後,繼續操作"新的備份"檔

7-3.如何使用Adafruit_NeoPixel.h第3方函式庫+亂數環燈
---
**A.宣告:顆數, 腳位,採用GRB,800KHZ通訊訊號的速率。**
Adafruit_NeoPixel 自訂名稱 = Adafruit_NeoPixel(顆數, 腳位, NEO_GRB + NEO_KHZ800);
**B啟動:**
自訂名稱.begin(); //初始化
**C.控制:**
指定那顆及顏色-->自訂名稱.setPixelColor(i, pixels.Color(R,G,B));
送出訊號------->自訂名稱.show(); //送出去
指定亮度------->自訂名稱.setBrightness(亮度); //亮度0~255
清除燈號------->自訂名稱.clear();//清除燈號
**亂數環燈程式:(將以下程式,貼入wokwi最終電路)**
```
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈
#define LED_PIN 0 //環號串列訊號腳位PB0
#define NUMLEDS 16//環燈=總顆數
//宣告環燈 顆數, 腳位,採用GRB,800KHZ通訊訊號的速率。
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
//-----環燈初始化動作
RingLED.begin(); //初始化(環燈)
RingLED.setBrightness(200); //燈亮度在15~50即可,最大亮度為255
}
//-------------------------------
void loop() {
LED_Random();//亂數顯示燈號(等待綠鍵被按!)
}
//----亂數顯示燈號----
void LED_Random(){
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i, random(0, 255), random(0, 255), random(0, 255));//黃色
delay(15);
RingLED.show();
}
}
```
https://www.youtube.com/watch?v=04PtnebPiaM
{%youtube 04PtnebPiaM %}
7-4.點亮單顆紅燈
---
**RGB顏色網站**
https://www.famous1993.com.tw/tech/tech1016.html
```
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈
#define LED_PIN 0 //環號串列訊號腳位PB0
#define NUMLEDS 16//環燈=總顆數
//宣告環燈 顆數, 腳位,採用GRB,800KHZ通訊訊號的速率。
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
//-------------------------------
void setup() {
//-----環燈初始化動作
RingLED.begin(); //初始化(環燈)
RingLED.setBrightness(200); //燈亮度在15~50即可,最大亮度為255
RingLED.setPixelColor(0, 255, 0, 0);
RingLED.show();
}
//-------------------------------
void loop() {
}
```

08.跑馬燈+使用millis()開機時間周期,做延遲!
===
8-1.跑馬燈影片+時間擷取及延遲
---
https://www.youtube.com/watch?v=c0hSTuDGXMw
{%youtube c0hSTuDGXMw %}


8-2.跑馬燈程式
---
1.用4個一維陣列,放四種不同的延時週期
2.本範例用RingSpeed[2]為60個延時當週期
3.16個燈,迴圈第16次歸零
4.while迴圈空轉當延時用
```
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈
#define LED_PIN 0 //環號串列訊號腳位PB0
#define NUMLEDS 16//環燈=總顆數
//宣告環燈 顆數, 腳位,採用GRB,800KHZ通訊訊號的速率。
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
byte led_run_at = 0; //跑馬燈號現在位置(led跑到那個位置)
byte RingSpeed[] = {110, 100, 60, 40}; //共有4個等級的遊戲
unsigned long Time_Get = 0;//擷取時間點,開機55天會溢位(歸0)
int period=0;
//-------------------------------
void setup() {
//-----環燈初始化動作
RingLED.begin(); //初始化(環燈)
RingLED.setBrightness(200); //燈亮度在15~50即可,最大亮度為255
period=RingSpeed[2];
}
//-------------------------------
void loop() {
Time_Get=millis();
LED_Runing();//呼叫跑馬燈
}
//----跑馬燈----
void LED_Runing(){
led_run_at++; //循環燈...往下累加
if (led_run_at >= NUMLEDS) { //如果循環紅點位置=16顆,則歸零
RingLED.setPixelColor(led_run_at-1, 0, 0, 0);//第16顆關閉
led_run_at = 0;//第0顆
}
RingLED.setPixelColor(led_run_at, 255, 0, 0);//亮燈
RingLED.setPixelColor(led_run_at-1, 0, 0, 0);//往後關燈
RingLED.show();
//用開機時間作延時
while(millis()-Time_Get<period){
//空轉消耗時間
}
}
```
09.遊戲燈隨機設定(例:設定連續3個點)
===
1.先隨機取0~15間一個值,往下延伸兩個,變成三個燈
例:隨機值=3,變成(3,3+1,3+2)
2.處理例外狀況,跨過邊界燈時。
隨機值14,需處理成(14,15,0)
隨機值15,需處理成(15,0,1)
https://www.youtube.com/watch?v=mH7xD8PvDgI
{%youtube mH7xD8PvDgI %}
```
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈
#define LED_PIN 0 //環號串列訊號腳位PB0
#define NUMLEDS 16//環燈=總顆數
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
byte Setting_Led = 0; //燈號設定點(亂數值存放)
byte Set_Led[]={0, 0, 0};//用陣列設定號燈(3燈=3個陣列.2燈2個陣列.1燈1個陣列)
//-------------------------------
void setup() {
//-----環燈初始化動作
RingLED.begin(); //初始化(環燈)
RingLED.setBrightness(200); //燈亮度在15~50即可,最大亮度為255
}
//-------------------------------
void loop() {
Setting_Led = random(NUMLEDS); //隨機取1點,再延伸為3個點
//以16個燈為例:處理跨界問題14-15-0)
Set_Led[0]=Setting_Led; //陣列0=放入亂數值
if(Setting_Led == (NUMLEDS-2)){ //隨機值若為14
Set_Led[1]=(NUMLEDS-1);//第15顆
Set_Led[2]=0;}//第0顆
//以16個燈為例:處理跨界15-0-1)
else if(Setting_Led == (NUMLEDS-1)){//隨機值若為15
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(); //顯示設置燈
delay(1000);
RingLED.clear();//清除燈號
}
```
10.單燈遊戲範例
===
https://www.youtube.com/watch?v=bpoBTRe139I
{%youtube bpoBTRe139I %}
```
//----02-C語言外部宣告--------------------------
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈WS2812
#define LED_PIN 0 //環號WS2812訊號腳位接PB0
#define KEY_PUSH 3//按鈕(綠)控制腳位(內建上拉電阻,平時為HIGH)
#define NUMLEDS 16//依環燈WS2812顆數修正
#define BRIGHTNESS 200//燈亮度在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 Score=0;//計分用
unsigned long Time_Get = 0;//擷取時間點,開機55天會溢位(歸0)
boolean Go_Play = false;//遊戲處於等待狀態(布林值)
//----03定義WS2812環燈: 顆數 腳位 頻率
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
//----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);//
randomSeed(analogRead(KEY_PUSH));//(擷取亂數因子)解決亂數不亂的問題
//---慢速跑馬---
period = RingSpeed[0];
Time_Get = millis(); //擷取當前時間
}
//----06 進入無窮迴圈 1.等待綠按鈕被觸發 2.執行"亂數燈(彩色燈)"-----
void loop() { // 按鍵按下 且 遊戲未初始
if (digitalRead(KEY_PUSH) == LOW && Go_Play == false) {
delay(1000);//除火花,延遲 1000 毫秒,也就是 1 秒鐘。
led_run_at = 0;//跑馬燈現在位置
Go_Play = true;//按鍵被按-->遊戲開始
Setting_Led =0;
GameState=3; //開始玩第3關
}
if (GameState == 3){Level_3();}//往第3關遊戲(每關4種變速)
}
//-----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; //隨機設定號燈完畢,回歸,等待按鈕!
}
//---設定1個點[]--------------------------------
//====以下亮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==3){ //第3關:1個燈選中,則得分
if (Set_Led[0]==led_run_at) {
Score++;
ScreLed(Score,550);//呼叫計分燈號函式(累計得分,高音頻)
}
else{ScreLed(Score,150);}//呼叫計分燈號函式(不累計,低音頻)
}
}
}
//----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();//清除燈號
}
//----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);
}
}
```
11.中斷優先(外部中斷)
===
11-1.中斷接腳圖
---


11-2.中斷程式影片
---
https://www.youtube.com/watch?v=4cCeGVs9mCo
{%youtube 4cCeGVs9mCo %}
11-3.中斷程式
---

```
#include <Adafruit_NeoPixel.h>//載入第三方程式控制環燈
#define LED_PIN 0 //環號串列訊號腳位PB0
#define NUMLEDS 16//環燈=總顆數
//宣告環燈 顆數, 腳位,採用GRB,800KHZ通訊訊號的速率。
Adafruit_NeoPixel RingLED = Adafruit_NeoPixel(NUMLEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
byte led_run_at = 0; //跑馬燈號現在位置(led跑到那個位置)
byte RingSpeed[] = {110, 100, 60, 40}; //共有4個等級的遊戲
unsigned long Time_Get = 0;//擷取時間點,開機55天會溢位(歸0)
unsigned long IntTime_Get = 0;//中斷擷取時間點
volatile byte Int_state = 0; //定義輸入狀態
int period=0;
int Int_period = 700;//中斷延時週期
//-------------------------------
//----04 重置函式 ------
void(* resetFunc)(void)=0; //如果有呼叫 resetFunc函式,則軟體重啟
void setup() {
//-----環燈初始化動作
RingLED.begin(); //初始化(環燈)
RingLED.setBrightness(200); //燈亮度在15~50即可,最大亮度為255
period=RingSpeed[2];
//中斷腳位:以下將GIMSK中斷暫存器的INT0啟用,MCUCR控制暫存器設為負緣觸發
pinMode(2, INPUT_PULLUP);//紅色按鈕,外部中斷腳位
sei(); //enabling global interrupt
GIMSK |= (1<<INT0); // INT0啟用
MCUCR |= (1<<ISC01); // MCUCR控制暫存器設為負緣觸發
}
//-------------------------------
void loop() {
Time_Get=millis();
LED_Runing();//呼叫跑馬燈
}
//----跑馬燈----
void LED_Runing(){
led_run_at++; //循環燈...往下累加
if (led_run_at >= NUMLEDS) { //如果循環紅點位置=16顆,則歸零
RingLED.setPixelColor(led_run_at-1, 0, 0, 0);//第16顆關閉
led_run_at = 0;//第0顆
}
RingLED.setPixelColor(led_run_at, 255, 0, 0);//亮燈
RingLED.setPixelColor(led_run_at-1, 0, 0, 0);//往後關燈
RingLED.show();
//用開機時間作延時
while(millis()-Time_Get<period){
//空轉消耗時間
}
}
//----16 外部中斷PB2腳(紅)按鈕被觸發1.黃光 2.閃黃光 3.軟體重啟
ISR (INT0_vect){
if ( millis() - IntTime_Get > Int_period ){
IntTime_Get = millis();
Int_state++;//累計按下次數
while(Int_state==1){ //按1次-->手電筒模式
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,255,255,102);//黃色
RingLED.setBrightness(180); //環燈亮度
RingLED.show();
}
}
while(Int_state==2){ //按2次-->閃白光模式
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,255,255,102);//黃色
RingLED.setBrightness(180); //環燈亮度
RingLED.show();
}
delay(400);
for (byte i = 0; i < NUMLEDS; i++) { //環燈號訊號
RingLED.setPixelColor(i,0,0,0);//黑色
RingLED.show();
}
delay(400);
}
if(Int_state==3){ //按3次-->軟體重啟模式
Int_state=0;
resetFunc();
}
}
}
```
11-4.所有程式完成(測試)
---
https://drive.google.com/file/d/1T8TF-KjEJxSr4o4_UhD8N0inxNlC6DYD/view?usp=drive_link
11-5.轉實際電路
---
注意由模擬器轉實際電路必須修改
第11行 #define NUMLEDS 24
第12行 #define BRIGHTNESS 58
12.燒錄程式(利用Arduino IDE燒錄ATtiny85開發版)
===
12-1.安裝Arduino IDE + ATtiny85開發版的USB驅動程式
---
Arduino IDE 下載網址,並安裝
https://www.arduino.cc/en/software/
Attiny85第一次燒錄,要下載USB驅動程式並安裝
https://github.com/digistump/DigistumpArduino/releases/download/1.6.7/Digistump.Drivers.zip

12-2.讓Arduino IDE能認識Digispark ATtiny85
---
讓Arduino IDE 能認識 Digispark ATtiny85 加入 Additional Boards Manager URLs複製下列網址
http://digistump.com/package_digistump_index.json
或
https://raw.githubusercontent.com/digistump/arduino-boards-index/master/package_digistump_index.json

12-3.安裝Digistump AVR Boards
---
打開IDE\工具\開發板管理員 (搜索 digispark) \安裝Digistump AVR Boards

12-4.選取ATtiny85適合的開發板
---

12-5.開新檔\貼上程式\(開始驗證) + 載入第三方程式Adafruit_NeoPixel.h
---

12-6.特殊:要先拔除USB,等IDE允許,才能插入燒錄 + 上傳燒錄
---


13.備線+焊接(杜邦線:14條-母.母 3條-公.公)
===
13-1.開發板焊9根L型Pin腳
---


13-2.電池扣焊6個母頭
---
電池扣杜邦線製作(6個母頭-->正極1個 + 負極5個)
注意:
(1)取杜邦線(母.母),拔去一頭,撥線後焊接,膠帶包裹!
(2)膠帶抽伸後,易延展

13-3.滑動開關製作(1公+1母)
---

13-4.按鈕製作2個(分別為 1公+1母)
---

13-5.電源+訊號線
---

14.成品配線
===



15.伺服器繁忙(解決)
===
15-1.伺服器繁忙訊息
---
Build server failure: Error: Project compilation takes too long, perhaps our build servers are too busy right now. You can try to compile the project on your computer and use Wokwi for VS Code to simulate it, or upgrade to a paid plan for access to high-performance builds: https://wokwi.com/pricing
解決方法:
https://docs.wokwi.com/vscode/getting-started


15-2.安裝擴充程式
---
https://marketplace.visualstudio.com/items?itemName=wokwi.wokwi-vscode

轉為正體中文

15-3.申請註冊碼
---
1.按F1 貼上 Wokwi:Start Simulator
右側會要求申請臨時的license,點入後有一串註冊碼
2.按F1 貼上 Wokwi:Manually Enter License Key
再點上註冊碼,即可註冊完成。
15-4.開始編輯,由wokwi Simulator核心模擬
---
開始編輯
創建一個新的 Arduino 項目
在 Visual Studio Code 中,按 Ctrl+Shift+P 打開命令面板。
輸入 Wokwi: New Project 並選擇它。
選擇 Arduino Uno 作為你的開發板。
這將創建一個新的項目,包含一個 sketch.ino 文件。