1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【MSX0】LCD.LIB

Last updated at Posted at 2023-11-01

はじめに

MSX0 (MSX-DOS) で使える Liquid Crystal Display (LCD) ライブラリを作ってみました。

image.png

ライブラリ

ライブラリは Arduino の Liquid Crystal ライブラリ互換となっています。

LCD.LIB

LCD ライブラリです。

  • I2C タイプの LCD に対応しています
  • LCD モジュールを PortA に接続して使います
  • 一般的な 1602 LCD の他に 2004 LCD も使えます
  • 別途、IOT.LIB が必要です
ファイル名 依存ライブラリ
LCD.LIB SYSUTILS.LIB, IOT.LIB
LCD.LIB
{
  LCD.LIB
}

type
  LCDStr  = string[40];
  TChrDef = array [0..7] of byte;
  TLCDRec = record
              Node: LibStr;
              Cols: byte;
              Rows: byte; 
              CharSize: byte; 
              Backlight: byte;
              Display: byte;
              DispFunc: byte;
              EntryMode: byte;
            end;

var
  _lcd: TLCDRec;

procedure LCD_Send(data, m: byte);
  procedure WriteData(data: byte);
  const
    En = 4;
  var
    s: string[2];
  begin
    s[0] := Chr(2); { SetLength(s, 2) }
    s[1] := Chr(data or En);
    s[2] := Chr(data);
    IoTPutStr(_lcd.Node, s);
  end;
begin
  WriteData(data and $F0 or _lcd.Backlight or m);
  WriteData(data shl 4   or _lcd.Backlight or m);
end;

procedure LCD_Command(data: byte);
begin
  LCD_Send(data, 0);
end;

procedure LCD_WriteData(data: byte);
begin
  LCD_Send(data, 1);
end;

function LCD_ColsInRange(col: byte): byte;
begin
  if col < 0 then 
    col := 0;
  if col > Pred(_lcd.Cols) then 
    col := Pred(_lcd.Cols);
  LCD_ColsInRange := col;
end;

function LCD_RowsInRange(row: byte): byte;
begin
  if row < 0 then 
    row := 0;
  if row > Pred(_lcd.Rows) then 
    row := Pred(_lcd.Rows);
  LCD_RowsInRange := row;
end;

procedure LCD_Begin(Node: LibStr; Cols, Rows: byte; Use5x10: boolean);
const
  FS = $20;
  CS: array [boolean] of byte = ($00, $04);
begin
  _lcd.Node      := Node;
  _lcd.CharSize  := CS[Use5x10];
  _lcd.Cols      := Pred(40);
  _lcd.Cols      := Succ(LCD_ColsInRange(Pred(Cols)));
  _lcd.Rows      := Pred(4);
  _lcd.Rows      := Succ(LCD_RowsInRange(Pred(Rows)));
  _lcd.BackLight := $08; { ON }
  _lcd.Display   := $0C; { ON }
  _lcd.EntryMode := $06; { Inclement }
  _lcd.DispFunc  := $00;
  if _lcd.Rows > 1 then
    _lcd.DispFunc := _lcd.DispFunc or $08; { 2 Line }
  if (_lcd.CharSize <> 0) and (_lcd.Rows = 1) then
    _lcd.DispFunc := _lcd.DispFunc or $04; { 5x10 }
  LCD_Command($33);                 { Function Set: 8bit }
  LCD_Command($32);                 { Function Set: 8bit }
  LCD_Command(FS or _lcd.DispFunc); { Function Set: 4bit }
  LCD_Command(_lcd.Display);
  LCD_Command($01);
  LCD_Command(_lcd.EntryMode);
end;

procedure LCD_Clear;
begin
  LCD_Command($01);
end;

procedure LCD_Home;
begin
  LCD_Command($02);
end;

procedure LCD_SetCursor(col, row: byte);
const
  Offset: array [0..3] of byte = ($00, $40, $14, $54);
begin
  col := LCD_ColsInRange(col);
  row := LCD_RowsInRange(row);
  LCD_Command($80 or (Offset[row] + col));
end;

procedure LCD_Write(s: LCDStr);
var
  i: integer;
begin
  for i:=1 to Length(s) do
    LCD_WriteData(Ord(s[i]));
end;

procedure LCD_Cursor;
begin
  _lcd.Display := _lcd.Display or $02;
  LCD_Command(_lcd.Display)
end;

procedure LCD_NoCursor;
begin
  _lcd.Display := _lcd.Display and not $02;
  LCD_Command(_lcd.Display);
end;

procedure LCD_Blink;
begin
  _lcd.Display := _lcd.Display or $01;
  LCD_Command(_lcd.Display);
end;

procedure LCD_NoBlink;
begin
  _lcd.Display := _lcd.Display and not $01;
  LCD_Command(_lcd.Display);
end;

procedure LCD_Display;
begin
  _lcd.Display := _lcd.Display or $04;
  LCD_Command(_lcd.Display);
end;

procedure LCD_NoDisplay;
begin
  _lcd.Display := _lcd.Display and not $04;
  LCD_Command(_lcd.Display);
