顯示具有 python 標籤的文章。 顯示所有文章
顯示具有 python 標籤的文章。 顯示所有文章

2019年6月21日 星期五

Raspberry Pi筆記:HC-SR04 超音波感測器

基本說明:

HC-SR04 超音波感測器透過超音波反彈來測定感測器與障礙物之間的距離。
根據說明書(ref.1),能測到的障礙物會在感測器方向15°角之內,有效測定距離為2公分~400公分之間。
驅動HC-SR04的方式,透過給Trig針腳高電壓持續10µs,即開始測定距離。
HC-SR04回傳時,會將Echo針腳維持在高電壓,透過維持高電壓的時間來回饋測定的距離。
這裡需要注意,當維持高電壓時間會介於150µs~25ms之間,若時間大於38ms表示未偵測到障礙物。
距離(cm) = 高電壓時間(µs) / 58 

接線:

VCC5V
Trig>GPIO#20
EchoGPIO#21
GNDGND
Ref.2內有建議接線圖,在Echo針腳與GND用一1K電阻連接,

Python程式:

import RPi.GPIO as GPIO
import time

TRIG = 20
ECHO = 21

# init GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()

GPIO.setup(TRIG, GPIO.OUT)
GPIO.setup(ECHO, GPIO.IN)
GPIO.setup(TRIG, GPIO.LOW)

time.sleep(0.1)
GPIO.output(TRIG, GPIO.HIGH)
time.sleep(0.00001)
GPIO.output(TRIG, GPIO.LOW)

echo_count = 0
while GPIO.input(ECHO) == GPIO.LOW:
  if echo_count < 1000:
    echo_count += 1
    sonarStartTime = time.time()
  else:
    exit(1)
while GPIO.input(ECHO) == GPIO.HIGH:
  sonarEndTime = time.time()
distance = (sonarEndTime - sonarStartTime) / 58 * 1000000
print("{}".format(distance))

討論:

1. HC-SR04技術文件(Ref.1)有提到距離的計算上,可以不使用推導出來的1/58作為係數,可以透過音波公式來做更精確的計算,音波會受到溫度影響而有變化,可以參考Ref.3的相關內容。
2. 距離公式中的距離係數1/58=0.01724 cm/µs = 172.4 m/s,但波傳遞的距離是從感測器至障礙物反彈再回到感測器上,實際距離是兩倍,因此公式中實際使用的音速是344.8 m/s,或空氣溫度在22.76°C下計算而得。

參考:

1. https://www.linuxnorth.org/raspi-sump/HC-SR04Users_Manual.pdf
2. https://www.linuxnorth.org/hcsr04sensor/
3. https://en.wikipedia.org/wiki/Speed_of_sound

2019年6月6日 星期四

Raspberry Pi筆記:5101BS 7段數字顯示器

基本說明:

5101BS由8個LED所組成的8字顯示器與一個小數點,透過10跟針腳來控制顯示。
由於網路上搜尋不到5101BS的技術文件,這邊我參照ref.1中1.3 Common Anode 0.56 Inch的腳位說明來作相關的接線,透過74HC595控制。

接線:

74HC595晶片
QBpin 6VCC3.3V
QCpin 4QApin 7
QDpin 2SERGPIO#16
QEpin 1OEGND
QFpin 9RCLKGPIO#20
QGpin 10SRCLKGPIO#21
QHpin 5SRCLR3.3V
GNDGNDQH'

5101BS顯示器
pin 1QEpin 10QG
pin 2QDpin 9QF
pin 3
pin 83.3V
pin 4QCpin 7QA
pin 5QHpin 6QB

注意5101BS各節點LED二極體是有方向性的,所以pin 3與pin 8擇一接電源就好
當pin為低電壓時,所對應的LED二極體就會發光

Python程式:


import RPi.GPIO as GPIO
import time

SRCLK = 21
RCLK = 20
SER = 16

def init():
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BCM)
  GPIO.cleanup()

  GPIO.setup(SRCLK, GPIO.OUT)
  GPIO.setup(RCLK, GPIO.OUT)
  GPIO.setup(SER, GPIO.OUT)
  GPIO.output(SER, GPIO.LOW)
  GPIO.output(SRCLK, GPIO.LOW)
  GPIO.output(RCLK, GPIO.LOW)

def display(frag):
  for v in frag:
    if v:
      GPIO.output(SER, GPIO.HIGH)
    else:
      GPIO.output(SER, GPIO.LOW)
    GPIO.output(SRCLK, GPIO.HIGH)
    GPIO.output(SRCLK, GPIO.LOW)
  GPIO.output(RCLK, GPIO.HIGH)
  GPIO.output(RCLK, GPIO.LOW)

init()
#       H  G  F  E  D  C  B  A
display([1, 0, 1, 0, 0, 1, 0, 0]) # display 2

數字2顯示節點為ABDEG,所以對應的點設定為低電壓形成通路。

