1.きっかけ
以前、Raspberry PI の5Vは出力されていると書いた。しかしLCD(1602aと表示されているが、1602と同じものと思われる。)を使い電子時計を作成したときに、誰も見ていなのに時刻表示しても意味ないし、無駄だなと思い、ON/OFFを制御できる3.3Vピンを使用したところ、バックパネルが暗くて文字の判読が困難だった。
理想的には、人感センサーを使って人がある距離に入ったら5Vをオン、去っていったら5VをOFFして表示を止める仕様だ。
そこで、どうしても5VピンのON/OFFを制御する必要性に迫られた。
もう1つの解決方法は3.3Vで可動するLCDを購入することだが、そんな無駄なことはしていられない。購入したキットの中に両者が入っているからだ。
LCDである1602の設定方法、人感センサー(型番が明確ではないがHC-SR501と思われる)のそれぞれのやり方については、ネット上にあふれているので、そちらを参考にしてほしい。
ここではこれらにトランジスターをプラスして5Vを制御してみることにする。
出来上がりはこんな調子。
2.準備したもの
- ラズパイ ZERO WH
- 人感センサー(HC-SR501)
- LCD(1602)
- トランジスター(S8550のデータシート)
- ジャンパーピン類
3.トランジスターの特性
あの板に乗ったかまぼこ型の板側(平らな面)からC(コレクタ)、B(ベース)、E(エミッタ)の順で(日本製はECBの順になるらしい。)
ポイントは2つ
1つ目は接続方法
「B-E間に弱い電流が流れると、C-E間にも流れる。C-E間には通常は流れていない。」と言う文章を読んで、そうか、C-E間に5Vの電流を流そうということかと思ったが、発熱して1個だめにした。
正解は、5VではなくGNDをつないで、5Vの通り道を作ってやる。B-E間の弱電流はスイッチの役目を果たすということ。
2つ目はトランジスターの型
NPN型とPNP型の2種類があって、上の説明文の「B-E間に電流が流れると」はNPN型に当てはまるが、PNP型は逆になるということ。
すなわちPNP型は「B-E間に電流が流れなくなると」C-E間に電流が流れるということ。
4.実際の配線
HC-SR501 | ラズパイ | S8550 | 1602A |
---|---|---|---|
SDA(GPIO2) | SDA | ||
SCL(GPIO3) | SCL | ||
3.3V(常時) | |||
GPIO21 | B(ベース)10KΩ経由 | ||
GND | E(エミッタ) | ||
GND | GND | C(コレクタ) | GND |
Power | 5V(常時) | VCC | |
センサー | GPIO12 |
ちょっと分かりづらいかもしれませんが、センサとしてのGPIO12がHighになると、トランジスターのB-E間に電流が流れなくなるようにします。するとPNP型トランジスタは、C-E間の通電回路GND(への通路)を開くので、LCDのVCC(5V)がC-E間を経由して、GNDに流れ落ちる(通電する)。こんな感じでしょう。
再度注意しますが、「5Vを制御する」と言ってもトランジスターに直接5Vを流すという意味ではありません。
5.Pythonコード
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
from time import sleep
from time import strftime
import datetime
import smbus
import RPi.GPIO as GPIO
import time
Sensor_PIN = 12 #人感センサーのセンサーピン
Switch_PIN = 21 #トランジスターのコレクタピン
GPIO.setmode(GPIO.BCM)
GPIO.setup(Sensor_PIN,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(Switch_PIN,GPIO.OUT)
# これ以下の関数関係のコードはネット上の諸先輩方のコードを借用させていただきました。
# Define some device parameters
I2C_ADDR = 0x27 # I2C device address
LCD_WIDTH = 16 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_BACKLIGHT = 0x08 # On
#LCD_BACKLIGHT = 0x00 # Off
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
#Open I2C interface
#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33,LCD_CMD) # 110011 Initialise
lcd_byte(0x32,LCD_CMD) # 110010 Initialise
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01,LCD_CMD) # 000001 Clear display
sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
sleep(E_PULSE)
bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
sleep(E_DELAY)
def lcd_string(message,line):
# Send string to display
message = message.ljust(LCD_WIDTH," ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)
def main(): #「日時」を表示
# Main program block
# Initialise display
lcd_init()
n = 0 # 表示のカウンター
while n < 10:
# ある程度の回数を表示したら、たとえ人が前にいても、この繰り返しを抜け出て、人感センサーに制御を移すため。While True:文だと、人がいなくなってもこの繰り返しから抜け出せなくなり、結果的にバックライトが点きっぱなしになってしまう。
local_time = datetime.datetime.now()
lcd_string(local_time.strftime("%Y.%m.%d (%a)") , LCD_LINE_1)
# 1行目は年月日と曜日の表示
lcd_string(local_time.strftime("%H:%M"), LCD_LINE_2)
# 2行目は時間の表示
sleep(0.5)
local_time = datetime.datetime.now()
lcd_string(local_time.strftime("%Y.%m.%d (%a)") , LCD_LINE_1)
lcd_string(local_time.strftime("%H %M"), LCD_LINE_2)
sleep(0.5)
n += 1 #カウンタの増加
try: #----こちらは人感センサーの赤外線でのサーチ
while True:
if (GPIO.input(Sensor_PIN) == GPIO.HIGH): #人感センサーに反応があったら
GPIO.output(Switch_PIN,GPIO.LOW) #トランジスターのB-E間を閉じる。
main() # 時刻表示に移ります。
time.sleep(1)
else:
GPIO.output(Switch_PIN,GPIO.HIGH) #通常はトランジスターのB-E間は通電。
time.sleep(1)
except KeyboardInterrupt:
print('Cancel')
finally:
LCD_BACKLIGHT = 0x00 #バックライトオフ
lcd_byte(0x01, LCD_CMD) #表示内容クリア
GPIO.cleanup()
print("-----end-----")
あとは crotab -eに登録して起動時に動き出させるようにします。
$ sudo nano crontab -e
@reboot python3 install-directory/disp1602a_on.py
コメント