標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第568回]

●Z80BASICのRS232C受信プログラム

このところ、RS232Cの処理で悩んでおります、ということを、前回書きました。
RS232Cの送受信も、USBの送受信も、それぞれの機能をマニュアル操作で使う分には、特にこれといった問題もなく使えるところまで、プログラムはできているのですが、RS232Cの受信と、その受信したデータを画面に表示する、といったごくごく簡単なプログラムをBASICで書いて実行すると、受信エラーが発生してしまうのです。

下はBASICのサンプルプログラムとその実行結果です。

>.
    10 A%=0
    20 READ #1,A$,A%
    30 IF A%<1 GOTO 20
    40 PRINT A$
    50 GOTO 10
>R.
80008058CD47023CCA00803DCD0E80C30080F5E
5D5C5214180856F461E1A503EF7D3982A000021
000015C21F80503EE7D3982A000021000015C22
E801DC21A80C1D1E1F1C97F77716A5F59544F47
33F3B35322F2C25272A4B38642321

いまどきはBASICなど時代遅れの一言で片付けられてしまいそうですが、簡単に記述できる、というのが最大の長所です。
これほど簡単に使える言語は他にはないのではありませんでしょうか?

READ #1がRS232C受信命令です。
文字変数A$に受信データが入ります。
A%は制御用の変数です。
A$、A%は使用例です。A$の代わりに任意の文字変数、A%の代わりに任意の整数型変数を使うことができます。
A%=0でREAD #1,A$,A%を実行すると、A$をクリアして受信データが入力されます。
Z80BASICは、少ないRAM容量を有効に使うためと、マシン語サブルーチンとの併用が簡単にできるようすることなどの理由から、文字変数は固定長(39バイト)です。
RS232C受信データは、0D0Aコードまでを一区切りとして扱います。
0D0Aコードを受信するまでA$にデータが格納されていきます。
データが途切れるか、0D0Aコードを受信するか、A$が一杯(39バイト)になるか、のいずれかでREAD #1,A$,A%は終了して次の行に移ります。
0D0Aが受信されたときはA%にその受信した文字数(A$に格納されている文字数と同じ)が入ります。
0D0Aが受信される前にA$に39バイトの受信文字データが入ると、A%=40になります。
それ以外のときはA%=−1になります。
このA%の値を見ることで受信の状況を判断することができます。

ここで受信されたデータはバイナリデータのように見えますが、ASCII文字データです。
RS232Cは通常は文字データ(キャラクタコード)を扱います。
送信側(C++で作成したプログラム)で使ったファイルは、MYCPU80のときのsound.htxです。
バイナリデータを16進数表現にして0〜9、A〜FのASCII文字コードで表現したファイルです。

実は、やっと昨晩になって、ここまでできるところまできたのです。
READ #1命令でのRS232C受信はPIC18F14K50で受けたあと、Z80CPUに渡されたものですし、PRINT文で画面に表示されたデータ(上のリストは画面に表示されたものをそのまま記録したログファイルの一部です)は、Z80CPUからPIC18F14K50に送られたあと、USB経由でWindowsパソコンに送られてきたものです。

PIC18F14K50のRS232C受信は、当初普通のプログラムでしたが、そのままではどうしようもないことがわかりましたので、急遽割り込みプログラムに書き換えてしまいました。
受信バッファは256バイトです。
そのあたりのPICプログラムの実際についても説明させていただくつもりなのですが、本日はとても時間がありません。
いずれあらためて、ということになると思います。

ともあれ、RS232C受信は、PRINT文の実行によるWindowsパソコンへのUSB送信と、同時並行的に行われています。

このサンプルではうまくいったのでしたが、さらにテストを重ねていきますと、やっぱり問題が出て来てしまいました。

●不正な処理メッセージが…

以前にRS232C送信(COM1)のためのテストプログラムを作ったものがありましたので、今回のテストにはそのプログラムw232com1.exeを使いました。
まあ、それが、ちょいといい加減なプログラムだったのですねえ。

