4

RS232C インターフェイス経由でコンピューターに接続するコイン カウンター マシン (SC350/360) があります。通信プロトコルを説明する技術文書を入手しました。マシンを操作するための動作するパスカル プログラムも含まれています。Pascal コードをコピーし、Windows 7 64 ビット用の DosBox を使用して Turbo Pascal でテストしたところ、コードは正常にコンパイルされました。私が今達成したかったのは、これらのパスカル コードを C#.Net に変換することでしたが、シリアル ポート プログラミングの経験があまりないため、数行を C# に変換するのに苦労しました。

これは、マシンとの通信を初期化する Pascal のコードです。(ボーレートを 9600、8 ビット、パリティなし、1 ストップ ビットに設定)

uses crt;
const
{ COM1: RS232 port address }
RXTX = $3F8; { $2F8 if COM2: is used }
ACK = 6;
NAK = 21;
ESC = 27;
var
dummy,
checkSum : integer;
key : char;
protocol : integer;

    var i : integer;
begin
i := 1843200 div 9600 div 16;
port[RXTX + 3] := $80;
port[RXTX + 1] := hi(i);
port[RXTX]:= lo(i);
port[RXTX + 3] := 3;
port[RXTX + 4] := $A;
while odd(port[RXTX + 5]) do
begin
dummy := port[RXTX];
delay(10);
end;
end; { InitComm }

私が思いついた上記のコードに対応する C# は次のとおりです。(間違っていたら訂正お願いします)

SerialPort port=new SerialPort("COM1",9600,Parity.None,8,StopBits.One);

しかし、残りのパスカル手順を変換する方法がわかりませんでした。私が苦労したこれらの手順のいくつかは次のとおりです。

procedure Tx(data : integer);
{ Transmit a character on serial channel }
begin
while port[RXTX + 5] and $20 = 0 do;
port[RXTX] := data and $FF;
end; { Tx }

function RxWait : integer;
{ Waits for a character from serial channel }
begin
while not odd(port[RXTX + 5]) do;
RxWait := port[RXTX];
end; { RxWait }

procedure Tx2(data : integer);
{ Transmit a char on serial channel + Calculate check sum }
begin
Tx(data);
checkSum := (checkSum + data) and $FF;
end; { Tx2 }

これらのパスカル コードを同等の C# に変換する方法を教えてください。「port.Write」メソッドを使用してポートに書き込むことができることはわかっていますが、ターボ パスカル コードをポート配列に正確に適合させることができませんでした。(例port[RXTX + 3] := $80;) ポート配列インデックス「RXTX+3」が何であるかわかりません。 C#に関連して言及しています。

これについて手を貸していただければ本当にありがたいです。残りのパスカル コードを自分で変換する方法を学べることを願っています。:)

私は、ここの善良な人々から得た助けを借りて、pascal プログラム用の次の同等の C# コードを作成しました。コードに間違いがあった場合は、修正してください。

            public void Tx(int data)
            {
                if (!port.IsOpen)
                    port.Open();
                port.Write(new byte[] { (byte)(data & 0xFF) }, 0, 1);
                port.Close();
            }
            /// <summary>
            /// Wait for a character from serial channel
            /// </summary>
            /// <returns></returns>
            public int RxWait()
            {
                if (!port.IsOpen)
                    port.Open();
                int readByte = port.ReadByte();
                port.Close();
                return readByte;
            }
            /// <summary>
            /// Transmit a char on serial channel + Calculate check sum
            /// </summary>
            /// <param name="data"></param>
            public void Tx2(int data)
            {
                Tx(data);
                checkSum = (checkSum + data) & 0xFF;
            }

ちなみに、デバイスのドキュメントに記載されているプロトコルは次のとおりです。

Computer SC 350/360
–––––––&gt; ESC (message start)
–––––––&gt; Command
<––––––&gt; Data (direction depends on command)
<––––––&gt; Check sum (direction depends on command)
<––––––– Receipt:
- ACK (if check sum is correct) or
- NAK (if check sum is incorrect)

