# Arduino 基礎 2023 台大電機系學會學術部 講師:吳柏均 ## 我的第一條 Arduino 指令 ```Arduino= void setup() { // set pin 2 to output mode pinMode(2, OUTPUT); } void loop() { // pin 2 output voltage HIGH digitalWrite(2, HIGH); // delay 0.5 seconds delay(500); // pin 2 output voltage LOW digitalWrite(2, LOW); // delay 0.5 seconds delay(500); } ``` ## 序列埠 ### Hello World! ```Arduino= void setup() { // set up the baud rate Serial.begin(9600); // print with line break Serial.println("Hello World!"); } void loop() { } ``` ### Bonus: Two-Way Communication 在序列埠監控視窗上方可以看到一個輸入文字的地方,按下 Enter 之後資料將從電腦傳輸到 Arduino,Arduino 會利用以下的程式接收資料。 ```Arduino= void setup() { // set up the baud rate Serial.begin(9600); } void loop() { // check if available to read if (Serial.available() > 0) { // read Serial data char receivedChar = Serial.read(); // print Serial data back to the computer Serial.print("Received: "); // no line break Serial.println(receivedChar); // line break } } ``` ## Bonus: Serial Plotter IDE 右上角有一個波動形狀的按鈕,即為序列埠繪圖工具,它可以自動偵測將序列埠監控視窗顯示的變數與數值,並在序列埠繪圖工具上以折現圖呈現,橫軸為時間,縱軸為值。 ```Arduino= void setup() { // set up the baud rate Serial.begin(9600); } // loop variable int t = 0; void loop() { // variable to be printed on the plotter Serial.print("sin:"); // value to be printed on the plotter Serial.println(sin(t*0.01)); delay(1); t += 10; } ``` ## 按鈕 ### 偵測按鈕按下 ```Arduino= void setup() { // set pin 3 to input mode pinMode(3, INPUT); // initialize Serial port Serial.begin(9600); } void loop() { // detect input if (digitalRead(3) == HIGH){ // print HIGH! if input is high Serial.println("HIGH!"); } else { // print LOW~ if input is low Serial.println("LOW~"); } delay(100); } ``` ### Bonus: Variable-State LED 按下按鈕,可以調整LED閃爍的模式。詳細內容請複習交換電路與邏輯設計第 12 單元。 ```Arduino= #define LED 2 #define PRESS 3 void setup() { pinMode(LED, OUTPUT); pinMode(PRESS, INPUT); Serial.begin(9600); } // which state the led is in int state = 0; // prevent release time delay bool pressed = false; void loop() { // review SCLD chapter 12 if (digitalRead(PRESS) == HIGH){ if (!pressed){ if (state == 3){ state = 0; } else { state += 1; } pressed = true; } } else { pressed = false; } // different light modes switch (state) { case 0: digitalWrite(LED, HIGH); break; case 1: digitalWrite(LED, LOW); break; case 2: digitalWrite(LED, HIGH); delay(200); digitalWrite(LED, LOW); delay(200); break; default: digitalWrite(LED, HIGH); delay(50); digitalWrite(2, LOW); delay(50); break; } } ``` ## 可變電阻 ### 手動式呼吸燈 ```Arduino= #define POTENT A0 #define LED 5 void setup() { // analog input pin A0 setup pinMode(POTENT, INPUT); // PWM output pin 5 setup pinMode(LED, OUTPUT); } int potent; int output; void loop() { // read pin A0, values ranging from 0 to 1023 potent = analogRead(POTENT); // 0 to 1023 -> 0 to 255 output = potent/4; // output PWM signal analogWrite(LED, output); delay(10); } ``` ## 蜂鳴器 ### 音階 ```Arduino= #define POTENT A0 #define BUZZER 5 void setup() { // analog input pin A0 setup pinMode(POTENT, INPUT); // tone output pin 5 setup pinMode(BUZZER, OUTPUT); } int potent; int output; void loop() { // read pin A0, values ranging from 0 to 1023 potent = analogRead(POTENT); output = potent; // output frequency with duration 100 tone(BUZZER, output, 100); delay(100); } ``` ### Bonus: Variable-Frequency "Buzzer" 這個程式藉由預先定義好的樂譜重複演奏小蜜蜂,並可以藉由可變電阻調整小蜜蜂的音高,最高可以上升到八倍(三個八度)。 ```Arduino= #define POTENT A0 #define BUZZER 5 // beats per minute #define bpm 120 // instruction delay (ms) #define delta 5 // maximum tone scaling #define scale 8 // array of notes and pauses int piano[128] = { 783,0 ,659,0 ,659,659,659,659, 698,0 ,587,0 ,587,587,587,587, 523,0 ,587,0 ,659,0 ,698,0 , 783,0 ,783,0 ,783,783,783,0 , 783,0 ,659,0 ,659,659,659,659, 698,0 ,587,0 ,587,587,587,587, 523,0 ,659,0 ,783,0 ,783,0 , 659,659,659,659,659,659,659,659, 587,0 ,587,0 ,587,0 ,587,0 , 587,0 ,659,0 ,698,698,698,698, 659,0 ,659,0 ,659,0 ,659,0 , 659,0 ,698,0 ,783,783,783,0 , 783,0 ,659,0 ,659,659,659,659, 698,0 ,587,0 ,587,587,587,587, 523,0 ,659,0 ,783,0 ,783,0 , 523,523,523,523,523,523,523,523 }; void setup() { pinMode(BUZZER, OUTPUT); pinMode(POTENT, INPUT); } int potent; int output; int i = 0; void loop() { potent = analogRead(POTENT); if (i == 128){ i = 0; } // scale the tone to higher frequencies output = piano[i]*(1+potent*scale/1024); tone(BUZZER, output, 60000/bpm/2); delay(60000/bpm/2 - delta); i += 1; } ``` ## What's Next? ### The Ultimate Arduino Roadmap 2023 ![](https://hackmd.io/_uploads/BJWidk3za.png) ### Learning Resources - [Tinkercad](https://www.tinkercad.com/) - [Arduino Reference](https://www.arduino.cc/reference/en/) - [NTUEE Makerspace](https://www.instagram.com/makerspace_ntuee/) - [NTUEE Makerspace Tutorial](https://docs.google.com/presentation/d/19QZOZTETPgk_5bTJkxV9ny4qLU06Fs_bf7tsFvSrDEs/edit?usp=sharing) - [NTUEE SAAD Tutorials](https://ntueesaad.notion.site/79798720a43e4539a98416ae1f4387e9) - NTUEE Virtual Makerspace (In Progress) ### Super Bonus: Ping-Pong Game! 一個可以在 Arduino IDE 的序列埠監控視窗上玩的小遊戲!透過可變電阻控制你的球拍,不要讓乒乓球落地! ![](https://hackmd.io/_uploads/Hkl0WiqMT.png) ```Arduino= // hardware parameters #define POTENT A0 // game parameters // game state #define START 0 #define PROGRESS 1 #define LOSE 2 // refresh rate #define fps 3 #define baud 500000 // the higher the better // MxN canvas on the serial monitor #define M 10 #define N 40 // space, ball, walls, and paddle #define X 0 #define O 1 #define W 2 #define P 3 const char icon[4] = {' ', 'O', '*', '_'}; // paddle length #define L 5 // game state int state = START; // points int points = 0; // game grid byte grid[M+2][N+2] = {X}; // paddle position int paddlePos = N/2; int prevPPos = N/2; // ball position int ballPos[2] = {1,1}; int ballV[2] = {1,1}; int prevIcon = 0; // set ball position void setBallPos(int i, int j){ grid[ballPos[0]][ballPos[1]] = prevIcon; ballPos[0] = i; ballPos[1] = j; prevIcon = grid[i][j]; grid[i][j] = O; } // ball move void ballMove(){ setBallPos(ballPos[0] + ballV[0], ballPos[1] + ballV[1]); if (ballPos[0] == 0){ ballV[0] = 0 - ballV[0]; setBallPos(2, ballPos[1]); } else if (ballPos[0] == M){ // bounce off paddle condition if (max(ballPos[1], paddlePos) == ballPos[1] && min(ballPos[1], paddlePos+L) == ballPos[1]){ ballV[0] = 0 - ballV[0]; setBallPos(M-2, ballPos[1]); } } else if (ballPos[0] == M+2){ state = LOSE; } if (ballPos[1] == 0){ ballV[1] = 0 - ballV[1]; setBallPos(ballPos[0], 2); } else if (ballPos[1] == N+1){ ballV[1] = 0 - ballV[1]; setBallPos(ballPos[0], N-1); } } // print grid void printGrid(){ Serial.print("SCORE: "); Serial.println(points); char output[(M+2)*(N+3)]; for (int i = 0; i < M+2; i++){ for (int j = 0; j < N+2; j++){ // output = output + icon[grid[i][j]]; output[(i*(N+3))+j] = icon[grid[i][j]]; } output[(i*(N+3))+(N+2)] = '\n'; } Serial.print(output); } // grid initialization void gridInit(){ for (int i = 0; i < M+2; i++){ grid[i][0] = W; grid[i][N+1] = W; } for (int j = 0; j < N+2; j++){ grid[0][j] = W; grid[M+1][j] = W; } } // read potentiometer int rawValue = 0; void readPotent(){ rawValue = analogRead(POTENT); paddlePos = 1+ ((rawValue*(N-L))/1024); paddlePos = (paddlePos>0)?paddlePos:(N+2+paddlePos); for (int i = 1; i < N; i++){ grid[M][i] = X; grid[M-1][i] = X; } for (int i = 0; i < L; i++){ grid[M][paddlePos + i] = P; } } void setup() { Serial.begin(baud); points = 0; setBallPos(1, 5); gridInit(); printGrid(); // game start state = PROGRESS; } void loop() { if (state == PROGRESS){ readPotent(); ballMove(); printGrid(); points += 1; delay(1000/fps); } else if (state == LOSE){ Serial.println(" "); Serial.println("--------------"); Serial.println("---YOU LOSE---"); Serial.println("--------------"); Serial.print("YOUR SCORE: "); Serial.println(points); Serial.println(" "); state = START; } } ``` ### Practice Problem: Music Player 使用可變電阻、按鈕,及蜂鳴器製作一個可以調整曲目的音樂播放器: - 可變電阻:旋轉旋鈕調整曲目 - 按鈕:播放 / 暫停 - "Bonus" LED 呼吸燈節拍器:利用 PWM 控制 LED 在拍點與拍點間有強弱變化 - 音符轉換樂譜:[轉換程式 By 吳柏均](https://frequencyconverter.pcwu2022.repl.co/) ## Appendix ### 簡易 C++ 語法表 ```Arduino= // declarations #define LED 3 // variables int age = 18; char grade = 'A'; float gpa = 4.3; String hi = "Hello"; // arrays int scores[3] = {100, 90, 80}; // functions int happyBirthday(int currAge){ return currAge + 1; } age = happyBirthday(age); // conditions if (grade == 'A'){ gpa = 4.0; } // loops int sum = 0; for (int i = 0; i < 3; i++){ sum += scores[i]; } ``` ### 簡易 Arduino 函式功能表 ```Arduino= // execute once void setup(){ // pinMode(pin, INPUT / OUTPUT) pinMode(2, OUTPUT); // Serial.begin(baud rate) Serial.begin(9600); } // loop until power off void loop(){ // digitalWrite(pin, HIGH / LOW) digitalWrite(2, HIGH); // digitalRead(pin) -> return HIGH / LOW int value1 = digitalRead(3); // analogWrite(pin, 0 ~ 255) analogWrite(5, 30); // analogRead(pin) -> return 0 ~ 1023 int value2 = analogRead(A0); // tone(pin, frequency, duration) tone(6, 440, 20); // delay(milliseconds) delay(1000); // Serial.print(text) Serial.print("Hello"); // Serial.println(text) Serial.println("Hello with line break"); } ```