--- 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 ![](https://i.imgur.com/Tb3XSZI.png) --- ### 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 :::