さらに、コインの数をカウントするために送信するコマンドの例とともに、残りのコードを提供しました。

 /// <summary>
    /// Transmit command (no data) on serial channel
    /// </summary>
        /// <param name="c1"></param>
        /// <param name="c2"></param>
        /// <param name="sendCheckSum"></param>
        public void TxCommand(char c1, char c2, bool sendCheckSum)
        {
            Tx(ESC);
            checkSum = 0;
            Tx2((int)c1);
            Tx2((int)c2);
            if (sendCheckSum)
            {
                Tx2(checkSum);
                dummy = RxWait();
            }
        }
        /// <summary>
        /// Read n bytes from serial channel
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public double ReadNumber(int n)
        {
            double number;
            int i;
            number = checkSum = 0;
            for (i = 0; i < n; i++)
                number = number * 256 + RxWait();
            dummy = RxWait();
            return number;
        }

        /// <summary>
        /// Read the number of Coins counted
        /// </summary>
        /// <returns>Number of Coins</returns>
        public double ReadCountReg()
        {
            TxCommand('R', 'C', false);
            double coinsCounted = ReadNumber(4);
            dummy = RxWait();
            return coinsCounted;
        }

コインをカウントするコマンドを送信するには;

double coinsCounted = ReadCountReg();
 Console.WriteLine(Math.Round(coinsCounted, 0) + " coins counted");

カウント レジスタを読み取るためのプロトコルは次のとおりです。

Computer SC 350/360
–––––––&gt; ESC
–––––––&gt; “R”
–––––––&gt; “C”
<––––––– CountRegister (CR)
<––––––– (CR ^ FF00,000016 + CR ^ FF,000016 + CR ^ FF0016 +
CR ^ FF16) ^ FF16
<––––––– ACK
4

2 に答える 2

6

うーん。8250 UART レジスタについては、こちらに記載されています。Windows での UART レジスタへの直接アクセスはサポートされていません。SerialPort の初期化は正しいです。実際のハードウェアがない限り、マシンに COM1 ポートがある可能性はほとんどないことに注意してください。USB エミュレーターは、より高いポート番号を選択する傾向があります。SerialPort.GetPortNames() を使用して参照してください。

Tx() は、トランスミッタのエンプティ ステータス ビットを待ちます。SerialPort.Write() に置き換えて 1 バイトを書き込むだけで、送信バッファーがいっぱいになると既にブロックされます。そうではありません。

RxWait() は、受信準備完了ステータス ビットを待ちます。SerialPort.ReadByte() に置き換えるだけです。

Tx2() は単純なチェックサムを更新し続けるヘルパー プロシージャにすぎません。送信したバイトをチェックサム変数に追加するだけです。

于 2014-02-01T15:40:16.193 に答える
4

ここで行われているのは、PC ハードウェア ポート (具体的には COM1) への直接アクセスです。何が起こっているのか興味がある方のために説明すると、ベース ポート + 5 は 8250 UART のライン ステータス レジスタであり、16450 や 16550 などのその後継のピン互換性があります。従来の PC スタイルのシリアル ポートの内部動作に関する詳細については、こちらを参照してください。

これが Windows で適切に動作するようになるかどうかさえ定かではありません (1 つ確かなことは、USB 経由で接続されたシリアル ポート ドングルなどでは決して動作しないことです)。ハードウェアは、タイミングを完全に制御し(DOSはシングルタスクでした)、どのハードウェアが期待されるかを完全に認識しています。ほとんどの場合、Windows (およびあなたの場合は .Net フレームワーク) が提供する機能に依存できるはずです。上記のものは、バイトを送信するためのものです (そのためにWriteメソッドを使用できます)。チェックサムの部分は簡単に再現できるはずです。

.Net は API SerialPortを提供します。その API を使用して、この「古き良き」DOS 時代の名残りをなくすことができるはずです。

于 2014-02-01T15:35:25.427 に答える