Samples_I2C - gfd-dennou-club/mrubyc-esp32 GitHub Wiki

はじめに

I2C クラスのメソッドについては,Class_I2C を参照されたい.

I2C とは

フィリップス社が提唱した周辺デバイスとのシリアル通信の方式.

  • マスタ側とスレーブ側を分け, マスタ側が全ての制御を行う.
  • 2 本の信号線から構成される.
    • SDA : シリアルデータ入出力
    • SCL : シリアルクロック信号 (送信側と受信側の同期に利用)
  • 信号線にはプルアップ抵抗が必要.
  • スレーブの識別にはアドレスを使う.
  • 多数のデバイスを接続する場合にも信号線が 2 本で済む (GPIO ピンを節約できる)
  • 1 バイト転送毎に受信側から ACK 信号を返送し, 互いに確認を取りながらデータ転送を行う.
  • 通信速度は遅い (標準モードで 0~100 kbps)
  • 同じ基板内など, 近距離で直結したデバイスでシリアル通信を行うために使われることが多い.

image

LCD + RTC

以下の LCD, RTC を使って動かす場合.「.....」の部分は穴埋めされたい.

  • 液晶ディスプレイ(LCD) AQM0802A-RN-GBW
  • リアルタイムクロック (RTC) RC-8035SA
@lcd_address = 0x3e   # LCD のアドレス
@rtc_address = 0x32   # RTC のアドレス

# コマンド (cmd) 送信
def lcd_cmd(i2c, cmd)
  i2c.write(@lcd_address, [ ... , cmd])
end

# 文字列 (data) 送信
def lcd_data(i2c, data)
  i2c.write(@lcd_address, [ ... , data])
end

# LCD の画面クリア
def lcd_clear(i2c)
  lcd_cmd(i2c, ....)
  sleep 0.1
end

# LCD のカーソルを 1 行目の 1 文字目へ
def lcd_home0(i2c)
  lcd_cmd(i2c, .....)
  sleep 0.1
end

# LCD のカーソルを 2 行目の 1 文字目へ
def lcd_home1(i2c)
  lcd_cmd(i2c, ......)
  sleep 0.1
end

# LCD の初期化
def lcd_init(i2c)
  sleep 0.2
  [......................].each do |cmd|
    lcd_cmd(i2c, cmd)
  end
  sleep(0.3)
  [......................].each do |cmd|
    lcd_cmd(i2c, cmd)
  end
  sleep(0.1)
end

# LCD への表示.引数で与えられた文字 1 つ 1 つを lcd_data メソッドで送信
def lcd_print(i2c, data)
  data.length.times do |n|
    lcd_data(i2c, data[n].ord)
  end
end

# RTC の初期化
def rtc2_init(i2c)
  i2c.write(0x32, [0xE0, 0x00, 0x00])
  sleep 0.1
end

# RTC の値のセット.
def rtc2_set(i2c)
  i2c.write(@rtc_address, [0x00, 0x50, 0x59, 0x23|0x80, 0x01, 0x09, 0x10, 0x24])  # 時刻の指定
  sleep 0.1
  i2c.write(@rtc_address, [0xF0, 0x00])
  sleep 0.1
end

# RTC から時刻を呼び出し配列にセットする
def rtc2_get(i2c, tt)
  buf = i2c.read(@rtc_address, 8).bytes   # 8 バイト分読み込み --> strings
  p buf

  tt['year'] = buf[7]
  tt['mon']  = buf[6]
  tt['mday'] = buf[5]
  tt['hour'] = buf[3] & 0x3f
  tt['min']  = buf[2]
  tt['sec']  = buf[1]
end


#I2C 初期化
i2c = I2C.new(22, 21)

# LCD 初期化
lcd_init(i2c)

# LCD に "Hello World" 表示
lcd_clear(i2c)
lcd_home0(i2c)
lcd_print(i2c, "Hello!")
lcd_home1(i2c)
lcd_print(i2c, "from ESP")

sleep(5)

# RTC 初期化. 時刻設定
rtc2_init(i2c)
rtc2_set(i2c)

while true
  # 時刻表示
  tt = {}            #ハッシュ定義
  rtc2_get(i2c, tt)  #時刻取得

  time0 = sprintf("%02x-%02x-%02x", tt['year'], tt['mon'], tt['mday'])  # 年月日
  time1 = sprintf("%02x:%02x:%02x", tt['hour'], tt['min'], tt['sec'])   # 時分秒

  lcd_home0(i2c)
  lcd_print(i2c, time0)

  lcd_home1(i2c)
  lcd_print(i2c, time1)

  sleep(1)
end

補足

RTC へ入力する時刻を,決め打ちではなく,メソッドの引数で指定する場合は,以下のように修正すると良い. 但し,メソッドの入力値は 10 進数整数であることを前提としている.

def rtc2_set( i2c, year, mon, mday, wday, hour, min, sec )
#  p year, mon, mday, wday, hour, min, sec

  # BCDコードへ変換. 年(下2桁), 月, 日, 曜日, 時, 分, 秒
  year0 = (year / 10).to_i(2) << 4 | (year % 10).to_i(2)
  mon0  = (mon  / 10).to_i(2) << 4 | (mon  % 10).to_i(2)
  mday0 = (mday / 10).to_i(2) << 4 | (mday % 10).to_i(2)
  wday0 = (wday / 10).to_i(2) << 4 | (wday % 10).to_i(2)
  hour0 = (hour / 10).to_i(2) << 4 | (hour % 10).to_i(2)
  min0  = (min  / 10).to_i(2) << 4 | (min  % 10).to_i(2)
  sec0  = (sec  / 10).to_i(2) << 4 | (sec  % 10).to_i(2)

  i2c.write(@rtc_address, [0x00, sec0, min0, hour0|0x80, wday0, mday0, mon0, year0])
  sleep 0.1
  i2c.write(@rtc_address, [0xF0, 0x00])
  sleep 0.1
end