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

用 Raspberry Pi 學 GPIO - 自己做遊戲機

用 Raspberry Pi 學 GPIO - 自己做遊戲機

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

購買學習套件:
http://www.piepie.com.tw/2557/gpio-game-console-starter-kit

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

台灣樹莓派

January 25, 2015
Tweet

More Decks by 台灣樹莓派

Other Decks in Technology

Transcript

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

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

    / 輸出 • 數位 / 類比 • 練習與實做 本次主題
  3. 8 • 硬體:Raspberry Pi 4B • 作業系統:2021-05-07-raspios-buster-armhf-full.img • 為了可以使用USB 轉TTL

    傳輸線 • 修改/boot/config.txt, 新增三行 – dtoverlay=pi3-miniuart-bt – core_freq=250 – enable_uart=1 • 修改/boot/cmdline.txt, 將quiet splash 的quiet 移除 今日環境 刪除 quiet 新增三行
  4. 9 • $ sudo apt-get update • $ sudo apt-get

    install -y python3-dev python3-pip libsdl1.2-dev vim • $ sudo pip3 install spidev evdev 安裝今日所需套件
  5. 11 • General Purpose Input Output • GPIO 是一種可用軟體控制的數位訊號 什麼是

    GPIO ? http://www.tek.com/datasheet/tps2000b-series-digital-storage-oscilloscopes-datasheet
  6. 14 • GPIO 高電位輸出為 3.3V • GPIO 容忍輸入電位為 3.3V •

    單一 Pin 輸出電流為 3mA-16mA • 全部 Pin 輸出總和小於 50mA • GPIO 輸入低電位為小於 0.8V, 高電位為大於 1.3V 幾個 GPIO 的數字 https://www.scribd.com/doc/101830961/GPIO-Pads-Control2
  7. 15 • C • C + wiringPi • C# •

    Ruby • Perl • Python • Scratch • Java Pi4J Library • Shell script 如何控制 Raspberry Pi 的 GPIO ?
  8. 16 • Python + RPi.GPIO = 70 kHz • C

    + BCM 2835 = 5.4 MHz • Ruby + wiringpi bindings = 21 kHz GPIO Benchmark http://www.tek.com/datasheet/tps2000b-series-digital-storage-oscilloscopes-datasheet
  9. 18 • 變數 , 物件 , 型別 , 註解 •

    模組 • 縮排 • 迴圈 • 條件判斷 • 函式 Python3 五分鐘速成
  10. 19 • 動態型別 (dynamic typing) # 這是註解 i = 3

    # 變數 i 指到數字物件 3 i = [1, 2, 3, 4, 5] # 變數 i 指到串列物件 print(i[2]) # 印出串列中第三個元素 i = "abcde" # 變數 i 指到字串物件 print(i[2]) # 印出字串中第三個元素 變數 , 物件 , 型別 , 註解
  11. 20 # import MODULE import RPi.GPIO # import MODULE as

    ALIAS import RPi.GPIO as GPIO 模組
  12. 22 • 自動迭代 (iterator) for i in range(start, stop[, step]):

    process for i in range(0, 11, 5): print(i) 迴圈
  13. 25 • 1. 存成檔案以後 , 用 python 執行 • $

    nano test.py • $ python3 test.py • 2. 進到互動模式 , 可直接看輸出結果 • $ python3 Python 3.5.3 (default, Sep 27 2018, 17:25:39) • [GCC 6.3.0 20170516] on linux • Type "help", "copyright", "credits" or "license" for more information. >>> 兩種執行 Python 的方法
  14. 26 電子入門套件 • 紅/ 黃/ 綠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
  15. 31 • 電路組成元件 : 電源、導線、負載 • 閉路 : 當三者形成一完整路徑 ,

    有電流經過電路 • 歐姆定律 : 導體兩端的電壓與通過的電流成正比 • V = I x R 電路一分鐘速成 I I V R V R I https://zh.wikipedia.org/wiki/ 电路
  16. 33 • V F : 順向電壓 • I F :

    在順向電壓下的安全電流 LED 的特性 https://learn.adafruit.com/all-about-leds/forward-voltage-and-kvl
  17. 34 • 在順向電壓下一般的 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 燒毀 如何解讀?
  18. 38 線路圖 LED RPi 長腳 (RED) Pin12 (GPIO18) 短腳 (BLACK)

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

    Pin6 (Ground) 1k 電阻 : 棕黑黑棕 ( 棕 )
  20. 46 • 載入模組 (Import module) • 選擇編號系統 (Define pin numbering)

    • 定義腳位 (Setup up a channel) • 讀取輸入 / 寫入輸出 (Input/Output) • 清理 (Cleanup) Python Code 基本流程 http://code.google.com/p/raspberry-gpio-python/wiki/BasicUsage
  21. 47 #!/usr/bin/python3 • import RPi.GPIO as GPIO # Import module

    import time 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 一個實際的範例 以下都是使用別名 (alias)
  22. 49 使用 :nano < 檔名 , 例如 led_on.py> 離開 :Ctrl

    + x > 令存新檔 :y > 不存離開 :n > 離開 :Ctrl + c nano 編輯器使用
  23. 50 $ cd ~ $ git clone https://github.com/piepie-tw/gpio-game-console $ cd

    ~/gpio-game-console $ cd 01-led_on $ python3 led_on.py 讀寫 GPIO 會存取 /dev/mem, 需 root 權限 (2015-09-24 以後的 image 可以用一般使用者身份執行 ) 執行方式
  24. 51 • Wiki • http://sourceforge.net/p/raspberry-gpio- python/wiki/Home/ • Code • 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/BCM2835-ARM-Peripherals.pdf 更多 RPi.GPIO 的使用方法
  25. 54 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) GPIO.cleanup() 永不停止的 while 迴圈 - 按 Ctrl+c 跳出迴圈
  26. 56 RuntimeWarning: This channel is already in use, continuing anyway.

    Use GPIO.setwarnings(False) to disable warnings.
  27. 59 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() 接住例外
  28. 62 • 紅 , 黃 , 綠燈依序亮燈 • 紅燈亮 4

    秒 , 黃燈亮 2 秒 , 綠燈亮 4 秒 設計一個紅綠燈 http://www.clipartbest.com/traffic-light-photo
  29. 65 def TrafficLight(pin, duration): GPIO.output(pin, GPIO.HIGH) time.sleep(duration) GPIO.output(pin, GPIO.LOW) try

    : while True: TrafficLight(RED_PIN, 4); TrafficLight(YEL_PIN, 2); TrafficLight(GRN_PIN, 4); finally: GPIO.cleanup() 把亮燈拿到外面
  30. 70 • 常開 (normally open, N.O.) • 常閉 (normally close,

    N.C.) 按鍵 Button / 開關 Switch http://www.engineersgarage.com/sites/default/files/imagecache/Original/wysiwyg_imageupload/4214/Switch-2_0.jpg
  31. 75 線路圖 BUTTON RPi 腳 1 Pin6 (Ground) 腳 3

    Pin11 (GPIO17) Pin1 (3.3V) 1k 電阻
  32. 76 BTN_PIN = 11 GPIO.setup(BTN_PIN, GPIO.IN) previousStatus = None try:

    while True: input = GPIO.input(BTN_PIN) if input == GPIO.LOW and previousStatus == GPIO.HIGH: print("Button pressed") previousStatus = input except KeyboardInterrupt: print("Exception: KeyboardInterrupt") finally: GPIO.cleanup() 判斷條件 : 這次低 && 上次高
  33. 80 • 硬體方法 : 以 RC 電路或正回授的比較器電路解決 • 軟體方法 :

    調整觸發的延遲時間 • 不同的按鍵會有不同的延遲時間 解決彈跳問題 (de-bounce) 10ms - 20ms
  34. 81 GPIO.setup(BTN_PIN, GPIO.IN) previousStatus = None previousTime = time.time() currentTime

    = None try: while True: input = GPIO.input(BTN_PIN) currentTime = time.time() if input == GPIO.LOW and \ previousStatus == GPIO.HIGH and \ (currentTime - previousTime) > 0.2: previousTime = currentTime print("Button pressed”) previousStatus = input 不反應在延遲時間內的觸發
  35. 84 • 先以背景方式執行單一程式 ( 加上 &) • $ python3 push_button_debounce.py

    & • 再看整體系統使用狀況 ( 按 q 離開 ) • $ top -c 如何看系統效能? PID
  36. 86 使用 ps 指令查詢程序 使用 ps aux | grep python3

    搜尋程序 使用指令 kill 送出中止訊號 9 給程序 再次使用 ps aux 已經沒有該程序了
  37. 87 • 輪詢 (polling) • SoC 每隔一段時間檢查週邊硬體的資料 • 中斷 (interrupt)

    • 當週邊硬體的狀態改變時 , 對 SoC 發出中斷要求 輪詢與中斷
  38. 88 • 建立回呼函數 • def mycallback() • 綁定事件和回呼函數 • add_event_detect(gpio,

    # 對象 edge, # 觸發條件 callback,# 回呼函數 bouncetime) • 多個事件可以綁定同樣的回呼函數 中斷的程式寫法 source/py_gpio.c
  39. 89 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() 即使在 sleep 狀態下也可立即回應
  40. 91 • 需要硬體或軟體 ( 作業系統 ) 的支援 • RPi.GPIO 在版本

    0.5.0a 有了中斷功能 • 加上 add_event_detect() 等機制 • RPi.GPIO 以建立多執行緒方式實現中斷 • 程式開始執行時 , 主執行序運行 • 當加入事件後 , 以 epoll_create 建立新的 fd • 當事件觸發時 , 第二個執行序和主執行序溝通 ( 回呼 ) • 程式碼可參考 source/event_gpio.c 中斷的意義 source/py_gpio.c
  41. 93 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() 要搭配內建的上拉電阻 (50k)
  42. 98 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() 要搭配內建的上拉電阻 (50k)
  43. 99 DEMO tilt_switch.py $ cd ~/gpio-game-console $ cd 05-tilt_switch $

    python3 tilt_switch.py 使用內建的上拉電阻
  44. 101 • 發聲原理 : 聲音是由振動產生 , 其頻率稱為音頻 • 蜂鳴器發聲原理 :

    電流 (6) 通過電磁線圈 (3) 產生 磁場來驅動振動膜 (11) • 人耳可聽到 20Hz - 20KHz 原理 http://www.itianer.com/diancishifengmingqigouzaoyuyuanlijieshao.html
  45. 102 • 自激 ( 有源 ): 只能發出同頻率的聲音 • 黑膠封裝 ,

    高低腳 • 他激 ( 無源 ): 需從外部輸入震盪方波發聲 • 綠色電路板 , 兩腳同長 • 腳位有正負之分 ( 看底板 ) 蜂鳴器 Buzzer http://www.buzzer-speaker.com/manufacturer/piezo%20buzzer.htm 自激式 他激式
  46. 104 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)) 可發出不同頻率聲音
  47. 106 • • 標準 88 鍵鋼琴 , 每個音的頻率 : •

    每段音階分為 12 個半音 • 每個音的頻率是前一個的 1.05946 倍 ( ) 鋼琴模擬 1 2 3 4 5 6 7 0 8 http://en.wikipedia.org/wiki/Piano_key_frequencies 12 2
  48. 107 • 標準 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
  49. 108 線路圖 RPi Pin7 Buzzer Pin11 Do Pin12 Re Pin13

    Me Pin15 Fa Pin16 So Pin18 La Pin22 Si
  50. 115 • 輸入電壓 :DC 3.3V - 24V • 輸出電壓 :3.3V(

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

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

    L: 不可重複觸發 ( 預設 ) 感應 & 輸出 感應 & 等待 & 輸出
  53. 119 PIR_PIN = 26 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() 再一次使用 interrupt 模式
  54. 120 DEMO pir.py $ cd ~/gpio-game-console $ cd 07_1-pir $

    python3 pir.py 觸發才拉高電位 , 因此用內建的下拉電阻
  55. 124 LED_PIN = 12 PIR_PIN = 26 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) 偵測到人 , 燈閃 3 次
  56. 126 • 聲音在 20°C (68°F) 的速度是 343 公尺 / 秒

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

    長距離 ) 、 US-100( 溫度補償 ) HC-SR04 超音波距離感測器 http://coopermaa2nd.blogspot.tw/2012/09/hc-sr04.html
  58. 128 • 避障 , 測距 • 物體移動感測 • 地鐵感測器 應用

    http://letsmakerobots.com/robot/project/rock-crawler https://www.dropbox.com/s/x0qdaq86rkc0zyv/MakerConf.pdf
  59. 132 • TRIG 腳位收到高電位 (3.3V) 後發送超聲波 • ECHO 腳位維持低電位 (0V),

    收到回應後拉到高電位 (5V) • Raspberry Pi 腳位的容忍電位為 3.3V => 將 ECHO 腳位的 5V 降壓為 3.3V 左右 分壓電路計算 https://www.modmypi.com/blog/hc-sr04-ultrasonic-range-sensor-on-the-raspberry-pi => R1=1K, R2 取 2K
  60. 133 注意 1K, 2K 電阻 ULTRASONIC RPi Vcc(RED) Pin2 (5V)

    Trig(YELLOW) Pin16 (GPIO23) Echo(PURPLE) Pin18 (GPIO24) Grnd(BLACK) Pin6 (Ground) 1k: 棕黑黑棕 2k: 紅黑黑棕 Vcc Gnd Echo Trig 這是背面
  61. 134 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 測量距離
  62. 138 • 數位 :0 與 1 的訊號 • 類比 :

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

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

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

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

    http://www.protostack.com/blog/2011/06/atmega168a-pulse-width-modulation-pwm/
  67. 145 • To create a PWM instance: • p =

    GPIO.PWM(channel, frequency) • To start PWM: • p.start(dc) # dc is the duty cycle • To change the duty cycle: • p.ChangeDutyCycle(dc) # where 0.0 <= dc <= 100.0 • To stop PWM: • p.stop() GPIO.PWM() http://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/
  68. 147 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() 互動式的調光
  69. 149 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) 呼吸燈就是漸明漸亮
  70. 151 • 兩者差異 • 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 函式呼叫 Software PWM vs. Hardware PWM
  71. 153 • 硫化鎘 (CdS) 或光敏電阻器 (LDR), 阻抗隨光落 在表面的總量而轉變 • 光越強阻值越小

    , 反之光越弱阻值則越大 • 應用 : 光控開關 , 電子玩具 , 工業控制 光敏電阻 http://www2.nkfust.edu.tw/~jlkuo2/31/a6.htm
  72. 155 • 類比數位轉換器 (Analog to Digital Converter) • 8 通道

    ,10 bits 解析度 • SPI 協議 利用 MCP3008
  73. 156 • 主從式架構 , 可一對多 • 四線同步序列資料協定 • SS: 週邊選擇線

    (CE) • SCK: 序列時脈線 (SCLK) • MOSI: 主往從送 • MISO: 從往主送 Serial Peripheral Interface(SPI) https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus SPI Master SCLK MOSI MISO SS1 SS2 SS3 SPI Slave SCLK MOSI MISO SS SPI Slave SCLK MOSI MISO SS SPI Slave SCLK MOSI MISO SS
  74. 160 • 測試確認 SPI 模組已載入 • $ ls /dev/spi* •

    安裝必要套件 ( 如果前面已裝過 , 就不需再裝 ) • $ sudo apt-get update • $ sudo apt-get install -y python-dev • $ sudo pip install spidev SPI 使用前的確認
  75. 161 線路圖 MCP3008 RPi CLK Pin23 (SCLK) Din Pin19 (MOSI)

    Dout Pin21 (MISO) CS Pin24 (CE0) 缺口朝左 1k 電阻
  76. 163 spi = spidev.SpiDev() spi.open(0,0) # (0,0)表示接到CE0腳位,對應到/dev/spidev0.0裝置檔 spi.max_speed_hz = 1800000

    # 10kHz to 3.6 MHz • • def ReadChannel(channel): adc = spi.xfer2([1,(8+channel)<<4,0]) data = ((adc[1]&3) << 8) + adc[2] return data def ConvertVolts(data,places): volts = (data * 3.3) / float(1023) volts = round(volts,places) return volts light_channel = 0 delay = 1 while True: light_level = ReadChannel(light_channel) light_volts = ConvertVolts(light_level, 2) print("Light:{} ({}V)".format(light_level,light_volts)) time.sleep(delay)
  77. 165 • input 一次送三個bytes • # byte 1: the start

    bit (always 0x01) • # byte 2: configure bits • # byte 3: don't care • spi.xfer2([1,(8+channel)<<4,0]) • Ch0 = 1000 0000 • Ch1 = 1001 0000 了解 spi.xfer2() 的意義 0x01 don't care Ch0/Ch1
  78. 172 • 模擬不同的硬體架構 • 常見的模擬器: • MAME (AdvanceMAME) • Nintendo

    Entertainment System (RetroArch) • Super Nintendo Entertainment System (PiSNES) • PC / x86 (rpix86) Video Game System Emulators https://en.wikipedia.org/wiki/List_of_video_game_emulators
  79. 174 • RFB 協定 + 螢幕畫面分享及遠端操作軟體 • 與作業系統無關 , 可跨平台使用

    • Client/Server 架構 用 Virtual Network Computing 看畫面 Raspberry Pi 當 VNC Server Laptop/PC 當 VNC client
  80. 179

  81. 181 • 下載編譯好的binary(已下載) • $ cd ~ • $ wget

    http://bit.ly/2OnUMwh -O ~/advmame • $ chmod 755 advmame • $ ./advmame • 2.下載ROM(已下載) • $ cd ~ • $ wget http://bit.ly/2K1dhUb -O ~/.advance/rom/suprmrio.zip • 3. 執行模擬器(還沒做) • $ cd ~ • $ ./advmame suprmrio 在 VNC 下執行 AdvanceMAME 大寫的英文 " 歐 "
  82. 182 • 搜尋 MAME • http://www.emuparadise.me/ • 中英文對照 • http://bbs.duowan.com/thread-41350071-1-1.html

    • 經典遊戲 • 超級瑪莉歐 • 彈珠台 • 小精靈 • 坦克大作戰 , 泡泡龍 ... 下載 ROM 放到對應的目錄下 http://en.wikipedia.org/wiki/Nintendo_Entertainment_System
  83. 183 • $ cd ~ • $ ./advmame suprmrio •

    按 'o' 'k' 進入畫面 • 按 '5' 投錢 • 按 '1' 開始 • 左邊 'ctrl' 是加速 • 左邊 'alt' 是跳 • 按 'esc' 是離開 使用模擬器
  84. 184 • 執行模擬器 , 使用 keyboard 控制 • 讀取 GPIO

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

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

    • • def ReadChannel(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 = ReadChannel(vrx_channel) • vry_pos = ReadChannel(vry_channel) • • print("X : {} Y : {} ".format(vrx_pos,vry_pos)) • • time.sleep(0.5)
  87. 194 • USB 或 PS2 keyboard 都是同一個 handler 處理 •

    我們可以加上 GPIO 的 driver, 讓 keyboard handler 來接? Linux Input Subsystem http://www.linuxjournal.com/article/6396 USB Keyboard PS2 Keyboard
  88. 196 • evdev(event device) • 是 linux kenel 的通用輸入事件介面 ,

    可從 driver 產 生原始的 input event, 並透過 /dev/input/ 發送事件 • python-evdev • 和 evdev 的 user space 實做 uinput 綁定 , 提供 python 介面的呼叫來發送 input event • 安裝 ( 如果前面已裝過 , 就不需再裝 ) • $ sudo pip install evdev python-evdev https://pypi.python.org/pypi/evdev
  89. 197 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()
  90. 198 DEMO evdev_keyboard.py $ cd ~/gpio-game-console $ cd 11_2-evdev_keyboard $

    sudo python3 evdev_keyboard.py 需要有 root 權限才能發送鍵盤事件
  91. 203 vrx_channel = 1 while True: vrx_pos = ReadChannel(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)
  92. 208 • 第一個執行超級瑪莉 (x11vnc) • $ cd ~ • $

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

    sudo python3 gaming_console.py 用搖桿控制超級瑪莉 從 serial 或 ssh 連線後執行搖桿按鍵對應程式
  94. 211 • 一次性的執行 , 可以放在 /etc/rc.local 裡 • 以服務的方式執行 ,

    需寫 systemd 設定檔 • 有畫面的程式前景執行 , 用 LXDE 的 autostart 開機就執行?
  95. 212 • $ sudo nano /etc/rc.local • 新增黃色字的部份 sudo python3

    /home/pi/gpio-game-console/13- gaming_console/gaming_console.py & # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi exit 0 開機就執行搖桿對應按鍵程式 這是同一行
  96. 213 • $ 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 • 設定完以後重開機試試看吧 進入桌面環境後就執行超級瑪莉
  97. 215 自製遊戲機 - 機構外殼很重要 demo board 大台 gameboy 正面 大台

    gameboy 內裝 小台 gameboy 正面 小台 gameboy 內裝 大台電動玩具
  98. 218 • 安裝 gcc-4.8 • $ sudo apt-get install gcc-4.8

    • 下載 advancemame-1.4.tar.gz • http://www.advancemame.it/download • 安裝 • $ sudo apt-get install -y gcc-4.8 libsdl1.2-dev • $ tar zxvf advancemame-1.4.tar.gz • $ cd advancemame-1.4/ • $ CC=gcc-4.8 GCC=g++-4.8 ./configure --disable- fb • $ make -j4 • $ ./advmame AdvanceMAME
  99. 219 • 1. 產生 rc 檔 • $ cd /home/pi/advancemame-1.4

    • $ chmod 755 advmame • $ ./advmame • 2. 下載 rom • $ cd /home/pi/.advance/rom • 3. 執行模擬器 • $ cd /home/pi/advancemame-1.4 • $ ./advmame suprmrio 執行模擬器
  100. 221 • 修改解析度 , 改為 256x240x60 • tab 鍵進入選單 ,

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

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

    選擇 Video Mode, ESC 離開 我的 AdvanceMAME 很慢?