上でお見せしたsound.htx程度のデータファイルを送出したときは問題無く実行できたのですけれど、今度はちょいと大きいデータを送ってみようと思いまして、w232送信プログラムのソースをそのまま送信してみましたところ、ご覧のように、あのどうしようもない「不正な処理」エラーが表示されてしまいました。



しかしこれはもう、多分データサイズだな、と思いましたので、一度に送る送信データを小さくしましたところ、エラーは表示されなくなりました。
まずは、めでたしめでたし、です。

そのように対策したプログラムw232com1_b.cppです。
毎々説明しておりますように、BorlandC++コンパイラでコンパイルしております。
VC++など他のコンパイラではエラーが出るかもしれません。

/// w232.cpp for mycpu  09/03/13 3/20
// 10/5/8 COM1
// 7/30
#include <windows.h>
#include <stdio.h>
//
        FILE *rfp;
        unsigned char outbf[1024]="\0";
        char comname[5]="\0";
        char *fname;
        int dtbyte=0;
        int e;
        int i;
        int j;
        int inbfn;
        int datan;
        unsigned long int dwWrite;
        HANDLE hcom;
        int open();
        int write();
        int close();
///
void main(int argn,char *args[])
{
fname=args[1];
//file open
rfp=fopen(fname,"rb");
if(!rfp){printf("can't open %s\n",fname);return;}
sprintf(comname,"COM1");
e=open();
if(e==0){printf("can't open %s\n",comname);fclose(rfp);return;}// pass to end
//file read & send data
        fseek(rfp,0,SEEK_END);
        datan=ftell(rfp);
        fseek(rfp,0,SEEK_SET);
        printf("datan=%d\n",datan);//test
        for(i=0,inbfn=0;i<=datan;i++)
                {
                outbf[inbfn]=fgetc(rfp);
                if(inbfn==999||i==datan)
                        {inbfn++;
                        e=write();
                        if(e==0){close();fclose(rfp);return;}
                        printf("send data %d bytes\n",dwWrite);
                        inbfn=0;
                        }
                else inbfn++;
                }
        close();
        fclose(rfp);
        printf("end\n");
}
///
/// com open
int open()
        {
        hcom=CreateFile(comname,GENERIC_READ|GENERIC_WRITE,0,NULL,
        OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        if(hcom==INVALID_HANDLE_VALUE)return 0;
/// get DCB
        DCB dcb;
        GetCommState(hcom,&dcb);
        dcb.BaudRate=9600;
        dcb.ByteSize=8;
        dcb.Parity=NOPARITY;
        dcb.StopBits=ONESTOPBIT;
        if(!SetCommState(hcom,&dcb))return 0;
        return 1;
        }
///
int write()
        {
        if(!WriteFile(hcom,outbf,inbfn,&dwWrite,NULL))
                        {printf("%s WRITE ERROR\n",comname);return 0;}
        return 1;}      /// end of elseif
//
int close()
        {CloseHandle(hcom);return 1;}

それにしても、BASICと比較すると、なんと面倒なことでしょう。
おまけに、不正な処理ですものねえ。

もとのプログラムではoutbf[]をうんと大きいサイズにしておいて、ファイルから全部読み込んでそのままWritefile()に突っ込んでいたのですけれど、そりゃあ少し乱暴でした。
上の実行例からすると、どうやら標準の出力バッファのサイズは1024バイトあたりのようです。
バッファサイズは指定することもできるようなのですが、どうせそうしたところで、どこかで区切らざるを得ないと思いますので、手ごろなところで、1000バイトごとに送信するように書き改めました。

なお送信側はプログラムでボーレートを9600ボーに設定していますが、Z80BASICの側はどこで設定しているのでしょう?
じつはND80ZV基板のDIPスイッチの余った部分を利用して、9600、4800、2400ボーの3通りを選択するようにしてあるのです。

さて、上のような送信プログラムにすることで、不正な処理メッセージは出なくなったのですが、今度は受信側でエラーが出てしまいました。

というところで、本日もタイムアウトになってしまいました。
この続きはまた次回にすることに致します。
2010.7.30upload

前へ
次へ
ホームページトップへ戻る