Последовательный порт Arduino nano 33 BLE не работает с приложением С#

serial arduino-nano arduino-nano-ble

Я использую Arduino Nano с некоторыми датчиками и отправляю данные на ПК через последовательный порт. Я только что получил новый Arduino Nano 33 BLE и попробовал тот же код, но он не работает. Поэтому для тестирования я написал простой тестовый код на стороне Arduino Nano 33 BLE:

void setup()
{
  Serial.begin(57600);
}

void loop()
{
  if (Serial.available())
  {
    char c = Serial.read();
    Serial.write(c);
  }
}

Это просто отправляет обратно все, что приходит через COM-порт. При использовании последовательного монитора Arduino IDE это очень хорошо работает с Arduino Nano 33 BLE. Я также сделал очень простой тестовый код C# (приложение Windows Forms):

SerialPort serialPort = new SerialPort("COM17", 57600);
serialPort.ReadTimeout = 4000;
serialPort.WriteTimeout = 4000;
serialPort.Encoding = Encoding.ASCII;
serialPort.DataReceived += SerialPort_DataReceived;
serialPort.Open();
if (serialPort.IsOpen)
{
    Debug.Print("COM port open");
}

Этот код C# отлично работает с моим старым добрым Arduino Nano, но не работает с Arduino Nano 33 BLE. У меня есть сообщение COM-порт открыт, значит, порт существует и открыт, но больше ничего, ни тайм-аута, ничего. Я уже потерял один день, пробуя всевозможные комбинации, но это просто не работает, мое приложение C# не может взаимодействовать с Arduino Nano 33 BLE. Это похоже на проблему с последовательным портом, поэтому я думаю, что пока отложу...

ИЗМЕНИТЬ: Остальная часть моего тестового кода, для справки:

private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        Debug.Print(serialPort.ReadExisting());
    }
    catch (Exception exception)
    {
        Debug.Print(exception.Message);
    }
}

private void buttonSend_Click(object sender, EventArgs e)
{
    try
    {
        serialPort.WriteLine("HELLO");
    }
    catch (Exception exception)
    {
        Debug.Print(exception.Message);
    }
}

, 👍1

Обсуждение

Я не эксперт в C #, но я не вижу, чтобы вы действительно что-то отправляли. И где определен SerialPort_DataReceived?, @chrisl

Я копирую/вставляю только основной код... но он есть... отредактирую вопрос и добавлю их, @Pedro Ferreira

Убедились ли вы на самом деле (например, с помощью отладочного сообщения), что serialPort.WriteLine("HELLO"); действительно выполняется? Из того, что вы описали, проблема заключается в вашем приложении С#, а не в части Arduino., @chrisl

«При использовании серийного монитора Arduino IDE это очень хорошо работает с Arduino Nano 33 BLE»... это означает, что данные попадают на ваш компьютер.. что вы делаете с данными после того, как они туда попадают, здесь не по теме., @jsotola

Как я также упоминаю в своем вопросе, этот код C# отлично работает с Arduino Nano, поэтому я уверен, что код C# работает. Это просто не работает с новым Arduino Nano 33 BLE. Вероятно, что-то связано со слоем mbed... но это не имеет смысла, работая с последовательным монитором Arduino IDE, а не с приложением, скомпилированным на C#. Я также где-то читал, что последовательный порт USB Arduino Nano 33 BLE является виртуальным, поэтому это чисто программный последовательный порт, а не аппаратное преобразование последовательного порта в USB., @Pedro Ferreira

Этот код _должен_ работать. Может глупый вопрос: Вы уверены, что порт правильный? IIRC есть некоторые подводные камни при использовании события DataReceived [другие говорят, что оно полностью не работает]. Вместо этого попробуйте использовать поток для принимающей стороны., @PMF

@PMF да, код работает, и это правильный порт, я привык к такому коду и обмену последовательным кодом, многопоточности, событиям и т. д. Я думаю, действительно есть проблема с новым Arduino Nano 33 BLE ... Я надеялся, что кто-то видел это раньше и у него есть какой-то обходной путь..., @Pedro Ferreira


1 ответ


Лучший ответ:

4

Я заметил, что многие параметры линейной дисциплины и управления потоком не были явно указаны в вашем коде C#, поэтому мне стало интересно, что они означают по умолчанию.

