简体   繁体   中英

Read only 8 characters from Serial Port

Im trying to teach myself C Sharp with making an RFID reader.

I have created some code to read from a serial port (rfid reader over Bluetooth RS232)

The issue im hoping someone can help me with is that:

My RFID reader transmits the card code in very quick succession meaning when I swipe a card it will fire my event handler more than once with different sections of the card code so at the moment I cant receive a full card code in one hit making it impossible to process the card.

The code I have so far is:

    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
        {  
        }
    }

Can anyone let me know how to limit the event handler from firing until 8 characters are received and only fire once a second?

Thanks in advance a very mind boggled Ryan

You seem to have two different questions here:

  1. How to read eight characters at a time.
  2. How to limit processing of input to one card code every second.

The two can (and should) be addressed together. You can fix the first issue in your DataReceived event handler, but the exact details will depend on the second.

Unfortunately, your question says you want eight characters at a time, but your code says nine. So I have no way to ensure that detail is correct. I'll just add a constant, and let you decide. :)

I'd recommend something like this to handle the input:

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
    {  
    }
}

Note that the above does not actually process the code. Instead, in order to accomplish the one-code-per-second design goal, you'll want to consume the codes outside of the above (introducing delays into the serial I/O itself will only cause problems).

So, in a different thread:

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);
    }
}

Don't forget to call codes.CompleteAdding() when you're done reading from the serial port, so the CodeConsumer() thread can exit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM