シェルスクリプトマガジン

ラズパイセンサーボードで学ぶ電子回路の制御(Vol.58掲載)

著者:米田 聡
シェルスクリプトマガジンでは、小型コンピュータボード「Raspberry Pi」(ラズパイ)向けのセンサー搭載拡張ボード「ラズパイセンサーボード」を制作しました。第5回では、このボードを使った電子回路制御を取り上げます。具体的には、明るさ・近隣センサーに近づく物体の検出です。

シェルスクリプトマガジン Vol.58は以下のリンク先でご購入できます。

図3 割り込みに対応したVCNL4020ライブラリ(VCNL4020.py)
import smbus
import time
import RPi.GPIO as GPIO
from threading import BoundedSemaphore

class VCNL4020():

  _ALS_OD       = 0b00010000  # オンデマンド明るさ計測スタート
  _PROX_OD      = 0b00001000  # オンデマンド近接計測スタート
  _ALS_EN       = 0b00000100  # 明るさ繰り返し計測有効
  _PROX_EN      = 0b00000010  # 近接繰り返し計測有効
  _SELFTIMED_EN = 0b00000001  # 内蔵タイマー有効
  
  _CONT_CONV    = 0b10000000  # Continue Conversion有効
  _AMBIENT_RATE = 0b00010000  # 明るさの計測レート(default:2sample/s)
  _AUTO_OFFSET  = 0b00001000  # 自動オフセットモード有効
  _AVERAGING    = 0b00000101  # 平均化(default:32conv)

  _COMMAND_REG       = 0x80  # コマンドレジスタ
  _PID_REG           = 0x81  # プロダクトIDレジスタ
  _PROX_RATE_REG     = 0x82  # 近接測定レートジスタ
  _IR_CURRENT_REG    = 0x83  # 近接測定用赤外線LED電流設定レジスタ(default=20mA)
  _AMBIENT_PARAM_REG = 0x84  # 明るさセンサーパラメータレジスタ

  _AMBIENT_MSB       = 0x85  # 明るさ上位バイト
  _AMBIENT_LSB       = 0x86  # 明るさ下位バイト

  _PROX_MSB          = 0x87  # 近接上位バイト
  _PROX_LSB          = 0x88  # 近接下位バイト

  _INT_CONTROL_REG   = 0x89  # 割り込み制御レジスタ

  _LOW_TH_MSB        = 0x8A  # Lowしきい値(MSB)
  _LOW_TH_LSB        = 0x8B  # Lowしきい値(LSB)
  _HIGH_TH_MSB       = 0x8C  # Highしきい値(MSB)
  _HIGH_TH_LSB       = 0x8D  # Highしきい値(LSB)

  _INT_STATUS_REG    = 0x8E  # 割り込みステータス

  _INT_NO            = 0x06  # int = GPIO6

  # コールバック
  __callbackfunc     = None

  def __init__(self, i2c_addr = 0x13, busno = 1):
    self.addr = i2c_addr
    self.i2c = smbus.SMBus(busno)
    
    self._write_reg(self._COMMAND_REG, self._ALS_OD  |\
                       self._PROX_OD |\
                       self._ALS_EN  |\
                       self._PROX_EN |\
                       self._SELFTIMED_EN )
                       
    self._write_reg(self._IR_CURRENT_REG, 2 )  # 20mA
                       
    self._write_reg(self._AMBIENT_PARAM_REG, self._CONT_CONV    |\
                        self._AMBIENT_RATE |\
                        self._AUTO_OFFSET  |\
                        self._AVERAGING )
    self.semaphore = BoundedSemaphore()

    # GPIO設定
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(self._INT_NO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.add_event_detect(self._INT_NO, GPIO.FALLING, callback=self.__interruptfunc)

    time.sleep(0.6)      # 初回測定まで待つ

  def _write_reg(self, reg, value):
    self.i2c.write_byte_data(self.addr, reg, value)

  def _read_reg(self, reg):
    return self.i2c.read_byte_data(self.addr, reg)

  # 高値用レジスタ設定
  def set_high_threshold(self, value):
    self.semaphore.acquire()
    h = (value & 0xFF00) >> 8
    l = value & 0x00FF
    self._write_reg(self._HIGH_TH_MSB, h)
    self._write_reg(self._HIGH_TH_LSB, l)
    self.semaphore.release()

  # 低値用レジスタ設定
  def set_low_threshold(self, value):
    self.semaphore.acquire()
    h = (value & 0xFF00) >> 8
    l = value & 0x00FF
    self._write_reg(self._LOW_TH_MSB, h)
    self._write_reg(self._LOW_TH_LSB, l)
    self.semaphore.release()

  # 割り込み有効化
  def enable_interrupt(self, callbackfunc=None, prox=True, samples=1):
    self.semaphore.acquire()

    self.__callbackfunc = callbackfunc
    value = self._read_reg(self._INT_CONTROL_REG)

    if callbackfunc is not None:
      if prox:
        value |= 0b00000010
      else:
        value |= 0b00000011
    else:
        value &= 0b11111100

    # samples
    samples &= 0b00000111
    samples = samples << 5
    value &= 0b00011111
    value |= samples

    self._write_reg( self._INT_CONTROL_REG, value)
    self.semaphore.release()

  # 割り込み関数
  def __interruptfunc(self, ch):
    if ch != self._INT_NO:
      return
    if self.__callbackfunc is not None:
      self.__callbackfunc(self.luminance, self.proximity)


  @property
  def luminance(self):
    self.semaphore.acquire()
    d = self.i2c.read_i2c_block_data(self.addr, self._AMBIENT_MSB, 2)
    self.semaphore.release()
    return (d[0] * 256 + d[1]) / 4
  
  @property
  def proximity(self):
    self.semaphore.acquire()
    d = self.i2c.read_i2c_block_data(self.addr, self._PROX_MSB, 2)
    self.semaphore.release()
    return (d[0] * 256 + d[1])
図4 物体が近づいたら割り込みを発生させるサンプルプログラム(simpletest.py)
#!/usr/bin/env python3
import time
from  VCNL4020 import  VCNL4020

sensor = VCNL4020()

# コールバック関数
def callback(lux, prox):
  print('センサーに何かが接近しています')
  print('現在の明るさ:'+str(lux) )
  print('近接センサー:'+str(prox) )
  # 割り込み再設定
  sensor.enable_interrupt(callback)

# しきい値高を設定
sensor.set_high_threshold(2500)
# しきい値低を設定
sensor.set_low_threshold(0)
# 割り込み有効化
sensor.enable_interrupt(callback)

try:
  while True:
    time.sleep(1)

except KeyboardInterrupt:
  term = True