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

用 Raspberry Pi 學 GPIO - 自己做遊戲機(Pi 5適用)

用 Raspberry Pi 學 GPIO - 自己做遊戲機(Pi 5適用)

已更新到最新版本,適合 Pi 5 + Bookworm/Trixie

用 Raspberry Pi 學 GPIO。
- 由淺入深,從 20 個實驗介紹 “數位/類比 x 輸入/輸出”。
- 硬體包括 Raspberry Pi,GPIO 遊戲機學習套件。
- 支援Pi 5/Pi 4/Pi 3B+/Pi 3B/Pi 2/Pi Zero 系列。

購買GPIO學習套件:
https://www.piepie.com.tw/buy/2557/

範例程式下載:
https://github.com/piepie-tw/gpio-game-console

Avatar for 台灣樹莓派

台灣樹莓派 PRO

January 25, 2015

Video

More Decks by 台灣樹莓派

Other Decks in Technology

Transcript

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

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

    • ☑ Raspberry Pi 5B ☑ Raspberry Pi Zero 2W ☑ Raspberry Pi 4B ☑ Raspberry Pi 3B+ ☑ Raspberry Pi 3A+ ☑ Raspberry Pi Zero W ☑ Raspberry Pi 3B ☑ Raspberry Pi 2B ☑ Raspberry Pi B+ ☑ Raspberry Pi Model B 6
  3. 本次主題 • Raspberry Pi GPIO 介紹 環境設定 • 輸入 /

    輸出 • 數位 / 類比 • 練習與實做 • 7
  4. 今日環境 • • 硬體 :Raspberry Pi 5B 作業系統 :2026-06-18-raspios-trixiearm64-full.img •

    系統下載: https://reurl.cc/yWMryO • 燒錄系統: https://reurl.cc/Vn1D6R 9
  5. 安裝今日所需套件 • $ sudo apt update • $ sudo apt

    remove python3-rpi.gpio • • $ sudo apt install -y python3-dev python3-pip libsdl1.2-dev $ sudo apt install -y python3-evdev python3-libevdev python3-rpi-lgpio python3-spidev 10
  6. 什麼是 GPIO ? • General Purpose Input Output • GPIO

    是一種可用軟體控制的數位訊號 http://www.tek.com/datasheet/tps2000b-series-digital-storage-oscilloscopes-datasheet 12
  7. 幾個 GPIO 的數字 • GPIO 高電位輸出為 3.3V • GPIO 容忍輸入電位為

    3.3V • 單一 Pin 輸出電流為 3mA-16mA • 全部 Pin 輸出總和小於 50mA • GPIO 輸入低電位為小於 0.8V, 高電位大於 1.3V https://www.scribd.com/doc/101830961/GPIO-Pads-Control2 15
  8. 如何控制 Raspberry Pi 的 GPIO ? • C • C

    + wiringPi • C# • Ruby • Perl • Python • Scratch • Java Pi4J Library • Shell script 16
  9. GPIO Benchmark • Python + RPi.GPIO = 70 kHz •

    C + BCM 2835 = 5.4 MHz • Ruby + wiringpi bindings = 21 kHz http://www.tek.com/datasheet/tps2000b-series-digital-storage-oscilloscopes-datasheet 17
  10. Python3 五分鐘速成 • 變數 , 物件 , 型別 , 註解

    模組 • 縮排 • 迴圈 • 條件判斷 • 函式 • 19
  11. 變數 , 物件 , 型別 , 註解 • 動態型別 (dynamic

    typing) # 這是註解 i = 3 # 變數 i 指到數字物件 3 i = [1, 2, 3, 4, 5]# 變數 i 指到串列物件 print(i[2]) i = "abcde" print(i[2]) # 印出串列中第三個元素 # 變數 i 指到字串物件 # 印出字串中第三個元素 20
  12. 迴圈 • 自動迭代 (iterator) for i in range(start, stop[, step]):

    process for i in range(0, 11, 5): print(i) 23
  13. 兩種執行 Python 的方法 • • 1. 存成檔案以後 , 用 python

    執行 • $ nano test.py • $ python3 test.py 2. 進到互動模式 , 可直接看輸出結果 • • • • $ python3 Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> 26
  14. 電子入門套件 • 紅 / 黃 / 綠 LED x2 •

    1/4W 電阻 ,1Kx5,2Kx5 • 830 洞大型麵包板 x1 • 按鍵 x4 • 蜂鳴器 x2 • 人體紅外線感測器 (PIR) x1 • 傾斜開關 x1 • MCP3008 ADC IC x1 • 光敏電阻 x1 • XY 搖桿 x1 • HC-SR04 超音波距離感測器 • 10K 可變電阻 • 20pin 公對公 / 公對母 / 母對母排線 x1 27
  15. LED 發光二極體 • 單向導通 • 省電 • 短腳接負極 GND 長腳接正極

    Vcc http://upload.wikimedia.org/wikipedia/commons/c/c8/5mm_Red_LED.jpg 31
  16. 電路一分鐘速成 • 電路組成元件 : 電源、導線、負載 • 閉路 : 當三者形成一完整路徑 ,

    有電流經過電路 I I V R V R I • 歐姆定律 : 導體兩端的電壓與通過的電流成正比 • V=IxR https://zh.wikipedia.org/wiki/ 电路 32
  17. 如何解讀? • 在順向電壓下一般的 LED 能承受的安全電流是 20mA • 由於順向電壓 (Typical) 為

    1.85V • Raspberry Pi 的 GPIO 腳位能提供 3.3V • 計算公式:電阻 = 電壓 / 電流 R =V/I R =(3.3-1.85)/0.02=72.5 歐姆 • 表示最小要接 72.5 歐姆的電阻 , 才能避免 LED 燒毀 35
  18. 電阻阻值計算 四環:右側為金或銀 1K= 棕黑黑棕 ( 棕 ) 2K= 紅黑黑棕 (

    棕 ) 五環:前四環很靠近 www.digikey.tw/tw/zht/mkt/5-band-resistors.html 36
  19. 接線圖 LED 長腳 (RED) 短腳 (BLACK) RPi Pin12 (GPIO18) Pin6

    (Ground) 1k 電阻 : 棕黑黑棕 ( 棕 ) 39
  20. 接線圖 LED 長腳 (RED) 短腳 (BLACK) RPi Pin12 (GPIO18) Pin6

    (Ground) 1k 電阻 : 棕黑黑棕 ( 棕 ) 40
  21. Python Code 基本流程 • 載入模組 (Import module) • 選擇編號系統 (Define

    pin numbering) • 定義腳位 (Setup up a channel) • 讀取輸入 / 寫入輸出 (Input/Output) • 清理 (Cleanup) http://code.google.com/p/raspberry-gpio-python/wiki/BasicUsage 47
  22. 一個實際的範例 #!/usr/bin/python3 • import RPi.GPIO as GPIO # Import module

    import time 以下都是使用別名 (alias) GPIO.setmode(GPIO.BOARD) # Define pin numbering LED_PIN = 12 GPIO.setup(LED_PIN, GPIO.OUT) # Setup up a channel print("LED is on") GPIO.output(LED_PIN, GPIO.HIGH) # Input/Output status time.sleep(3) GPIO.cleanup() # Cleanup 48
  23. nano 編輯器使用 使用 :nano < 檔名 , 例如 led_on.py> 離開

    :Ctrl + x > 令存新檔 :y > 不存離開 :n > 離開 :Ctrl + c 50
  24. 執行方式 $ cd ~ $ git clone https://github.com/piepie-tw/gpio-game-console $ cd

    ~/gpio-game-console $ cd 01-led_on $ python3 led_on.py 51
  25. 更多 RPi.GPIO 的使用方法 • Wiki • • Code • •

    http://sourceforge.net/p/raspberry-gpio-python/wiki/ Home/ http://sourceforge.net/p/raspberry-gpio-python/code/ ci/default/tree/ Reference detail • http://elinux.org/RPi_Low-level_peripherals • http://elinux.org/RPi_BCM2835_GPIOs • http://www.raspberrypi.org/wp-content/uploads/2012/02/ 52 BCM2835-ARM-Peripherals.pdf
  26. 永不停止的 while 迴圈 - 按 Ctrl+c 跳出迴圈 GPIO.setmode(GPIO.BOARD) LED_PIN =

    12 GPIO.setup(LED_PIN, GPIO.OUT) while True: print("LED is on") GPIO.output(LED_PIN, GPIO.HIGH) time.sleep(1) print("LED is off") GPIO.output(LED_PIN, GPIO.LOW) time.sleep(1) 55 GPIO.cleanup()
  27. RuntimeWarning: This channel is already in use, continuing anyway. Use

    GPIO.setwarnings(False) to disable warnings. 說明: 該警告在 Bookworm 之後版本是使用 rpi-lgpio 套件,因此不會看到。 因為舊版 RPI.GPIO 是將暫存寄直接映射到記憶體後操作硬體, 而 rpi-lgpio 是採用 Linux 核心標準的 GPIO character device 介面。 但建議使用者還是注意 GPIO.cleanup() 函式的使用時機和程式邏輯。57
  28. 為什麼出現 Warning ? 說明: 該警告在 Bookworm 之後版本是使用 rpi-lgpio 套件,因此不會看到。 因為舊版

    RPI.GPIO 是將暫存寄直接映射到記憶體後操作硬體, 而 rpi-lgpio 是採用 Linux 核心標準的 GPIO character device 介面。 但建議使用者還是注意 GPIO.cleanup() 函式的使用時機和程式邏輯。58
  29. 接住例外 try: while True: print "LED is on" GPIO.output(LED_PIN, GPIO.HIGH)

    time.sleep(1) print("LED is off") GPIO.output(LED_PIN, GPIO.LOW) time.sleep(1) except KeyboardInterrupt: print("Exception: KeyboardInterrupt") finally: GPIO.cleanup() 60
  30. 設計一個紅綠燈 • 紅 , 黃 , 綠燈依序亮燈 • 紅燈亮 4

    秒 , 黃燈亮 2 秒 , 綠燈亮 4 秒 http://www.clipartbest.com/traffic-light-photo 63
  31. 把亮燈拿到外面 def traffic_light(pin, duration): GPIO.output(pin, GPIO.HIGH) time.sleep(duration) GPIO.output(pin, GPIO.LOW) try

    : while True: traffic_light(RED_PIN, 4); traffic_light(YEL_PIN, 2); traffic_light(GRN_PIN, 4); finally: GPIO.cleanup() 66
  32. 按鍵 Button / 開關 Switch • 常開 (normally open, N.O.)

    • 常閉 (normally close, N.C.) 71 http://www.engineersgarage.com/sites/default/files/imagecache/Original/wysiwyg_imageupload/4214/Switch-2_0.jpg
  33. 按鍵的內部結構 1 2 • 按下前 長邊相連 (1&2,3&4) • 短邊不相連 •

    3 4 • 按下後 • 四點都通 http://www.ladyada.net/learn/arduino/lesson5.html 72
  34. 判斷條件 : 這次低 && 上次高 BTN_PIN = 11 GPIO.setup(BTN_PIN, GPIO.IN)

    previous_status = None try: while True: digital_input = GPIO.input(BTN_PIN) if digital_input == GPIO.LOW and previous_status == GPIO.HIGH: print("Button pressed") previous_status = digital_input except KeyboardInterrupt: print("Exception: KeyboardInterrupt") finally: GPIO.cleanup() 77
  35. 解決彈跳問題 (de-bounce) • 硬體方法 : 以 RC 電路或正回授的比較器電路解決 • 軟體方法

    : 調整觸發的延遲時間 • 不同的按鍵會有不同的延遲時間 10ms - 20ms 81
  36. 不反應在延遲時間內的觸發 GPIO.setup(BTN_PIN, GPIO.IN) previous_status = None previous_time = time.time() current_time

    = None try: while True: digital_input = GPIO.input(BTN_PIN) current_time = time.time() if digital_input == GPIO.LOW and \ previous_status == GPIO.HIGH and \ (current_time - previous_time) > 0.2: previous_time = current_time print("Button pressed”) previous_status = digital_input 82
  37. 如何看系統效能? • PID • 先以背景方式執行單一程式 ( 加上 &) • $

    python3 push_button_debounce.py & 再看整體系統使用狀況 ( 可以按 q 離開 ) • $ top -c 85
  38. 中斷的程式寫法 • 建立回呼函數 • • def mycallback() 綁定事件和回呼函數 • add_event_detect(gpio,

    # 對象 edge, # 觸發條件 callback, # 回呼函數 bouncetime) • 多個事件可以綁定同樣的回呼函數 source/py_gpio.c 89
  39. 即使在 sleep 狀態下也可立即回應 BTN_PIN = 11 GPIO.setup(BTN_PIN, GPIO.IN) def mycallback(channel):

    print("Button pressed") try: GPIO.add_event_detect(BTN_PIN, \ GPIO.FALLING, \ callback=mycallback, \ bouncetime=200) while True: time.sleep(10) finally: GPIO.cleanup() 90
  40. 中斷的意義 需要硬體或軟體 ( 作業系統 ) 的支援 • RPi.GPIO 在版本 0.5.0a

    有了中斷功能 • 加上 add_event_detect() 等機制 • RPi.GPIO 以建立多執行緒方式實現中斷 • 程式開始執行時 , 主執行序運行 • 當加入事件後 , 以 epoll_create 建立新的 fd • 當事件觸發時 , 第二個執行序和主執行序溝通 ( 回 呼) • 程式碼可參考 source/event_gpio.c • source/py_gpio.c 94
  41. 要搭配內建的上拉電阻 (50k) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) def mycallback(channel): print("Button pressed") try:

    GPIO.add_event_detect(BTN_PIN, \ GPIO.FALLING, \ callback=mycallback, \ bouncetime=WAIT_TIME) while True: time.sleep(10) finally: GPIO.cleanup() 96
  42. 要搭配內建的上拉電阻 (50k) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) def mycallback(channel): print("Button pressed") try:

    GPIO.add_event_detect(BTN_PIN, \ GPIO.FALLING, \ callback=mycallback, \ bouncetime=WAIT_TIME) while True: time.sleep(10) finally: GPIO.cleanup() 101
  43. 原理 • • • 發聲原理 : 聲音是由振動產生 , 其頻率稱為音頻 蜂鳴器發聲原理

    : 電流 (6) 通過電磁線圈 (3) 產生 磁場來驅動振動膜 (11) 人耳可聽到 20Hz - 20KHz http://www.itianer.com/diancishifengmingqigouzaoyuyuanlijieshao.html 104
  44. 蜂鳴器 Buzzer • 自激 ( 有源 ): 只能發出同頻率的聲音 • •

    黑膠封裝 , 高低腳 他激 ( 無源 ): 需從外部輸入震盪方波發聲 • 綠色電路板 , 兩腳同長 • 腳位有正負之分 ( 看底板 ) 自激式 他激式 http://www.buzzer-speaker.com/manufacturer/piezo%20buzzer.htm 105
  45. 可發出不同頻率聲音 def buzz(pitch, duration) : period = 1.0 / pitch

    half_period = period / 2 cycles = int(duration * pitch) for i in range(cycles) : GPIO.output(buzzer_pin, GPIO.HIGH) time.sleep(half_period) GPIO.output(buzzer_pin, GPIO.LOW) time.sleep(half_period) while True : pitch_s = input("Enter Pitch (200 to 2000): ") duration_s = input("Enter Duration (seconde): ") buzz(float(pitch_s), float(duration_s)) 107
  46. 鋼琴模擬 0 2 4 6 8 • 1 3 5

    • 標準 88 鍵鋼琴 , 每個音的頻率 : • 每段音階分為 12 個半音 • 每個音的頻率是前一個的 1.05946 倍 ( http://en.wikipedia.org/wiki/Piano_key_frequencies 7 12 2 ) 109
  47. 鋼琴頻率 • 標準 88 鍵鋼琴 , 以第 49 鍵 A4

    為基準 (440Hz) • 各半音頻率如下: • C5 (52th, DO): 523Hz • D5 (54th, RE): 587Hz • E5 (56th, ME): 659Hz • F5 (57th, FA): 698Hz • G5 (59th, SO): 784Hz • A5 (61th, LA): 880Hz • B5 (63th, SI): 988Hz http://en.wikipedia.org/wiki/Piano_key_frequencies 110
  48. 線路圖 RPi Pin7 Buzzer Pin11 Do Pin12 Re Pin13 Me

    Pin15 Fa Pin16 So Pin18 La Pin22 Si 111
  49. 瞭解規格 • 輸入電壓 :DC 3.3V - 24V • 輸出電壓 :3.3V(

    可直接接上 Raspberry Pi) • 延遲時間 (Tx):2.45 秒 – 248 秒 感應之後輸出維持的時間 • 封鎖時間 (Ti):2.4 秒 • • 感應輸出結束之後 , 再次觸發必須等待的時間 • 感應角度 :110 度 x 70 度 • 感應距離 :3 米 - 7 米 118
  50. 感測距離 / 延遲時間設定 • • 感測距離設定 • 順時針 : 最高為

    7 米 • 逆時針 : 最小為 3 米 延遲時間設定 (Tx) • • • 順時針 : 最長為 248 秒 逆時針 : 最短為 2.45 秒 感測距離設定 延遲時間設定 實際可調整時間要看 R10,C6,R9,C7 而定 119
  51. 觸發模式 • 可重複觸發模式 (H) • 不可重複觸發模式 (L) H: 可重複觸發 感應

    & 輸出 感應 & 等待 & 輸出 L: 不可重複觸發 ( 預設 ) 120
  52. 再一次使用 interrupt 模式 PIR_PIN = 16 GPIO.setup(PIR_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) def

    mycallback(channel): print("Motion detected") try: GPIO.add_event_detect(PIR_PIN, GPIO.RISING, \ callback=mycallback, \ bouncetime=200) while True: time.sleep(1) finally: GPIO.cleanup() 122
  53. 偵測到人 , 燈閃 3 次 LED_PIN = 12 PIR_PIN =

    16 GPIO.setup(PIR_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.setup(LED_PIN, GPIO.OUT) def mycallback(channel): print("Motion detected") for i in range(3) : GPIO.output(LED_PIN, GPIO.HIGH) time.sleep(0.5) GPIO.output(LED_PIN, GPIO.LOW) time.sleep(0.5) try: GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=mycallback, bouncetime=200) while True: time.sleep(1) 127
  54. 測距離原理 • 聲音在 20°C (68°F) 的速度是 343 公尺 / 秒

    • 溫度每增加 1°, 速度增加 0.6 公尺 / 秒 http://en.wikipedia.org/wiki/Speed_of_sound 129 https://www.modmypi.com/blog/hc-sr04-ultrasonic-range-sensor-on-the-raspberry-pi
  55. HC-SR04 超音波距離感測器 • 內建發射 (40kHz) 與接收電路 • 根據發射與接收的時間差計算距離 • 特殊功能

    :US-020( 長距離 ) 、 US-100( 溫度補 償) http://coopermaa2nd.blogspot.tw/2012/09/hc-sr04.html 130
  56. 分壓電路計算 • TRIG 腳位收到高電位 (3.3V) 後發送超聲波 • ECHO 腳位維持低電位 (0V),

    收到回應後拉到高電位 (5V) • Raspberry Pi 腳位的容忍電位為 3.3V => 將 ECHO 腳位的 5V 降壓為 3.3V 左右 => R1=1K, R2 取 2K 135 https://www.modmypi.com/blog/hc-sr04-ultrasonic-range-sensor-on-the-raspberry-pi
  57. 注意 1K, 2K 電阻 Gnd Echo Trig Vcc 這是背面 1k:

    棕黑黑棕 2k: 紅黑黑棕 ULTRASONIC Vcc(RED) Trig(YELLOW) Echo(PURPLE) Grnd(BLACK) RPi Pin2 (5V) Pin16 (GPIO23) Pin18 (GPIO24) Pin6 (Ground) 136
  58. 測量距離 v = 343 # (331 + 0.6*20) def measure()

    : GPIO.output(TRIGGER_PIN, GPIO.HIGH) time.sleep(0.00001) # 10uS GPIO.output(TRIGGER_PIN, GPIO.LOW) pulse_start = None pulse_end = None while GPIO.input(ECHO_PIN) == GPIO.LOW: pulse_start = time.time() while GPIO.input(ECHO_PIN) == GPIO.HIGH: pulse_end = time.time() t = pulse_end - pulse_start d = t * v d = d/2 return d*100 137
  59. 數位與類比 • 數位 :0 與 1 的訊號 • 類比 :

    連續的訊號 http://www.bitscope.com/software/blog/DJ/?p=DJ19A 141
  60. 從 LED 的角度來看 • 數位 : 亮和不亮 • 類比 :

    亮 , 有點亮 , 有點不亮 ..., 不亮 • 可是 GPIO 腳位輸出都是固定值 , 怎麼辦? 142
  61. 可變電阻 Potentiometer(VR) • 旋轉式 , 滑動式 • 線性關係 (B 型

    ), 對數關係 (A 型 ) • 常見規格 :0 -10k Ohm( 線性 ) 接低電位 滑動接點 ( 可變輸出 ) 接高電位 https://en.wikipedia.org/wiki/Potentiometer 143
  62. 脈寬調變 (Pulse-Width Modulation) • 是將數位信號轉為脈波的一種技術 • 頻率不變 + 改變工作週期 ,

    使整體平均電壓值改變 • 改變工作週期 (duty cycle)= 改變平均電壓 http://wiki.csie.ncku.edu.tw/embedded/PWM 146
  63. 公式計算 • 輸出總功率 = 脈衝寬度 ( 時間 )x 高電位值 147

    http://www.protostack.com/blog/2011/06/atmega168a-pulse-width-modulation-pwm/
  64. GPIO.PWM() • To create a PWM instance: • • To

    start PWM: • • p.start(dc) # dc is the duty cycle To change the duty cycle: • • p = GPIO.PWM(channel, frequency) p.ChangeDutyCycle(dc) # where 0.0 <= dc <= 100.0 To stop PWM: • p.stop() 148 http://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/
  65. 互動式的調光 LED_PIN = 12 • GPIO.setup(LED_PIN, GPIO.OUT) pwm_led = GPIO.PWM(LED_PIN,

    100) • pwm_led.start(0) • • • try: while True: • duty_s = input("Enter Brightness (0 to 100):") • duty = int(duty_s) • • • if duty >= 0 and duty <=100 : pwm_led.ChangeDutyCycle(duty) • • except KeyboardInterrupt: • pwm_led.stop() • GPIO.cleanup() 150
  66. 呼吸燈就是漸明漸亮 LED_PIN = 12 GPIO.setup(LED_PIN, GPIO.OUT) pwm_led = GPIO.PWM(LED_PIN, 100)

    pwm_led.start(0) while True: for dc in range(0, 101, 5): pwm_led.ChangeDutyCycle(dc) time.sleep(0.1) time.sleep(0.5) for dc in range(100, -1, -5): pwm_led.ChangeDutyCycle(dc) time.sleep(0.1) time.sleep(0.5) 152
  67. Software PWM vs. Hardware PWM • • • • 兩者差異

    • Software PWM 是透過 kernel 做 duty cycle 的調整 • Hardware PWM 是 SoC 透過 DMA 做調整 使用時機 • 不需要精準時用 Software PWM, 例如 LED 調光 • 需要低延遲時用 Hardware PWM, 例如伺服馬達 Hardware PWM GPIO 只有 GPIO12(Pin32), GPIO13(Pin33), GPIO18(Pin12), GPIO19(Pin35) 目前已經內建 pigpio 提供 Hardware PWM 函式呼叫 154
  68. 光敏電阻 • 硫化鎘 (CdS) 或光敏電阻器 (LDR), 阻抗隨光落 在表面的總量而轉變 • 光越強阻值越小

    , 反之光越弱阻值則越大 • 應用 : 光控開關 , 電子玩具 , 工業控制 http://www2.nkfust.edu.tw/~jlkuo2/31/a6.htm 156
  69. 類比訊號轉換為數位訊號 • Raspberry Pi 沒有硬體的類比數位轉換器 (ADC) IN ADC OUT 此

    ADC 的解析度為 4bits 從 0000 到 1111( 看 Y 軸 ) 157 http://www.planetoftunes.com/digital-audio/how-do-analogue-to-digital-converters-work.html
  70. Serial Peripheral Interface(SPI) • 主從式架構 , 可一對多 • 四線同步序列資料協定 •

    SS: 週邊選擇線 (CE) • SCK: 序列時脈線 (SCLK) • MOSI: 主往從送 • SPI Master SCLK MOSI MISO SS1 SS2 SS3 MISO: 從往主送 https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus SCLK MOSI MISO SS SPI Slave SCLK MOSI MISO SS SPI Slave SCLK MOSI MISO SS SPI Slave 159
  71. SPI 使用前的確認 • 測試確認 SPI 模組已載入 • • $ ls

    /dev/spidev* 安裝必要套件 ( 如果前面已裝過 , 就不需再裝 ) • $ sudo apt-get update • $ sudo apt-get install python3-spidev 163
  72. MCP3008 CLK Din Dout CS RPi Pin23 (SCLK) Pin19 (MOSI)

    Pin21 (MISO) Pin24 (CE0) 接線圖 1k 電阻 缺口朝左 164
  73. spi = spidev.SpiDev() spi.open(0,0) # (0,0) 表示接到 CE0 腳位 ,

    對應到 /dev/spidev0.0 裝置檔 spi.max_speed_hz = 1800000 # 10kHz to 3.6 MHz • • def read_channel(channel): adc = spi.xfer2([1,(8+channel)<<4,0]) data = ((adc[1]&3) << 8) + adc[2] return data def convert_volts(data, places): volts = (data * 3.3) / float(1023) volts = round(volts,places) return volts light_channel = 0 delay = 1 while True: light_level = read_channel(light_channel) light_volts = convert_volts(light_level, 2) print("Light:{} ({}V)".format(light_level,light_volts)) time.sleep(delay) 166
  74. 了解 spi.xfer2() 的意義 • input 一次送三個 bytes • # byte

    1: the start bit (always 0x01) • # byte 2: configure bits • # byte 3: don't care 0x01 Ch0/Ch1 • don't care spi.xfer2([1,(8+channel)<<4,0]) • Ch0 = 1000 0000 • Ch1 = 1001 0000 168
  75. Video Game System Emulators 模擬不同的硬體架構 • 常見的模擬器: • • •

    • • MAME (AdvanceMAME) Nintendo Entertainment System (RetroArch) Super Nintendo Entertainment System (PiSNES) PC / x86 (rpix86) https://en.wikipedia.org/wiki/List_of_video_game_emulators 175
  76. 用 Virtual Network Computing 看畫面 • RFB 協定 + 螢幕畫面分享及遠端操作軟體

    • 與作業系統無關 , 可跨平台使用 • Client/Server 架構 Raspberry Pi 當 VNC Server Laptop/PC 當 VNC client 177
  77. 182

  78. 在 VNC 下執行 AdvanceMAME • • • 下載編譯好的 binary •

    $ cd ~ • $ wget https://bit.ly/advmame -O ~/advmame • $ chmod 755 advmame • $ ./advmame 2. 下載 ROM 大寫的英文 " 歐 " • $ cd ~ • $ wget https://bit.ly/suprmrio -O ~/.advance/rom/suprmrio.zip 3. 執行模擬器 • $ cd ~ • $ ./advmame suprmrio 大寫的英文 " 歐 " 183
  79. 下載 ROM 放到對應的目錄下 • 搜尋 MAME • • 中英文對照 •

    • http://www.emuparadise.me/ http://bbs.duowan.com/thread-41350071-1-1.html 經典遊戲 • 超級瑪莉歐 • 彈珠台 • 小精靈 • 坦克大作戰 , 泡泡龍 ... 184 http://en.wikipedia.org/wiki/Nintendo_Entertainment_System
  80. 使用模擬器 • $ cd ~ • $ ./advmame suprmrio •

    按 'o' 'k' 進入畫面 • 按 '5' 投錢 • 按 '1' 開始 • 左邊 'ctrl' 是加速 • 左邊 'alt' 是跳 • 按 'esc' 是離開 185
  81. 遊戲機製作步驟 • 執行模擬器 , 使用 keyboard 控制 • 讀取 GPIO

    搖桿的值 • 讓 GPIO 搖桿和 keyboard 對應 • 開機就啟動按鍵與 keyboard 對應程式 • 開機就啟動模擬器 186 http://www.linuxuser.co.uk/tutorials/emulate-a-bluetooth-keyboard-with-the-raspberry-pi
  82. XY 雙軸搖桿 • 3.3V-5V 工作電壓 • 輸出形式: • x,y 軸

    - 類比輸出 • z 軸 - 數位輸出 http://www.aliexpress.com/cheap/cheap-arduino-joystick.html 188
  83. spi = spidev.SpiDev() • spi.open(0,0) • spi.max_speed_hz = 1800000 •

    • def read_channel(channel): • adc = spi.xfer2([1,(8+channel)<<4,0]) • data = ((adc[1]&3) << 8) + adc[2] • return data • • vrx_channel = 1 • vry_channel = 2 • • while True: • vrx_pos = read_channel(vrx_channel) • vry_pos = read_channel(vry_channel) • • print("X : {} • • Y : {} ".format(vrx_pos,vry_pos)) 190 time.sleep(0.5)
  84. Linux Input Subsystem • USB 或 PS2 keyboard 都是同一個 handler

    處理 USB Keyboard PS2 Keyboard • 我們可以加上 GPIO 的 driver, 讓 keyboard handler 來接? http://www.linuxjournal.com/article/6396 196
  85. python3-evdev • evdev(event device) • • python3-evdev • • 是

    linux kenel 的通用輸入事件介面 , 可從 driver 產生原始的 input event, 並透過 /dev/input/ 發送事件 和 evdev 的 user space 實做 uinput 綁定 , 提供 python 介面的呼 叫來發送 input event 安裝 ( 如果前面已裝過 , 就不需再裝 ) • $ sudo apt install python3-evdev python3-libevdev https://pypi.python.org/pypi/evdev 198
  86. python-evdev keyboard example from evdev import UInput, ecodes as e

    ui = UInput() ui.write(e.EV_KEY, e.KEY_H, 1) # KEY_H down ui.write(e.EV_KEY, e.KEY_H, 0) # KEY_H up ui.write(e.EV_KEY, e.KEY_E, 1) ui.write(e.EV_KEY, e.KEY_E, 0) ui.write(e.EV_KEY, e.KEY_L, 1) ui.write(e.EV_KEY, e.KEY_L, 0) ui.write(e.EV_KEY, e.KEY_L, 1) ui.write(e.EV_KEY, e.KEY_L, 0) ui.write(e.EV_KEY, e.KEY_O, 1) ui.write(e.EV_KEY, e.KEY_O, 0) ui.syn() • ui.close() 199
  87. vrx_channel = 1 while True: vrx_pos = read_channel(vrx_channel) if vrx_pos

    > 700 : ui.write(e.EV_KEY, e.KEY_DOWN, 1) ui.write(e.EV_KEY, e.KEY_UP, 0) ui.syn() elif vrx_pos < 200 : ui.write(e.EV_KEY, e.KEY_DOWN, 0) ui.write(e.EV_KEY, e.KEY_UP, 1) ui.syn() else : ui.write(e.EV_KEY, e.KEY_DOWN, 0) ui.write(e.EV_KEY, e.KEY_UP, 0) ui.syn() time.sleep(0.1) 205
  88. 用搖桿控制超級瑪莉 - 需要開啟兩個視窗 • 第一個執行超級瑪莉 (VNCViewer) • $ cd ~

    • $ ./advmame suprmrio 從 x11vnc 連線後執行超級瑪莉 ( 顯示畫面 ) 210
  89. 用搖桿控制超級瑪莉 • 第二個執行搖桿按鍵對應程式 (serial 或 ssh) • $ cd ~/gpio-game-console/13-gaming_console

    • $ sudo python3 gaming_console.py 從 serial 或 ssh 連線後執行搖桿按鍵對應程式 211
  90. 開機就執行搖桿對應按鍵程式 • 先建立搖桿對應按鍵程式的腳本 • $ nano ~/my-script.sh • #!/bin/bash •

    sudo python3 /home/pi/gpio-gameconsole/13-gaming_console/gaming_co nsole.py • $ chmod 755 ~/my-script.sh 這是同一行 214
  91. 進入桌面環境後就執行超級瑪莉 • $ nano ~/.config/lxsession/LXDE-pi/autostart 或是 • $ sudo nano

    /etc/xdg/lxsession/LXDE-pi/autostart • 新增黃色字的部份 @lxpanel --profile LXDE-pi @pcmanfm --desktop --profile LXDE-pi @xscreensaver -no-splash @lxterminal -e /home/pi/advmame suprmrio • 設定完以後重開機試試看吧 217
  92. 三種自動程式方案比較 方案 cron @reboot autostart .desktop systemd 執行時機 開機 桌面登入後

    開機,可精確控制 順序 需要 root 可選 否 可選 GUI 相關程式 所有情境,最彈性 適合情境 簡單一次性指令 執行搖桿對應按鍵程式 執行超級瑪莉遊戲畫面 218
  93. 自製遊戲機 - 機構外殼很重要 demo board 小台 gameboy 正面 大台 gameboy

    內裝 大台 gameboy 正面 小台 gameboy 內裝 220 大台電動玩具
  94. AdvanceMAME • 安裝 gcc • • 下載 advancemame-5.0.tar.gz • •

    $ sudo apt-get install gcc http://www.advancemame.it/download 安裝 • $ sudo apt-get install -ylibsdl1.2-dev • $ tar zxvf advancemame-5.0.tar.gz • $ cd advancemame-5.0 • $ ./configure --disable-fb • $ make -j4 • $ ./advmame 223
  95. 執行模擬器 • • 1. 產生 rc 檔 • $ cd

    /home/pi/advancemame-5.0 • $ chmod 755 advmame • $ ./advmame 2. 下載 rom • • $ cd /home/pi/.advance/rom 3. 執行模擬器 • $ cd /home/pi/advancemame-5.0 • $ ./advmame suprmrio 224
  96. 我的 AdvanceMAME 很慢? • 修改解析度 , 改為 256x240x60 • tab

    鍵進入選單 , 選擇 Video Mode, ESC 離開 226
  97. 我的 AdvanceMAME 很慢? • 修改解析度 , 改為 256x240x60 • tab

    鍵進入選單 , 選擇 Video Mode, ESC 離開 227
  98. 我的 AdvanceMAME 很慢? • 修改解析度 , 改為 256x240x60 • tab

    鍵進入選單 , 選擇 Video Mode, ESC 離開 228