成安造形大学コラボレーション・プロジェクト

アーティストのための汎用センサ自作応援講座

2001年1月 長嶋洋一


第6話

さて、秋月電子の「AKI-H8マザーボードキット(フラッシュROMライタ付)」を 第5話 に従って製作した、というビギナーのための、今度は続編で「ソフト開発」編 です。ただし、アセンブラによるAKI-H8のプログラミング、というのは ちょっといきなりハイレベルに飛躍してしまうので、ここでは「既に完成 しているAKI-H8ソフトを自分のAKI-H8にプログラムして動かす」という 開発環境についてです。アセンブラとかC言語とかでAKI-H8を開発する、と いうお話は、いずれもしかしたら書こうとも思いますが、可能性は不明です。 僕のここのWebには、AKI-H8モノについては、この「完成して書き込む だけのプログラム(MOTファイル)」というのを必ず置いていますので、 ハンダ付けでハードを製作すれば、今回のやり方でソフトを仕込んで、動作 させることができるようになります。

それでは、秋月電子のマニュアルに従って環境設定から行っていきましょう。 ここでのスクリーンショットは、僕のPowerBookの画面内のVirtual PC内の Windowsということになりますので、次の図のあとはその中だけをクリップします。 奇特にもWindowsな人(^_^;)は、そのまま中だけを見て下さい。同等のお話です。

これ は、エクスプローラで、秋月CDROM(ないしその中身をコピーした)フォルダの 中の、WRITERというものです。他のファイルは圧縮していないのですが、 これだけはインストーラがあるので、まずこれを設定しておきます。なお、 ここでは例として「c:\MSDOS\SSS」というディレクトリを設定して、その中の 世界として環境を作ります。

この中のSETUP.EXEというのをダブルクリックして起動すると、 このような インストーラが起動します。 「OK」以外の選択肢がないのでクリックすると、 こんな ことを聞いてきます。この「ディレクトリ」には、AKI-H8開発を 行う場所を指定します。あらかじめ、専用のディレクトリを作っておくと、 他とまざって混乱しないでしょう。「ポート番号」というのは、 RS-232Cのシリアルポートですが、よく判らない場合には1にしておいて、 うまく行かなかったらあとで2とか3とか試します。(^_^;)

そして、「OK」クリックでインストールされた結果が、 これ です。なんのことはない、結果としては、 指定した作業領域(ここではディレクトリ"SSS")の中に、 3048という二つのファイルとFLASH.EXEというファイルが、そのまんまコピーされる だけです。

これでフラッシュROMライタ関係ができたので、あとは普通に入っていた アセンブラ関係も、同じ作業ディレクトリ"SSS"にコピーするだけです。 これ は、秋月CDROMの中のASMというディレクトリの中身です。必要なのは EXE全てです。ちなみに、H38HMAN.TXTというのは、H8のアセンブラの マニュアルですので、いずれプログラミングに挑戦したい人はこれも せっかくなのでコピーしておきます。ところでH38HMAN.DOCというのは、 エディタで見てもバイナリ文字化けしているし、なんなのか不明です。(^_^;)
ドキュメントっぽいファイル名なのにテキストファイルでもない、 こういう邪悪なファイルというのは、ウイルスに感染したりしますので、 さっさと消去してしまうというのもいいですね。当然、AKI-H8の開発環境に こういう怪しいものはコピーする必要はありません。僕はワープロというもの をもう10年ぐらい使っていないので、"Word"なんて知りませんし。

ということで、AKI-H8開発に必要なファイルとしては、アセンブラの マニュアルも含めて こんな 感じで並ぶことになります。少ないしシンプルですよね。ここに、AKI-H8の ソースプログラムを置いて、この中でアセンブル等を行って、そのままこの 中でフラッシュROMの書き込みまで行ってしまう、という閉じた世界を構成 することで、Windowsのわけわからん怪しい環境よりもスッキリと作業する ことができます。(^_^)

