Очень часто, разрабатывая какое-нибудь «микроконтроллерное устройство», возникает необходимость подключить его к компьютеру. При этом не требуется каких-нибудь «сверх-задач», всего-то и нужно передать из компьютера в устройство какую-нибудь команду или небольшой массив даннных; и/или, наоборот — из устройства выгрузить данные в компьютер. Обычно для таких целей используют старый, проверенный RS232. Однако, сейчас найти компьютер с подобным интерфейсом — весьма не простая задача…
Взглянув на заднюю стенку Вашего компьютера, Вы вряд ли увидите что-то подходящее для задачки — кроме нескольких портов USB.
USB — очень удачное решение в эволюции компьютерной техники: и «горячее» подключение, и питание есть и еще много чего хорошего… Одно плохо — уж очень мудреный интерфейс получился. Если копнуть интернет в этом направлении — сразу… руки опускаются.
Есть прекрасный выход из ситуации — использование эмуляции СОМ-порта. Для этого есть масса «копеечных» микросхем: CP2102, PL2303, CH340 и др.
Все что касается USB — они берут на себя, а нам дают хорошо знакомый UART. По этому принципу устроено множество изделий, например, так построено взаимодействие Arduino с компьютером…
Интересно обойтись без этих «костылей» — благо — ресурсов даже ATtiny для этого хватает с избытком… Посмотрим — как реализована эмуляция COM порта в широко распространенном проекте Digispark. Ранее был рассмотрен вариант подключения платы к компьютеру и Arduino IDE
Все нюансы эмуляции описаны в первоисточнике на Digistump. Сейчас рассмотрим вариант использования платы для ее взаимодействия с компьютером через USB — DigiCDC. Для этого удобно использовать слегка доработанный под DigiCDC пример Echo из раздела Примеры -> DigisparkUSB -> Echo
#include <DigiCDC.h> void setup() { pinMode(1, OUTPUT); SerialUSB.begin(); } void get_input() { int lastRead; // when there are no characters to read, or the character isn't a newline while (true) { // loop forever if (SerialUSB.available()) { // something to read lastRead = SerialUSB.read(); SerialUSB.write(lastRead); if (lastRead == '\n') { break; // when we get a newline, break out of loop } if (lastRead == '0') { digitalWrite(1, LOW); // turn the LED off SerialUSB.println(" LED Off ..."); break; // break out of loop } if (lastRead == '1') { digitalWrite(1, HIGH); // turn the LED on SerialUSB.println(" LED On ..."); break; // break out of loop } } // refresh the usb port for 10 milliseconds SerialUSB.delay(10); } } void loop() { // print output SerialUSB.println("Waiting for input..."); SerialUSB.println("Press 0 to LED off or 1 to LED On..."); // get input get_input(); }
Ключевым моментом в программе является строка
SerialUSB.begin();
после ее выполнения Digispark превращается в Digispark Virtual Com Port и компьютер его так и обнаруживает (при этом DigisparkBootloader из устройств в диспетчере исчезает). Для того чтобы компьютер определил новое устройство так как надо, компьютеру надо подсунуть нужный драйвер (указать на файл DigiSerial.inf)
Если компьютер нужный драйвер сам не нашел, указываем ему на то что надо и получаем требуемое устройство в Диспетчере устройств:
С получившимся COM портом можно делать все, что угодно. Самое простое — «натравить» на него монитор Arduino IDE. Просто в настройках среды выбираем наш новый COM порт и работаем с ним …
В использовании такого «порта» есть нюансы:
- Библиотека DigiCDC использует довольно много оперативной памяти. Рекомендуется при выводе в порт текста пользоваться функцией F(), например: SerialUSB.print(F(“test”)).
- Порт можно использовать для обмена сообщениями, как это обычно принято (типовая строка Serial.print() используется почти во всех творениях). Но, теперь надо использовать, например, SerialUSB.read() вместо Serial.read() и т.п.
- Никакого указания скорости обмена при инициализации теперь не требуется, просто пишем: SerialUSB.begin().
- Обмен через эмулируемый порт о-о-очень медленный. На передачу символа уходит 5 мс!!! Это надо иметь ввиду при разработке решений.
- Если в проекте надо использовать задержку функцией delay(), то ее надо заменить на SerialUSB.delay().
- В проектах с DigiCDC функции SerialUSB.delay() или SerialUSB.refresh() нужно вызывать не реже, чем каждые 10 мс, если нет вызовов других функций SerialUSB.
Пример работы скетча:
Waiting for input…
Press 0 to LED off or 1 to LED On…
0 LED Off …
Waiting for input…
Press 0 to LED off or 1 to LED On…
1 LED On …
Waiting for input…
Press 0 to LED off or 1 to LED On…
Приведенный выше скетч реагирует на клавишу «1» — включением светодиода на плате Digispark, а, при нажатии клавиши «0», выключает его.
Подскажите, есть ли решение такой проблемы:
После перезагрузки компьютера устройство Digispark перестает определяться в Windows, если на нем работали DigiUSB или SerialUSB. Приходится вынимать и втыкать устройство после каждой перезагрузки вручную.
Есть ли решения данной проблемы? Спасибо.