【MSX0】ANALOG_G.PAS【Turbo Pascal】

# はじめに
『MSX0 Stack』付属の IoT BASIC サンプルを『Turbo Pascal』へ移植してみます。

 - [【MSX0】IoT BASIC サンプルの移植【Turbo Pascal】(Qiita)](https://qiita.com/ht_deko/items/2362488c5c99aec4afbf)

# ANALOG_G.BAS
◆アナログ入力

| 項目 | 説明 |
|:---|:---|
| 概要 | Port B (黒) のピン 36 からのアナログ入力信号で簡単なグラフを描きます。 |
| ファイル名 | ANALOG_G.BAS |
| 対応デバイス | Seeed Grove [A0] Rotary Potentionmeter<br>Seeed Grove [A6] Light<br>Seeed Grove [A2] Sound<br>Seeed Grove [D6] Button<br>その他自作の機器 |
| コメント | ※[A6]太陽光など比較的強い光でないと反応しないようです。<br>※[D6]本来はデジタル入力です |

:::note warn
このサンプルを動作させるには外部センサーが必要です。
:::

**See also:**

 - [『MSX0 Stack』の操作方法 - ハードウェア (Qiita)](https://qiita.com/ht_deko/items/cdb1594e9879a5e9e660)
 - [Grove Beginner Kit for Arduino (Switch Science)](https://www.switch-science.com/products/6361)

## MSX0 Stack での挙動

`ANALOG_G.BAS` をロードして、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/429625bb-6bce-6bc7-289b-8b56187b9f4a.png)

実行してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/1b6fb4fe-fe0e-fe02-c368-3b88028c44b3.png)

MSX0 側の黒い **Port B** とセンサーの Grove コネクタをケーブルで接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/d46d7daa-3a91-3969-9353-38122ad6e57c.png)


| センサー | 操作 |
|:---|:---|
| [A0] Rotary Potentionmeter | ツマミを回す |
| [A6] Light | 強い光 (日光やスマホのフラッシュライト) をあてる |
| [A2] Sound | ~~「ハドソン！」と叫んでみる~~ 息を吹きかける |
| [D6] Button | ボタンを押してみる |

:::note info
プログラムは〔Ctrl〕+〔Stop〕(リモートコントロールパネルからは〔Ctrl〕+〔F12〕)で中断できます。
:::

## Turbo Pascal へ移植

別途、MDL-LIB と `SYSUTILS.LIB`、`IOT.LIB` が必要です。

 - [MDL-LIB version 2.2 の使い方 (Qiita)](https://qiita.com/ht_deko/items/6f15aee0bd25b550e4df)
 - [【MSX0】IOT.LIB (Qiita)](https://qiita.com/ht_deko/items/a5c0bf6e7969093beb3c)

```pascal:ANALOG_G.PAS
program ANALOG_G;
{$I MDLLIB.LIB}
{$I VRAM2.LIB}
{$I GRAPMSX2.LIB}
{$I SYSUTILS.LIB}
{$I IOT.LIB}
var
  A, X, Y: Integer;
begin
  ScrMode(5);
  while not KeyPressed do
  begin
    A := IoTGetInt('device/analog/in');
    Y := 206 - Trunc(A / 4096 * 200);
    if X = 0 then
      Plot(X, Y, 15) 
    else 
      DrawTo(X, Y, 15);
    X := X + 1;
    if X >= 256 then 
    begin
      X := 0;
      ClrScr;
    end;  
  end;
  TextMode;
end.
```

実行してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/49649d6e-192e-f119-1fff-b51250c5124f.png)

BASIC の時同様、各種センサーで値が変動します。

:::note info
任意のキーで中断できます。
:::

### 解説
アナログ入力の解像度は 12bit (0..4095) です。

#### Y 軸の求め方
Y 軸の計算は実数型 (Real) で行いました。オリジナル (BASIC) の式は次のようになっています。

```
40 Y=206-A/4096*200
```

これを Pascal に置き換えるわけですが、次の式だと整数除算なので、4096 で割っている箇所で値は 0 になってしまいます。

```pascal
 Y := 206 - A div 4096 * 200;
``` 

式を変形して次のようにやってしまうと、式の途中で MAXINT の範囲 (-32768..32767) を超えてしまいます。Turbo Pascal 3.0 の整数型には Integer (Int16) しかないのです。

```pascal
 Y := 206 - A * 200 div 4096;
``` 

`Trunc()` で括れば、その部分だけを実数演算できます。Turbo Pascal 3.0 の実数型は 48bit なので、計算結果が範囲を超える事はありません。

```pascal
Y := 206 - Trunc(A / 4096 * 200);
```

変数 Y を最初から実数型で宣言してもいいのですが、スクリーン座標は整数なので整数型で宣言したかったのです。

#### スクリーンモード
MSX-DOS 自身はテキストモードである `SCREEN 1 or 0` で実行されています。

テキスト画面の桁数を指定する MSX-DOS の内部コマンド `MODE n` で n に 32 以下の数字を設定すると `SCREEN 1`、それよりも大きな数を指定すると `SCREEN 0` で動作します。

プログラムは実行時にグラフィックモードの `SCREEN 5 (256x212 / 1 ドットごとにパレットからの 1 色)` に移行しているので、プログラム終了時に `TextMode()` を使って、プログラム実行前のテキストモードに戻しています。こうしないと Turbo Pascal や MSX-DOS へ戻った時にバグってしまうようです。

MDLLIB で、MSX2 以降用のライブラリ (`VRAM2.LIB` および `GRAPHMSX2.LIB`) をリンクしていますが、これは `SCREEN 5` が MSX2 以降で使えるスクリーンモードだからです。

# おわりに
今回の移植もあまり難しい所はありませんでしたね。