さて、実際の作業では、この DOS窓 を使います。頻繁に使うので、\WINDOWSディレクトリの中の「MS-DOSプロンプト」 のショートカットを作ってデスクトップに置いておくのもいいでしょう。 ここで、秋月CDROMの"MB"というディレクトリに置かれたサンプルプログラム を題材にしますので、"MBTEST.MAR"というファイルを、さらに ここにコピーしてきます。カレントディレクトリ(現在、自分が いるディレクトリ)のファイルの一覧のコマンドは「 dir 」です。...なんてことは、最近の学校では 教えないのかなぁ。(^_^;)

"MBTEST.MAR"というのがAKI-H8のソースプログラムになりますが、 このMBTEST.MARをアセンブラにかけた、というのが これ です。つまり、DOSのプロンプト「>」のところに、いちいち このように打ち込むわけです。MBTESTのところが、自分のプログラム であればそれに代わります。 ここで、人間に読めるアセンブラプログラムが、機械語になります。
特にエラーがなければこのように出てきて、エラーがあればそのラインナンバー が表示されるので、それを頼りにバグをつぶします。 結果として、MBTEST.OBJというのとMBTEST.LISというファイルが新しく できました。OBJは次のステップで使います。LISは内部作業記録ファイル ですが、テキストですので、エラーが出ても原因が判らない時に、これを 読んで解析するのに使います。

アセンブルに成功したOBJファイルを、次にリンカにかけたのが これ です。つまり、DOSのプロンプト「>」のところに、いちいち このように打ち込むわけです。MBTESTのところが、自分のプログラム であればそれに代わります。リンクとは、ここでは単なる内部変換ぐらいに 思っておきましょう。 特にエラーがなければこのように出てきます。 結果として、MBTEST.ABSというのが新しくできました。これは次のステップで使います。

リンクの結果のABSファイルは、さらにコンバータで変換します。 これは、モトローラ形式のSファイル、というものにしている作業です。 これ です。つまり、DOSのプロンプト「>」のところに、いちいち このように打ち込むわけです。MBTESTのところが、自分のプログラム であればそれに代わります。 特にエラーがなければこのように出てきます。 結果として、MBTEST.MOTというのが新しくできました。

ということで、いわゆる「ソフト開発」の作業が終わりました。あとは、 AKI-H8マザーボードのフラッシュROMライタ機能を使って、このMOT ファイル(AKI-H8の実行プログラムをROMに書き込める形にしたもの) をダウンロードすればいいだけです。
この時点での風景は、 こんな ものです。ここでは開発マシンはPowerBookですが、Windowsでも同様です。 スクリーンにはDOSプロンプトがあり、シリアルポート(RS-232C)からは AKI-H8マザーボードにケーブルが伸びています。電源は、マザーボードの 電源スイッチS6がOFFであるのを確認した上でACに差し込みます。

まず、 このように 電源スイッチS6がOFFである、という事を確認して、DOS窓の中で このように FLASH.EXEを起動します。
すると、 このように 聞いてきますので、3048.INFが設定されていることを 確認して、「設定」をクリックします。
すると、 このように 聞いてきますので、まずはAKI-H8マザーボードのモード切り替えスイッチS7が このように ONになっている事を確認した上で、電源スイッチS6を このように ONにします。その上で、画面内の「設定」をクリックします。

すると、接続とかハード関係が全て正常であれば、 このように 0%から100%まで、ブートローダプログラムが転送されて、転送が 完了します。どこかにミスがあればまったく画面は進行しませんが、 いずれ「タイムアウトエラー」で終了できますので、慌ててリセット しなくても大丈夫です。
ブートローダの転送が無事に終了したら、引き続きそのまま、今度は メニューの「WRITE」コマンドの先頭で このような ものを出します。設定するのは「ファイル名」だけで、あとは そのままでOKです。とりあえず「参照」のボタンをクリックして、 AKI-H8に転送したMOTファイルの場所を このように 捜して、 このように ファイル名の欄をセットしたら「OK」をクリックします。
すると、 このように 0%から100%まで、ユーザプログラムが転送されて、転送が 完了します。たいていの場合、こちらはほんの一瞬です。(^_^)

これで、AKI-H8のプログラミングは完了です。そこで、 このように まず、いったん電源スイッチS6をOFFにします。S7を電源を入れた 状態で変化させてはいけません。
そして次に、 このように モードスイッチのS7をOFF側にします。このスイッチの意味は、 プログラミングモードのON/OFFということですので、OFFという のは、「通常の実行モード」ということになります。
そして、S7がOFF側(実行モード)にあることを確認した上で、再び このように 電源スイッチS6をONにします。これは、通常の電子機器としての AKI-H8システムの電源をONにした、という事に相当します。

すると このように AKI-H8が動作して、LCDパネルにメッセージが見事に表示されました。 下段の数字の羅列はスイッチ状態の表示で、右側の8ビットはDIPスイッチの 状態とちゃんと対応しています。また、 このように 右側の二つのプッシュスイッチについては、LCDパネルとともに DIPの上のLEDも対応して光るようになっています。

この秋月のサンプルプログラムは、以下のようなものです。

;	サンプルソフト MBTEST.MOT
;	16文字*2行LCDの接続
;	データ=ポート3
;	E  =ポート3のビット5
;	RS =ポート3のビット4
;
;■液晶表示の使い方
;1,ソフトウエアリセット
;	ファンクションセット1
;	ファンクションセット2
;	ファンクションセット3
;	ファンクションセット
;2,初期設定
;	ファンクションセット
;	表示on
;	エントリーモード
;3、上記終了後
;1文字のデータ表示または、コマンド
;	RAM H'FEF10(@LCD_D)にデータをセット後
;	データの場合はRSを1にセット、
;	コマンドの場合はRSを0にセットし
;	LCD_OUTをサブルーチンコールする。
;16文字2行表示
;	RAM H'FEF11(@LCD162)から32文字文のデータをセット後
;	LCDDSPをサブルーチンコールする。
;
;	接続
;	H8マイコン	LCD
;	P3ー0	D4
;	P3ー1	D5
;	P3ー2	D6
;	P3ー3	D7
;	P3−5	E
;	P3−4	RS
;	GND		R/W
;-----CPUの指定-----	
	.CPU 300HA
;-----シンボル-----
SW_D	.EQU	H'FFEF10	;SW1-4の状態を入れるRAM
SW_D5	.EQU	H'FFEF11	;SW5の状態を入れるRAM
LCD_D	.EQU	H'FFEF12	;LCDへのデータを入れるRAM
				;(1バイト分)
LCD162	.EQU	H'FFEF13	;16文字2行分のデータをいれるRAM

P2DR	.EQU	H'FFFFC3	;ポート2データレジスタ 8P-DIP(S5)

P3_D	.EQU	H'FFFFC6	;ポート3データレジスタ
				;LCDのデータ線
E_SIG	.BEQU	5,P3_D		;イネーブル信号
RS	.BEQU	4,P3_D		;RS信号

P4DR	.EQU	H'FFFFC7	;ポート4データレジスタ

P5DR	.EQU	H'FFFFCA	;ポート5データレジスタ
LED1 	.BEQU	0,P5DR		;LED1
LED2	.BEQU	1,P5DR		;LED2
;-----リセットベクトル-----
	.SECTION RESET0,DATA,LOCATE=H'00000
	.DATA.L	INIT		;リセットベクトル
;-----I/Oの初期設定-----	
	.SECTION ROM,CODE,LOCATE=H'00100
INIT:	MOV.L	#H'FFF10,ER7	;スタックポインタ設定
	MOV.B	#H'00,R0L	;ポート2を入力に設定(S5)
	MOV.B	R0L,@H'FFFFC1	;ポート2
	MOV.B	#H'FF,R0L	;ポート2をプルアップに設定
	MOV.B	R0L,@H'FFFFD8	;ポート2

	MOV.B	#H'FF,R0L	;ポート3を出力に設定
	MOV.B	R0L,@H'FFFFC4	;ポート3

	MOV.B	#H'00,R0L	;ポート4を入力に設定
	MOV.B	R0L,@H'FFFFC5	;ポート4
	MOV.B	#H'FF,R0L	;ポート4をプルアップに設定
	MOV.B	R0L,@H'FFFFDA	;ポート4

	MOV.B	#H'FF,R0L	;ポート5を出力に設定
	MOV.B	R0L,@H'FFFFC8	;ポート5
