Подтвердить что ты не робот

Как использовать событие DataReceived объекта SerialPort Port в С#?

Я пытаюсь создать небольшое приложение для сбора данных, полученных от внешнего датчика, подключенного к COM10. Я успешно создал небольшой объект консоли и приложение С#, которое открывает порт и передает данные в файл в течение фиксированного периода времени с использованием цикла for.

Я хотел бы преобразовать это приложение, чтобы вместо него использовать событие dataReceived. После прочтения Top 5 SerialPort Tips, я все еще не могу показаться, что он работает, и я не знаю, чего мне не хватает. Я переписал консольное приложение, чтобы весь код находился в Main и был вставлен ниже. Может кто-то, пожалуйста, помогите рассказать мне, почему обработчик события port_OnReceiveDatazz не вызывается, хотя я знаю, что данные передаются в порт аппаратными средствами?

Спасибо

Азим

PS: Благодаря @Gabe, @Jason Down и @abatishchev для всех предложений. Я в тупике и не могу заставить обработчик событий работать. Возможно, это имеет какое-то отношение к устройству. Я могу жить, просто прочитав порт в потоке и передавая данные прямо в файл.


код


namespace serialPortCollection
{   class Program
    {
        static void Main(string[] args)
        {

            const int bufSize = 2048;
            Byte[] buf = new Byte[bufSize]; //To store the received data.

            SerialPort sp = new SerialPort("COM10", 115200);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            // Wait for data or user input to continue.
            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

       // My Event Handler Method
        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            const int bufSize = 12;
            Byte[] buf = new Byte[bufSize];
            Console.WriteLine("DATA RECEIVED!");
            Console.WriteLine(spL.Read(buf, 0, bufSize));
        }
    }
}
4b9b3361

Ответ 1

Я думаю, что ваша проблема - это строка: **

sp.DataReceived + = port_OnReceiveDatazz;

Не должно быть:

sp.DataReceived + = новый SerialDataReceivedEventHandler (port_OnReceiveDatazz);

** Nevermind, синтаксис в порядке (не понял ярлык в то время, когда я первоначально ответил на этот вопрос).

Я также видел предложения по включению следующих параметров для вашего последовательного порта:

sp.DtrEnable = true;    // Data-terminal-ready
sp.RtsEnable = true;    // Request-to-send

Вам также может потребоваться установить рукопожатие в RequestToSend (через перечисление рукопожатия).


UPDATE:

Нашел предложение, в котором говорится, что вы должны сначала открыть свой порт, а затем назначить обработчик события. Может быть, это ошибка?

Итак, вместо этого:

sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);
sp.Open();

Сделайте это:

sp.Open();
sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);

Сообщите мне, как это происходит.

Ответ 2

Во-первых, я рекомендую использовать следующий конструктор вместо того, который вы используете в данный момент:

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

Далее вы действительно должны удалить этот код:

// Wait 10 Seconds for data...
for (int i = 0; i < 1000; i++)
{
    Thread.Sleep(10);
    Console.WriteLine(sp.Read(buf,0,bufSize)); //prints data directly to the Console
}

И вместо этого просто зацикливайтесь до тех пор, пока пользователь не нажмет клавишу или что-то вроде:

namespace serialPortCollection
{   class Program
    {
        static void Main(string[] args)
        {
            SerialPort sp = new SerialPort("COM10", 115200);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

       // My Event Handler Method
        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            byte[] buf = new byte[spL.BytesToRead];
            Console.WriteLine("DATA RECEIVED!");
            spL.Read(buf, 0, buf.Length);
            foreach (Byte b in buf)
            {
                Console.Write(b.ToString());
            }
            Console.WriteLine();
        }
    }
}

Также обратите внимание на изменения обработчика обработанных данных, он должен фактически распечатать буфер сейчас.

ОБНОВЛЕНИЕ 1


