RS 232 中断信号

发布于 2024-08-02 03:14:39 字数 330 浏览 6 评论 0原文

我有一个RS232信号捕获设备。 而且效果很好。

我需要一些帮助来理解数据。 基本上我们购买它是因为我们正在处理 80 年代末使用串行通信的机器控制器。 尽管知道端口参数,但我们运气不佳。

从我转储的数据来看,机器控制正在使用中断信号作为其协议的一部分。 我在使用 VB 和 MSComm 复制它时遇到问题。 我知道如何切换中断信号以及打开和关闭。 但我不确定我应该用它做什么。 我应该为发送的每个字节数据保留它。 或者发送一个字节的数据然后进行切换。

我也很困惑我应该如何从控制器接收任何数据。 当中断打开时我是否切换标志,然后当它关闭时读取输入?

I got a RS232 signal capture device. and it working great.

I need some help making sense of the data. Basically we bought it because we are dealing a late 80's machine controller that uses serial communication. We had little luck despite knowing the port parameters.

From the data I dumped machine control is using the break signal as part of it's protocol. I am having trouble duplicating it using VB and the MSComm. I know to toggle the break signal and on and off. But I am not sure what I am supposed to be doing with it. I am supposed to leave it on for each byte of data I send. Or send a byte of data and then toggle.

Also I am confused how I supposed to receive any data from the controller. Do I toggle a flag when the break is turned on and then when it turned off read the input?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

橙幽之幻 2024-08-09 03:14:39

迈克尔·伯尔 (Michael Burr) 对休息工作方式的描述是准确的。 通常,发送“中断”信号的时间明显长于一个字符的时间。

如今,“Break”在串行通信中很少使用,但最常见的用途是作为提供数据包同步的“廉价”方式。 “Break”可以在数据包开始之前发送,以提醒接收者新的数据包正在路上(并允许其重置缓冲区等),或者在数据包结束时发送,以表明不再需要数据。 它是一种“元字符”,因为它允许您保留数据包内容的 8 位或 7 位值的完整范围,而不必担心如何描述数据包的开头或结尾。

要发送中断,通常您可以调用 SetCommBreak ,等待适当的时间(例如,9600 波特率下大约 2 毫秒),然后调用 ClearCommBreak。 当然,在此期间您不能发送任何其他内容。

因此,假设协议要求在数据包开始处“中断”,我会这样做(抱歉伪代码):-

procedure SendPacket(CommPort port, Packet packet)
{
    SetCommBreak(port)
    Sleep(2);  // 2 milliseconds - assuming 9600 baud. Pro-rata for others
    ClearCommBreak(port)

    foreach(char in packet)
        SendChar(port, char)
}

接收器的伪代码更加困难,因为您必须对传入数据包做出大量​​假设格式和用于接收中断的 API 调用。 这次我将用 C 语言编写,并假设存在一个虚函数。 WaitCommEvent 可能是处理传入中断的关键。

bool ReadCharOrBreak(char *ch); // return TRUE if break, FALSE if ch contains received char

我们还将假设固定长度的 100 字节数据包,在每个数据包之前发送“break”。