;-----LCDの初期設定-----
;ーーーーーソフトウエアリセット-----
	JSR	@TIME00		;15mSのWAIT	(4mS*4)
	JSR	@TIME00
	JSR	@TIME00
	JSR	@TIME00		

	MOV.B	#B'00100011,R0L	;LCDファンクションセット1
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT8

	JSR	@TIME00		;4mSのWAIT

	MOV.B	#B'00100011,R0L	;LCDファンクションセット2
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT8
	JSR	@TIME00		;4mSのWAIT

	MOV.B	#B'00100011,R0L	;LCDファンクションセット3
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT8
	JSR	@TIME00		;4mSのWAIT

	MOV.B	#B'00100010,R0L	;ファンクションセット
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT8
	JSR	@TIME00		;4mSのWAIT
;-----初期設定----
	MOV.B	#B'00101000,R0L	;ファンクションセット
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT4
	JSR	@TIME00		;4mSのWAIT
	
	MOV.B	#B'00001110,R0L	;表示ON
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT4
	JSR	@TIME00		;4mSのWAIT

	MOV.B	#B'00000110,R0L	;エントリーモード
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT4
	JSR	@TIME00		;4mSのWAIT
;-----初期設定終了----
;-----液晶初期画面表示-----
	MOV.B	#B'00000001,R0L	;表示クリア
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT4

	JSR	@TIME00		;4mSのWAIT

	MOV.B	#32,R0L
	MOV.L	#LCD162,ER1	;液晶表示RAMのアドレスをセット
	MOV.L	#MOJI,ER2	;初期文字データのアドレスをセット
SYOKI0:	MOV.B	@ER2+,R0H	;初期文字データをレジスタにいれる。
	MOV.B	R0H,@ER1	;レジスタ値を液晶表示RAMにいれる
	INC.L	#1,ER1
	DEC.B	R0L		;文字数から1を引く
	BNE	SYOKI0		;文字数が0になるまでくりかえす。
	JSR	@LCDDSP
;-----MAIN-----
	MOV.B	#0,R0L		;RAMのクリア
	MOV.B	R0L,@SW_D
	MOV.B	R0L,@SW_D5
BOTAN:	MOV.B	@P4DR,R0L	;SW1-4の状態の取得
	MOV.B	@SW_D,R0H	;RAMの内容をレジスタに読む
	CMP.B	R0H,R0L		;SWの状態をチェック
	BEQ	S5CHK		;変化が無ければS5CHKにジャンプ
	JSR	@S1_4		;変化が有るので処理ルーチンへ
S5CHK:	MOV.B	@P2DR,R0L	;S5の状態を取得
	MOV.B	@SW_D5,R0H	;RAMの内容をレジスタに読む
	CMP.B	R0H,R0L		;SWの状態をチェック
	BEQ	BOTAN		;変化が無ければBOTANにジャンプ
	JSR	@S5		;変化が有るので処理ルーチンへ
	JMP	@BOTAN
;-----MAINEND-----
;-----サブルーチン-----
;----液晶文字出力16文字*2行
LCDDSP:	PUSH.L	ER0
	PUSH.L	ER1
	MOV.B	#B'00000010,R0L	;カーソルホーム
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT4
	JSR	@TIME00		;4mSのWAIT

;--1行目
	MOV.B	#16,R0L		;文字数のセット
	MOV.L	#LCD162,ER1	;液晶表示RAMのアドレスをセット
LCDDSP1:	MOV.B	@ER1+,R0H	;文字データをレジスタにいれる。
	MOV.B	R0H,@LCD_D	;文字データをRAMにいれる。
	BSET	RS		;データなのでRSを1にする。
	JSR	@LCD_OUT4	;サブルーチンコール
	BCLR	RS		;RSを0にもどす。
	DEC.B	R0L		;文字数から1を引く
	BNE	LCDDSP1		;文字数が0になるまでくりかえす。

	MOV.B	#B'11000000,R0L	;カーソルを2行目にする。
	MOV.B	R0L,@LCD_D
	BCLR	RS
	JSR	@LCD_OUT4
