cairoでLCDに表示


FTDIのFT245Rにグラフィック有機ELモジュール(とりあえずLCD)をつないで、mruby-cairoでデータを作り表示してみました。いつものように環境はFreeBSD 12-Currentです。

LCDは4bitモードで利用して、データ4本のコントロール3本の接続にしています。

mrubyはmruby-cairomruby-ftdiを入れてZRouterビルドしています。

#
# LCD sample code on libftdi
#

class LCD4
  RW = 0x10
  RS = 0x20
  E = 0x40

  def lcd4init()
    @ftdi = Ftdi.new(0x6001, 0xff)
    @ftdi.baudrate(115200)
    @cache = 0
    self.out(0)
  end

  def out(ch)
    @ftdi.write([ch])
  end

  def cmd(ch)
    arr = Array.new
    c = (ch >> 4)
    arr << c
    arr << (c | E)
    arr << c
    c = (ch & 0xf)
    arr << c
    arr << (c | E)
    arr << c
    if @chache == 1 then
      @garr << arr
    else
      @ftdi.write(arr)
    end
  end

  def data(ch)
    arr = Array.new
    c = (ch >> 4) | RS
    arr << c
    arr << (c | E)
    arr << c
    c = (ch & 0xf) | RS
    arr << c
    arr << (c | E)
    arr << c
    if @chache == 1 then
      @garr << arr
    else
      @ftdi.write(arr)
    end
  end

  def start()
    @cache = 1
    @garr = Array.new
  end

  def flash()
    @ftdi.write(@garr)
  end
end

class HD44780 < LCD4
  Clear_Display = 0x10
  Return_Home = 0x02
  Set_Entry_Mode = 0x04
  Set_Display = 0x08
  Set_Cursor_and_Display_Shift = 0x10
  Set_Function = 0x20
  Set_CGRAM_Address = 0x40
  Set_DDRAM_Address = 0x80

  Decrement_Address = 0x00
  Increment_Address = 0x02
  Shift_Display_Off = 0x00
  Shift_Display_On = 0x01

  Display_Off = 0x00
  Display_On = 0x04
  Cursor_Off = 0x00
  Cursor_On = 0x02
  Blink_Off = 0x00
  Blink_On = 0x01

  Cursor = 0x00
  Display_and_Cursor = 0x08
  Left = 0x00
  Right = 0x04

  Data_Length_4 = 0x00
  Data_Length_8 = 0x10
  One_Display_Line = 0x00
  Two_Display_Lines = 0x08
  Font_5x7 = 0x00
  Font_5x10 = 0x04

  def initialize()
    lcd4init
    cmd(Set_Function)
    usleep(1000)
    cmd((Set_Function | Data_Length_4) >> 4 )
    usleep(100)
    cmd((Set_Function | Data_Length_4) | Two_Display_Lines)
    usleep(100)
    cmd(0x06)
    usleep(100)
    cmd(0x0f)
    usleep(100)
    cmd(0x1f)
    usleep(100)
    cmd(Return_Home)
  end
end

def copylcd(c, t)
  for n in 1..2 do
    rgba = c.getpix(0, 8 * (n - 1), 100 * 8)
    t.start
    t.cmd(0x40 + (n - 1))
    for i in 1..100 do
      t.cmd(0x80 + (i - 1))
      pat = 0
      for k in 1..8 do
        if rgba[1 + (i - 1) * 4 + 100 * (k - 1) * 4] == 0xff
          bit = 1
        else
          bit = 0
        end
        pat = pat | bit << (k - 1)
      end
    t.data(pat)
  end
  t.flash
  end
end

t = HD44780.new

c = Cairo.new(100,16)

c.set_source_rgb(1, 1, 1)
c.set_line_width(1)
c.rectangle(0.5, 0.5, 99, 15)
c.stroke();

c.move_to(20, 12)
c.set_source_rgb(1, 1, 1)
c.font_create("/tmp/6x13.pcf")
c.set_font_size(13)
c.show_text("mruby cairo")
c.stroke();

copylcd(c, t)

白黒(単色)なので0xffかそれ以外で処理しています。

rectangleがx,yともに0.5になっているのはcairoではこのx,yを中心にしてwidthのラインを引くためです。0,0だと上と下のピクセルにまたがりデータを拾うと0xffになっていませんでした。

斜めの線はピクセルが0xffにならないので、このコードでは引けません。

漢字も表示できます。

これはk8x12ですが、12ポイントくらいが収まりがよいです。

FreeBSDのツリーにパラレルポートを使ってLCDをコントロールするサンプルコードがありました。最近ではパラレルポートが付いたマシンはほとんどありませんが。