SerialSend: утилита для работы с виртуальным COM-портом |
![]() |
Добавил(а) microsin | ||||
SerialSend это маленькое приложение Windows, запускаемое из командной строки, которая создана автором (Ted Burke [1]) для отправки строк текста через последовательный порт. Программа удобна для использования вместе с устройствами на микроконтроллерах, которые подключаются к компьютеру через порт USB как виртуальный последовательный COM-порт (VCP). Примечание: это могут быть различные устройства, например подключенный к USB микроконтроллер AVR, в который записан проект VCP на основе библиотеки V-USB (см. [2]), либо микроконтроллер AVR с аппаратным USB (проект на основе библиотеки LUFA [3]). В этих выше перечисленных случаях микроконтроллеры AVR подключаются к USB напрямую, без специальных микросхем. Также микроконтроллеры AVR могут подключаться к USB через специальные переходники USB-RS232TTL на чипах FT232RL, CP1021, CH340G, ATmega16U2 и т. п. (так называемые схемы USB-to-serial, по такому принципу подключаются к UART через USB популярные платы Arduino).
Программа SerialSend позволит Вам: • Послать строку произвольных символов текста в устройство через последовательный порт с помощью одной команды. Причина, по которой была добавлена последняя возможность, следующая. Часто Windows присваивает различные номера COM-портов даже для одного и того же устройства, если он подключается в разные порты USB (прим. переводчика: это происходит в том случае, если в устройстве USB VCP нет встроенного серийного номера; тогда Windows сама генерирует идентификаторы для такого устройства VCP, привязываясь к номеру порта USB). Чаще всего при подключении переходника USB VCP к порту USB операционная система присваивает ему следующий по порядку не используемый номер COM-порта, так что номер COM-порта получается самый большой из всех доступных COM-портов. Поэтому автоматическое подключение к COM-порту по самому большому номеру в таком случае оказывается полезным, потому что не надо специально задавать номер COM-порта для подключения. Автор предоставил полный исходный код на языке C для своей утилиты SerialSend (см. врезку). Код компилировался в среде MinGW (gcc), как это показано в комментариях к коду, но также можно скомпилировать SerialSend под управлением Visual C++ или другого компилятора Windows C/C++. Также Вы можете загрузить и использовать уже скомпилированный вариант (SerialSend.exe, 54 KB, date: 8-4-2015). [Примеры использования] Примечание: если передаваемый текст содержит пробелы, то он должен быть заключен в двойные кавычки. Следующая команда посылает символы abc 123 через доступный последовательный порт с самым большим номером и скоростью по умолчанию (38400 baud). SerialSend.exe "abc 123" Следующая команда посылает текст Hello world! через самый большой по номеру и доступный последовательный порт на скорости 9600 baud. SerialSend.exe /baudrate 9600 "Hello world!" Следующая команда посылает текст S120 E360 через COM10 со скоростью по умолчанию (38400 baud). Если порт COM10 не доступен в системе, то вместо него будет использован доступный порт с самым большим номером. SerialSend.exe /devnum 10 "S120 E360" Произвольные байты, включая не печатаемые символы (такие, как табуляция TAB, символы возврата каретки CR и перевода строки LF), могут быть добавлены в строку как шестнадцатеричные числа с помощью опции /hex командной строки и esc-символа \x в задаваемом тексте. Например, следующая команда отправляет строку abc, за которой следует символ перевода строки LF (line feed, шестнадцатеричное значение 0x0A). В этом примере получается, что всего будет отправлено 4 байта. SerialSend.exe /hex "abc\x0A" Также вместе с опцией /hex можно использовать esc-последовательности \n и \r для вставки в строку символа перевода строки (LF) и возврата каретки (CR) соответственно. Например, следующая команда отправит строку Hello, за которой идут символы CR и LF (всего будет отправлено 7 байт). SerialSend.exe /hex "Hello\r\n" Опция командной строки /closedelay позволяет вставить задержку (указанную в миллисекундах) после того, как текст будет отправлен, но до того, как последовательный порт будет закрыт. Это может понадобиться, когда нужно посылать порции данных в устройство, и необходимо при этом дать ему время на обработку и ответ для каждой порции. Например, следующая команда посылает символы ABCD и CR в порт COM5, и после этого делает задержку 500 мс, и после истечения этой задержки COM5 будет закрыт (освобожден). SerialSend.exe /devnum 5 /closedelay 500 "ABCD\r" Пример скриншота запуска SerialSend в консоли: // [SerialSend.c]
// Эта программа посылает текст через последовательный порт
// Автор Ted Burke, последнее обновление 8-4-2015
//
// Текст для отправки указывается в аргументах командной строки.
// По умолчанию используется COM-порт с самым большим найденным номером.
// Используемая по умолчанию скорость 38400 baud.
//
// Как компилировать с помощью установленной системы MinGW:
//
// gcc -o SerialSend.exe SerialSend.c
//
// Как компилировать компилятором cl компании Microsoft:
//
// cl SerialSend.c
//
// Пример запуска (отправка последовательности символов S365 E120):
//
// SerialSend.exe "S356 E120"
// #include < stdio.h >
int main(int argc, char *argv[]) { // Декларация переменных и структур: int m, n; unsigned char buffer[MAX_PATH]; unsigned char text_to_send[MAX_PATH]; unsigned char digits[MAX_PATH]; int baudrate = 38400; int dev_num = 50; int parse_hex_bytes = 0; int close_delay = 0; char dev_name[MAX_PATH]; HANDLE hSerial; DCB dcbSerialParams = {0}; COMMTIMEOUTS timeouts = {0}; // Вывод приветственного сообщения: fprintf(stderr, "SerialSend (last updated 8-4-2015)\n"); fprintf(stderr, "See http://batchloaf.com for more information\n"); // Парсинг аргументов командной строки: int argn = 1; strcpy(buffer, ""); while(argn < argc) { if (strcmp(argv[argn], "/baudrate") == 0) { // Parse baud rate if (++argn < argc && ((baudrate = atoi(argv[argn])) > 0)) { fprintf(stderr, "%d baud specified\n", baudrate); } else { fprintf(stderr, "Baud rate error\n"); return 1; } } else if (strcmp(argv[argn], "/devnum") == 0) { // Обработка номера устройства. SerialSend начинает поиск доступных // COM-портов с этого номера, постепенно уменьшая его до нуля. if (++argn < argc) { dev_num = atoi(argv[argn]); fprintf(stderr, "Device number %d specified\n", dev_num); } else { fprintf(stderr, "Device number error\n"); return 1; } } else if (strcmp(argv[argn], "/closedelay") == 0) { // Обработка задержки перед закрытием порта. После передачи // указанного текста SerialSend выполнит задержку на это // количество миллисекунд, после чего закроет COM-порт. if (++argn < argc) { close_delay = atoi(argv[argn]); fprintf(stderr, "Delay of %d ms specified before closing COM port\n", close_delay); } else { fprintf(stderr, "Close delay error\n"); return 1; } } else if (strcmp(argv[argn], "/hex") == 0) { // Обработка hex-флага для передаваемого байта. // Если этот флаг установлен, то в строку передачи можно // добавить произвольный байт, указывая его через нотацию '\x'. // Например, команда "SerialSend /hex Hello\x0D" // отправит 6 байт, где последним будет байт перевода строки CR // (символ '\r', у которого код 0x0D). parse_hex_bytes = 1; } else { // Этот аргумент командной строки будет отправляемым текстом: strcpy(buffer, argv[argn]); } // Переход к следующему аргументу командной строки: argn++; } // Проверка, предоставлен ли для передачи какой-нибудь текст: if (strlen(buffer) == 0) { fprintf(stderr, "Usage:\n\n\tSerialSend [/baudrate BAUDRATE] "); fprintf(stderr, "[/devnum DEVICE_NUMBER] [/hex] \"TEXT_TO_SEND\"\n"); return 1; } // Если hex-парсинг разрешен, то текст для передачи модифицируется: n = 0; m = 0; while(n < strlen(buffer)) { if (parse_hex_bytes && buffer[n] == '\\') { n++; if (buffer[n] == '\\') text_to_send[m] = '\\'; else if (buffer[n] == 'n') text_to_send[m] = '\n'; else if (buffer[n] == 'r') text_to_send[m] = '\r'; else if (buffer[n] == 'x') { digits[0] = buffer[++n]; digits[1] = buffer[++n]; digits[2] = '\0'; text_to_send[m] = strtol(digits, NULL, 16); } } else { text_to_send[m] = buffer[n]; } m++; n++; } text_to_send[m] = '\0'; // Null-символ, завершающий строку. // Открыть доступный порт с самым большим номером: fprintf(stderr, "Searching serial ports...\n"); while(dev_num >= 0) { fprintf(stderr, "\r "); fprintf(stderr, "\rTrying COM%d...", dev_num); sprintf(dev_name, "\\\\.\\COM%d", dev_num); hSerial = CreateFile( dev_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hSerial == INVALID_HANDLE_VALUE) dev_num--; else break; } if (dev_num < 0) { fprintf(stderr, "No serial port available\n"); return 1; } fprintf(stderr, "OK\n"); // Установка параметров устройства (38400 baud, 1 start bit, // 1 stop bit, no parity) dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (GetCommState(hSerial, &dcbSerialParams) == 0) { fprintf(stderr, "Error getting device state\n"); CloseHandle(hSerial); return 1; } //dcbSerialParams.BaudRate = CBR_38400; dcbSerialParams.BaudRate = baudrate; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; if(SetCommState(hSerial, &dcbSerialParams) == 0) { fprintf(stderr, "Error setting device parameters\n"); CloseHandle(hSerial); return 1; } // Настройки таймаута COM-порта: timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if(SetCommTimeouts(hSerial, &timeouts) == 0) { fprintf(stderr, "Error setting timeouts\n"); CloseHandle(hSerial); return 1; } // Отправка указанного текста: DWORD bytes_written, total_bytes_written = 0; fprintf(stderr, "Sending text... "); while(total_bytes_written < m) { if(!WriteFile(hSerial, text_to_send + total_bytes_written, m - total_bytes_written, &bytes_written, NULL)) { fprintf(stderr, "Error writing text to %s\n", dev_name); CloseHandle(hSerial); return 1; } total_bytes_written += bytes_written; } fprintf(stderr, "\n%d bytes written to %s\n", total_bytes_written, dev_name); // Сброс (Flush) буфера передачи перед закрытием последовательного порта: FlushFileBuffers(hSerial); if (close_delay > 0) { fprintf(stderr, "Delaying for %d ms before closing COM port... ", close_delay); Sleep(close_delay); fprintf(stderr, "OK\n"); } // Закрытие последовательного порта: fprintf(stderr, "Closing serial port..."); if (CloseHandle(hSerial) == 0) { fprintf(stderr, "Error\n", dev_name); return 1; } fprintf(stderr, "OK\n"); // Нормальный выход: return 0; } [Ссылки] 1. SerialSend site:batchloaf.wordpress.com. |