;--2行目
	MOV.B	#16,R0L		;文字数のセット
	MOV.L	#LCD162 + 16,ER1	;液晶表示RAMのアドレスをセット
LCDDSP2:	MOV.B	@ER1+,R0H	;文字データをレジスタにいれる。
	MOV.B	R0H,@LCD_D	;文字データをRAMにいれる。
	BSET	RS		;データなのでRSを1にする。
	JSR	@LCD_OUT4	;サブルーチンコール
	BCLR	RS		;RSを0にもどす。
	DEC.B	R0L		;文字数から1を引く
	BNE	LCDDSP2		;文字数が0になるまでくりかえす。

	POP.L	ER1
	POP.L	ER0
	RTS
;-----LCDへのデータ、コマンド出力-----
LCD_OUT8:	PUSH.L	ER0	;レジスタ待避
	BSET	E_SIG		;液晶のE信号をセットする。
	MOV.B	@LCD_D,R0L	;データ(コマンド)をレジスタに入れる
	MOV.B	R0L,@P3_D	;液晶にデータ(コマンド)を出力
	JSR	@TIME10		;WAIT
	BCLR	E_SIG		;液晶のE信号を0にする。
	JSR	@TIME10		;WAIT
	POP.L	ER0		;レジスタの復帰
	RTS
;-----LCDへのデータ、コマンド出力 4bit -----
LCD_OUT4:	PUSH.L	ER0	;レジスタ待避
;--上位4ビット送出
	BSET	E_SIG		;液晶のE信号を1にする。
	MOV.B	@LCD_D,R0L	;データ(コマンド)をレジスタに入れる
	SHLR.B	R0L		;4ビットモードなので上位4ビットを
	SHLR.B	R0L		;下位に移動
	SHLR.B	R0L
	SHLR.B	R0L
	AND.B	#B'00001111,R0L	;データ線以外をマスクする。
	MOV.B	@P3_D,R0H	;RS信号の待避
	AND.B	#B'11110000,R0H	;RS信号、E信号以外をマスク
	OR.B	R0H,R0L		;RS信号,E信号、データ(4ビット)
				;を合成する。
	MOV.B	R0L,@P3_D	;合成したすべての信号を液晶に出力
	JSR	@TIME10		;WAIT
	BCLR	E_SIG		;液晶のE信号を0にする
	JSR	@TIME10		;WAIT
;--上位4ビット送出
	BSET	E_SIG		;液晶のE信号を1にする
	MOV.B	@LCD_D,R0L	;データ(コマンド)をレジスタに入れる
	AND.B	#B'00001111,R0L	;データ線下位4ビット以外をマスクする
	MOV.B	@P3_D,R0H	;RS信号の待避
	AND.B	#B'11110000,R0H	;RS信号、E信号以外をマスク
	OR.B	R0H,R0L		;RS信号,E信号、データ(4ビット)
				;を合成する
	MOV.B	R0L,@P3_D	;合成したすべての信号を液晶に出力
	JSR	@TIME10		;WAIT
	BCLR	E_SIG		;液晶のE信号を0にする
	JSR	@TIME10		;WAIT
	POP.L	ER0		;レジスタの復帰
	RTS
;-----液晶表示S1-4-----
S1_4:	MOV.B	R0L,@SW_D 	;現在の状態をRAMに格納
	MOV.B	#4,R1L		;文字数のセット
	MOV.L	#LCD162 + 20,ER2	;液晶表示アドレスをセット
	MOV.B	@SW_D,R0L	;スイッチの状態をレジスタに読む
BOTAN1:	ROTL.B	R0L
	MOV.B	R0L,R0H
	AND.B	#B'00000001,R0H	;SWの状態をアスキーコードに変換
	OR.B	#B'00110000,R0H
	MOV.B	R0H,@-ER2	;アスキーコードを液晶表示RAMに格納
	DEC.B	R1L		;文字数から1を引く
	BNE	BOTAN1		;文字数が0になるまでくりかえす。
	JSR	@LCDDSP