void ReadAndProcessPackets()
{
  char buff[100];
  int count;

  count = 0;

while (true)
{
  char ch;
  if (ReadcharOrBreak(ch))
    count = 0; // start of packet - reset count
  else 
  {
     if (count < 100)
     {
       buff[count++] = ch;
       if (count == 100)
         ProcessPacket(buff);
     }
     else 
       Error("too many bytes rx'd without break")
  } 
} 

警告 - 完全未经测试,但应该可以让您了解...

有关使用 Break 的协议示例,请查看 DMX-512 舞台灯光协议

数据包的开始由
一个 Break 后跟一个“mark”(a
逻辑一)被称为“标记后
中断”(MAB)。中断信号结束
一个数据包和下一个数据包的开始。
它导致接收器启动
接待。 分手后达到513
插槽已发送。

Michael Burr's description of the way break works is accurate. Often, "break" signals are sent for significantly longer than one character time.

These days, "Break" is infrequently used in serial comms, but the most common use is as a 'cheap' way of providing packet synchronization. "Break" may be sent before a packet starts, to alert the receiver that a new packet is on the way (and allow it to reset buffers, etc.) or at the end of a packet, to signal that no more data is expected. It's a kind of 'meta-character' in that it allows you to keep the full range of 8 or 7-bit values for packet contents, and not worry about how start or end of packet are delineated.

To send a break, typically you call SetCommBreak, wait an appropriate period (say, around 2 millseconds at 9600 baud) then call ClearCommBreak. During this time you can't be sending anything else, of course.

So, assuming that the protocol requires 'break' at the start of the packet, I'd do this (sorry for pseudocode):-

procedure SendPacket(CommPort port, Packet packet)
{
    SetCommBreak(port)
    Sleep(2);  // 2 milliseconds - assuming 9600 baud. Pro-rata for others
    ClearCommBreak(port)

    foreach(char in packet)
        SendChar(port, char)
}

Pseudocode for a receiver is more difficult, because you have to make a load of assumptions about the incoming packet format and the API calls used to receive breaks. I'll write in C this time, and assume the existence of an imaginary function. WaitCommEvent is probably the key to handling incoming Breaks.

bool ReadCharOrBreak(char *ch); // return TRUE if break, FALSE if ch contains received char

We'll also assume fixed-length 100 byte packets with "break" sent before each packet.

void ReadAndProcessPackets()
{
  char buff[100];
  int count;

  count = 0;

while (true)
{
  char ch;
  if (ReadcharOrBreak(ch))
    count = 0; // start of packet - reset count
  else 
  {
     if (count < 100)
     {
       buff[count++] = ch;
       if (count == 100)
         ProcessPacket(buff);
     }
     else 
       Error("too many bytes rx'd without break")
  } 
} 

WARNING - totally untested, but should give you the idea...

For an example of a protocol using Break, check out the DMX-512 stage lighting protocol.

The start of a packet is signified by
a Break followed by a "mark" (a
logical one) known as the "Mark After
Break" (MAB). The break signals end of
one packet and the start of the next.
It causes the receivers to start
reception. After the break up to 513
slots are sent.

鸠魁 2024-08-09 03:14:39

中断信号是无效字符。 当RS-232线路空闲时,电压处于“标记”(或“1”)状态(如果我没记错的话,是-12伏)。 发送字符时,协议将线路切换到“空格”(或“0”)状态并持续一位时间(起始位),然后根据数据(数据位)和任何奇偶校验位切换信号。 然后,它将线路保持在空闲/标记(或 1)状态,持续数个由停止位定义的位,这通常是可配置的(根据我的经验,通常为 1 个停止位)。

由于在数据字符之间总有一段时间该行处于标记状态,因此总是可以识别字符的开头。 这也意味着线路可以处于空间状态的最长时间为:

1 start bit + however many data bits + a parity bit (if any)

中断信号定义为将线路保持在空间状态的时间长于该时间段 - 没有有效的数据字节可以做到这一点,因此中断“字符”并不是真正的字符。 这是一个特殊的信号。

至于何时需要发出中断信号完全取决于所使用的协议。

A break signal is an invalid character. When the RS-232 line is idle, the voltage is in the 'mark' (or '1') state (which is -12 volts if I remember right). When a character is sent, the protocol toggles the line to the 'space' (or '0') state for one bit time (the start bit) then toggles the signal as appropriate for the data (the data bits) and any parity bits. It then holds the line in an idle/mark (or 1) state for a number of bits defined by the stop bits, which is typically configurable (usually 1 stop bit in my experience).

Since there is always some period of time where the line will be in a mark state between data characters, the start of a character can always be recognised. This also means that the longest period of time that the line can be in a space state is:

1 start bit + however many data bits + a parity bit (if any)

A break signal is defined as holding the line in the space state for longer than that period of time - no valid data byte can do that, so the break 'character' isn't really a character. It's a special signal.

As far as when you need to issue a break signal depends entirely on the protocol being used.

寻找一个思念的角度 2024-08-09 03:14:39

“中断”的目的是当线路同步完全混乱时。

我应该为发送的每个字节数据保留它。 或者发送一个字节的数据然后进行切换。

尝试发送一个很好的长“中断”信号(500 毫秒?),然后稍等一下(50 毫秒?),然后发送数据。

'Break' was intended for when the line synchronization got totally mixed up.

I am supposed to leave it on for each byte of data I send. Or send a byte of data and then toggle.

Try sending a nice long 'break' signal (500 ms?) then wait a bit (50 ms?) then send your data.

猫七 2024-08-09 03:14:39

发送中断可以通过以下方式实现:

  • 降低发送0x00的码率
  • ,看起来像中断。
  • 将比特率改回来。

在中断期间,由于比特率不正确,将无法接收数据。

我将其用于 Linbus 通信,该通信具有 1 个主发送中断,然后将 0x55 作为同步。

Sending break can be achieved by:

  • lowering the bit-rate
  • sending 0x00 which will seem as break.
  • change bit-rate back.

During the break, it won't be possible to receive data since the bit-rate is not correct.

I used this for Linbus communication which has 1 master sending break then 0x55 as sync.

踏雪无痕 2024-08-09 03:14:39

我帮助朋友用C#实现了Comm Break,

它可以用作扩展方法

System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort("COM1");
              //... serial communications code
            myPort.SendCOMMbreak(5); //sends a break for rougly 5ms

或者直接调用:

RS232_Com_Break.UseWinAPItoSendBreak("COM1", 5); //aquires serial port and sends a break for rougly 5ms

下面是支持类的完整代码:

using System;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;

public static class RS232_Com_Break
{
    /*===================================================================================
     *  EXTENSION METHOD TO HOLD THE VOLTAGE ON A COMM PORT HIGH FOR X(ms), 
     *     for talking to old devices that need an RS232 "break" signal sent.
     *     
     *          1/5/23 Blue Mosaic Software ~mwr
     *          
     *       Use:   System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort("COM1");
     *              ... serial communications code
     *             myPort.SendCOMMbreak(5); //sends a break for rougly 5ms
     *
     *        Or: RS232_Com_Break.UseWinAPItoSendBreak("COM1", 5); //aquires serial port and sends a break for rougly 5ms
     * ==================================================================================*/


    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAsAttribute(UnmanagedType.Bool)]
    static extern bool SetCommBreak([InAttribute] IntPtr fileHandle);

    [DllImport("kernel32.dll")]
    static extern bool ClearCommBreak(IntPtr hFile);

    public const short FILE_ATTRIBUTE_NORMAL = 0x80;
    public const short INVALID_HANDLE_VALUE = -1;
    public const uint GENERIC_READ = 0x80000000;
    public const uint GENERIC_WRITE = 0x40000000;
    public const uint CREATE_NEW = 1;
    public const uint CREATE_ALWAYS = 2;
    public const uint OPEN_EXISTING = 3;

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
        uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
        uint dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll")]
    static extern public bool CloseHandle(IntPtr hObject);


    /// <summary>
    /// Extension method to reset a serial port. Holds Port high (+5vdc) for the duration requested.
    ///    should work with an open or closed port.
    /// </summary>
    /// <param name="oPort"></param>
    public static void SendCOMMbreak(this SerialPort oPort, int milliseconds)
    {
        // I think it takes 1 ms to set and clear the break.
        int iPauseLength = milliseconds > 1 ? milliseconds - 1 : 1;

        //little management to insure the port is free.
        if (oPort.IsOpen)
        {
            oPort.Close();
            UseWinAPItoSendBreak(oPort.PortName, iPauseLength);
            oPort.Open();
        }
        else
        {
            UseWinAPItoSendBreak(oPort.PortName, iPauseLength);
        }
    }

    /// <summary>
    /// All the windows API calls are here, so this would be the code to use if 
    ///     not using the .NET System.IO.Ports.SerialPort object.
    /// </summary>
    /// <param name="sPortName">The name of the COM port</param>
    /// <param name="iPauseLengthMS">pause time in milliseconds</param>
    public static void UseWinAPItoSendBreak(string sPortName, int iPauseLengthMS)
    {
        //get a handle to the port.  Once we have done this sucessfully, it is unavalible elsewhere
        IntPtr port_ptr = CreateFile(sPortName, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

        if (port_ptr.ToInt32() == INVALID_HANDLE_VALUE) // -1 = oops
        {
            // Did not get a handle.  We need to ask the framework to marshall the win32 error code to an exception
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }
        else
        {
            SetCommBreak(port_ptr);
            Thread.Sleep(iPauseLengthMS);
            ClearCommBreak(port_ptr);

            //Close only happens if handle achieved.
            CloseHandle(port_ptr);
        }

    }
}

I helped out a friend and implemented the Comm Break in C#

It can be used as an extension method:

System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort("COM1");
              //... serial communications code
            myPort.SendCOMMbreak(5); //sends a break for rougly 5ms

Or a direct call:

RS232_Com_Break.UseWinAPItoSendBreak("COM1", 5); //aquires serial port and sends a break for rougly 5ms

Here is the complete code for the supporting class:

using System;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;

public static class RS232_Com_Break
{
    /*===================================================================================
     *  EXTENSION METHOD TO HOLD THE VOLTAGE ON A COMM PORT HIGH FOR X(ms), 
     *     for talking to old devices that need an RS232 "break" signal sent.
     *     
     *          1/5/23 Blue Mosaic Software ~mwr
     *          
     *       Use:   System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort("COM1");
     *              ... serial communications code
     *             myPort.SendCOMMbreak(5); //sends a break for rougly 5ms
     *
     *        Or: RS232_Com_Break.UseWinAPItoSendBreak("COM1", 5); //aquires serial port and sends a break for rougly 5ms
     * ==================================================================================*/


    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAsAttribute(UnmanagedType.Bool)]
    static extern bool SetCommBreak([InAttribute] IntPtr fileHandle);

    [DllImport("kernel32.dll")]
    static extern bool ClearCommBreak(IntPtr hFile);

    public const short FILE_ATTRIBUTE_NORMAL = 0x80;
    public const short INVALID_HANDLE_VALUE = -1;
    public const uint GENERIC_READ = 0x80000000;
    public const uint GENERIC_WRITE = 0x40000000;
    public const uint CREATE_NEW = 1;
    public const uint CREATE_ALWAYS = 2;
    public const uint OPEN_EXISTING = 3;

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
        uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
        uint dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll")]
    static extern public bool CloseHandle(IntPtr hObject);


    /// <summary>
    /// Extension method to reset a serial port. Holds Port high (+5vdc) for the duration requested.
    ///    should work with an open or closed port.
    /// </summary>
    /// <param name="oPort"></param>
    public static void SendCOMMbreak(this SerialPort oPort, int milliseconds)
    {
        // I think it takes 1 ms to set and clear the break.
        int iPauseLength = milliseconds > 1 ? milliseconds - 1 : 1;

        //little management to insure the port is free.
        if (oPort.IsOpen)
        {
            oPort.Close();
            UseWinAPItoSendBreak(oPort.PortName, iPauseLength);
            oPort.Open();
        }
        else
        {
            UseWinAPItoSendBreak(oPort.PortName, iPauseLength);
        }
    }

    /// <summary>
    /// All the windows API calls are here, so this would be the code to use if 
    ///     not using the .NET System.IO.Ports.SerialPort object.
    /// </summary>
    /// <param name="sPortName">The name of the COM port</param>
    /// <param name="iPauseLengthMS">pause time in milliseconds</param>
    public static void UseWinAPItoSendBreak(string sPortName, int iPauseLengthMS)
    {
        //get a handle to the port.  Once we have done this sucessfully, it is unavalible elsewhere
        IntPtr port_ptr = CreateFile(sPortName, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

        if (port_ptr.ToInt32() == INVALID_HANDLE_VALUE) // -1 = oops
        {
            // Did not get a handle.  We need to ask the framework to marshall the win32 error code to an exception
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }
        else
        {
            SetCommBreak(port_ptr);
            Thread.Sleep(iPauseLengthMS);
            ClearCommBreak(port_ptr);

            //Close only happens if handle achieved.
            CloseHandle(port_ptr);
        }

    }
}
静赏你的温柔 2024-08-09 03:14:39

不是一个真正的问题,但让我从我的
很久以前(事实上是 20 世纪 80 年代)
作为通信程序员的日子。 您通常通过将所有位保持为低电平来发送中断
或高(取决于您的通信硬件)。 所以要引起休息
要么重复发送值 0x00 大约半秒,要么发送值 0xFF。

Not really an SO question, but let me dredge up stuff from my
long-past (1980s in fact)
days as a comms programmer. You normally send a break by holding all bits low
or high (depending on your comms hardware). So to cause a break
either send the value 0x00 repeatedly for about half a second, or the value 0xFF.

空‖城人不在 2024-08-09 03:14:39

您应该能够看到端口正在发送的数据。 您需要一根零调制解调器电缆、一台带有串行端口(或串行 USB 加密狗)的计算机和一个终端程序(如 Windows 上的超级终端 - Vista 中不包含)。 如果您充分配置终端程序(正确的速度、数据位数、正确的启停设置和正确的端口),所有数据都将显示在屏幕上。
有时需要按回车键才能开始查看数据。 您可以在测试期间切换终端程序的设置以查看是否发生变化(数据的“噪声”)。

You should be able to see the data that the port is sending. You'll need a null-modem cable, a computer with a serial port (or a serial-USB dongle) and a terminal program (as HyperTerminal on Windows -- not included in Vista). If you configure your terminal program adequately (correct speed, number of bits for data, the correct setting of start-stop, and correct port) all the data will be show on screen.
Sometimes it is requiered to hit the enter key to start seeing the data. You can toggle the setting for the terminal program during the test to see if something changes ("noise" to data).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文