Я только что успешно выполнил следующий код на своей машине (используя нуль-модемный кабель между COM33 и COM34)

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread writeThread = new Thread(new ThreadStart(WriteThread));
            SerialPort sp = new SerialPort("COM33", 115200, Parity.None, 8, StopBits.One);
            sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler

            sp.Open();
            sp.WriteLine("$"); //Command to start Data Stream

            writeThread.Start();

            Console.ReadLine();

            sp.WriteLine("!"); //Stop Data Stream Command
            sp.Close();
        }

        private static void port_OnReceiveDatazz(object sender, 
                                   SerialDataReceivedEventArgs e)
        {
            SerialPort spL = (SerialPort) sender;
            byte[] buf = new byte[spL.BytesToRead];
            Console.WriteLine("DATA RECEIVED!");
            spL.Read(buf, 0, buf.Length);
            foreach (Byte b in buf)
            {
                Console.Write(b.ToString() + " ");
            }
            Console.WriteLine();
        }

        private static void WriteThread()
        {
            SerialPort sp2 = new SerialPort("COM34", 115200, Parity.None, 8, StopBits.One);
            sp2.Open();
            byte[] buf = new byte[100];
            for (byte i = 0; i < 100; i++)
            {
                buf[i] = i;
            }
            sp2.Write(buf, 0, buf.Length);
            sp2.Close();
        }
    }
}

ОБНОВЛЕНИЕ 2


Учитывая весь трафик по этому вопросу в последнее время. Я начинаю подозревать, что ваш последовательный порт не настроен должным образом или что устройство не отвечает.

Я настоятельно рекомендую вам попытаться связаться с устройством, используя некоторые другие средства (я часто использую гипертерминал). Затем вы можете играть со всеми этими настройками (битрейт, четность, бит данных, стоп-биты, управление потоком), пока не найдете набор, который работает. В документации к устройству также должны быть указаны эти параметры. Как только я это понял, я бы удостоверился, что мой .NET SerialPort настроен правильно, чтобы использовать эти настройки.

Некоторые советы по настройке последовательного порта:

Обратите внимание, что когда я сказал, что вы должны использовать следующий конструктор, я имел в виду, что использовать эту функцию, не обязательно эти параметры! Вы должны заполнить параметры для своего устройства, приведенные ниже настройки являются общими, но могут отличаться для вашего устройства.

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

Также важно настроить .NET SerialPort на использование того же элемента управления потоком, что и ваше устройство (как говорили другие люди ранее). Вы можете найти более подробную информацию здесь:

http://www.lammertbies.nl/comm/info/RS-232_flow_control.html

Ответ 3

У меня была такая же проблема с модемом, который ранее работал, а затем однажды прекратил поднимать событие DataReceived.

Решение в моем случае, очень случайным образом, заключалось в том, чтобы включить RTS, например,

sp.RtsEnable = true;

Не знаю, почему это сработало на этом конкретном куске набора (а не на самом деле комм), и почему это сработало, а затем остановилось, но однажды это может помочь кому-то другому, поэтому просто отправьте его на всякий случай...

Ответ 4

Кстати, вы можете использовать следующий код в обработчике событий:

switch(e.EventType)
{
  case SerialData.Chars:
  {
    // means you receives something
    break;
  }
  case SerialData.Eof:
  {
    // means receiving ended
    break;
  }
}

Ответ 5

Я считаю, что это не сработает, потому что вы используете консольное приложение, и нет цикла Event Loop. Буфер событий/сообщений, используемый для обработки событий, настраивается автоматически при создании приложения Winforms, но не для консольного приложения.

Ответ 6

Возможно, будет Console.ReadLine блокировка вашего обратного вызова Console.Writeline. Образец в MSDN выглядит ALMOST одинаковым, за исключением того, что они используют ReadKey (который не блокирует консоль).

Ответ 7

Помните, что существуют проблемы с использованием .NET/С# и любого COM-порта выше COM9.

Смотрите: HOWTO: укажите последовательные порты больше, чем COM9

Существует обходной путь в формате: "\\.\COM10", который поддерживается в базовом методе CreateFile, но .NET предотвращает использование этого формата обхода; ни конструктор SerialPort, ни свойство PortName не будут иметь имя порта, начинающегося с "\"

Я пытаюсь получить надежную связь с COM10 в С#/. NET. В качестве примера, если у меня есть устройство на COM9 и COM10, трафик, предназначенный для COM10, отправляется на устройство на COM9! Если я удалю устройство на COM9, COM10-трафик перейдет на устройство на COM10.

Я до сих пор не понял, как использовать дескриптор, возвращенный CreateFile, для создания объекта SerialPort класса С#/. NET, если бы я знал, как это сделать, то я думаю, что я мог бы использовать COM10 + просто отлично от С#.