# 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

### 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 的序列埠監控視窗上玩的小遊戲!透過可變電阻控制你的球拍,不要讓乒乓球落地!

```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");
}
```