如何将Turbo Pascal for Win32的I / O端口访问转换为C#.Net

时间:2014-02-01 15:26:49

标签: c# .net turbo-pascal

我有一台硬币计数器(SC350 / 360),通过RS232C接口连接到计算机。我有描述通信协议的技术文档,还包括一个工作pascal程序来操作机器。我复制了pascal代码,并在Turbo Pascal上使用DosBox对Windows 7 64位进行了测试,代码编译成功。我现在想要实现的是将这些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);

但我无法理解如何转换其余的pascal程序。我遇到困难的一些程序是;

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 }

你们可以帮助我如何将这些pascal代码转换为等效的C#吗?我知道我可以使用'port.Write'方法写入端口但是这不能完全适合turbo pascal代码和端口数组。(例如port[RXTX + 3] := $80;)我不知道端口数组索引是什么'RXTX + 3'指的是C#。

如果你能帮助我,我真的很感激,我希望我能学会自己转换其余的pascal代码。 :)

我使用我从好人那里得到的帮助,为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
–––––––> ESC (message start)
–––––––> Command
<––––––> Data (direction depends on command)
<––––––> 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
–––––––> ESC
–––––––> “R”
–––––––> “C”
<––––––– CountRegister (CR)
<––––––– (CR ^ FF00,000016 + CR ^ FF,000016 + CR ^ FF0016 +
CR ^ FF16) ^ FF16
<––––––– ACK

2 个答案:

答案 0 :(得分:6)

唉。 8250 UART寄存器为documented here。不支持直接访问Windows中的UART寄存器。您的SerialPort初始化是正确的。请注意,除非您有真正的硬件,否则您的机器不太可能具有COM1端口。 USB仿真器倾向于选择更高的端口号。使用SerialPort.GetPortNames()来查看。

Tx()等待发送器空状态位。只需用SerialPort.Write()代替写入一个字节,如果发送缓冲区已满,它就会阻塞。它不会。

RxWait()等待接收器就绪状态位。只需用SerialPort.ReadByte()替换。

Tx2()只是一个帮助程序,可以更新简单的校验和,只需将发送的字节添加到 checksum 变量。

答案 1 :(得分:4)

这里做的是直接的PC硬件端口(特别是COM1)访问。对于那些好奇的人来说,基本端口+ 5是8250 UART的线路状态寄存器及其引脚兼容的后继器件,如16450和16550.有关经典PC型串口的内部工作原理的详细信息,请参阅here

不确定你是否能够在Windows上正常工作(有一件事是肯定的,它永远不会用于通过USB连接的串口加密狗),它的DOS代码部分依赖于非常接近硬件,完全控制时间(DOS是单任务)并完全知道期望的硬件。在大多数情况下,应该可以依赖Windows(以及在您的情况下,.Net框架)提供的功能 - 您在上面显示的内容是用于发送字节(您可以使用Write方法) 。校验和部分应该很容易重现。

.Net提供了一个API SerialPort,应该可以使用该API,并废除这些“好”的旧DOS日。