USB-IO LCD Rubyからの制御

「USB-IO LCD接続」で書いたように『手作りUSB機器』に載っていた USB-IO 液晶表示機を
既に作成し、動作確認済みである。
今回、液晶表示機をスクリプト言語 Ruby で制御するプログラムを書いてみた。

前回は、RBB PRESSの「手作りUSB機器」に置いてあった、本に載っているプログラムを
取ってきて動作させただけであった。
しかも、実行ファイルも含まれていたので、コンパイルさえしないという手抜きをしていた。

動作環境



  • Windows XP
  • テクノキット 汎用USB-I/Oキット USBIOV8/K
  • 秋月のシリアル制御液晶表示モジュールキットについていたLCD
  • 26P フラットケーブル
  • USBケーブル(ストレート)
  • 「USB-IO LCD接続」で作成した LCD 接続用基板
  • ruby 1.8.5 p12 mswin32
  • vbausbio.dll

準備


まず、以下を用意しておく

以下を実行しておく

  • ruby-1.8.5-p12-i386-mswin32.zip を展開する
  • 制御用のスクリプトを置くディレクトリに vbausbio.dll を置く
  • コマンドプロンプト(DOS窓)で制御用のスクリプトを置くディレクトリに移動する(例: cd c:\tmp)


Ruby スクリプトへの書き換え


本に載っていた ActiveBasic のプログラムを以下のように書き換えた。
ほとんどごく単純な書き換えだった。

ActiveBasic の sleep 関数の単位は ms のようである。
一方、Ruby の sleep 関数の単位は「秒」なのでその点は変更した。

require 'dl/import'

module USB_IO
extend DL::Importable
dlload "vbausbio.dll"
extern "long uio_out(long, long, long)"
end

class LCD
RS_BIT = 0x02
E_BIT = 0x01

def initialize
@p1_save = 0xff

@p1_save = (@p1_save & ~RS_BIT) | E_BIT
USB_IO.uio_out(1, @p1_save, 0)

USB_IO.uio_out(0, 0x30, 1)
#sleep(5)
sleep(0.005)
USB_IO.uio_out(0, 0x30, 1)
USB_IO.uio_out(0, 0x30, 1)
USB_IO.uio_out(0, 0x38, 1)
USB_IO.uio_out(0, 0x08, 1)
USB_IO.uio_out(0, 0x01, 1)
USB_IO.uio_out(0, 0x06, 1)
USB_IO.uio_out(0, 0x0e, 1)
end

def cmd_out(cmd)
if (@p1_save & RS_BIT) != 0
@p1_save = @p1_save & ~RS_BIT
USB_IO.uio_out(1, @p1_save, 0)
end
USB_IO.uio_out(0, cmd, 1)
end

def locate_xy(ypos, xpos)
pos = (ypos * 0x40 + xpos) & 0x7f
cmd_out(pos + 0x80)
end

def clear
cmd_out(0x01)
end

def data_out(data)
if data == 0x0c
clear
elsif data < 0x20
locate_xy(1, 0)
else
if (@p1_save & RS_BIT) == 0
@p1_save = @p1_save | RS_BIT
USB_IO.uio_out(1, @p1_save, 0)
end
USB_IO.uio_out(0, data, 1)
end
end

def message_out(mes)
mes.each_byte {|c| data_out(c)}
end
end

lcd = LCD.new
if ARGV.size > 0
lcd.message_out(ARGV.shift)
else
lcd.message_out("01234567890123456789\n01234567890123456789")
end

コマンドプロンプト(DOS窓)で以下のように実行するか、

> D:\tmp\soft\ruby-1.8.5-p12-i386-mswin32\bin\ruby.exe lcd00.rb

もしくは、スクリプトの後に表示したい文字列を指定して、以下のように実行する。

> D:\tmp\soft\ruby-1.8.5-p12-i386-mswin32\bin\ruby.exe lcd00.rb abcdefghijklmnopqrstuvwxyz

前半の実行では以下のように表示される。
画像:rubyスクリプトによるLCD表示

本に載っていたプログラム自体の挙動


上記プログラムを動かしてみて、表示文字列によっては表示がおかしいことに気がついた。
調べてみると、そもそも本に載っていたプログラム自体うまく動かない場合があるのが分かった。

例えば、以下のような文字列をテキストボックスに入力し LCD に表示させてみると、
意図したものとは違う表示があった。

  • 「0123456789」「abcdefghij」
  • 「abcdefghijklmnopqrstuvwxyz」
  • 「abcdefghijklmnopqrstuvwxyz」「ABCDEFGHIJKLMNOPQRSTUVWXYZ」

以下のように「0123456789」「abcdefghij」をテキストボックスに入力する。
画像

そのとき、以下のように LCD に表示された。
画像


以下のように「abcdefghijklmnopqrstuvwxyz」をテキストボックスに入力する。
画像

そのとき、以下のように LCD に表示された。
2行目に表示されて欲しい文字列が3行目に表示されてしまっている。
画像


