# **RaspberryPi**
###### tags: `智慧聯網` `RaspberryPi`
<style>
.flex-container {
display: flex;
justify-content: center;
}
</style>
## 簡介
<div class="flex-container">
<img src="https://i.imgur.com/Muqt3H2.png" width="50%"></div>
>樹莓派(英語:Raspberry Pi)是基於Linux的單晶片電腦,由英國樹莓派基金會開發,目的是以低價硬體及自由軟體促進學校的基本電腦科學教育。
>樹莓派是源自一個開放源程式碼的硬體專案平台,該平台包括一塊具備簡單I/O功能的電路板以及一大堆的Linux 軟體。
### 命名由來
>樹梅派 Raspberry Pi 的 Pi 就是指 ![](https://i.imgur.com/K9UQZc6.png =15x15) python,一開始只打算使用 python 當 Raspberry Pi 的專屬語言,但之後各種的語言都可以在 Raspberry Pi 上面運行了。
>而以樹莓為命名 Raspberry 則是為了致敬 Apple、Tangerine Computer Systems、Apricot Computers、Acorn等以水果為命字的公司。
><div class="flex-container"><img src="https://i.imgur.com/0UN4LvW.png" width="100%"></div>
### 應用
>樹莓派可以用來開發交互產 品,比如它可以讀取大量的開關和感測器信號,並且可以控制電燈、電機和其他各 式各樣的物理設備;也可以開發出與PC一樣的周邊裝置,也可以運行在Linux PC 上的軟體進行通信。
>
> ![](https://i.imgur.com/Muqt3H2.png =25x20)**機器人、自走車** ![](https://i.imgur.com/Muqt3H2.png =25x20)**做成掌機**
> ![](https://i.imgur.com/jeWNguB.png =50%x)![](https://i.imgur.com/ipqlQ9X.png =50%x)
> <br/>
> ![](https://i.imgur.com/Muqt3H2.png =25x20)**物聯網通訊的閘道器** ![](https://i.imgur.com/Muqt3H2.png =25x20)**四軸飛行器、無人機**
> ![](https://i.imgur.com/BnHsTwO.png =50%x)![](https://i.imgur.com/s5sxjw8.png =50%x)
> <br/>
> ![](https://i.imgur.com/Muqt3H2.png =25x20)**做成平板** ![](https://i.imgur.com/Muqt3H2.png =25x20)**影音播放器**
> ![](https://i.imgur.com/YLhzLPF.png =50%x)![](https://i.imgur.com/kcxePA9.png =50%x)
>
### Arduino uno 與 Raspberry Pi B 比較
| | Arduino uno | Raspberry Pi Model B |
| --------------------------------- | ----------------- | ------------------------------------------ |
| Price | $30 | $35 |
| Size | 7.6x1.9x16.4 cm | 8.6x5.4x1.7 cm |
| Memory | 0.002MB | 512MB |
| Clock Speed | 16MHz | 700MHz |
| On Board Network | None | 10/100 wired Ethernet RJ45 |
| Multitasking | No | Yes |
| Iput voltage | 7~12V | 5V |
| USB | One,input only | Two,peripherals OK |
| Flash | 32KB | SD Card(2~16G) |
| Operating System | None | Linux distributions |
| Integrate Development Environment | Arduino | Scratch、IDLE、anything with Linux support |
官網 : https://www.raspberrypi.org
各式硬體種類 : https://www.raspberrypi.org/products/
## Raspberry Pi 3 Model B+
與 Pi 3 最大的改變是網路效能增加了!
### 特色
> * 新增四根 PoE 的 Pin 腳支援,並有對應的擴充板(HAT)。
><div class="flex-container"><img src="https://i.imgur.com/KMKztkX.jpg" width="70%"></div>
></br>
>
> * 網路效能提升!
>
><div class="flex-container"><img src="https://i.imgur.com/E1sj9Oo.png" width="90%"></div>
></br>
><div class="flex-container"><img src="https://i.imgur.com/7TgOldf.png" width="90%"></div>
></br>
>
### 規格
<div class="flex-container"><img src="https://i.imgur.com/yiahr6f.png" width="100%"></div>
</br>
| 型號 | 樹莓派 3B+ |
|:--------:| ------------------------------------------------------------------------------ |
| 晶片 | 博通 BCM2837B0, Cortex-A53 |
| 處理器 | 64-bit SoC@1.4GHz 四核 |
| 記憶體 | 1GB LPDDR2 記憶體 |
| Wifi | Zero W天線 2.4GHz and 5GHz雙頻Wi-Fi, 支持IEEE 802.11 b/g/n/ac Wireless LAN |
| 藍芽 | Bluetooth 4.2, BLE |
| 乙太網路 | 300Mbps |
| USB | USB 2.0 接口 x 4 |
| IO | 40pin GPIO 針腳 |
| 影像音頻 | HDMI 接口 x 1 、 DSI 顯示連接器 x 1 、 CSI 攝像頭接口 x 1 、 RCA av端口 音頻輸出 x1 |
| 電源IC | Microchip LAN7515 |
| 電源 | 5V / 2.5A DC Via Micro USB 接口、5V DC Via GPIO Header、獨立乙太網路供電(PoE) |
</br>
* **Fusion 360 Raspberry Pi 3 Model B+** 若看不到,請點擊此[連結](https://bit.ly/2QsnYmW)
<div class="flex-container"><iframe src="https://mail61250.autodesk360.com/shares/public/SH56a43QTfd62c1cd9689c02d7782677d1ee?mode=embed" width="750" height="600" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" frameborder="0"></iframe></div>
## Raspberry Pi 4 Model B
和之前的版本最大的改變是多了 2GB/4GB/8GB 的記憶體版本可供選擇
<div class="flex-container"><img src="https://i.imgur.com/Qx72dtN.png" width="80%"></div>
</br>
<div class="flex-container"><img src="https://i.imgur.com/zSDmikV.png" width="60%"></div>
</br>
紅色圈起來的地方是MicroSD卡插槽 (樹莓派背面)
<div class="flex-container"><img src="https://i.imgur.com/BfyJrGz.jpg" width="80%"></div>
</br>
### 特色
1. 使用 Broadcom 2711 四核心晶片(原本為 BCM2837B0)Quad-core Cortex-A72 64-bit SoC,單核心時脈可達 1.5GHz,有三倍速快。
2. 三種記憶體(LPDDR4 SDRAM)大小可選擇,分別是 1GB, 2GB, 4GB 和 8GB。
3. 乙太網路(Ethernet)達 True Gigabit Ethernet。
4. 支援藍牙5.0(Bluetooth 5.0)。
5. 兩個 USB 3.0 和 兩個 USB 2.0。
6. 支援雙螢幕輸出,解析度可達 4K。
7. 使用 VideoCore VI,可支援 OpenGL ES 3.x。
8. 可硬體解 4Kp60 HEVC 影片。
### 規格
| 型號 | 樹莓派 4B |
|:--------:| -------------------------------------------------------------------------------------------------------------------------------- |
| 晶片 | Broadcom 2711,Quad-core Cortex-A72 |
| 處理器 | 四核ARM Cortex-A72(v8) 64位元 1.5GHz處理器 |
| 記憶體 | 1GB, 2GB or 4GB LPDDR4 SDRAM |
| Wifi | 2.4GHz / 5.0GHz IEEE 802.11.b/g/n/ac wireless LAN |
| 藍芽 | **Bluetooth 5.0**, BLE |
| 乙太網路 | **ports delivering true Gigabit Ethernet** |
| USB | **2 x USB 2.0 / 2 x USB 3.0** |
| IO | Extended 40-pin GPIO header |
| 影像音頻 | **2 x micro HDMI、4k video(支援雙螢幕輸出)**、1 X MIPI DSI display port、1 X MIPI CSI camera port、4 pole stereo output and composite video port |
| 電源IC | Microchip LAN7515 |
| 電源 | DC 5V3A, 從**USB Type-C**接頭,或GPIO排針,或PoE輸入皆可|
* **Fusion 360 Raspberry Pi 4 Model B+** 若看不到,請點擊此[連結](https://bit.ly/379pgxW)
<div class="flex-container"><iframe src="https://mail61250.autodesk360.com/shares/public/SH56a43QTfd62c1cd968946788175dc3610a?mode=embed" width="750" height="600" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" frameborder="0"></iframe></div>
# 環境設置
## 安裝作業系統
將官方作業系統透過Raspberry Pi Imager 燒錄到MicroSD卡中,完成後將MicroSD插入樹莓派然後開機啟動,就完成安裝啦
> 安裝系統前須注意 :
>
> 1.確認您的電腦是否有Micro SD讀卡機,若沒有須自行準備並接至電腦
> 2.周邊設備是否備齊,如圖所示 :
><div class="flex-container"><img src="https://i.imgur.com/RGYoLjE.png" width="80%"></div>
> 3.將作業系統燒錄至Micro SD的動作只會用到電腦,固可先將設備先接至電腦(ex.鍵盤、滑鼠....),待燒錄完畢後再轉移到樹莓派即可。
### 安裝流程
* 步驟一 : 將Micro SD 接至電腦
><div class="flex-container"><img src="https://i.imgur.com/aNKAvIX.jpg" width="80%"></div></br>
>
* 步驟二 : 至[官網](https://www.raspberrypi.org/software/)下載Raspberry Pi Imager 在這裡選擇windows版本
>不須下載傳統燒錄軟體、映像檔,更簡便快速
><div class="flex-container"><img src="https://i.imgur.com/s1hamA9.png" width="80%"></div>
></br>
* 步驟三 : 開啟執行檔後 繼續在Windows中開啟Raspberry Pi Imager
></br>
><div class="flex-container"><img src="https://i.imgur.com/B8kbC6g.png" width="80%"></div>
></br>
> - 選擇作業系統 >Operating System>Raspberry Pi OS(other)>Raspberry Pi OS Full(32-bit)
> </br>
><div class="flex-container"><img src="https://i.imgur.com/9agbYrk.gif" width="80%"></div>
></br>
> - 選擇你的SD卡
> <div class="flex-container"><img src="https://i.imgur.com/q1Eqi6W.gif" width="80%"></div>
></br>
> - 開始燒錄 燒錄完成後會驗證(Verifying...⏳)
> <div class="flex-container"><img src="https://i.imgur.com/k3Pxlkg.gif" width="80%"></div>
* 步驟四 : 取出Micro SD卡 插入樹莓派的SD卡插槽
><div class="flex-container"><img src="https://i.imgur.com/BfyJrGz.jpg" width="80%"></div>
</br>
* 步驟五 : 將樹梅派接上螢幕、鍵盤、滑鼠、網路後開機進行設定區域、語言、密碼、網路等等的設定,就完成啦::tada::
><div class="flex-container"><img src="https://i.imgur.com/cRRq15g.gif" width="90%"></div>
</br>
## 網路設定
### wifi連線
#### 方法一 : raspi-config
尚未連接WiFi(Wlan0)時觀察網路介面的相關參數
```bash
$ifconfig
```
><div class="flex-container"><img src="https://i.imgur.com/A95ApzH.png" width="90%"></div>
>
```bash
$sudo raspi-config
```
* 步驟一 : 選擇Network Options
><div class="flex-container"><img src="https://i.imgur.com/SJ3Kea5.png" width="90%"></div>
>
* 步驟二 : 選擇N2 Wi-fi
><div class="flex-container"><img src="https://i.imgur.com/uYx8vSt.png" width="90%"></div>
>
* 步驟三 : 選擇你所在的國家Taiwan(TW)
><div class="flex-container"><img src="https://i.imgur.com/cdBYzQg.png" width="90%"></div>
>
* 步驟四 : 輸入你的WiFi名稱(必須大小寫一致)
><div class="flex-container"><img src="https://i.imgur.com/yLLIQcU.png" width="90%"></div>
>
* 步驟五 : 輸入你的WiFi密碼,若沒設密碼直接按確定
><div class="flex-container"><img src="https://i.imgur.com/ydYtWPa.png" width="90%"></div>
>
* 步驟六 : 重新開機
><div class="flex-container"><img src="https://i.imgur.com/j40IiHq.png" width="90%"></div>
>
再觀察一次網路參數,連線成功::tada::
```bash
$ifconfig
```
><div class="flex-container"><img src="https://i.imgur.com/z1cKHld.png" width="90%"></div>
#### 方法二 : 修改 /network/interfaces
* 步驟一 : 所在的區域必須擁有網路(無線分享器WIFI或是有線分享器)。
* 步驟二 : 設定你的WIFI名稱與密碼(名稱必須完全一致)
> ```bash
> $sudo nano /etc/network/interfaces
> ```
> <div class="flex-container"><img src="https://i.imgur.com/TVB7EEy.png" width="80%"></div>
> <br/>
>
> ::: info
> 輸入完成後按下Ctrl+O(英文O) → Enter → Ctrl+X重新開機等候數分鐘約5~10分鐘,樹莓派就會自行連上WIFI
> :::
* 步驟三 : **重新開機**後檢查連線是否成功,也可以隨便開個網頁來看看
> ```bash
> $ifconfig
> ```
><div class="flex-container"><img src="https://i.imgur.com/PJYqzlR.jpg" width="80%"></div>
> <br/>
## 遠端連線
### ssh
就是secure shell,透過網路連線到其他台主機上。
* 步驟一 : 我們首先要獲得Raspberry pi的ip address
>網路的話可以連wifi,也可以把網路線連接在電腦上或路由器上,在terminal輸入ifconfig可以得到目前的ip address。
>
> ```bash
> $ifconfig
> ```
> 此範例用的是wlan0(wifi)的網路
><div class="flex-container"><img src="https://i.imgur.com/PJYqzlR.jpg" width="80%"></div>
> <br/>
* 步驟二 : 接下來要啟用ssh
>從2016年底開始,Raspberry pi預設ssh都是關閉的,所以我們要先前往設定啟用它。
>
> -偏好設定>Raspberry Pi 設定
>
> <div class="flex-container"><img src="https://i.imgur.com/RR5yb3v.png" width="80%"></div>
> <br/>
> -啟用SSH
> <div class="flex-container"><img src="https://i.imgur.com/klZum6H.png" width="80%"></div>
> <br/>
>
> :::info
> 也可以透過樹梅派的terminal打開它,輸入:
> ```bash
> $sudo raspi-config
> ```
> -選擇Interface Options
> <div class="flex-container"><img src="https://i.imgur.com/4wOfRFH.png" width="80%"></div><br/>
> -選擇ssh
> <div class="flex-container"><img src="https://i.imgur.com/SKaZxy3.png" width="80%"></div><br/>
> -選擇enable後它就會告訴你SSH server已經啟用了
> <div class="flex-container"><img src="https://i.imgur.com/E4oMaag.png" width="80%"></div><br/>
> :::
* 步驟三 : 下載[putty](https://the.earth.li/~sgtatham/putty/latest/w64/putty.exe)
><div class="flex-container"><img src="https://i.imgur.com/V0S08Gb.png" width="80%"></div><br/>
> - 回到我們的電腦,我們已經獲得ip address,也啟用ssh,開啟putty,輸入相對應的IP位置後便完成後就可以遠端控制Raspberry pi了。
> <div class="flex-container"><img src="https://i.imgur.com/osj781Y.png" width="80%"></div><br/>
>
> :::warning
> 預設帳號是 **pi**
> 預設密碼是 **raspberry** (密碼是盲打喔 不是鍵盤壞掉)
> :::
> 完成 ::tada::
> <div class="flex-container"><img src="https://i.imgur.com/CQkebu2.png" width="80%"></div><br/>
### VNC
VNC是一個遠端桌面的軟體,分成我們的VNC Server(Raspberry pi),與VNC Viewer(筆電端)。
直接從樹莓派設定可以看到系統預設的VNC伺服器也不見了,也不是消失無蹤,而是預設不啟動了。此時想以VNC操控,就會失敗。
<div class="flex-container"><img src="https://i.imgur.com/D1Po6DF.png" width="50%"></div><br/>
不過只要自己在命令列下打指令,啟動TightVNC伺服器:
* 步驟一 : 透過putty連線下開啟vnc的指令(也可以直接在樹莓派的terminal下指令)
> ```bash
> $tightvncserver
> ```
> <div class="flex-container"><img src="https://i.imgur.com/fb5qSkh.png" width="80%"></div><br/>
>
* 步驟二 : 在筆電上下載[VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/windows/)進行連線
> -在此下載的是windows版本
> <div class="flex-container"><img src="https://i.imgur.com/PqXFgG4.png" width="80%"></div></br>
> -完成後開啟執行檔
> <div class="flex-container"><img src="https://i.imgur.com/JLxsfeo.png" width="80%"></div></br>
> -建立連線設定 >File>New connection...
> <div class="flex-container"><img src="https://i.imgur.com/DGxahJy.png" width="80%"></div></br>
>
> :::info
> VNC Server : 樹莓派IP加上 **:1**
> (簡單的說:0代表實體連接的螢幕,而剛剛的指令會開出另一個螢幕:1。)
> Name : 隨意取名,方便辨識
> :::
>
> -建立完成,點擊右鍵兩下、輸入密碼就能看到連線畫面 :tada:
> <div class="flex-container"><img src="https://i.imgur.com/yDCKzAx.gif" width="80%"></div></br>
>
## 中文化
### 介面中文化
* 步驟一 : 在左上角按「Raspberry 圖案」 > Preferences > Raspberry Pi Configuration
> <div class="flex-container"><img src="https://i.imgur.com/9CRRDpU.png" width="100%"></div></br>
* 步驟二 : Set Locale...
**Language :** zh(Chinese)
**Country :** TW(Taiwan)
**Character Set :** UTF 8
> <div class="flex-container"><img src="https://i.imgur.com/KW8Toa8.jpg" width="100%"></div></br>
>
* 步驟三 : 重新開機
> <div class="flex-container"><img src="https://i.imgur.com/6Mcxs80.png" width="80%"></div></br>
完成啦 :tada:
> <div class="flex-container"><img src="https://i.imgur.com/O2isX8W.jpg" width="100%"></div>
### 中文輸入法
#### 下載輸入法
* 步驟一 : 點選開始功能表的 偏好設定/Add/Remove Software
> <div class="flex-container"><img src="https://i.imgur.com/bNvzgrb.png" width="80%"></div>
* 步驟二 : 在搜尋欄中輸入<font color="red">scim-chewing</font>
> <div class="flex-container"><img src="https://i.imgur.com/aem0RTY.png" width="80%"></div>
* 步驟三 : 勾選最下面兩個選項,按下Apply,系統會要求輸入設定時預設的管理者密碼
【Chewing IM engine module for SCIM】
【Chinese input method data tables for SCIM platform】
> <div class="flex-container"><img src="https://i.imgur.com/X0AzrG3.png" width="80%"></div>
* 步驟四 : 系統會將相關的應用程式工具一併勾選,按下OK鍵
> <div class="flex-container"><img src="https://i.imgur.com/T3qyJtZ.png" width="80%"></div>
#### 設定輸入法介面的切換鍵
* 步驟一 : 點選 開始功能表/偏好設定/SCIM Input Method(SCIM輸入法框架)
> <div class="flex-container"><img src="https://i.imgur.com/aFeBVN9.png" width="80%"></div>
* 步驟二 : 點選**介面(前端)設定**,設定輸入法的切換鍵與快速鍵,設定切換下一種輸入法的快速鍵(...)
> <div class="flex-container"><img src="https://i.imgur.com/xef7bxX.png" width="80%"></div>
* 步驟三 : 點選【...】符號
> <div class="flex-container"><img src="https://i.imgur.com/6UP2w5u.png" width="80%"></div>
* 步驟四 : 再按一下鍵盤上的左側【Shift】按鍵
> <div class="flex-container"><img src="https://i.imgur.com/uvWwVVF.png" width="50%"></div>
* 步驟五 : 在空白欄裡會出現「Shift_L」,點選<b><font color="blue">+</font></b>新增至選定的按鍵欄位中
> <div class="flex-container"><img src="https://i.imgur.com/LFlyyLO.png" width="80%"></div>
><br>
> <div class="flex-container"><img src="https://i.imgur.com/R2Uxo4p.png" width="80%"></div>
* 步驟六 : 這樣就完成切換至下一種輸入法快速鍵的設定,記得要點選 ✔
> <div class="flex-container"><img src="https://i.imgur.com/ooxobqn.png" width="80%"></div>
#### 輸入法引擎設定
* 步驟一 : 點選 輸入法引擎/全域設定
> <div class="flex-container"><img src="https://i.imgur.com/3gPv6wb.png" width="80%"></div>
* 步驟二 : 取消簡體中文項目的勾選(需要則保留),勾選自己常用繁體中文的輸入法、其他語文項目,點選✔
> <div class="flex-container"><img src="https://i.imgur.com/SKFsUof.png" width="80%"></div>
* 步驟三 : 新增完成關閉設定時會要求重新啟動電腦
> <div class="flex-container"><img src="https://i.imgur.com/lDMG44O.png" width="80%"></div>
* 步驟四 : 右上角會出現小鍵盤,完成啦 ::tada::
> <div class="flex-container"><img src="https://i.imgur.com/bgGjVoL.png" width="80%"></div>
> <br>
> <div class="flex-container"><img src="https://i.imgur.com/I0sFikD.gif" width="80%"></div>
# 程式範例
## GPIO
<div class="flex-container"><img src="https://i.imgur.com/24cEkJS.png" width="50%"></div>
> GPIO(General Purpose I/O Ports)意思是通用型輸入/輸出介面,也就是一些針腳可以通過它們輸出高電位或者低電位,可以供使用者由程式控制自由使用,與裝置進行通訊,達到控制裝置的目的。
>
> 既然一個針腳可以用於輸入、輸出或其他特殊功能,那麼一定有暫存器用來選擇這些功能。
>
> 對於輸入,一定可以透過讀取某個暫存器來確定針腳電位的高低;對於輸出,一定可以透過寫入某個暫存器來讓這個針腳輸出高電位或者低電位;對於其他特殊功能,則有另外的暫存器來控制它們,所以掌握了 GPIO 就相當於掌握了硬體的控制。
<div class="flex-container"><img src="https://i.imgur.com/wUfYzs3.png" width="100%"></div>
</br>
> 這裡可以看到有二種編號規則,分別是紅框內的 BOARD 編號規則,與紅框外的 BCM 編號規則。
## LED發光二極體的控制實作
### 控制單科LED閃爍練習
程式範例 : [led_single.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
> 開始撰寫程式碼:
> ```bash
> $nano /home/pi/led_single.py
> ```
> ```python=
> #匯入模組
> import time
> import RPi.GPIO as GPIO
>
> #宣告設定
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(4, GPIO.OUT)
>
> #主程式區
> while True:
> GPIO.output(4,1)
> time.sleep(1)
> GPIO.output(4,0)
> time.sleep(1)
> ```
>
> * 匯入模組
> <font color="orange">import time </font>: 匯入時間模組,要完成閃爍效果,需要用到時間暫停的技巧。
> <font color="orange">import RPi.GPIO as GPIO </font>: 匯入RPi.GPIO模組物件,用於控制Raspberry Pi GPIO引腳。
> <div class="flex-container"><img src="https://i.imgur.com/VfiaNCw.png" width="80%"></div>
>
> * 宣告設定
> <font color="orange">setwarnings(False) </font>: 在執行過程中將所有警告提示關閉(False)。
> <font color="orange">setmode(GPIO.BCM) </font>: 設定模式
> -- GPIO.BCM : 使用GPIO編號
> -- GPIO.BOARD : 使用電路板腳位(pin的)編號
> <font color="orange">setup(4, GPIO.OUT) </font>: 設定GPIO.4(BOARD模式7)作為輸出(Output)腳位
> * 主程式區
> 透過無窮迴圈讓LED燈反覆閃爍,若要停用則按<font color="red">Ctrl+C</font>強制停止。
> <font color="orange">GPIO.output(4,1) </font>: (對應腳位,電位),1代表輸出高電位(High)的3.3V信號使LED點亮,0代表輸出低電位(Low)的0V信號使LED熄滅。
> <font color="orange">time.sleep(1) </font>: 利用第2行的時間模組,將時間暫停1秒,sleep()方法暫停執行給定秒數。
電路圖 :
> <div class="flex-container"><img src="https://i.imgur.com/ukuAVhF.png" width="100%"></div>
</br>
### LED按鍵控制練習: 按著才會亮
程式範例 : [led_switch.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
> ```python=
> import RPi.GPIO as GPIO
> import time
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(4, GPIO.OUT)
> GPIO.setup(17, GPIO.IN)
>
> while True:
> value01 = GPIO.input(17)
> GPIO.output(4, value01)
> time.sleep(0.1)
> ```
### LED按鍵控制練習: 按一下亮,按一下滅
程式範例 : [led_switch_on_off.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
> ```python=
> import RPi.GPIO as GPIO
> import time
>
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(4, GPIO.OUT)
> GPIO.setup(17, GPIO.IN)
>
> led = 0
>
> '''def my_callback(channel):
> if led == 0:
> led = 1
> GPIO.output(4, led)
> else:
> led = 0
> GPIO.output(4, led)'''
>
> GPIO.add_event_detect(17, GPIO.RISING)
> #GPIO.add_event_callback(17, my_callback)
>
> while(True):
> if GPIO.event_detected(17):
> print('Button pressed')
> if led == 0:
> led = 1
> GPIO.output(4, led) #(pin,電位高低)
> else:
> led = 0
> GPIO.output(4, led)
> ```
電路圖 :
> <div class="flex-container"><img src="https://i.imgur.com/XrMDyNH.png" width="100%"></div>
</br>
### PWM範例 : LED亮度變化 暗到亮
使用硬體 PWM 可以達到更精準的控制效果,對系統的負擔也小了許多。
而樹莓派支援硬體PWM的腳位,分別是 BCM 編號 12, 13, 18, 19 的四隻腳位。
儘管有四隻腳位支援硬體 PWM 功能,但是卻只有兩個頻道 (Channel)。
其中 12/18 屬於同一個頻道 (Channel 0)、而 13/19 則同屬於另外一個頻道 (Channel 1)。
### PWM範例 : LED漸亮
程式範例 : [led_pwm1.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
**Duty Cycle**(工作週期,高電位佔用整個波形周期的比例),下圖分別呈現工作週期為 50% 與 25% 時的電位波形。
<div class="flex-container"><img src="https://i.imgur.com/piQ0lr4.png" width="80%"></div>
在控制 LED 燈泡方面,只要記得工作週期越大燈泡就越亮,而工作週期越小時燈泡就越暗。
> ```python=
> import time
> import RPi.GPIO as GPIO
>
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(4, GPIO.OUT)
>
> #GPIO.PWM(GPIO接脚,頻率設定(Hz))
> p1 = GPIO.PWM(4, 1000)
> #開始PWM, Duty Cycle(工作週期,表示在一個週期之中,高電位持續時間的比例)為0%
> p1.start(0)
>
> while True:
> #dc範圍 : 1~100,步長為5
> for dc in range(1,101,5):
> #設定工作週期進而改變LED燈泡的亮度,dc單位為赫茲(Hz)
> #工作週期寬度:5% →10% → 15%...→ 100%,即可完成漸亮的效果
> p1.ChangeDutyCycle(dc)
> time.sleep(0.2)
> ```
電路圖 :
> <div class="flex-container"><img src="https://i.imgur.com/ukuAVhF.png" width="100%"></div>
</br>
### PWM範例 : LED閃爍頻率慢到快
程式範例 : [led_pwm2.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
> ```python=
> import time
> import RPi.GPIO as GPIO
>
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(4, GPIO.OUT)
>
> p2 = GPIO.PWM(4, 50) #(GPIO接脚,頻率設定(Hz))
> p2.start(50)#開始PWM, Duty Cycle(工作週期,高電位佔用整個波形周期的比例)為50%
>
> while True:
> for dc in range(5,101,5): #dc範圍 : 5~100,步長為5
> p2.ChangeFrequency(dc)#設置新的頻率
> time.sleep(1)
> ```
電路圖 :
> <div class="flex-container"><img src="https://i.imgur.com/ukuAVhF.png" width="100%"></div>
</br>
## 超音波感測器
<div class="flex-container"><img src="https://i.imgur.com/4ew1u51.png" width="30%"></div>
</br>
超音波模組HC-SR04,算是常見的模組,特別是用在智慧車等專案中,用來測量前方障礙物的距離。
它的運作原理很簡單,模組會送出8個40khz的聲波,如果前方有障礙物,信號就會返回,模組收到信號後,再利用返回的時間,去計算該障礙的距離。
常見的HC-SR04都有4個腳,除了VCC和GND以外,Trig就是發送訊號,Echo就是接收返回的訊號。然後我們就能利用一發一收,去算出中間的距離了。
### 範例程式 : 測距儀
程式範例 : [distance.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
> ```python=
> import time, RPi.GPIO as GPIO
>
> GPIO_TRIGGER = 24 #設定觸發腳位編號名稱,方便未來變更腳位
> GPIO_ECHO = 25 #設定迴聲腳位編號名稱
> GPIO.setwarnings(False) #關閉警告提示
> GPIO.setmode(GPIO.BCM) #設定trigger為輸出腳位
> GPIO.setup(GPIO_TRIGGER, GPIO.OUT) #設定echo為輸入腳位
> GPIO.setup(GPIO_ECHO, GPIO.IN)
>
> def measure():
> GPIO.output(GPIO_TRIGGER, False) #設定觸發腳位為低電位,準備開始觸發
> time.sleep(0.5)
> GPIO.output(GPIO_TRIGGER, True) #設定觸發腳位為高電位,開始觸發
> time.sleep(0.00001)
> GPIO.output(GPIO_TRIGGER, False) #設定觸發腳位為低電位,停止觸
> start = time.time()
> while GPIO.input(GPIO_ECHO) == 0: #當echo=0再開始計算時間
> start = time.time()
> while GPIO.input(GPIO_ECHO) == 1: #當echo=1紀錄收到停止的時間
> stop = time.time()
> elapsed = stop - start #計算echo脈波寬度
> distance = elapsed * 34300 #換算echo實際來回的總距離(cm/s)
> distance = distance / 2 #來回除以2,即為與待測物的距離
> return distance
>
> print("Ultrasonic Measurement")
> while 1:
> cm = measure()
> print("Distance : %.1f cm" % cm)
> ```
> 實作結果 :
> <div class="flex-container"><img src="https://i.imgur.com/cR220Eh.gif" width="100%"></div></br>
>
> 電路圖 :
> 使用杜邦線將工作電壓(Vcc)接5V、接地(GND)接GND、觸發(Tig)接GPIO.24、迴聲(Echo)接GPIO.25
> <div class="flex-container"><img src="https://i.imgur.com/sfqQ1Y4.png" width="100%"></div>
</br>
### 範例程式 : 測量平均值距離
程式範例 : [ultrasonic_distance_average.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
> ```python=
> import time, RPi.GPIO as GPIO
>
> GPIO_TRIGGER = 24
> GPIO_ECHO = 25
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
> GPIO.setup(GPIO_ECHO, GPIO.IN)
>
> def measure():
> GPIO.output(GPIO_TRIGGER, False)
> time.sleep(0.5)
> GPIO.output(GPIO_TRIGGER, True)
> time.sleep(0.00001)
> GPIO.output(GPIO_TRIGGER, False)
> start = time.time()
> while GPIO.input(GPIO_ECHO) == 0:
> start = time.time()
> while GPIO.input(GPIO_ECHO) == 1:
> stop = time.time()
> elapsed = stop - start
> distance = elapsed * 34300
> distance = distance / 2
> return distance
>
> #求平均三次的測量結果
> def measure_average():
> distance1=measure()
> time.sleep(0.1)
> distance2=measure()
> time.sleep(0.1)
> distance3=measure()
> distance = (distance1 + distance2 + distance3) / 3
> return distance
>
> print("Ultrasonic Measurement")
> try: #例外處理
> while True:
> cm = measure_average()
> print("Distance : %.1f cm" % cm)
> time.sleep(1) #每隔一秒測試一次平均值
> except KeyboardInterrupt: #按Ctrl+C中斷
> GPIO.cleanup() #重置釋放GPIO,然後離開程式,防止下次執行其他程式可能發生仍然在使用中的錯誤
> ```
## 人體紅外線感測器
<div class="flex-container"><img src="https://i.imgur.com/9KNrj5F.png" width="30%"><img src="https://i.imgur.com/TPBbHR7.png" width="30%"></div>
<br>
### 範例程式 : 入侵偵測
程式範例 : [pir.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
> ```python=
> import RPi.GPIO as GPIO
> import time
>
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.setup(13, GPIO.IN)#Read output from PIR motion sensor
> GPIO.setup(4, GPIO.OUT)#LED output pin
> try:
> while True:
> i=GPIO.input(13)
> if i==0: #When output from motion sensor is LOW
> print ("No intruders", i)
> GPIO.output(4, 0)#Turn OFF LED
> time.sleep(1)
> elif i==1: #When output from motion sensor is HIGH
> print ("Intruder detected",i)
> GPIO.output(4, 1) #Turn ON LED
> time.sleep(10)
> except KeyboardInterrupt:
> print("Bye Bye!")
> finally:
> GPIO.cleanup()
> ```
>
> 電路圖 :
> <div class="flex-container"><img src="https://i.imgur.com/E8i3Ns2.png" width="100%"></div>
</br>
## 伺服馬達(SERVO)
<div class="flex-container"><img src="https://i.imgur.com/tvvmzSi.gif" width="50%"></div></br>
> 伺服馬達(Servomotor)是對用於使用伺服機構的馬達(電動機)總稱。
> 伺服(Servo)一詞來自拉丁文"Servus",本為奴隸(Slave)之意,此指依照命令動作的意義。
> 所謂伺服系統,就是依照指示命令動作所構成的控制裝置,應用於馬達的伺服控制,將感測器裝在馬達與控制對象機器上,偵測結果會返回伺服放大器與指令值做比較。
### 硬體方式
程式範例 : [servo_hardware.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
之前透過RPIGPIO的PWM指令,以便讓LED漸亮,PWM是屬於**軟體模擬**控制,所以不限制特殊腳位編號,缺點是無法精準控制。而本範例特別匯入使用**pigpio**函式庫模組,PWM是屬於**硬體模擬**控制,有支援硬體PWM的腳位,分別是BCM編號12、13、18、19的四隻腳位而已,如果PWM使用其他腳位,執行時會出現<font color="red">pigpio.error:GPIO has no hardware PWM </font>錯誤。
> 在執行程式碼前,請在樹莓派上下載**pigpio**套件:
> ```bash
> $sudo apt-get install pigpio
> ```
> 並且執行:
> ```bash
> $sudo pigpiod
> ```
> 若未下載套件、執行套件.執行程式碼時會有以下的錯誤訊息產生:
> :::danger
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> Can't connect to pigpio at localhost(8888)
>
> Did you start the pigpio daemon? E.g. sudo pigpiod
>
> Did you specify the correct Pi host/port in the environment
> variables PIGPIO_ADDR/PIGPIO_PORT?
> E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888
>
> Did you specify the correct Pi host/port in the
> pigpio.pi() function? E.g. pigpio.pi('soft', 8888)
> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> Traceback (most recent call last):
> File "/home/pi/servo_hardware.py", line 14, in <module>
> pi.hardware_PWM(PWMPIN, PWM_FREQ, update(90))
> File "/usr/lib/python2.7/dist-packages/pigpio.py", line 1964, in hardware_PWM
> self.sl, _PI_CMD_HP, gpio, PWMfreq, 4, extents))
> File "/usr/lib/python2.7/dist-packages/pigpio.py", line 1006, in _pigpio_command_ext
> sl.s.sendall(ext)
> AttributeError: 'NoneType' object has no attribute 'sendall'
>
> :::
> 開始撰寫程式:
> ```python=
> import time
> import sys #匯入系統模組
> import pigpio
>
> PWMPIN = 18 #使用GPIO.18腳位
> PWM_FREQ = 50 #PWM頻率設為50
> version = sys.version #讀取Python版本
> pi = pigpio.pi() #將pigpio命名為pi
>
> #將角度換算成PWM的工作週期
> def update(angle):
> duty_cycle = int(500 * PWM_FREQ + (1900 * PWM_FREQ * angle / 180))
> return (duty_cycle)
>
> #主程式開始
> pi.hardware_PWM(PWMPIN, PWM_FREQ, update(90)) #初始值轉到90度的位置
> try:
> while True:
> if version[0] == '3': #判斷是否為python3
> text = input('Angle:') #輸入控制的角度
> else:
> text = raw_input('Angle:')
> angle = int(text) #轉換成數值
> if(angle >= 0 and angle <= 180): #如果介於0~180才轉動馬達
> dc = update(angle)
> pi.hardware_PWM(PWMPIN, PWM_FREQ, dc)
> except KeyboardInterrupt: #按下Ctrl+C中斷
> pass #不做任何動作
> finally: #最後
> pi.set_mode(PWMPIN, pigpio.INPUT) #恢復輸入模式離開
> ```
電路圖 :
> <div class="flex-container"><img src="https://i.imgur.com/EEInBJ5.png" width="100%"></div>
</br>
實際操作 :
> <div class="flex-container"><img src="https://i.imgur.com/cQYHlha.gif" width="100%"></div>
</br>
### 軟體方式
程式範例 : [servo_software.py](https://drive.google.com/drive/folders/1glqcCGJ8rV3s-mAqVNVvJSNdwEKJ0erf?usp=sharing)
>使用軟體來模擬PWM功能有一些缺點,因為執行PWM軟體模擬功能時,需要CPU不斷地計算時間訂控制波形,造成CPU資源部只要提供PWM軟體使用,還必須同時提供各式各樣的程式使用,所以很容易造成無法**即時**處理PWM功能,進而影響PWM輸出的波形。
一旦波形不正確,PWM也失去了精確性,造成伺服馬達可能無法定位到正確的角度。使用硬體PWM才可以達到更精準地控制效果,對系統的負擔比較小。
>
> 在執行程式碼前,請在樹莓派上下載**pigpio**套件(載過的可以忽略):
> ```bash
> $sudo apt-get install pigpio
> ```
> 並且執行(執行過的可以忽略):
> ```bash
> $sudo pigpiod
> ```
> ```python=
> import pigpio
> import time
> import sys
>
> PWMPIN = 27 #改接GPIO.27
> version = sys.version
> pi = pigpio.pi()
>
> def update(angle):
> duty_cycle = int(angle * 11.1 + 500.0)
> return (duty_cycle)
>
> pi.set_servo_pulsewidth(PWMPIN, update(90))
> try:
> while True:
> if version[0] == '3':
> text = input('Angle:')
> else:
> text = raw_input('Angle:')
> angle = int(text)
> if(angle >= 0 and angle <= 180):
> dc=update(angle)
> pi.set_servo_pulsewidth(PWMPIN, dc)
> except KeyboardInterrupt:
> pass
> finally:
> pi.set_mode(PWMPIN, pigpio.INPUT)
> ```
電路圖 :
> <div class="flex-container"><img src="https://i.imgur.com/NGzSJRL.png" width="100%"></div>
</br>
## DHT11 數位溫溼度感測模組的控制
<div class="flex-container"><img src="https://i.imgur.com/IOG9cIB.png" width="50%"></div></br>
DHT11數位溫溼度感測模組屬於**數位輸入**,而非類比輸入。
溫度測量範圍為0-50度,測量誤差±2度,溼度測量範圍為20-95%,測量誤差±5,工作電壓5V。
DHT11可同時監測周圍環境的溫度與濕度的變化,價格低廉,經常使用於物聯網環境溫溼度監測。
### 顯示溫溼度
程式範例 : [dht11.py、dht11_example.py](https://drive.google.com/drive/folders/1hK4MSnCZwmaflIqCppBL7PpFwAJSTcuK?usp=sharing)
> dht11.py (做為副程式,用來模擬1線通信介面程式)
> ```python=
> import time
> import RPi
>
>
> class DHT11Result:
> 'DHT11 sensor result returned by DHT11.read() method'
>
> ERR_NO_ERROR = 0
> ERR_MISSING_DATA = 1
> ERR_CRC = 2
>
> error_code = ERR_NO_ERROR
> temperature = -1
> humidity = -1
>
> def __init__(self, error_code, temperature, humidity):
> self.error_code = error_code
> self.temperature = temperature
> self.humidity = humidity
>
> def is_valid(self):
> return self.error_code == DHT11Result.ERR_NO_ERROR
>
>
> class DHT11:
> 'DHT11 sensor reader class for Raspberry'
>
> __pin = 0
>
> def __init__(self, pin):
> self.__pin = pin
>
> def read(self):
> RPi.GPIO.setup(self.__pin, RPi.GPIO.OUT)
>
> # send initial high
> self.__send_and_sleep(RPi.GPIO.HIGH, 0.05)
>
> # pull down to low
> self.__send_and_sleep(RPi.GPIO.LOW, 0.02)
>
> # change to input using pull up
> RPi.GPIO.setup(self.__pin, RPi.GPIO.IN, RPi.GPIO.PUD_UP)
>
> # collect data into an array
> data = self.__collect_input()
>
> # parse lengths of all data pull up periods
> pull_up_lengths = self.__parse_data_pull_up_lengths(data)
>
> # if bit count mismatch, return error (4 byte data + 1 byte checksum)
> if len(pull_up_lengths) != 40:
> return DHT11Result(DHT11Result.ERR_MISSING_DATA, 0, 0)
>
> # calculate bits from lengths of the pull up periods
> bits = self.__calculate_bits(pull_up_lengths)
>
> # we have the bits, calculate bytes
> the_bytes = self.__bits_to_bytes(bits)
>
> # calculate checksum and check
> checksum = self.__calculate_checksum(the_bytes)
> if the_bytes[4] != checksum:
> return DHT11Result(DHT11Result.ERR_CRC, 0, 0)
>
> # ok, we have valid data, return it
> return DHT11Result(DHT11Result.ERR_NO_ERROR, the_bytes[2], the_bytes[0])
>
> def __send_and_sleep(self, output, sleep):
> RPi.GPIO.output(self.__pin, output)
> time.sleep(sleep)
>
> def __collect_input(self):
> # collect the data while unchanged found
> unchanged_count = 0
>
> # this is used to determine where is the end of the data
> max_unchanged_count = 100
>
> last = -1
> data = []
> while True:
> current = RPi.GPIO.input(self.__pin)
> data.append(current)
> if last != current:
> unchanged_count = 0
> last = current
> else:
> unchanged_count += 1
> if unchanged_count > max_unchanged_count:
> break
>
> return data
>
> def __parse_data_pull_up_lengths(self, data):
> STATE_INIT_PULL_DOWN = 1
> STATE_INIT_PULL_UP = 2
> STATE_DATA_FIRST_PULL_DOWN = 3
> STATE_DATA_PULL_UP = 4
> STATE_DATA_PULL_DOWN = 5
>
> state = STATE_INIT_PULL_DOWN
>
> lengths = [] # will contain the lengths of data pull up periods
> current_length = 0 # will contain the length of the previous period
>
> for i in range(len(data)):
>
> current = data[i]
> current_length += 1
>
> if state == STATE_INIT_PULL_DOWN:
> if current == RPi.GPIO.LOW:
> # ok, we got the initial pull down
> state = STATE_INIT_PULL_UP
> continue
> else:
> continue
> if state == STATE_INIT_PULL_UP:
> if current == RPi.GPIO.HIGH:
> # ok, we got the initial pull up
> state = STATE_DATA_FIRST_PULL_DOWN
> continue
> else:
> continue
> if state == STATE_DATA_FIRST_PULL_DOWN:
> if current == RPi.GPIO.LOW:
> # we have the initial pull down, the next will be the data pull up
> state = STATE_DATA_PULL_UP
> continue
> else:
> continue
> if state == STATE_DATA_PULL_UP:
> if current == RPi.GPIO.HIGH:
> # data pulled up, the length of this pull up will determine whether it is 0 or 1
> current_length = 0
> state = STATE_DATA_PULL_DOWN
> continue
> else:
> continue
> if state == STATE_DATA_PULL_DOWN:
> if current == RPi.GPIO.LOW:
> # pulled down, we store the length of the previous pull up period
> lengths.append(current_length)
> state = STATE_DATA_PULL_UP
> continue
> else:
> continue
>
> return lengths
>
> def __calculate_bits(self, pull_up_lengths):
> # find shortest and longest period
> shortest_pull_up = 1000
> longest_pull_up = 0
>
> for i in range(0, len(pull_up_lengths)):
> length = pull_up_lengths[i]
> if length < shortest_pull_up:
> shortest_pull_up = length
> if length > longest_pull_up:
> longest_pull_up = length
>
> # use the halfway to determine whether the period it is long or short
> halfway = shortest_pull_up + (longest_pull_up - shortest_pull_up) / 2
> bits = []
>
> for i in range(0, len(pull_up_lengths)):
> bit = False
> if pull_up_lengths[i] > halfway:
> bit = True
> bits.append(bit)
>
> return bits
>
> def __bits_to_bytes(self, bits):
> the_bytes = []
> byte = 0
>
> for i in range(0, len(bits)):
> byte = byte << 1
> if (bits[i]):
> byte = byte | 1
> else:
> byte = byte | 0
> if ((i + 1) % 8 == 0):
> the_bytes.append(byte)
> byte = 0
>
> return the_bytes
>
> def __calculate_checksum(self, the_bytes):
> return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255
> ```
> dht11_example.py (主程式)
> ```python=
> #!/usr/bin/python3
> # -*- coding: utf-8 -*-
> import RPi.GPIO as GPIO
> import dht11 #匯入dht11.py副程式
> import time
> import datetime #匯入日期時間模組套件
>
> GPIO.setwarnings(False)
> GPIO.setmode(GPIO.BCM)
> GPIO.cleanup()
> instance = dht11.DHT11(pin=18) #使用GPIO.18腳位
>
> #主程式開始
> try:
> while True:
> result = instance.read() #讀取溫溼度結果
> if result.is_valid(): #如果讀值是有效才顯示
> print("目前監測的時間" + str(datetime.datetime.now())) #顯示目前系統時間
> print("目前溫度: %d 度C" % result.temperature) #顯示溫度
> print("目前濕度: %d %%" % result.humidity) #顯示濕度
> time.sleep(3) #間隔3秒取樣
> except KeyboardInterrupt:
> print("Bye Bye!")
> finally:
> GPIO.cleanup()
> ```
電路圖:
> <div class="flex-container"><img src="https://i.imgur.com/fOCO5ic.png" width="80%"></div></br>
執行主程式:
> <div class="flex-container"><img src="https://i.imgur.com/r7HQbv7.gif" width="80%"></div>
## 火焰感測器模組
<div class="flex-container"><img src="https://i.imgur.com/AgY7YWS.png" width="30%"><img src="https://i.imgur.com/0mriIdm.png" width="50%"></div>
火焰感測器模組工作電壓 3V 或 5V 均可,利用紅外線對火焰非常敏感的特點,使用特製的紅外線接收管來檢測火焰,然後把火焰的亮度轉化為高低變化的電壓信號,使用打火機測試火焰距離為 80cm 以內,但火焰越大,測試距離越遠,探測角度約 60 度左右,越靠近火焰,AO 讀值越小,DO 則為高電位。一般常用做智慧居家的火焰警報等用途。
程式範例 : [fire_sensor.py、AnaloginOutSerial.ino](https://drive.google.com/drive/folders/1hrlduOXHv_QpuIWWndV349xnSpXMe0dK?usp=sharing)
### UART
UART(Universal Asynchronous Receiver/Transmitter)是指通用非同步收發傳輸器,只允許兩個裝置直接對接,無法接更多裝置,除非使用 RS-422、RS-485 則可接多個裝置,基本傳送僅需利用 Tx 傳輸與 Rx 接收兩個接腳,跟 SPI 均屬於全雙工通訊,連接方式如下圖,由於速度不是很快,一般而言最高為 115.2Kbps,雖有更高速版本但不太普及,所以**不適合用在高速、大量傳輸上**。
<div class="flex-container"><img src="https://i.imgur.com/uCoXP13.png" width="50%"></div>
</br>
接著程式範例是利用樹莓派的 UART 傳輸方式,讀取 Arduino 開發板的類比腳位數值。
> fire_sensor.py
> ```python=
> #!/usr/bin/python3
> # -*- coding: utf-8 -*-
> import tkinter as tk
> import serial # 匯入串列傳輸模組
>
> def update_data(): # 建立資料更新副程式
> response = ser.readline() # 讀取串列傳輸的值
> now = response[:len(response) - 1] # 去掉最後面的換行字元
> label2.configure(text = now) # 顯示類比讀值(0~1023)
> root.after(1, update_data) # 每隔1mS 呼叫update_data副程式
>
> ser = serial.Serial("/dev/ttyACM0", 9600) # 設定串列傳輸裝置與傳輸速率
> root = tk.Tk()
> root.wm_title("Arduino DEMO")
> root.geometry("300x80+10+10")
> label1 = tk.Label(text="UART", font = ("Times", 18))
> label1.pack()
> label2 = tk.Label(text="", font = ("Times", 18))
> label2.pack()
> update_data()
> root.mainloop()
> ser.close() # 關閉串列傳輸
>
> ```
> AnaloginOutSerial.ino
> ```arduino=
> const int analogInPin = A0;
> int sensorValue = 0;
> void setup() {
> Serial.begin(9600);
> }
>
> void loop() {
> sensorValue = analogRead(analogInPin);
> Serial.println(sensorValue);
> delay(2);
> }
>
> ```
> * 找到A0腳位,根據感測器的腳位用杜邦線與arduino做連接
> <div class="flex-container"><img src="https://i.imgur.com/DqOue18.png" width="80%"></div></br>
>
> * 依序點選「軟體開發→ Arduino IDE」進入編輯環境
> <div class="flex-container"><img src="https://i.imgur.com/NhRl5Yt.png" width="80%"></div></br>
>
> * 撰寫完成,編譯並上傳資料
> <div class="flex-container"><img src="https://i.imgur.com/IBqadef.png" width="80%"></div></br>
>
> * 打開 Terminal,執行py檔
>
> ```bash
> $python3 /home/pi/fire_sensor.py
> ```
> * 便會看到GUI畫面,顯示類比讀值 (測試時請小心喔!)
> <div class="flex-container"><img src="https://i.imgur.com/MWh3eSy.gif" width="80%"></div></br>
## 從樹莓派控制 Arduino 輸出信號
利用樹莓派控制 Arduino 的 Pin13 腳位狀態,讓內建 LED 每隔 1 秒閃爍。
程式範例 : [led_control.py、ledOnOff.ino](https://drive.google.com/drive/folders/1hsrziYVtVaeiwk9dm6CWICJ4gxYR9voL?usp=sharing)
led_control.py
> ```python=
> import serial
> import time
>
> ser = serial.Serial('/dev/ttyACM0', 9600)
> prevtime = time.time() # 設定目前時間到pretime變數
> tt = '0'
> while 1:
> if time.time() - prevtime > 1: # 當間隔超過1秒
> if tt == '0':
> tt = '1' # 若之前輪出0,就改為輸出1
> else:
> tt = '0' # 若之前輪出1,就改為輸出0
> ser.write(tt.encode())
> #由於使用 time.sleep 會讓 serial 當機,所以需利用 time time技巧做1秒間隔的閃爍
> prevtime = time.time() # 重新設定目前時間
> ```
ledOnOff.ino
> ```arduino=
> // These constants won't change. They're used to give names to the pins used:
> const int analogInPin = A0; // Analog input pin that the potentiometer is attached to
> int sensorValue = 0;
> const int LedPin=13;
> void setup() {
> // initialize serial communications at 9600 bps:
> Serial.begin(9600);
> pinMode(LedPin,OUTPUT);
> digitalWrite(LedPin,LOW);
> }
>
> void loop() {
> // read the analog in value:
> sensorValue = analogRead(analogInPin);
> Serial.println(sensorValue);
> // wait 50 milliseconds before the next loop for the analog-to-digital
> // converter to settle after the last reading:
> delay(50);
> if(Serial.available()>0){
> char comdata=Serial.read();
> if(comdata=='0'){
> digitalWrite(LedPin,LOW);
> }
> if(comdata=='1'){
> digitalWrite(LedPin,HIGH);
> }
> }
> }
>
> ```
> * 依序點選「軟體開發→ Arduino IDE」進入編輯環境
> <div class="flex-container"><img src="https://i.imgur.com/NhRl5Yt.png" width="80%"></div></br>
>
> * 撰寫完成,編譯並上傳資料
> <div class="flex-container"><img src="https://i.imgur.com/ruH7Dee.png" width="80%"></div></br>
>
> * 打開 Terminal,執行py檔
>
> ```bash
> $python /home/pi/led_control.py
> ```
> * 觀察 Arduino 閃爍變化的速度是否也跟著改變,亮紅燈的LED以及下方左側LED即為對應D13的LED。
> <div class="flex-container"><img src="https://i.imgur.com/gt1yry7.gif" width="80%"></div></br>