I2C (mruby/c)

はじめに

教育ボードに搭載されている液晶ディスプレイ (LCD) とリアルタイムクロック (RTC) を使う. 下記で述べるように, プログラムを穴埋め形式にしているので, データシートから必要な情報を読み取って それを埋めることを試みて欲しい.

プロジェクトの準備

基本的に ESP-IDF 環境と同じなので, ESP-IDF 環境がインストールされているディレクトリ (ここでは $HOME/esp) 以下にプロジェクト用のディレクトリを作る. GitHub から j5_es_2020 ブランチを git clone する. なお, このブランチは make menuconfig で機能を設定することはできないので注意すること.

$ cd ~/esp

$ git clone -b j5_es_2020 https://github.com/gfd-dennou-club/iotex-esp32-mrubyc.git mrubyc-04-i2c

$ cd mrubyc-04-i2c

プログラムの作成

LCD に最初の 10 秒間 "Hello!! from ESP" と表示させ, その後に時刻を表示させるようにする.

プログラムの中身については, データシートとプログラム中の注釈を参照のこと. なお, プログラムに対する詳細なコメントは Arduino IDE 版に付けたので, そちらも参照して欲しい.

mrblib/loops/master.rb

1  # coding: utf-8-hfs
2 
3  #I2C 初期化
4  i2c = I2C.new(0, 22, 21)
5  i2c.driver_install
6 
7  # LCD 初期化
8  lcd = AQM0802A.new(i2c)
9  lcd.setup
10 
11 # LCD に "Hello World" 表示
12 lcd.cursor(1, 0)
13 lcd.write_string("Hello!")
14 lcd.cursor(0, 1)
15 lcd.write_string("from ESP")
16 sleep(10)
17 
18 # RTC 初期化. 時刻設定 (2020/03/31 23:59:50 に手動で設定)
19 rtc = RC8035SA.new(i2c)
20 rtc.write([0x20, 0x03, 0x31, 1, 0x23, 0x59, 0x50]) #年(下2桁), 月, 日, 曜日, 時, 分, 秒
21 
22 while true
23   # 時刻表示
24   tt = rtc.read
25   lcd.cursor(0, 0)
26   lcd.write_string(sprintf("%02x-%02x-%02x", tt[0], tt[1], tt[2]))
27   lcd.cursor(0, 1)
28   lcd.write_string(sprintf("%02x:%02x:%02x", tt[4], tt[5], tt[6]))
29   sleep(1)
30 end

mrblib/models/i2c.rb

1 class I2C
2   def initialize(port, scl, sda)
3     @port = port
4     @scl  = scl
5     @sda  = sda
6   end
7 end

[穴埋め問題] mrblib/models/aqm0802a.rb

1  # AQM0802A-RN-GBW
2  #
3  # I2C address : 0x3e
4 
5  class AQM0802A
6   
7    def initialize(i2c)
8      @i2c = i2c
9    end
10 
11   def setup
12     @i2c.write(0x3e, []) # データシートから適切なコントロールバイト, データバイトを与えよ
13     sleep(1)
14     @i2c.write(0x3e, []) # データシートから適切なコントロールバイト, データバイトを与えよ
15   end
16 
17   def clear
18     @i2c.write(0x3e, []) # データシートから適切なコントロールバイト, データバイトを与えよ
19   end
20 
21   def cursor(x, y)
22     @i2c.write(0x3e, []) # データシートから適切なコントロールバイト, データバイトを与えよ
23   end
24 
25   def write_string(s)
26     a = Array.new
27     a.push(0x40)           # コントロールバイト (0x40 は書き込み) を配列に追加
28     s.length.times do |n|
29       a.push(s[n].ord)     # データバイトを配列に追加
30     end
31     @i2c.write(0x3e, a)    # I2C アドレスと, コントロールバイト・データバイトの配列を与える
32   end
33 
34 end
  • 7-9 行目 : コンストラクタ
  • 11-15 行目 : 初期化メソッド.
    • 12, 14 行目 : I2C 通信の中核部分 (C 言語のライブラリの読み出し部分). 引数として I2C アドレス (0x3e) と, コントロールバイトとデータバイトから成る配列を与える.
  • 17-19 行目 : LCD の画面のクリアするメソッド
  • 21-23 行目 : LCD の画面のカーソルを指定の場所に移動させるメソッド
    • x は左から何番目かを示す (x = 0..7). y は行数を示す (y = 0 or 1)
  • 25-32 行目 : LCD に文字列を書くメソッド

[穴埋め問題] mrblib/models/rc8035sa.rb

1  # coding: utf-8
2  # RTC: EPSON RC-8035SA
3  #
4  # I2C address : 0x32
5 
6  class RC8035SA
7    def initialize(i2c)
8      @i2c = i2c
9      @i2c.write(0x32, [])  # データシートから適切な値を与えよ
10     sleep 0.1
11   end
12 
13   def read
14     a = @i2c.read(0x32, 8)   # 8 バイト分読み込み
15     ctrl2 = a.shift
16     return [a[6], a[5], a[4], a[3], 0x3f & a[2], a[1], a[0], ctrl2]
17   end
18 
19   def write(date)
20     @i2c.write(0x32, [])   # 時刻の設定部分をデータシートから考えてみよ
21     sleep 0.1
22     @i2c.write(0x32, [0xF0, 0x00])
23     sleep 0.1
24   end
25 end
  • 7-11 行目: コンストラクタ
    • 9 行目: 初期化プロセスも同時に行っている. レジスタ Eh, Fh をゼロクリアする命令を書き加えよ.
  • 13-17 行目: 読み出しメソッド.
    • 8 バイト分読み出し, それぞれを配列に格納する (配列の各要素が「年」, 「月」, ... を表す).
    • 16 行目 : なぜ 0x3f との AND を取っているかデータシートを元に考えてみよ.
  • 19-24 行目: 書き込みメソッド
    • 20 行目: 時刻の設定.
      • mrblib/loops/master.rb の 20 行目と対応させて考えてみよ.

コンパイルと実行

コンパイルと実行を行う.

$ make

$ make flash monitor