;---LED
SW3LED:	MOV.B	@SW_D,R0L	;在の状態をRAMに格納
	BTST	#6,R0L		;S3の状態をチェック
	BEQ	BOTAN2		;押されていればBOTAN2にジャンプ
	BCLR	LED1		;押されていないので消灯
	JMP	@SW4LED
BOTAN2:	BSET	LED1		;押されているので点灯
SW4LED:	BTST	#7,R0L		;S4の状態をチェック
	BEQ	BOTAN3		;押されていればBOTAN3にジャンプ
	BCLR	LED2		;押されていないので消灯
	RTS
BOTAN3:	BSET	LED2		;押されているので点灯
	RTS
;-----液晶表示S5-----	
S5:	MOV.B	R0L,@SW_D5 	;現在の状態をRAMに格納
	MOV.B	#8,R1L		;文字数のセット
	MOV.L	#LCD162 + 29,ER2	;液晶表示アドレスを読む
	MOV.B	@SW_D5,R0L	;RAMの内容をレジスタに読む
BOTAN4:	ROTL.B	R0L
	MOV.B	R0L,R0H
	AND.B	#B'00000001,R0H	;SWの状態をアスキーコードに変換
	OR.B	#B'00110000,R0H
	MOV.B	R0H,@-ER2	;アスキーコードを液晶表示RAMに格納
	DEC.B	R1L		;文字数から1を引く
	BNE	BOTAN4		;文字数が0になるまでくりかえす。
	JSR	@LCDDSP		;
	RTS
;-----4mSタイマ-----
TIME00:	PUSH.L	ER0
	MOV.L	#H'2000,ER0
TIME01:	SUB.L	#1,ER0
	BNE	TIME01
	POP.L	ER0
	RTS

TIME10:	PUSH.L	ER0
	MOV.L	#H'AA,ER0	;450nS	TIMER
TIME11:	SUB.L	#1,ER0
	BNE	TIME11
	POP.L	ER0
	RTS
;-----サブルーチン終了-----	
;-----文字データ-----
	.ALIGN 2
	.SECTION LCDDATA,DATA,LOCATE=H'01000
MOJI:	.SDATA "AKI-H8 "
	.DATA.B	H'0CF,H'0BB,H'0DE,H'0B0,H'0CE
	.DATA.B	H'0DE,H'0B0,H'0C4,H'0DE
	.SDATA "1111 11111111   "
	.END	
あまり見やすいという気はしませんが(^_^;)、まともに馬鹿正直に やっている、というところでしょう。プログラミングに興味のある人は これを解読できれば、もう自分で作れますね。

ということで、もう、AKI-H8はびしばし走ってしまいました。 この状態で、作業ディレクトリ内には、 このように ごちゃごちゃと不要なファイルが増えています。必要な時にはまた アセンブルすればいい、という視点に立てば、ソースだけあれば いいのです。そこで このように お掃除してやると、スッキリします。また、MOTファイルは毎回、 同じファイル名にすると、いちいち捜す時に何も考えなくてよく なります。

このような発想をまとめて、実際に僕が使っているのは、 このような バッチプログラムです。いまどきのWindowsな人たち(DOSな人でない(^_^;))は、 MS-DOSのバッチなんて知らないかもしれませんが、いい勉強になるので 調べてみましょう。
この場合、たとえばソースプログラムが「TEST01.SRC」であれば、 「ASM TEST01」とだけ入力してやると、フルオートで アセンブル、リンク、コンバート、が進行してMOTファイルが 出来ます。そしてキー入力を待ってFLASH.EXEも起動され、 最後には不要ファイルも消してくれます。こういう文化は 残したいものですが。(^_^;)

ということで、これにて「ソフト開発」編もおしまいです。秋月のLCD ソフトを改造する、というのも面白そうですし、AKI-H8マザーボード のユニバーサル部分にMIDIを増設したいところですが、これは またいずれ。(^_^)