【问题标题】:How to convert the I/O port access of Turbo Pascal for Win32 to C#.Net如何将 Turbo Pascal for Win32 的 I/O 端口访问转换为 C#.Net
【发布时间】:2014-02-01 15:26:48
【问题描述】:

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

【问题讨论】:

    标签: c# .net turbo-pascal


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我明白了。当您说“只需将发送的字节添加到校验和变量”时,这是否正确?;
    • 正确。大概您需要将该校验和值作为消息的最后一个字节发送。并在开始发送下一条消息之前将其设置回 0。无论如何,这通常是它的工作方式。
    • 感谢您的回复。起初我试图使用 FreePascal 编译 pascal 代码,但它不支持 win32 的端口数组和 go32 单元。如果我能以任何可能的方式从 FreePascal 中操作端口,我会将其编译为 dll 文件,然后将其导出以使用平台调用从 C#.NET 中使用它。有没有办法实现这一目标?l
    • 感谢您的帮助。我已经为 pascal 代码编写了等效的 C# 代码,并在我之前的问题中进行了更新。如果我弄错了,请恕我直言,因为我在这方面没有太多经验。非常感谢。
    【解决方案2】:

    这里所做的是直接的、PC 硬件端口(特别是 COM1)访问。对于那些好奇发生了什么的人,基本端口+5 是 8250 UART 及其引脚兼容的后续产品(如 16450 和 16550)的线路状态寄存器。有关经典 PC 风格串行端口内部工作的更多详细信息,请参阅here

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

    .Net 提供了一个 API SerialPort,应该可以使用该 API 并消除这种“好的”旧 DOS 时代的残余。

    【讨论】:

    • 感谢您的回复。起初我试图使用 FreePascal 编译 pascal 代码,但它不支持 win32 的端口数组和 go32 单元。如果我能以任何可能的方式从 FreePascal 中操作端口,我会将其编译为 dll 文件,然后将其导出以使用平台调用从 C#.NET 中使用它。有什么办法可以实现吗?
    • 我的另一个问题是我编译的 Turbo Pascal 程序(带有端口数组的帕斯卡代码)如果我通过将它连接到硬币计数器机器在 Windows 7 PC 上运行和测试它是否可以工作?正如我之前提到的,我已经设法使用 DosBox 在 Turbo Pascal 中编译它
    • @Eliyah 不会,因为它在 Dosbox 中没有直接的 io 端口访问权限。
    • 那么如何使用c#实现pascal代码中的任务呢?您能否提供一个 C# 代码 sn-p 来实现这些程序的相同任务?
    • @Eliyah 参考 Hans Passant 的回答,他已经给出了等价物列表。关于校验和,您必须分析它是如何被使用的,并模拟这种行为。
    猜你喜欢
    • 1970-01-01
    • 2013-02-12
    • 2013-02-05
    • 1970-01-01
    • 2015-10-14
    • 2012-10-12
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    相关资源
    最近更新 更多