參考文件:

1. https://e-radionica.com/productdata/LD3361BS.pdf

2019年6月5日 星期三

Raspberry Pi筆記:Python控制74HC595晶片

基本原理:

74HC595晶片透過三個輸入針腳來產生1與0給74HC595晶片,晶片會將最新輸入的值塞在8個位元的最前面,原先在晶片的值則往後位移。晶片紀錄的8個值分別透過QA~QH輸出。
輸入值的方式,是透過變動SER、RCLK、SRCLK三個針腳的電壓達成。
參閱ref.1 page.2
- SRCLK電壓由 低 ➡ 高 變化時會依據SER針腳的電壓狀態產生一個值
- 當SER為高電壓時,會產生1;當SER為低電壓時,會產生0
- 最後,當RCLK電壓由 低 ➡ 高 變化時會將所有產生的值塞到8位元紀錄當中

接線:

QBLED 2VCC3.3V
QCLED 3QALED 1
QDLED 4SERGPIO#16
QELED 5OEGND
QFLED 6RCLKGPIO#20
QGLED 7SRCLKGPIO#21
QHLED 8SRCLR3.3V
GNDGNDQH'
74HC595允許電壓從3V到6V,可以放心使用5V作為工作電壓

Python程式:

import RPi.GPIO as GPIO
import time

SRCLK = 21
RCLK = 20
SER = 16

# init
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()

GPIO.setup(SRCLK, GPIO.OUT)
GPIO.setup(RCLK, GPIO.OUT)
GPIO.setup(SER, GPIO.OUT)
GPIO.output(SER, GPIO.LOW)
GPIO.output(SRCLK, GPIO.LOW)
GPIO.output(RCLK, GPIO.LOW)

# mode 1: all 1
GPIO.output(SER, GPIO.HIGH)
for i in range(8):
  GPIO.output(SRCLK, GPIO.HIGH)
  GPIO.output(SRCLK, GPIO.LOW)
GPIO.output(RCLK, GPIO.HIGH)
GPIO.output(RCLK, GPIO.LOW)
time.sleep(1)

# mode 2: all 0
GPIO.output(SER, GPIO.LOW)
for i in range(8):
  GPIO.output(SRCLK, GPIO.HIGH)
  GPIO.output(SRCLK, GPIO.LOW)
GPIO.output(RCLK, GPIO.HIGH)
GPIO.output(RCLK, GPIO.LOW)
time.sleep(1)

# mode 3: A ~ G to 1 sequentially
GPIO.output(SER, GPIO.HIGH)
for i in range(8):
  GPIO.output(SRCLK, GPIO.HIGH)
  GPIO.output(SRCLK, GPIO.LOW)
  GPIO.output(RCLK, GPIO.HIGH)
  GPIO.output(RCLK, GPIO.LOW)
  time.sleep(0.5)

# mode 4: A ~ G to 0 sequentially
GPIO.output(SER, GPIO.LOW)
for i in range(8):
  GPIO.output(SRCLK, GPIO.HIGH)
  GPIO.output(SRCLK, GPIO.LOW)
  GPIO.output(RCLK, GPIO.HIGH)
  GPIO.output(RCLK, GPIO.LOW)
  time.sleep(0.5)

# mode 5: 0 & 1 crossing sequence
mode = GPIO.HIGH
for i in range(8):
  GPIO.output(SER, mode)
  GPIO.output(SRCLK, GPIO.HIGH)
  GPIO.output(SRCLK, GPIO.LOW)
  GPIO.output(RCLK, GPIO.HIGH)
  GPIO.output(RCLK, GPIO.LOW)
  GPIO.output(RCLK, GPIO.HIGH)
  GPIO.output(RCLK, GPIO.LOW)
  if mode == GPIO.HIGH:
    mode = GPIO.LOW
  else:
    mode = GPIO.HIGH
  time.sleep(0.5)
GPIO.output(SER, GPIO.LOW)
for i in range(8):
  GPIO.output(SRCLK, GPIO.HIGH)
  GPIO.output(SRCLK, GPIO.LOW)
  GPIO.output(RCLK, GPIO.HIGH)
  GPIO.output(RCLK, GPIO.LOW)
  time.sleep(0.5)

程式下載:

https://github.com/1412chen/rpi_learning/tree/master/74HC595N
- led.py: 控制LED交互閃爍

參考:

1. https://www.ti.com/lit/ds/symlink/cd74hc595.pdf
2. https://circuitdigest.com/microcontroller-projects/raspberry-pi-74hc595-shift-register-tutorial

2019年5月28日 星期二

Raspberry Pi筆記:DHT11溫濕度感測器

硬體安裝:

參考ref.1的Figure.1 (page 5)
在pin 2的部份與RPi的GPIO 4連接,並使用一電阻與VCC相連

python程式:

1. 快速上手方式:

