Как правильно написать приложение Win32, используя boost :: asio для связи через последовательное соединение - PullRequest
0 голосов
/ 12 ноября 2018

Я разрабатываю приложение для Windows, которое должно взаимодействовать (как с входом, так и с выходом) с Arduino через его последовательный порт. Я использую boost :: asio по причинам переносимости, и я хочу продолжать использовать его. Что происходит, когда я запускаю свое приложение в первый раз, оно работает отлично, но если я запускаю его во второй раз, данные из Arduino больше не поступают, и приложение застревает в операции чтения. Единственный способ восстановления - отключить и снова подключить USB-кабель Arduino к компьютеру.

Это поведение зависит от Windows. Тот же код отлично работает в Linux.

Компилятор - Visual Studio 2017 Community Edition.

Вот пример кода для воспроизведения проблемы:

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>


int main() {
  boost::asio::serial_port port(ioctx, "COM3"); // "/dev/ttyACM0" on Linux

  port.set_option(boost::asio::serial_port::baud_rate(9600));
  port.set_option(boost::asio::serial_port::character_size(8));
  port.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
  port.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
  port.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
  char c = 'e';
  auto const s = boost::asio::write(port, boost::asio::buffer(&c, 1));
  std::cout << "sent " << s << " bytes" << std::endl;
  boost::asio::streambuf response;
  boost::asio::read_until(port, response, "\r\n");
  std::istream response_stream(&response);
  std::string line;
  std::getline(response_stream, line);
  std::cout << line << std::endl;

  port.close(); // last-ditch effort to get it working
}

Вот эскиз Arduino (полученный с сайта Arduino):

int incomingByte = 0;   // for incoming serial data                         

void setup() {
  Serial.begin(9600);   // opens serial port, sets data rate to 9600bps
}

void loop() {
  // send data only when you receive data:                            
  if (Serial.available() > 0) {
    // read the incoming byte:                                  
    incomingByte = Serial.read();                               

    // say what you got:
    Serial.print("I received: ");                               
    Serial.println(incomingByte, DEC);                          
  }
}

Есть ли способ восстановить правильное состояние соединения? Я что-то упустил?

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

После изучения нескольких вещей, вот решение:

  1. Arduino использует свою USB-связь для записи эскиза и передачи данных назад и вперед на ПК.Последовательность загрузки предусматривает, что в течение 2 секунд (для новых версий Arduino и стандартного загрузчика) связь с загрузчиком активна.По истечении этого времени выполняется эскиз.
  2. Windows API позволяет одновременно устанавливать все параметры подключения с помощью функции SetCommState и извлекать их аналогично функции GetCommState.Именно этот метод используется функцией set_option для установки параметров, но бывает так, что вызов GetCommState - SetCommState несколько раз подряд сильно замедляет процесс (возможно, путем сброса Arduino несколько раз).

Я закончил писать следующую функцию:

    #include <Windows.h>
    #include <chrono>

    void init_arduino(boost::asio::serial_port& port, std::chrono::milliseconds const& sleep = 2000)
    {
      DCB dcbSerialParams = { 0 };
      GetCommState(port.native_handle(), &dcbSerialParams);
      // this is the optimal way to set the whole serial port configuration
      // just in one shot.
      dcbSerialParams.BaudRate = CBR_9600;
      dcbSerialParams.ByteSize = 8;
      dcbSerialParams.StopBits = ONESTOPBIT;
      dcbSerialParams.Parity = NOPARITY;
      //Setting the DTR to Control_Enable ensures that the Arduino is properly
      //reset upon establishing a connection
      dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
      SetCommState(port.native_handle(), &dcbSerialParams);
      PurgeComm(port.native_handle(), PURGE_RXCLEAR | PURGE_TXCLEAR);

      // Wait for Arduino to boot the sketch
      Sleep(sleep.count());
    }

и использовал ее для замены строк port.set_option( в примере вопроса.

Я также установил управление потокомна DTR_CONTROL_ENABLE вместо исходного none для сброса Arduino при подключении.

0 голосов
/ 02 декабря 2018

Последовательные адаптеры USB могут иметь ошибки в драйвере устройства и проблемы с оборудованием.Тот факт, что вам необходимо отключить и снова подключить устройство, чтобы оно снова заработало, свидетельствует об ошибке драйвера устройства.

  • Найдите обновленный драйвер.Это, вероятно, будет набор микросхем Prolific или FTDI, убедитесь, что вы получаете драйвер от производителя чипов.См. Prolific или FTDI
  • Если это аппаратная проблема, связанная с управлением потоком, вы можете соединить выводы DTR, DSR и CD, а также соединить RTS и CTSконтакты разъема RS-232 на адаптере USB.Я видел USB-адаптеры там, где это необходимо, несмотря на то, что в программном обеспечении не установлен контроль потока.
...