---
tags: 單晶片
---
# 2020單晶片課程:RTOS(上)
## RTOS - 簡介
* 即時作業系統(Real-time operating system,RTOS),是指作業系統要在一個固定時間內,做出正確反應。
* RTOS相較一般的作業系統,最大的特色就在於「即時性」
* 即時作業系統可分類為「軟式(Soft)」與「硬式(Hard),此間差別主要在於完成 process 之間的時間差是否符合設定。
| | **硬性即時作業系統** | **軟性即時作業系統** |
| -------- | -------- | -------- |
| **簡介** | 也可稱為安全臨界系統(Safety-Critical System),有最迫切的需求,必須在特定期限之前回應事件,保證在它們的期限內完成臨界即時任務。 | 跟硬性即時系統比較起來,限制的範圍比較少,簡單提供一件臨界的即時系統,將在其它的任務上接受優先權並保有優先權直到它完成。 |
|**工作延遲**| 所有工作都不能夠延遲 | 允許少量的工作延遲,若沒有在回應時間內完成,只是造成系統的效能變差,不會影響系統的執行 |
|**要求** | 非常嚴苛| 比較寬鬆|
## Mbed-OS RTOS
Mbed OS RTOS 的物件導向功能包括執行緒管理( thread )、同步處理( synchronization objects )和定時器 ( timer )。它還提供用於附加於特定應用程序 idle hook function 的介面,用來讀取操作系統計數並提供 RTOS 報錯功能。
:::info
Hook 是用來與作業系統掛勾進而攔截並處理某些訊息之用。idle hook function 即是由介面觸發後,使程式進入 Idle 狀態的函式。
:::
---
### Thread
**Program**:一群程式碼的集合。
**Process**:由Program所產生的執行個體(或稱做處理序、進程)。
**<font color = "red">**執行緒**(Thread)</font>**
是作業系統能夠進行運算排程的最小單位,被包含在行程之中,式行程中的實際運作單位。在 Mbed OS RTOS 中以 thread 的函式庫來設定 thread的運作,而在 main 函式中,因為其為初始化程式本體的函式,所以他的初始排序優先權(os Priority)為`osPriorityNormal`。
**Firefox**:單獨只有firefox.exe這個Process,所有分頁是用Multi-Thread完成。
**Chrome**:每個分頁都相當於一個執行個體(Multi-Process)。

:::info
RTOS函式庫 : https://os.mbed.com/handbook/RTOS
:::
以下為簡單的應用 :
``` C++=
#include "mbed.h"
#include "rtos.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
Thread thread;
void led2_thread() {
while (true) {
led2 = !led2;
Thread::wait(1000);
}
}
int main() {
thread.start(led2_thread);
while (true) {
led1 = !led1;
Thread::wait(500);
}
}
```
:::info
The main function is already the first thread scheduled by the rtos
:::
執行緒之間會在以下階段間轉換 :
* **RUNNING** : 執行緒在執行的階段,若為單執行緒晶片,則只會有一執行緒在執行。
* **READY** : 執行緒準備好執行的階段,一旦執行的執行緒(RUNNING thread)結束或等待下一個準備好的執行緒(READY thread)完成(補進的執行緒必須有最高的執行優先權),此執行緒才會進入執行的階段(RUNNING state)。
* **WAITING** : 此類執行緒會等待事件發生(event occur)才會觸發,因此歸類為等待階段 (WAITING state)。
* **INACTIVE** : 已經在程式碼內但未創造或者已經結束的執行緒會被歸類為此一階段,此階段基本上不會耗損任何系統資源。

在執行緒中執行優先權可以有以下幾種可以設定 :
``` javascript=
typedef enum {
osPriorityIdle = -3, ///< Priority: idle (lowest)
osPriorityLow = -2, ///< Priority: low
osPriorityBelowNormal = -1, ///< Priority: below normal
osPriorityNormal = 0, ///< Priority: normal (default)
osPriorityAboveNormal = +1, ///< Priority: above normal
osPriorityHigh = +2, ///< Priority: high
osPriorityRealtime = +3, ///< Priority: realtime (highest)
osPriorityError = 0x84, ///< System cannot determine priority or illegal priority.
osPriorityReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
} osPriority;
```
並以以下函式設定優先順序 :
```
set_priority(osPriority priority)
```
當然也可以在宣告時便將所有執行緒要設定的參數設定好 :
```
Thread (osPriority priority=osPriorityNormal, uint32_t stack_size=DEFAULT_STACK_SIZE, unsigned char *stack_pointer=NULL)
//Allocate a new thread without starting execution.
```
宣告範例
```
Thread t1(osPriorityHigh);
```
---
### Signals
任何一個執行緒可以被標註為等待 signal 的執行緒。
以下為 `Signal` 範例程式 :
```javascript=
#include "mbed.h"
#include "rtos.h"
DigitalOut led(LED1);
Thread thread;
void led_thread() {
while (true) {
// Signal flags that are reported as event are automatically cleared.
thread.signal_wait(0x1);
led = !led;
}
}
int main (void) {
thread.start(callback(led_thread));
while (true) {
Thread::wait(1000);
thread.signal_set(0x1);
}
}
```
---
### Lab 1
請利用上述 RTOS 中的 thread 來完成跑馬燈功能:<font color = "red">**※必須執行3條以上執行緒**</font>
相關語法可以參考 : [Thread](https://os.mbed.com/docs/mbed-os/v6.15/apis/thread.html)。
1. 每隔1秒亮一顆LED,總共8顆輪流。
2. 當開發板上 Button 按下後,每隔1秒同時亮兩顆LED。
3. 再按一次開發板上的 Button 後,每隔1秒亮一顆LED且每隔0.5秒亮一顆LED(同時)。
4. 在按一次 Button 後,LED燈全部閃爍。
5. 最後再按一次Button回歸每隔1秒亮一顆LED的狀態
<font color = "red">注意</font>:更換狀態LED不是從起始開始,是從上次中斷位置開始
<iframe width="1086" height="620" src="https://www.youtube.com/embed/M8pl_XcQngo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
---
### Lab 2
請利用上述 RTOS 中的 Signals 來控制開發版的LED:<font color = "red">**※必須以Signals觸發Thread**</font>
<font color = "blue">hint:</font>
```
Serial pc(SERIAL_TX,SERIAL_RX);
while(ture){
if(pc.readable()){
w = pc.getc();
---------------------
.
.
.
}
}
```
1. 輸入"1",亮綠燈。
2. 輸入"2",亮藍燈。
3. 輸入"3",亮紅燈。
<iframe width="1086" height="620" src="https://www.youtube.com/embed/SkWUko-RJBE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
---
### Lab 3
請利用上述 RTOS 中的 Signals 來完成以下功能:<font color = "red">**※以Signals觸發Thread**</font>
超音波測距:https://os.mbed.com/components/HC-SR04/
1. 將超音波模組測量到的距離(cm)顯示於七段顯示器。
2. 根據距離的遠近分別亮開發版上的LED
10cm 以內亮紅燈
10-15cm 之間亮藍燈
15-20cm 之間亮綠燈
20cm 以上全亮
<iframe width="1086" height="620" src="https://www.youtube.com/embed/AFsb2ovgzpA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## 課後問題
:::info
* Q1.請詳述 Thread 在 Mbed 平台中是如何運作的。
* Q2.請解釋執行多執行緒之死結(DeadLock)的問題,以及如何避免。
* Q3.請解釋program、process、thread彼此之間的關係,並舉例說明。
:::