---
tags: 單晶片助教
---
# [W11] [STM32] I/O & interupt
# (零) IDE & board
STM32 board:NUCLEO-F207ZG
https://hackmd.io/uJrNrB3rTgKHdyLhTJY74Q
online IDE操作、ST-Link驅動安裝、Tera Term設置
https://hackmd.io/@Kirashi/SJR-2slKt
# (一) Basic
## Mbed API list
* 在網路搜尋Mbed API,會找到網站
https://os.mbed.com/docs/mbed-os/v6.15/apis/index.html
通常開發函數庫(Library)或板子(Board)的開發者,會提供使用者API,讓使用者不需要了解函數的實作細節,只需要知道函數如何使用,以提高使用者的編程效率。
* Mbed API 提供I/O、Serial等周邊設備的控制方法、函數的輸入輸出、函數使用範例等。
---
## DigitalOut Class
* API:https://os.mbed.com/docs/mbed-os/v6.15/apis/digitalout.html
* DigitalOut (PinName pin)
讓DigitalOut物件能與實際腳位連結,PinName參照Pinout圖。
* write (int value)
輸出高準位(1)或低準位(0)。
* is_connected ()
確認物件是否與實際腳位有連結了。
* DigitalOut& operator= (int value)
例如:testled = 1;
其中testled是DigitalOut物件
---
### Example 1-1
* 實驗目標:使用DigitalOut使LED閃爍
{%youtube 8XiyZekZUJY %}
* 使用 Member Function 方法,實現LED Blink
```cpp
#include "mbed.h"
DigitalOut blinkled(LED1);
int main()
{
// Blink LED
while(1) {
blinkled.write(1);
wait(1);
blinkled.write(0);
wait(1);
}
}
```
* 使用operator方法,實現LED Blink
```cpp
#include "mbed.h"
DigitalOut blinkled(LED1);
int main()
{
// Blink LED
while(1) {
blinkled = !blinkled;
wait(1);
}
}
```
---
### LAB 1-1
* 實驗目標:以LED1~3實現單向跑馬燈
{%youtube TnfkaCK3IHQ %}
---
## DigitalIn Class
* API:https://os.mbed.com/docs/mbed-os/v6.15/apis/digitalin.html
* DigitalIn (PinName pin)
讓DigitalIn物件能與實際腳位連結,PinName參照Pinout圖。(設定數位輸入接腳用)
* int read ()
讀取pin電壓準位。回傳1或0。(高準位或低準位)。
* is_connected ()
確認物件是否與實際腳位有連結了。
* mode(PinMode pull)
設定輸入模式。pull={PullUp, PullDown, PullNone, OpenDrain}
* operator int()
An operator shorthand for read()
:::info
如果button是DigitalIn,led是DigitalOut,下列兩個敘述等價:
led = button;
led.write(button.read());
:::
---
### Example 2-1
* 實驗目標:讀取USER_BUTTON,若開關被按下令LED1發光;開關放開則LED1不發光。
{%youtube BGmNbP1HD2Y %}
* 使用memeber function方法
```cpp
#include "mbed.h"
DigitalIn button(USER_BUTTON); //the button on your board
DigitalOut led(LED1);
int main()
{
// 檢查物件button是否完成pin連結
if(button.is_connected()) {
printf("button is connected and initialized! \n\r");
}
button.mode(PullNone); // 浮接
while(1) {
led.write(button.read()); // member function expression
wait(0.25);
}
}
```
* 使用operator寫法
```cpp
#include "mbed.h"
DigitalIn button(USER_BUTTON); //the button on your board
DigitalOut led(LED1);
int main()
{
button.mode(PullNone); // 浮接
while(1) {
led = button; // operator expression
wait(0.25);
}
}
```
---
### LAB 2-1
* 實驗目標:承LAB1-1之跑馬燈,在USER_BUTTON被按下時停止,放開時往反方向運行跑馬燈
{%youtube eXKiuNYbWLk%}
---
## Serial Class
* API:https://os.mbed.com/docs/mbed-os/v5.15/apis/rawserial.html
* Serial (PinName tx, PinName rx, int baud)
建構Serial物件,tx與rx填上有支援UART的pin腳位代號,baud預設為9600。
* baud (int baudrate)
如果沒有在建構式上設定鮑率,可以使用member function設定。
* printf(char* string)
向螢幕輸出字串
* putc(int c)
tx端輸出
* getc(int c)
rx端接受字元
---
### Tera Term設定
1. Setup -> Serial Port...
2. Port : 選擇連接Mbed的port
3. Speed : 鮑率選擇9600