В частности, DtrEnable выглядит как false по умолчанию и Handshake по умолчанию имеет значение None (что кажется неуместным). Другая сумма по умолчанию равна 8N1. Первая часть показалась мне интересной, потому что для последовательных API более типичным является автоматическое утверждение DTR при открытии порта, когда вы явно не просите об этом. Если я правильно читаю документацию по .NET, это не для вашего приложения. Первоначальный Nano не особо заботится о DTR, за исключением сброса триггера спадающего фронта. Правление с удовольствием общается с ним солидно либо самоутверждено, либо нет. DTR оригинального Nano имеет только емкостную связь для сброса; код, работающий на AVR, не может реагировать на DTR (если не считать сброс). Это приводит к вопросу о том, в какой степени Nano 33 BLE будет заботиться о DTR.

Как оказалось, Nano BLE не все равно. Если я отключу DTR в тесте с pyserial, плата перестанет отправлять трафик обратно. Я могу писать, пока он не подтвержден, и после повторного подтверждения поступают некоторые данные из очереди. Тестовая среда с pyserial просто более доступна для меня; если понадобится, и у меня будет шанс, я настрою тест .net/C# и подтвержу это, но я подозреваю, что в этом нет необходимости. Увидев этот результат, я поискал и нашел этот пост на форуме Arduino с некоторым аналогичное описание проблемы. ОП отвечает на свой пост, говоря:

Проблема решена. Arduino nano BLE требует сигналов DTR и RTS для Быть на. Тогда это работает как FDTI.

Отключение RTS не помогло во время моих тестов с pyserial. Я не уверен, почему это так. Возможно, они просто заявили об этом превентивно. Быть полностью виртуальным портом RTS на самом деле не имеет смысла для управления потоком. DTR, возможно, по-прежнему имеет больше смысла в этом контексте; на уровне последовательных сигналов это обычно говорит вам, что что-то обращает внимание на другой стороне соединения. В любом случае я не очень удивлен, что BLE-чувство будет реагировать на отключение DTR, не отправляя данные на хост; есть большая свобода в том, как эти сигналы могут быть обработаны. То, что он не используется автоматически при открытии порта (или до тех пор, пока он специально не запрошен), кажется в основном вещью C#. Но похоже, что разная обработка DTR между двумя платами заставляет ваш код работать с одной, но не с другой.

Поэтому представляется необходимым и достаточным добавить

serialPort.DtrEnable = true;

среди прочих настроек после открытия порта.

Если то, что постер Arduino Forum сказал о RTS, правда, то вам также понадобится

serialPort.RtsEnable = true;

но на это не указывают проведенные мной тесты (опять же с pyserial).

,

Tx @timemage, ты спас мой день... черт возьми, ты спас мне неделю! Да, я подтверждаю, что достаточно просто добавить **DtrEnable = true**. О чем, черт возьми, они думали? Это проклятый виртуальный порт, где даже не нужно указывать скорость передачи! И их волнует состояние сигнала DTR? Что-то, что вы обычно оставляете неподключенным в аппаратном последовательном порту? сыр..., @Pedro Ferreira

Я думаю получить ваше разочарование. Но, чтобы быть ясным в отношении того, что он виртуальный: хост-компьютер не знает, приводят ли логические запросы на изменения в бодах или DTR к реальным изменениям уровней сигнала и времени или они просто заканчивают стек USB. С точки зрения .NET, он даже не знает, что Serial API поддерживается периферийным устройством USB, а не последовательным портом старого типа. Существует давняя традиция захвата последовательных сигналов для целей, о которых вы никогда не догадались бы, исходя из их имен., @timemage

Запрос 1200 бод _вместе с DTR_ (а также RTS в случае плат Due и обычных плат ESP32/ESP8266) используется во многих платах типа Arduino как только в стеке USB (где нет фактического сигнала DTR или синхронизации uart) и также через приемопередатчики, чтобы вызвать вход в загрузчики, стереть чип и т. д. У меня не было особой причины (до тестирования) думать, что BLE будет заботиться (или нет) о скорости, отличной от 1200 бод (мнимой бод). В той мере, в какой я _слегка удивлен_ чем-либо здесь, это поведение по умолчанию API SerialPort .NET., @timemage