end;

procedure LCD_ScrollDisplayLeft;
begin
  LCD_Command($18);
end;

procedure LCD_ScrollDisplayRight;
begin
  LCD_Command($1C);
end;

procedure LCD_Autoscroll;
begin
  _lcd.EntryMode := _lcd.EntryMode or $01;
  LCD_Command(_lcd.EntryMode);
end;

procedure LCD_NoAutoscroll;
begin
  _lcd.EntryMode := _lcd.EntryMode and not $01;
  LCD_Command(_lcd.EntryMode);
end;

procedure LCD_LeftToRight;
begin
  _lcd.EntryMode := _lcd.EntryMode and not $02;
  LCD_Command(_lcd.EntryMode);
end;

procedure LCD_RightToLeft;
begin
  _lcd.EntryMode := _lcd.EntryMode or $02;
  LCD_Command(_lcd.EntryMode);
end;

procedure LCD_CreateChar(loc: byte; data: TChrDef);
var
  i: integer;
begin
  loc := loc and $07;
  LCD_Command($40 or (loc shl 3));
  for i:=0 to 7 do
    LCD_WriteData(data[i]);
end;

ルーチン

名前 定義 説明
LCD_Begin procedure LCD_Begin(Node: LibStr; Cols, Rows: byte; Use5x10: boolean); LCD の使用を開始します
LCD_Clear procedure LCD_Clear; LCD の 画面をクリアし、カーソルをホームポジションに移動します
LCD_Home procedure LCD_Home; カーソルをホームポジション (左上) へ移動します
LCD_SetCursor procedure LCD_SetCursor(col, row: byte); カーソルの位置を指定します (0 オリジン)
LCD_Write procedure LCD_Write(s: LCDStr); カーソル位置に文字列を表示します
LCD_Cursor procedure LCD_Cursor; カーソルを表示します
LCD_NoCursor procedure LCD_NoCursor; カーソルを非表示にします
LCD_Blink procedure LCD_Blink; カーソルの点滅を開始します
LCD_NoBlink procedure LCD_NoBlink; カーソルの点滅を停止します
LCD_Display procedure LCD_Display; 画面を表示します
LCD_NoDisplay procedure LCD_NoDisplay; 画面を非表示にします
LCD_ScrollDisplayLeft procedure LCD_ScrollDisplayLeft; 画面を 1 文字分左へスクロールします
LCD_ScrollDisplayRight procedure LCD_ScrollDisplayRight; 画面を 1 文字分右へスクロールします
LCD_Autoscroll procedure LCD_Autoscroll; 自動スクロール機能を有効にします
LCD_NoAutoscroll procedure LCD_NoAutoscroll; 自動スクロール機能を無効にします
LCD_LeftToRight procedure LCD_LeftToRight; テキスト表示の向きを左から右に設定します
LCD_RightToLeft procedure LCD_RightToLeft; テキスト表示の向きを右から左に設定します
LCD_CreateChar procedure LCD_CreateChar(loc: byte; data: TChrDef); カスタム文字の字形を指定します。ASCII コード表の 0x00~0x07 の文字を書き替えられます

Arduino の LiquidCrystal ライブラリにある print() は実装されていません。print() には数値表示、書式、基数変換等の機能があります。Write() はシンプルな文字列出力のみです。

名前 定義 説明
LCDStr type LCDStr = string[40]; 文字列出力用
TChrDef type TChrDef = array [0..7] of byte; カスタム文字の定義用
TLCDRec type TLCDRec =
record
  Node: LibStr;
  Cols: byte;
  Rows: byte;
  CharSize: byte;
  Backlight: byte;
  Display: byte;
  DispFunc: byte;
  EntryMode: byte;
end;
ステータス保存用

変数

名前 定義 説明
_lcd var _lcd: TLCDRec; ステータス保存用

サンプル

冒頭の画像と同じものを出力するサンプルです。

LCDTEST.pas
program LCDTEST;
type
  LibStr = string[80];
{$I SYSUTILS.LIB}
{$I IOT.LIB}
{$I LCD.LIB}
const
  Monster: TChrDef = ($00, $0E, $1F, $15, $1F, $1F, $15, $00);
  Pacman:  TChrDef = ($0E, $0F, $1E, $1C, $1E, $0F, $0E, $00);
begin
  LCD_Begin('device/i2c_a/27', 16, 2, False); { I2C Address 0x27 / 1602 Display}
  LCD_Write('Hello,MSX0world!');
  LCD_CreateChar($00, Monster);
  LCD_CreateChar($01, Pacman);
  LCD_SetCursor(1, 1);
  LCD_Write(#$00#$00' '#$00'   '#$01);
end.

image.png

サンプル例では I2C アドレス が 0x27 の LCD を使っています。お手持ちの LCD の I2C アドレスが判らない場合には I2C スキャナを使って調べてください。

See also:

参考資料

ライブラリを作るにあたって参考にしたサイトです。

おわりに

簡単に I2C 接続 LCD が使えて便利ですね。

image.png

See also:

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?