# 2021 機器人加課
###### tags:`2020KGHS` `i2trc2`
# PWM
## Simulating a PWM output
這個練習只是為了幫助你熟悉 C 語言的使用方式,實際上我們不常這樣應用!
現在你已經知道 PWM 就是控制 Duty cycle ,為了更了解運作原理,我們可以用程式模擬硬體電路的運作方式。
### 策略

- 設定 number of slots (num)
- 為每個燈設定亮度 (brightness)
- 假設有一個 counter 會不斷從 0 數到 num 也就是 $counter = [0, num), counter \in \mathbb Z$
- 當 counter 大於 brightness 的時候,輸出 `1` ,否則為 `0`
:::spoiler
### Blocking v.s. Non-blocking
- Blocking: 利用 `delay()` 製造 $\Delta T$ 的延遲
- Non-blocking: 如果用 `delay()` 程式會卡住,因此會被 **block** 在 `delay()` 。如果要 Non-blocking 有兩種常見的方法:
- 可以用 `millis()` 判斷當下時間是否需要更新資料
- 利用硬體 timer 輔助
:::
# Timer interrupt
## Why Interrupt Is Necessary?
試想像在煮開水,三不五時總要走過來看一下確定水開了沒,假設我們3分鐘走回來檢查一次,那麼會有二種情況:
- 走過來時水早已開了。 ← 大部份的情況。
- 走過來時水剛剛好開了。 ← 機率很低。
若很忙時間被打亂,沒辦法固定時間來檢查怎麼辦?
有沒有什麼更好的做法?
:::warning
### 情境
如果在上面 `Simulating a PWM output` 的例子中, Arduino 不就沒辦法做其他的事情了嗎? 大部分的時間都被困在 `delay()` 裡面了
:::
## What is interrupt?
『處理器接收到來自硬體或軟體的訊號,提示發生了某個事件,應該被注意,這種情況就稱為中斷。』
中斷觸發與執行的流程:
1. 中斷觸發,暫停目前的Process,並保存執行狀況。
2. 根據Interrupt Table查詢對應的中斷服務常式(ISR, Interrupt Service Routine)Address。
3. 跳至該Address(執行)。
4. ISR執行完畢。
5. 回到中斷前的Process並繼續執行。
## Types of interrupts
### 硬體中斷 (Hardware Interrupt)
以某個Pin做為外部中斷的觸發,當發生特殊條件時進行中斷。Arduino 328中,具有Interrupt的pin為2、3。

Example:
```cpp=
attachInterrupt(0, functionA, CHANGE);
```
Note: `functionA` 是一個自定義 function 的名字,你可以自己設計。
### 軟體中斷(Software Interrupt)
當發生特殊情況時,E.X.除以零。
## Traps in writing ISR functions
在 ISR 函式內部會 **改變** 其值的變數,在宣告時必須在前面加上 `volatile` 這個關鍵字。當一個變數加入了 volatile 的宣告,那麼程式在 Compile 時就不會去最佳化與此變數相關的程式碼。
Example:
```cpp=
volatile boolean sw = false;
```
:::info
### General OS Usually are Interrupt Driven
由於電腦主要在處理各種 I/O 操作,而 I/O 操作過程往往會因為速度不能相比( I/O 相較於 CPU 慢許多),故會以非同步的方式進行處理,I/O device 會在處理完後產生 Interrupt 告知 CPU 。

:::
## And Timer?
Arduino 利用內部的計數器電路計算 clock 震盪的次數,可以得到規律的時間計數。