在RPi已經安裝好pip的狀態下,只需要額外安裝Adafruit_DHT (ref.2)
sudo pip install Adafruit_DHT
接著,在python環境中輸入:
import Adafruit_DHT as dht

sensor = dht.DHT11
gpio = 4
print( dht.read_retry(sensor, gpio) )
可以快速得到DHT11偵測到的相對濕度與溫度:
(76.0, 29.0)
在Googled結果,可以看到許多類似的maker分享,許多是從git clone Adafruit_DHT 開始,安裝Adafruit_DHT,有興趣的可以參考ref.4。

2. 透過GPIO方式:

要透過GPIO操控DHT11,基本上要了解DHT11的運作機制 (ref.1):
RPi GPIO控制階段:
a. pin 2針腳在高電位下時,給予不少於18ms長的低電位,讓DHT11能截取到電壓變化
b. 恢復pin 2針腳回高電位
DHT11初始化階段:
c. DHT11將pin 2針腳調整為低電壓,持續80μs
d. DHT11將pin 2針腳調整為高電壓,持續80μs
DHT11訊號傳回階段:
e. DHT11會連續的將pin 2針腳,在低電壓與高電壓之間變換共40個循環;
 低電位維持50μs,高電位維持26~28μs時,表示為0
 低電位維持50μs,高電位維持70μs時,表示為1
f. DHT11將pin 2針腳調整為低電位50μs後,結束控制pin 2針腳電位控制

DHT11輸出的40個bits,共由5個8 bits所組成:
1~8 bits: 相對濕度整數部位
9~16 bits: 相對濕度小數部位
17~24 bits: 溫度整數部位
25~32 bits: 溫度小數部位
33~40 bits: checksum檢查碼,等於前4個數字的總和

在了解DHT11的訊號控制方式,可以寫相對應的GPIO控制來讀取訊號
import RPi.GPIO as GPIO
import time

PIN = 4

# initial GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()

# step a, b
GPIO.setup(PIN, GPIO.OUT)
GPIO.output(PIN, GPIO.LOW)
time.sleep(0.0181)
GPIO.output(PIN, GPIO.HIGH)

# step c, d
GPIO.setup(PIN, GPIO.IN, GPIO.PUD_UP)
while GPIO.input(PIN) == GPIO.LOW:
  continue
while GPIO.input(PIN) == GPIO.HIGH:
  continue

# step e
bits = []
MAXCount = 3000
for n in range(40):
  lowCount = 1
  highCount = 1
  while GPIO.input(PIN) == GPIO.LOW:
    lowCount += 1
  while GPIO.input(PIN) == GPIO.HIGH:
    highCount += 1
    if highCount > MAXCount:
      print("missing data")
      exit(1)
  if lowCount < highCount:
    bits.append(1)
  else:
    bits.append(0)

# bits to bytes
RH = 0
RHD = 0
T = 0
TD = 0
checksum = 0
for bit in bits[:8]:
  RH = (RH << 1) | bit
for bit in bits[8:16]:
  RHD = (RHD << 1) | bit
for bit in bits[16:24]:
  T = (T << 1) | bit
for bit in bits[24:32]:
  TD = (TD << 1) | bit
for bit in bits[32:40]:
  checksum = (checksum << 1) | bit

# checksum
if RH+RHD+T+TD != checksum:
  print("checksum error")
  exit(1)

print("RH: {}%, T: {}C".format(RH+0.1*RHD, T+0.1*TD))
執行結果:
RH: 76.0%, T: 29.6C

程式下載:

https://github.com/1412chen/rpi_learning/tree/master/dht11
- dht11.py: 直接呼叫Adafruit_DHT讀取溫濕度值
- dht11_gpio_direct.py: 透過GPIO讀取溫濕度值
- dht11_gpio.py: 透過GPIO讀取溫濕度值,一次讀取完DHT11電壓變化後才解析。

討論:

1. 在寫這個document的時候,我發現到使用Adafruit_DHT跑出來的結果,不會有小數點,讓我在確認GPIO結果一直充滿疑問。我想這個應該是Adafruit_DHT故意忽略小數位輸出,DHT11本身的誤差太大(相對濕度±5%,溫度±2°C),描述到小數點,確實沒有太大意義。
2. 控制GPIO擷取資料,蠻容易出現missing data與checksum error的結果。
3. 相對於Adafruit_DHT是python呼叫C的GPIO控制,ref.3中的dht11是python透過GPIO對DHT11進行操作,該程式為了避免python在擷取pin 2電位過程中額外的操作的時間差導致電位資料遺失或延遲,先將所有電位資料擷取下來後再解析。這樣也許能比較穩定得到結果,我有參照這個邏輯重新撰寫,參考程式下載的dht11_gpio.py。

參考:

1. https://www.mouser.com/ds/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
2. https://github.com/adafruit/Adafruit_Python_DHT
3. https://github.com/szazo/DHT11_Python
4. https://kknews.cc/zh-tw/digital/ea26b4q.html