# 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 |
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up