从串行端口只读8个字符

时间:2015-01-14 21:07:24

标签: c# event-handling serial-port

我试图通过制作RFID​​阅读器来教自己C Sharp。

我创建了一些代码来从串口读取(rfid阅读器通过蓝牙RS232)

希望有人可以帮助我的问题是:

我的RFID阅读器非常快速地传输卡片代码,这意味着当我刷卡时它将使用卡片代码的不同部分多次激活我的事件处理程序,所以目前我无法在一次点击中收到完整的卡片代码无法处理卡片。

我到目前为止的代码是:

    private SerialPort serialPort = new SerialPort("COM14", 9600, Parity.None, 8, StopBits.One); // set com port

    String code; // this stores the code from the RFID reader / serial port
    Int32 id; // this is the ID of the person that the RFID code belongs to
    String data;

    bool addtag;

    public Int32 ID // set the ID so it can be passed to other forms
    {
        get { return id; }
    }

    public rfidreader()
    {
        serialPort.DtrEnable = true; // enable data to flow from the SerialPort
        OpenSerialPort(); // Call the OpenSerialPort section below

        serialPort.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); // when data is recieved from the RFID reader fire the event handaler
    }

    public void PauseRFIDReader()
    {
        addtag = false;
        OpenSerialPort();
    }

    public void CloseSerialPort()
    {
        serialPort.Close();
        addtag = true;
    }

    private void OpenSerialPort() // called from above
    {
        try
        {
            serialPort.Open(); // open the serialport
        }
        catch // if serail port unavalable show message box, if Retry is pressed run this section again, if cancel carry on without serial port
        {
            DialogResult result = MessageBox.Show("Failed to connect to the RFID reader" + "\n" + "Check the reader is powered on and click Retry" + "\n\n" + "Press Cancel to use the program without RFID reader", "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error);
            if (result == DialogResult.Retry)
            {
                OpenSerialPort(); // if retry is pressed run the sectiona gain
            }
            else
            {
            } 
        }
    }

    private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) // data recieved from RFID reader
    {
        if (addtag == false)
        {
            data = serialPort.ReadExisting(); // read what came from the RFID reader

            if (data.Length >= 9) // check if the string if bigger than 9 characters
            {
                code = data.Substring(0, 9); // if string is bigget than 9 characters trim the ending characters until it is only 9 long
            }
            else
            {
                code = data; // if less that 9 characters use however many it gets
            }
            MessageBox.Show(code.ToString());
            Start(); // start to process the person

        }
        else
        {  
        }
    }

任何人都可以让我知道如何限制事件处理程序被触发,直到收到8个字符并且每秒只触发一次?

提前感谢一个非常令人难以置信的瑞恩

1 个答案:

答案 0 :(得分:0)

您似乎有两个不同的问题:

  1. 如何一次阅读八个字符。
  2. 如何限制每秒输入一张卡片代码的处理。
  3. 这两者可以(并且应该)一起解决。您可以在DataReceived事件处理程序中修复第一个问题,但具体细节将取决于第二个问题。

    不幸的是,你的问题是你一次想要八个字符,但你的代码却说九个字符。所以我无法确保细节是正确的。我只是添加一个常量,让你决定。 :)

    我建议使用这样的方法来处理输入:

    private const _maxCharacters = 8;
    private code = "";
    private BlockingCollection<string> codes = new BlockingCollection<string>();
    
    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        if (addtag == false)
        {
            data = serialPort.ReadExisting(); // read what came from the RFID reader
    
            while (data.Length > 0)
            {
                string fragment =
                    data.Substring(0, Math.Min(maxCharacters - code.Length, data.Length));
    
                code += fragment;
                data = data.Substring(fragment.Length);
    
                if (code.Length == maxCharacters)
                {
                    codes.Add(code);
                    code = "";
                }
            }
        }
        else
        {  
        }
    }
    

    请注意,上述内容实际上并不处理代码。相反,为了实现每秒一码的设计目标,您需要使用上述代码之外的代码(将延迟引入串行I / O本身只会导致问题)。

    所以,在另一个主题中:

    private static readonly TimeSpan minInterval = TimeSpan.FromSeconds(1);
    
    private void CodeConsumer()
    {
        TimeSpan lastCode = TimeSpan.MinValue;
        Stopwatch sw = Stopwatch.StartNew();
    
        foreach (string code in codes.GetConsumingEnumerable())
        {
            TimeSpan interval = sw.Elapsed - lastCode;
    
            if (interval < minInterval)
            {
                Thread.Sleep(minInterval - interval);
            }
    
            ProcessOneCode(code);
        }
    }
    

    当您从串口读取完成后,不要忘记调用codes.CompleteAdding(),这样CodeConsumer()线程就可以退出。