Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pico 從 IoT 到 AIoT (Day 2)

Pico 從 IoT 到 AIoT (Day 2)

這是 Raspberry Pi Pico 入門套件的說明(Day 2)。

購買 Raspberry Pi Pico 入門套件(含 Pico)。
https://piepie.com.tw/39346/raspberry-pi-pico-starter-kit

範例程式。
https://github.com/piepie-tw/pico-aiot

台灣樹莓派

February 10, 2023
Tweet

More Decks by 台灣樹莓派

Other Decks in Technology

Transcript

  1. 姓名標示 — 非商業性 — 相同方式分享 CC (Creative Commons) 姓名標示 —

    你必須給予 適當表彰、提供指向本授權 條款的連結,以及 指出(本作品的原始版本)是否已 被變更。你可以任何合理方式為前述表彰,但不得以 任何方式暗示授權人為你或你的使用方式背書。 非商業性 — 你不得將本素材進行商業目的之使 用。 相同方式分享 — 若你重混、轉換本素材,或依本 素材建立新素材,你必須依本素材的授權條款來 散布你的貢獻物。
  2. • COSCUP, MakerConf, PyCon, HKOSCon 講者 • 投影片 • https://speakerdeck.com/piepie_tw

    • 程式碼 • https://github.com/piepie-tw • 台灣樹莓派網站 : • https://piepie.com.tw/ • Facebook: • https://www.facebook.com/RaspberryPi.Taiwan 分享 x 教學
  3. 6 • Raspberry Pi Pico 介紹 • 環境設定 • 輸入

    / 輸出 • 數位 / 類比 • I2C 協定 本次主題
  4. 8 • 數位 :0 與 1 的訊號 • 類比 :

    連續的訊號 數位與類比 http://www.bitscope.com/software/blog/DJ/?p=DJ19A
  5. 9 • 數位 : 亮和不亮 • 類比 : 亮 ,

    有點亮 , 有點不亮 ..., 不亮 • 可是 GPIO 腳位輸出都是固定值 , 怎麼辦? 從 LED 的角度來看
  6. 10 • 旋轉式 , 滑動式 • 線性關係 (B 型 ),

    對數關係 (A 型 ) • 常見規格 :0 -10k Ohm( 線性 ) 可變電阻 Potentiometer(VR) https://en.wikipedia.org/wiki/Potentiometer 接高電位 接低電位 滑動接點 ( 可變輸出 )
  7. 14 • 是將數位信號轉為脈波的一種技術 • 頻率不變 + 改變工作週期 , 使整體平均電壓值改變 •

    改變工作週期 (duty cycle)= 改變平均電壓 脈寬調變 (Pulse-Width Modulation) http://wiki.csie.ncku.edu.tw/embedded/PWM
  8. 15 • 輸出總功率 = 脈衝寬度 ( 時間 )x 高電位值 公式計算

    http://www.protostack.com/blog/2011/06/atmega168a-pulse-width-modulation-pwm/
  9. 16 • 建立PWM 實體: • p = machine.PWM(pin) # 預設freq=5kHz

    • 設定duty cycle: • p.duty_u16(dc) # set duty cycle, range 0-65535 • 讀取duty cycle: • p.duty_u16() # get current duty cycle • 關閉該腳位的PWM: • p.deinit() MicroPython PWM https://docs.micropython.org/en/latest/rp2/quickref.html
  10. 19 led = PWM(Pin(15)) • led.freq(100) led.duty_u16(0) while True: for

    dc in range(0, 65536, 4096): led.duty_u16(dc) utime.sleep(0.1) utime.sleep(2) for dc in range(65535, -2, -4096): led.duty_u16(dc) utime.sleep(0.1) utime.sleep(2) 呼吸燈就是漸明漸亮
  11. 23 • 工作電壓 :4.8V~6V • 工作電流 :100mA(4.8V)/120mA(6V) • 堵轉電流 :700mA(4.8V)/800mA(6V)

    • 扭矩 :1.3kg·cm(4.8V)/1.5kg·cm(6V) • 速度 :0.12s/60º(4.8V)/0.12s/60º(6V) • 轉動角度 :0(0.5ms)~180 度 (2.5ms) • 尺寸 :23x12.2x29mm • 重量 :9g SG90 塑膠齒輪伺服馬達 https://electronics.stackexchange.com/questions/246642/ power-supply-circuit-for-powering-sg90-servo-how-to-handle-high-current-require
  12. 25 接線圖 SERVO Pico 橘線 (ORANGE) Pin1 (GP0) 棕線 (BROWN)

    Pin3 (Ground) 紅線 (RED) 訊號線接 Pin1
  13. 27 • 頻率 =1/ 週期 • 週期 =On 時間 +Off

    時間 Duty Cycle 和週期 / 頻率的關係 https://circuitdigest.com/microcontroller-projects/ control-a-servo-motor-with-raspberry-pi-pico-using-pwm-in-micropython
  14. 28 • SG90 轉動角度 :0(0.5ms)~180 度 (2.5ms) • MicroPython 用

    0-65535 對應 0-100% DC • Duty Cycle = 2.5+( 角度 /180)*10 • 轉動角度 0 度 =65535*2.5%=1638( 取 1000) • 轉動角度 90 度 =65535*12.5%=8191( 取 9000) 從 Duty Cycle 轉換成時間和角度 脈寬 轉動角度 Duty Cycle 0.5ms 0 度 2.5% (0.5ms 高電位 + 19.5ms 低電位 ) 1ms 45 度 5% (1ms 高電位 + 19.0ms 低電位 ) 1.5ms 90 度 7.5% (1.5ms 高電位 + 18.5ms 低電位 ) 2.0ms 135 度 10% (2ms 高電位 + 18.0ms 低電位 ) 2.5ms 180 度 12.5% (2.5ms 高電位 + 17.5ms 低電位 )
  15. 29 servo = PWM(Pin(0)) servo.freq(50) servo.duty_u16(1000) • utime.sleep(5) • while

    True: for dc in range(1000, 9000, 50): servo.duty_u16(dc) utime.sleep(0.01) utime.sleep(1) for dc in range(9000, 1000, -50): servo.duty_u16(dc) utime.sleep(0.01) utime.sleep(1) 使用 PWM 控制伺服馬達 一開始先定位到 0 度
  16. 32 • 工作電壓 :4.8V~6V ( ) ✓ • 工作電流 :100mA(4.8V)/120mA(6V)

    (×) • 堵轉電流 :700mA(4.8V)/800mA(6V) (×) • Pico 的 GPIO 腳位無法提供足夠的電流 , 直接接 上 GPIO 有可能會燒毀 RP2040 SG90 這樣有什麼問題?
  17. 35 • 硫化鎘 (CdS) 或光敏電阻器 (LDR), 阻抗隨光落 在表面的總量而轉變 • 光越強阻值越小

    , 反之光越弱阻值則越大 • 應用 : 光控開關 , 電子玩具 , 工業控制 光敏電阻 http://www2.nkfust.edu.tw/~jlkuo2/31/a6.htm
  18. 36 • Pico 內建 3 個可用的 12bits ADC, 第四個用於內 建的溫度感測器

    (ADC4), 但在 MicroPython 會用 read_u16() 轉成 0~65535 之間的數字 類比訊號轉換為數位訊號 http://www.planetoftunes.com/digital-audio/how-do-analogue-to-digital-converters-work.html IN ADC OUT 此 ADC 的解析度為 4bits 從 0000 到 1111( 看 Y 軸 )
  19. 37 • ADC 轉換時間為 2μs 等於 500k/s( 頻率 ) •

    計算方式是由於 RP2040 預設時脈為 48MHZ, 而 ADC 需 96 CPU 週期 (clock cycle) 轉換 , 因此 每次轉換時間為 96 x 1 / 48MHz = 2μs • Pico 可用的 ADC 腳位有四個 , 但只有 3 個對外 RP2040 ADC 特色
  20. 40 • 由於 MCU 無法直接讀取電阻值 , 需透過分壓電路回推阻值 • 分壓電路是根據已知的 Vin,

    Vout, R2 計算未知的 R1 • Vin = 3.3V • Vout = ADC • R2 = 330Ω 分壓電路計算 https://www.elprocus.com/voltage-divider-rule-with-examples/
  21. 41 photoresistor = ADC(Pin(26)) • • def readADC(pin): • vout

    = photoresistor.read_u16() • vout = round((vout/65535)*3.3, 2) • r1 = 330*(3.3-vout)/vout • • return (vout, r1) • • while True: • vout = readADC(photoresistor)[0] • r1 = readADC(photoresistor)[1] • • print("Vout: " + str(vout) +" V") • print("R1: " + str(r1) +" ohm") • • utime.sleep(1) 用分壓電路計算光敏電阻阻值 用已知的 Vin, Vout, R2 計算未知的 R1
  22. 45 • MQ-2 感測器適用於檢測液化石油氣 (LPG), 例 如異丁烷 (C4H10), 丙烷 (C3H8),

    甲烷 (CH₄), 酒精 (C₂H₆O), 氫氣 (H2) 和煙霧 MQ-2 煙霧感測器 https://peppe8o.com/mq-2-with-raspberry-pi-pico-gas-sensor-wiring-and-micropython-code/
  23. 51 from machine import ADC, Pin • import utime •

    • mq2 = ADC(Pin(26)) • conversion_factor = 3.3 / (65535) • • while True: • value = mq2.read_u16() * conversion_factor • print("MQ-2:", value) • utime.sleep(1) 規格書建議預熱 24Hrs 讀出 0-65535(16-bits) 的數值 將讀出的數值正規化成電壓
  24. 55 • Pico 內建的溫度感測器連接到 AINSEL=4 的 ADC • 內建溫度感測器在 27

    攝氏度時 Vbe=0.706V, 斜 率為每度 -1.721mV Pico 內建溫度感測器 https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
  25. 57 from machine import ADC • • sensor_temp = machine.ADC(ADC.CORE_TEMP)

    • normalization = 3.3 / (65535) • • while True: • reading = sensor_temp.read_u16() * normalization • temperature = 27 - (reading - 0.706)/0.001721 • • print(temperature) • utime.sleep(1) 根據 ADC 數值計算溫度方程式 將讀出的數值正規化成電壓 溫度方程式
  26. 61 • Pico 的檔案系統大小為 1.375MB=4096*352 • LittleFS 目標是使用在 32KB RAM

    和 512KB ROM 和 4MB 存儲空間的 32 位元微控制器上 • 設計特點在於 • 能從任何寫操作期間從斷電中恢復 • 避免重複寫入同一個 block 降低 flash 耗損 • 和因應有限的 RAM 與 ROM 需簡化設計 Pico 的檔案管理系統 LittleFS https://hackmd.io/@RinHizakura/SJ8Sv7kBY https://github.com/littlefs-project/littlefs
  27. os.stat("FILE") 顯示檔案統計資訊 0. Type(Directory) 4000HEX = 16384Decimal (File) 8000HEX =

    32768Decimal 1. inode 2. Device 3. Number of Hard Links 4. User ID of Owner 5. Group ID of Owner 6. File Size 7. Time of most recent access 8. Time of most recent content modification 9. Time of most recent metadata change
  28. os.statvfs("/") 顯示檔案系統資訊 0. File system block size 1. Fragment size

    2. Size of the total file system in blocks 3. Number of free blocks 4. Number of free blocks for unprivileged users 5. Number of nodes 6. Number of free inodes 7. Number of free inodes for unprivileged users 8. Mount flags 9. Maximum filename length
  29. 68 • os.listdir() # 列出檔案和目錄 • os.mkdir() # 建立目錄 •

    os.chdir() # 切換目錄 • os.getcwd() # 列出所在目錄 • os.rmdir() # 刪除目錄 • os.remove() # 刪除檔案 • os.rename() # 更換檔案或目錄名稱 更多 os 函式 https://docs.micropython.org/en/latest/library/os.html
  30. 69 file = open("test.txt", "w") • file.write("Hello, File!\n") • file.close()

    • • file = open("test.txt") • line=file.readline() • print(line) • file.close() • • file = open("test.txt", "a") • file.write("Append, Hello!\n") • file.close() • • file = open("test.txt") • line=file.readline() • line=file.readline() • print(line) • file.close() 開檔 / 寫檔 / 讀檔 / 關檔 開檔 寫檔 關檔 讀檔
  31. 73 • 1602 LCD 表示有 16 欄 2 列 ,

    共可顯示 32 字元 • 每個字元由 5x8 像素組成 1602 LCD https://how2electronics.com/interfacing-16x2-lcd-display-with-raspberry-pi-pico/ 16 欄 2 列 每個字元由 5x8 像素組成
  32. 74 • 要處理 1602 LCD 顯示 , 每次需要處理 5x8x32 像

    素的位置 , 因此通常會透過 HD44780 IC, 幫忙從 MCU 獲取命令和資訊並在 LCD 顯示有意義的資訊 • HD44780 靠 RS 腳位初始化 ,E 腳位做命令控制 1602 LCD 顯示
  33. 76 透過 I2C 通訊簡化接線 (PCF8574T) I2C LCD Pico 黑線 (GND)

    Pin3 (GND) 紅線 (Vcc) Pin40 (5V) 藍線 (SDA) Pin1 (GP0) 紫線 (SCL) Pin2 (GP1)
  34. 78 • 全名為 Inter-Integrated Circuit Bus, 是 1982 年由荷蘭飛利浦半導體公司所開發 ,

    設計目 的是讓 MCU 連接眾多的低速週邊裝置 • I2C 是同步傳輸界面 , 僅需兩條接線 , 是半雙工 • I2C 是主從式架構 , 以匯流排型式介接 , 可以有 多個 master 和多個 slave, 個別有位址通訊用 I2C 通訊介紹 https://magicjackting.pixnet.net/blog/post/173061691
  35. 79 • I2C 位址空間為 7 bits, 可定址 128 個地址 ,

    但保留 16 個地址作為系統擴充使用 , 因此理論可 同時使用 112=128-16 個節點 • I2C Bus 的傳輸都是由 master 端發起 ,slave 只能就 master 送出的命令作出回應 • 訊號傳輸為 8 bits, 外加 1 bit 的 ACK/NACK I2C 通訊介紹 https://magicjackting.pixnet.net/blog/post/173061691
  36. 80 • 優點 : • 電路簡單 , 僅需兩條線就可以進行同步傳輸 • 可連接多個週邊裝置

    , 方便當 IC 間溝通的橋樑 • 缺點: • 速度慢 , • 不適合長距離的傳輸 • 不支援不同工作電壓的晶片連接 I2C 優缺點
  37. 82 from machine import Pin, I2C sda = Pin(0) scl

    = Pin(1) i2c = I2C(0, sda=sda, scl=scl, freq=200000) print(i2c.scan()) 先掃描 I2C Address PCF8574T I2C 頻率使用 200K
  38. 86 from lcd_api import LcdApi • from pico_i2c_lcd import I2cLcd

    • I2C_ADDR = 0x27 I2C_NUM_ROWS = 2 I2C_NUM_COLS = 16 sda = Pin(0) scl = Pin(1) i2c = I2C(0, sda=sda, scl=scl, freq=200000) lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS) • lcd.move_to(5, 0) lcd.putstr("It Works!") utime.sleep(5) lcd.clear() 使用 pico_i2c_lcd 移動游標 I2C Address (x, y)
  39. 88 • 每個字元由 5x8 像素組成 自定義圖形 0x02, 0x00, 0x00, 0x00,

    0x00, 0x00, 0x00, 0x01 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  40. 92 lcd.custom_char(0, bytearray([ 0x0E, • 0x11, • 0x11, • 0x02,

    • 0x04, • 0x04, • 0x00, • 0x04])) • lcd.move_to(0, 0) • lcd.putstr(chr(0)) • utime.sleep(10) • lcd.clear() 將剛剛記錄下來的值貼上去 自定義圖形
  41. 94 i2c = I2C(0, sda=sda, scl=scl, freq=200000) • lcd =

    I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS) • • lcd.clear() • lcd.show_cursor() # Turning cursor on • lcd.hide_cursor() # Turning cursor off • lcd.blink_cursor_on() # Turning blink cursor on • lcd.blink_cursor_off() # Turning blink cursor off • lcd.backlight_off() # Turning backlight off • lcd.backlight_on() # Turning backlight on • lcd.display_off() # Turning display off • lcd.display_on() # Turning display on 更多控制 LCD 的範例
  42. 96 • Qwiic 是由美國的 SparkFun 所設計的界面 , 可讓多 種 I2C

    設備快速連接 , 特點為 • 使用 4-pin JST 接頭最為唯一接頭 • Qwiic 接頭的腳位是固定的 , 避免 SDA 和 SCL 反接 • 可在開發板上建立多個接頭 , 方便設備串接 • 可串接多個設備 , 並達到 1 米長度的通訊 • 但目前 Qwiic 只支援 3.3V 逐漸流行的 Qwiic 界面
  43. 99 • 如何控制紅色黃色共兩個 LED, 紅色 LED 每 1 秒 閃一次

    , 黃色 LED 每 0.5 秒閃一次? • 由於 MicroPython 程式是循序執行 , 可以用 • 1. 計時器 (Timer) 定時執行 • 2. 多執行緒 (multi-thread) 分別執行 問題
  44. 100 接線圖 紅 LED Pico 長腳 (RED) Pin20 (GPIO15) 短腳

    (BLACK) Pin38 (Ground) 黃 LED Pico 長腳 (YELLOW) Pin19 (GPIO14) 短腳 (BLACK) Pin38 (Ground)
  45. 103 • 並行 (Concurrency) 通常指 multitasking • 如果有很多 CPU 時

    , 就可以”同時”執行多個工作 Multitasking vs. Parallel Processing http://www.dabeaz.com/usenix2009/concurrent/
  46. 104 • 一個工作 (task) 可以拆成多個 process 執行 • 但有多個 process

    就需要透過 IPC 溝通 • 常用的 IPC 有 Pipes, FIFOs, shared memory Multi-Processes http://www.dabeaz.com/usenix2009/concurrent/
  47. 105 • Thread( 執行緒 ) 是最小的執行單位 , 也稱為 light-weight process

    • 一個 process( 行程 ) 最少有一個 thread Process vs. Thread https://sites.google.com/site/sureshdevang/thread-vs-process process
  48. 106 • 如果講 "concurrent programming", 大部 分的 programmer 想的是 multi-threading

    • 一個行程裡可獨立運行的工作 • 在行程中共享記憶體 , 檔案 , 或是網路連線等 • 每個執行緒有獨立的執行流程與資源 (stack, current instruction 等等 ) Threads http://www.dabeaz.com/usenix2009/concurrent/
  49. 107 • $ python program.py 慢動作拆解 Threads statement statement 當程式

    (program) 被載入以後 , 會順序執行 statement “main thread” http://www.dabeaz.com/usenix2009/concurrent/
  50. 108 • $ python program.py create thread(foo) def foo(): 慢動作拆解

    Threads statement statement 建立一個執行緒 (thread), 並執行 foo() http://www.dabeaz.com/usenix2009/concurrent/
  51. 109 • $ python program.py create thread(foo) def foo(): 慢動作拆解

    Threads statement statement statement statement ...... statement statement ...... 同時執行 statement http://www.dabeaz.com/usenix2009/concurrent/
  52. 110 • $ python program.py create thread(foo) def foo(): 慢動作拆解

    Threads statement statement statement statement statement statement ...... statement statement ...... return or exit 執行緒結束後 , 返回 (return) 或是離開 (exit) http://www.dabeaz.com/usenix2009/concurrent/
  53. 111 • $ python program.py create thread(foo) def foo(): 慢動作拆解

    Threads statement statement statement statement statement statement ...... statement statement ...... return or exit 執行緒像是一個小工作 (task) 獨立在行程中 http://www.dabeaz.com/usenix2009/concurrent/
  54. 112 • 雙核心可同時執行兩個執行緒 , 預設 Core0 執行 所有任務 ,Core1 保持空閒或待機模式

    RP2040 雙核心 ,Core0 和 Core1 https://microcontrollerslab.com/dual-core-raspberry-pi-pico-programming-micropython/
  55. 113 • 每個核心分別執行自己的程式 , 並各自有獨立的程 式碼和記憶體空間 , 雙核心通訊採 FIFO( 先進先

    出 ) 雙核心通訊 https://www.theengineeringprojects.com/2022/05/raspberry-pi-pico-dual-core-programming-with-micropython.html
  56. 114 • 1. 主執行緒使用 core0 • 2. 當執行 start_new_thread(), 由

    core1 產 生新的執行緒 , 並將 function 當參數傳入執行 用 _thread 模組產生新的執行緒
  57. 115 import _thread • red = Pin(16, Pin.OUT) green =

    Pin(15, Pin.OUT) def core0_thread(t): for i in range(t): red.toggle() utime.sleep(0.5) def core1_thread(t): for i in range(t): green.toggle() utime.sleep(1) _thread.start_new_thread(core1_thread, (20,)) core0_thread(10) • 將 function 當作參數傳入 core1 建立執行緒 , 並傳入函式執行