以下のように「abcdefghijklmnopqrstuvwxyz」「ABCDEFGHIJKLMNOPQRSTUVWXYZ」をテキストボックスに入力する。
画像

そのとき、以下のように LCD に表示された。
2行目に表示されて欲しい文字列が3行目に表示され、
3行目に表示されて欲しい文字列が2行目に表示されてしまっている。
画像

1行あたり20文字を超えた文字列の表示がおかしいようである。
また、テキストボックスには 2行しか入力できないようである。

LCD の説明書を見ると、以下のようなアドレスになっていた。

1行:00-0F,10-13
2行:40-4F,50-53
3行:14-23,24-27
4行:54-63,64-67

本の解説では1行40文字まではちゃんと表示されるよう考慮してあるように思える。
しかし、ActiveBasic のコードを見る限り、使用 LCD のアドレスマップでは
うまく表示されない場合がありそうだ。

Ruby スクリプトの改良


以下のような仕様でスクリプトを改良してみた。

  • 20文字を超える文字列は次行に表示する
  • 改行が含まれている場合はそこで改行する
  • 4行を超えた場合は動作不定

以下のようになった。

いろいろな文字数や行数の LCD を考えてはいない。
あくまでも、今回試している 20文字4行の LCD 用に書いたので、
他の LCD だと問題があると思う。

require 'dl/import'

module USB_IO
extend DL::Importable
dlload "vbausbio.dll"
extern "long uio_out(long, long, long)"
end

class LCD
RS_BIT = 0x02
E_BIT = 0x01

def initialize
@p1_save = 0xff
@xpos = 0; @ypos = 0

@p1_save = (@p1_save & ~RS_BIT) | E_BIT
USB_IO.uio_out(1, @p1_save, 0)

USB_IO.uio_out(0, 0x30, 1)
sleep(0.005)
USB_IO.uio_out(0, 0x30, 1)
USB_IO.uio_out(0, 0x30, 1)
USB_IO.uio_out(0, 0x38, 1)
USB_IO.uio_out(0, 0x08, 1)
USB_IO.uio_out(0, 0x01, 1)
USB_IO.uio_out(0, 0x06, 1)
USB_IO.uio_out(0, 0x0e, 1)
end

def cmd_out(cmd)
if (@p1_save & RS_BIT) != 0
@p1_save = @p1_save & ~RS_BIT
USB_IO.uio_out(1, @p1_save, 0)
end
USB_IO.uio_out(0, cmd, 1)
end

def locate_xy(ypos, xpos)
@ypos = ypos; @xpos = xpos
#pos = (ypos * 0x40 + xpos) & 0x7f
case ypos
when 0 then pos = xpos & 0x7f
when 1 then pos = (0x40 + xpos) & 0x7f
when 2 then pos = (0x14 + xpos) & 0x7f
when 3 then pos = (0x54 + xpos) & 0x7f
else
raise "no support ypos locate(#{ypos},#{xpos})"
end
cmd_out(pos + 0x80)
end

def clear
cmd_out(0x01)
end

def data_out(data)
if (@p1_save & RS_BIT) == 0
@p1_save = @p1_save | RS_BIT
USB_IO.uio_out(1, @p1_save, 0)
end
USB_IO.uio_out(0, data, 1)
end

def message_out(mes)
mes.each_byte do |c|
if c < 0x20
locate_xy(@ypos + 1, 0)
else
if @xpos >= 20
locate_xy(@ypos + 1, 0)
end

data_out(c)
@xpos += 1
end
end
end
end

lcd = LCD.new
if ARGV.size > 0
lcd.message_out(ARGV.shift)
else
lcd.message_out("0123456789\nabcdefghij")
#lcd.message_out("abcdefghijklmnopqrstuvwxyz")
#lcd.message_out("abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ")
end

さきほどと同じように「0123456789」「abcdefghij」、「abcdefghijklmnopqrstuvwxyz」、
「abcdefghijklmnopqrstuvwxyz」「ABCDEFGHIJKLMNOPQRSTUVWXYZ」をそれぞれ
表示させてみると、順に以下のようになった。
画像

画像

画像

ちなみに、コマンドプロンプト(DOS窓)で改行コードを入力する方法が分からなかった。
以下のように実行した。

> D:\tmp\soft\ruby-1.8.5-p12-i386-mswin32\bin\ruby.exe lcd01.rb 0123456789\nabcdefghij

すると、「\n」が改行とはみなされずに以下のように LCD にそのまま
「\n」と表示されてしまった。
画像:コマンドプロンプトで改行を入れるには?

まとめ



  • USB-IO 液晶表示機をスクリプト言語 Ruby で制御するプログラムを書いてみた。
  • 本に載っていたプログラム自体の挙動が使用 LCD では正しくない場合があることが分かった。
  • それを考慮した Ruby スクリプトを書いた。

この記事へのコメント

この記事へのトラックバック