Files
2026-06-27 00:39:04 +03:00

5.9 KiB

Компонент USB Virtual COM Port (DS_VirtualComPort)

Готовый к интеграции программный компонент на базе официального стека STMicroelectronics USB Device Middleware (класс CDC — Communication Device Class).

Репозиторий полностью оптимизирован: из него удалены все неиспользуемые USB-классы (Audio, HID, MSC), а файлы низкоуровневой конфигурации (usbd_conf.c/.h) и пользовательского интерфейса (usbd_cdc_if.c/.h) перенесены прямо внутрь компонента. Это позволяет разворачивать виртуальный COM-порт в проектах с любой архитектурой (HAL/LL) без CubeMX-генерации кода самого USB.

📌 Структура оптимизированного компонента

Library/DS_VirtualComPort/
├── Class/
│   └── CDC/
│       ├── Inc/usbd_cdc.h, usbd_cdc_if.h
│       └── Src/usbd_cdc.c, usbd_cdc_if.c   # Интерфейс приема/передачи данных
└── Core/
    ├── Inc/usbd_core.h, usbd_conf.h ...
    └── Src/usbd_core.c, usbd_conf.c   # Конфигурация аппаратного USB-драйвера

🚀 Способ добавления в проект (Git Submodule)

1. Подключение подмодуля

Выполните команду в корневом каталоге вашего проекта:

git submodule add https://domstudent.ru Library/DS_VirtualComPort

2. Автоматическое обновление сборки CMake

Запустите PowerShell-скрипт автоматизации из вашей библиотеки утилит (DS_UpdateCMakeList):

cd tools/
./UpdateCMakeList.ps1

Скрипт автоматически найдет заголовочные файлы и исходный код (включая usbd_cdc_if.c и usbd_conf.c), после чего корректно пропишет их в конфигурацию вашего CMakeLists.txt.


🛠 Настройка тактирования (Clock Configuration)

Для успешной работы USB требуется стабильная частота тактирования шины строго 48 MHz. В микроконтроллерах с поддержкой безкварцевого USB (например, STM32F042 / STM32G4) это реализуется через внутренний осциллятор HSI48.

Пример конфигурации тактирования через LL-драйверы:

void SystemClock_Config(void)
{
  LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
  LL_RCC_HSI48_Enable(); // Включаем внутренний генератор 48 МГц

  while(LL_RCC_HSI48_IsReady() != 1) {} // Ожидаем стабилизации
  
  LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
  LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI48); // Назначаем системным источником
  
  LL_SetSystemCoreClock(48000000);
  LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_HSI48); // Назначаем источником тактов USB
}

💻 Интеграция и пример использования в main.c

Поскольку конфигурация скрыта внутри подмодуля, запуск USB-стека в пользовательском коде сводится к четырем последовательным вызовам функций в секции инициализации периферии.

#include "usbd_core.h"
#include "usbd_cdc_if.h"

/* Глобальные хэндлеры управления стеком */
USBD_HandleTypeDef hUsbDeviceFS;
extern USBD_DescriptorsTypeDef Class_Desc;

int main(void)
{
  // Буфер сообщения (символ конца строки \n обязателен для терминалов)
  uint8_t TxMessageBuffer[] = "MY USB IS WORKING! \r\n";

  HAL_Init();
  SystemClock_Config();
  
  // Инициализация ваших таймеров и портов ввода-вывода (MX_GPIO_Init, MX_TIM2_Init...)

  /* --- РУЧНОЙ ЗАПУСК СТЕКА USB VCP --- */
  USBD_Init(&hUsbDeviceFS, &Class_Desc, DEVICE_FS); // Инициализация ядра USB
  USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);    // Регистрация класса CDC
  USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS); // Привязка функций интерфейса
  USBD_Start(&hUsbDeviceFS);                       // Физический старт USB-устройства

  while (1)
  {
      /* Отправка данных на ПК */
      // Передаем указатель на буфер и его длину (исключая нуль-терминатор строки)
      CDC_Transmit_FS(TxMessageBuffer, sizeof(TxMessageBuffer) - 1);
      
      HAL_Delay(500); // Период отправки пакетов
  }
}

📋 Справочник API функций

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

Основная функция верхнего уровня для отправки массива данных на ПК.

  • Buf: Указатель на массив байт для отправки.
  • Len: Размер отправляемого пакета данных в байтах.
  • Возвращаемое значение: USBD_OK (0) при успешной постановке пакета в очередь отправки, или USBD_BUSY (1), если предыдущий пакет еще не успел улететь по шине.