本文所述内容基于STM32 HAL库完成
安装stm32CubeMx(ver4.26.0)
新建工程,选择stm32f412zg tx
配置RCC->HSE->crystal/Ceramic Resonnator
配置USB_OTG_FS->device only(disable Activate_VBUS)
配置MiddleWares->USB_DEVICE->communication device class(virtual Port com)
配置clock,input frequency设置为8Mhz
其他参数全部默认,生成代码
其中USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);是关键,主要的功能是把CDC类的功能和我们用户要调用的_fops_FS函数都注册到USB的设备类里,这样在USB内核运行的时候就会调动我们注册进去的函数,点击USBD_Interface_fops_FS进去,这里面的函数指针 指向的函数就是我们需要使用和修改的了
找到CDC_Control_FS所在的文件usbd_cdc_if.c,添加如下代码
USBD_CDC_LineCodingTypeDef linecoding =
{
115200, /* baud rate*/
0x00, /* stop bits-1*/
0x00, /* parity - none*/
0x08 /* nb. of bits 8*/
};
在函数CDC_Control_FS中增加如下代码
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
linecoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\
(pbuf[2] << 16) | (pbuf[3] << 24));
linecoding.format = pbuf[4];
linecoding.paritytype = pbuf[5];
linecoding.datatype = pbuf[6];
break;
case CDC_GET_LINE_CODING:
pbuf[0] = (uint8_t)(linecoding.bitrate);
pbuf[1] = (uint8_t)(linecoding.bitrate >> 8);
pbuf[2] = (uint8_t)(linecoding.bitrate >> 16);
pbuf[3] = (uint8_t)(linecoding.bitrate >> 24);
pbuf[4] = linecoding.format;
pbuf[5] = linecoding.paritytype;
pbuf[6] = linecoding.datatype;
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
调用CDC_Transmit_FS,即可以实现USB虚拟串口的功能,示例代码如下
int main(void)
{
/* USER CODE BEGIN 1 */
char buf_2[]=" who am i\r\n";
uint8_t cnt=0;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
//if(cnt<10)
{
buf_2[0] = cnt;
CDC_Transmit_FS(buf_2,strlen(buf_2));
HAL_Delay(100);
cnt++;
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
为了方便使用,可以重载printf函数如下,
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART3 and Loop until the end of transmission */
//CDC_Transmit_FS((uint8_t *)&ch, 1);
while(CDC_Transmit_FS((uint8_t*)(&ch),1)!=USBD_OK){}
return ch;
}
然后就可以在函数里方便的调用printf函数了