---
### Example 3-1
* 實驗目標:通過Tera Term,將鍵盤每次輸入的字元顯示到螢幕上
{%youtube oNQ5bQv6rVg %}
```cpp
#include "mbed.h"
RawSerial pc(USBTX, USBRX); // tx, rx
int main() {
pc.printf("Hello World!\n\r");
while(1) {
pc.putc(pc.getc()); // echo input back to terminal
}
}
```
---
### LAB3-1
* 實驗目標:通過Tera Term,完成下列目標
1. 輸入'G'切換LED1狀態
2. 輸入'B'切換LED2狀態
3. 輸入'R'切換LED3狀態
4. 輸入'1'切換所有LED狀態
5. 輸入錯誤會顯示錯誤訊息
{%youtube hLG9WDviPgA %}
---
### Bonus 1
* 實驗目標:
1. 一開始跑馬燈以G(LED1)、B(LED2)、R(LED3)、A(外接的LED)順序運行
2. USER_BUTTON長按進入使用Tera Term輸入指令狀態
3. 輸入RGBA的不同排列順序改變亮燈順序
4. 按下Enter後回到跑馬燈狀態並依照先前指令之排列順序運行。
<font color = red>註1:一開始跑馬燈順序GBRA。</font>
<font color = red>註2:要能偵測input錯誤並告知使用者。</font>
<font color = red>註3:可以參考使用如下面提示之物件導向寫法。也歡迎使用其他方法</font>d(`・∀・)b
※有字幕
{%youtube VCUG5ImizQs %}
{%youtube AzCw4xBxYcg %}
Hint:
※以下為Pointer物件導向宣告方式
```cpp
#include "mbed.h"
/////Variable Declaration/////
DigitalOut *output;
DigitalOut *X[1];
int main(){
output = new DigitalOut(LED1);
X[0] = output;
while(1){
*X[0] = !*X[0];
wait(0.5);
}
}
```
---
## Timer Class
* API:https://os.mbed.com/docs/mbed-os/v5.15/apis/timer.html
* start():開始計時。
* stop():停止計時。
* reset():重新計時。
* read():讀取時間,浮點數型態輸出,單位為秒。
* read_ms():讀取時間,整數型態輸出,單位為毫秒。
---
### Example 4-1
#### 實驗目標:利用Timer計時,並輸出時間到Tera Term
```cpp
#include "mbed.h"
Timer timer;
float t1;
int t2;
int main()
{
timer.start(); // 計時開始
while(1) {
t1 = timer.read(); // 讀取時間 浮點表示
t2 = timer.read_ms(); // 讀取時間 整數表示
printf("%f seconds \r\n",t1);
printf("%d miliseconds \r\n",t2);
printf("\r\n");
if(t2 > 10000)
timer.stop(); //計時停止
wait(0.5);
}
}
```
---
### LAB 4-1
#### 實驗目標:使用Timer,消除USER_BUTTON的彈跳現象,然後記錄BUTTON被按下的次數,在USER_BUTTON被按下時輸出次數到Tera Term。(當按鈕被按著不放時,只算一次)
<font color = red>Hint: 使用timer時間差決定按下和放開的情況</font>
{%youtube 2pxvcr-CQR0 %}
---
# (二) 中斷(Interrupt)
## Interrupt Class
除了能觸發中斷的Timer外,Mbed也提供了另外三種Interupt Class API,給開發者利用。
* InteruptIn:讀取腳位信號,上、下緣時引發中斷。
API:https://os.mbed.com/docs/mbed-os/v5.15/apis/interruptin.html
* Ticker:每經過一段時間就引發中斷。
API:https://os.mbed.com/docs/mbed-os/v5.15/apis/ticker.html
* Timeout:延遲一段時間後引發中斷。
API:https://os.mbed.com/docs/mbed-os/v5.15/apis/timeout.html
* 在使用Interupt Class時需要注意,盡量避免在ISR中使用wait()、無限迴圈(infinite while loop)、blocking calls(除非指派的任務完成否則會持續等待的函數,例如:cin函數)。也不要使用printf、new、malloc函數。詳細參照API中**Warnings and notes**條目。
---
### Example 5-1
#### 實驗目標:使用InterruptIn,實現USER_BUTTON被按下時,切換LED1狀態(亮/不亮),而LED3保持閃爍
{%youtube Q78zg6nZO6M %}
```cpp
#include "mbed.h"
InterruptIn button(USER_BUTTON);
DigitalOut led(LED1);
DigitalOut blinkled(LED3);
void change() {
led = !led;
}
int main() {
button.rise(&change); // 上緣觸發執行flip()
// LED3 每2秒亮暗一次
while(1) {
blinkled = !blinkled;
wait(1);
}
}
```
---
### Example 5-2
#### 實驗目標:使用Ticker,實現兩個不同頻率的LED Blinking
{%youtube KDZW_Al1kjQ %}
```cpp
#include "mbed.h"
Ticker tick[2];
DigitalOut blinkled[2] = {LED1, LED3};
void change0() {
blinkled[0] = !blinkled[0];
}
void change1() {
blinkled[1] = !blinkled[1];
}
int main() {
tick[0].attach(&change0,0.5);
tick[1].attach(&change1,0.8);
while(1){ }
}
```
---
### LAB 5-1
#### 實驗目標:一開始LED1閃爍,使用Timeout 5秒後轉為閃爍LED2。
{%youtube yA6x41DshqQ %}
---
### LAB 5-2
#### 實驗目標:實現呼吸燈
1. 亮暗週期:
* 由亮至暗 : 2s
* 由暗至亮 : 2s
#### Tips:AnalogOut API、Pinout中尋找支援AnalogOut的Pin
{%youtube ZqlWxEkbdNQ %}
---
### Bonus 2
#### 實驗目標:完成一個簡易碼表。並實現以下目標:
1. 使用七段顯示器顯示秒數,並且精準到小數2位,並且遵守接下來例如的顯示方式。例如:2.31秒,則顯示[ ][2.][3][1]而不是[0][2.][3][1];0.02秒,則顯示[ ][0.][0][2]。
2. 碼表初始狀態為停止。並且顯示[ ][0.][0][0]。
3. 短按開關,則切換碼表狀態(停止/開始)。
4. 長按開關,則碼表時間歸零。
{%youtube 0LKOuc7_hr0 %}
```cpp
```
---
:::info
課後問題:
* 列出一表簡單表示STM32 NUCLEO-F207ZG與Arduino Uno的規格差異。(例如:震盪器頻率、Pin腳數、Flash memory大小)
* 簡述Mbed項目的創立目的與可能造成的影響
* 什麼是API
:::