Note: 所有的 timer 都會相依於 Arduino 的 system clock 。大部分 Arduino 的 clock 是 16MHz ,但是有些電源使用 3.3V 的 clock 是 8MHz ,所以設定 timer function 時要注意當時的 clock 。
Q: 很多 library 都會使用 timer ,那你也要用的時候怎麼辦?
A: 沒辦法,要不就你換一個 timer 用,要不就你不要用 library
Atmega 328p 有三組 timer 可以用:
- Timer 0(8bit):像是 `delay()`、`millis()`、`micros()` 都是使用到 timer 0
- Timer 1(16bit) :Servo library 使用 timer 1
- Timer 2(8bit) :`tone()` 使用到 timer 2
可以在其他晶片上還有更多 timer。E.X. Arduino mega Board(Atmega 2560)
- Timer 3,4,5(16bit):
### How to configure a timer?
Atmega 328p 上的三個 timer 都不太一樣,大家一定要習慣查表,不要一直複製貼上不知道自己在寫什麼,核心概念都是一樣的,這邊有一個很完整的 [資料](https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328) ,甚至有人做出 [計算機](http://www.arduinoslovakia.eu/application/timer-calculator)。
接下來以 timer2 舉例:
下面是存放各種 timer 資料的 Registers:
- TCCRx - Timer/Counter Control Register. The prescaler can be configured here.
用來設定 timer 工作模式的 register ,例如說如果要 timer 工作在 CTC mode 表示要讓 register 中 `WGM21` 的地方為 `1` 其他為 0。

如果要設定 prescaler:

- TCNTx - Timer/Counter Register. The actual timer value is stored here.
- OCRx - Output Compare Register (Trigger Value)
- ICRx - Input Capture Register (only for 16bit timer)
- TIMSKx - Timer/Counter Interrupt Mask Register. To enable/disable timer interrupts.
- TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt.
Example:
```cpp=
// this code sets up timer2 for a 250us @ 16Mhz Clock
// cited from: https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
OCR2A = 62;
TCCR2A |= (1 << WGM21);
// Set to CTC Mode
TIMSK2 |= (1 << OCIE2A);
//Set interrupt on compare match
TCCR2B |= (1 << CS21);
// set prescaler to 64 and starts PWM
sei();
// enable interrupts
while (1)
{
// Main loop
}
}
ISR (TIMER2_COMPA_vect)
{
// action to be done every 250 usec
}
```
# Create your own library
Steps:
1. Create an **INTERFACE** to your library: mylib.h
2. Create an **IMPLEMENTATION** of your library: mylib.c
3. Create a **LIBRARY OBJECT FILE** that can be linked with programs that want to use our library code (Compiler 會幫你做這件事)
4. USE the library in other C code: #include “mylib.h”
將介面 (INTERFACE) 與實作 (IMPLEMENTATION) 分開,Why?
## Create a `.h` file
在 header file 內宣告函式介面 (Interface)
```cpp=
#ifndef _MYLIB_H
#define _MYLIB_H
// write your code (interface) here
// ...
// write your code (interface) here
#endif
```
P.S. #開頭的敘述是給編譯器的指示
為了防止編譯器重複宣告及定義(每當include header file就會讀到這段程式碼)所以需要用 if 來判斷是否已經執行。

## Create a `.cpp` file
Cpp file,Arduino IDE 會自動編譯並 link ,不需要手動操作。

## Include the header file
在程式碼中,用include將建立的header file include進來。
```cpp=
#include <FILE NAME>
// 從預設的lib路徑尋找
#include ”FILE NAME”
// 從專案目錄中尋找
```

## Declare a Global Variable in Your Library
若要定義全域變數,需在宣告的型態前面加上 extern 關鍵字,表示該變數的宣告會在某個 include 該 header file 的檔案中。

## Overloading in Arduino

# Learning to use third party library
不要再只會複製貼上了!
如果今天,你要用一個全新的 library 或是很少人在用,沒有什麼文獻資料,怎麼辦?
學會看懂別人在寫什麼,別人想要表達什麼!
舉例:
[Servo Library](https://github.com/arduino-libraries/Servo)
# 移位暫存器 (Shift Register)
Arduino 上面的 pin 不夠多怎麼辦 ?
A: 將序列 (serial) 資料轉成 並列 (parallel) 資料
功能

移位暫存器 74595 的內部構造,包含
- Shift register
- storage register
- 3 state output (control)


## 74HC595
74595 [datasheet](https://www.ti.com/lit/ds/symlink/cd74hc595.pdf?ts=1617958415024&ref_url=https%253A%252F%252Fwww.google.com%252F)


| 74575 | Name | Description | Arduino |
| ----- | ----- | -------- | ------- |
| ST_CP | Latch | latch | 10 |
| SH_CP | Shift Clock| clock | 13 |
| DS | Data In | 資料(data) | 11 |
| Output Enable | OE | Enable (negative logic) | GND |
| RESET | MR | 重置 (negtive logic) | +5 |
| SQH | Q7' | Serial Data Out | X |