Обмен данными между ПК и Arduino через последовательный порт (с примером на C#)

Микроконтроллеры Arduino могут интегрироваться с ПК через последовательный порт. В аппаратном отношении подключение реализовано через интерфейс USB, но операционная система воспринимает устройство так, как будто оно подключено при помощи последовательного порта.

Рассмотрим организацию обмена данными между микроконтроллером Arduino и ПК на примере языка программирования C#.

В .NET для программирования взаимодействия с последовательным портом существует специальный класс под названием SerialPort. На его основе и будет строиться наша реализация. Однако для начала необходимо запрограммировать сам микроконтроллер, чтобы он мог воспринимать поступающую с ПК информацию и соответствующим образом на неё реагировать.

Программирование микроконтроллера

В нашем случае для простоты будет реализована «заглушка» интерфейса управления микроконтроллером при помощи ПК. Микроконтроллер будет получать через последовательный порт некие команды и отправлять на ПК ответ, что та или иная команда принята.

Для работы с последовательным портом в Arduino используется стандартная библиотека Serial. Далее приведён пример реализации, описанной выше «заглушки» с её использованием. Работа программы поясняется в комментариях к коду.

void setup() {
  // Инициализация последовательного порта с указанием скорости обмена данными ( по умолчанию лучше использовать 9600 бод)
  Serial.begin(9600);
  // Устанавливаем таймаут (значение по умолчанию слишком велико)
  Serial.setTimeout(100);
}
void loop() {
  // Если поступили данные с ПК
  if (Serial.available() > 0) {
    // Считываем полученные данные
    String command = Serial.readString();
    // Формируем ответ
    String response = "Command " + command + " is accepted!";
    // Отправляем ответ ПК
    char buf[response.length() + 1];
    response.toCharArray(buf, response.length() + 1);
    Serial.write(buf);
  }
}

Программирование последовательного порта на C#

Объявим две переменные. Первая будет экземпляром класса SerialPort. Вторая – величина таймаута для чтения данных.

SerialPort port;
int timeout = 3000;

Инициализация порта:

port = new SerialPort("COM3", 9600);
port.Open();
port.ReadTimeout = timeout;

Обратите внимание, что для инициализации порта требуется указать его имя (в данном примере это «COM3») и скорость обмена данными (должна обязательно совпадать со скоростью, которая была ранее задана для микроконтроллера). Также лучше всего сразу задать таймаут для чтения данных.

Объявляем переменную для отправки через порт микроконтроллеру.

String message = "Test";

Далее при помощи методов Write и ReadExists класса SerialPort отправим наше сообщение и получим ответ. Для того, чтобы узнать поступил ли ответ от микроконтроллера, воспользуемся методом BytesToRead этого же класса.

Так как ответ может прийти не сразу необходимо предусмотреть ожидание перед попыткой чтения. Однако продолжительность этого ожидания следует обязательно ограничивать. В том числе потому, что, например при разрыве связи ответ от контроллера может вообще не поступить, а программа будет всё равно будет его ждать.

Ниже представлен пример реализации обмена данными с микроконтроллером. Работа программы поясняется в комментариях к коду.

// Если порт открыт
if (port.IsOpen)
{
    // Отправляем сообщение
    port.Write(message);
    // Ждём получения данных
    int seconds = 0;
    while ((port.BytesToRead <= 0) && (seconds <= ((timeout / 1000) - 1)))
    {
         Thread.Sleep(1000);
         seconds++;
    }
    // Если и после истечения таймаута данные не поступили, выдаём ошибку
    if (port.BytesToRead <= 0)
    {
        throw new Exception("Нет ответа от микроконтроллера! Время ожидания истекло!");
    }
    else
    {
        // Если данные поступили пытаемся их прочитать
        try
        {
            string returnedMesssage = port.ReadExisting();
            return returnedMesssage;
        }
            catch (TimeoutException ex)
        {
            throw new Exception("Невозможно прочитать ответ микроконтроллера! Время выполнения операции истекло!");
        }
    }
}
else
{
    throw new Exception("Порт закрыт!");
}

Возможности библиотеки System не ограничиваются работой со строками, но, к сожалению, класс SerialPort может передавать данные только в виде строк, а принимать только в виде строк, массива символов или байтов. Это обстоятельство следует обязательно учитывать при разработке программного обеспечения для работы с Arduino в .NET

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

Во всём остальном рассмотренный в статье механизм является универсальным для Arduino и .NET.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *