完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
应用场景:
本次在项目中,由于对方的上位机软件比较老旧。 该软件只能通过串口通讯。而我们的设备只引出了USB口。还好STM32 的USB类型可以设置成虚拟串口。所以可以通过把USB枚举成虚拟串口(virtual com port设备)来与该上位机软件通讯。 本来是想直接移植STM32 的USB_FS库。奈何移植失败。(给跪了orz orz orz…) 又想起CubeMX也可以配置的。就用CubeMX配置工程,效果出奇的好。PC能够正常的枚举和通讯。所以趁热和大家分享分享,自己也做个记录。 以下内容就是如何一步一步通过CubeMX,把STM32的USB配置成虚拟串口的过程。 文章最后放上了本次CubeMX的工程和对应的虚拟串口代码。 配置过程: 1、点开CubeMX,新建工程,选择MCU。我用的是STM32F103VCT6。你们根据自己实际的MCU选择对应的型号以及封装格式。 2、选择系统时钟源。这边必须要配置,没配置系统时钟,不能生成正确的代码。 这里我使用的是外部晶振。(根据实际配置) 3、配置USB的上拉PIN脚。我这边的上拉PIN是PA13(根据实际情况配置)。注意硬件上DP要接个1.5K的上拉。用以表示高速设备以及枚举控制。 4、选上USB FS功能 5、继续“去中间层”,设置USB的识别类型。我们是虚拟口,所以选VCP设备。 6、配置系统时钟树参数。我的外部晶振是12M,所以要得到72M时钟,要选择倍频系数为6倍频。(晶振是8M则选择9倍频) 注意USB时钟要为48M。所以选1.5分频。 7、配置结束,去设置工程保存的位置。注意工具和版本。 8、生成工程。 9、打开工程,已经直接生成好了USB虚拟串口的代码。并可以直接编译不报错。 int main(void) { /* USER CODE BEGIN 1 */ /* 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 */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 10、这个时候载入生成的文件到MCU里,是不枚举的。因为自动生成的代码里,只完成初始化等一些基本功能。 PA13上拉以及收、发函数还需要我们自己完善才可以。 11、加入PA13上拉。编译载入,可以看到枚举出了com12虚拟口。 /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USB_DEVICE_Init(); /* USER CODE BEGIN 2 */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_SET); 12、调用发送函数。发送使用的是CDC_Transmit_FS函数。 所以我们在系统运行时,直接扔出个信息查看。编译并运行。发现确实有扔出信息(USB SYSTEM ON)。 13、调用接收函数CDC_Receive_FS。在CDC_Receive_FS里,把收到的数据进行计数以及保存。 static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 6 */ if(*Len<0x100) { uint16_t i; receive_len = *Len; for(i=0;i<*Len;i++) receivebuf = Buf; } USBD_CDC_SetRxBuffer(&hU***DeviceFS, &Buf[0]); USBD_CDC_ReceivePacket(&hU***DeviceFS); return (USBD_OK); /* USER CODE END 6 */ } 14、做好了接收,我们在main里判断,接收的数据非空,则直接输出收到的数据。到此工程结束。 int main(void) { /* USER CODE BEGIN 1 */ uint32_t i; /* 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 */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_SET); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ for(i = 0;i < 5;i++) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); delay_1000ms(); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); delay_1000ms(); } CDC_Transmit_FS("USB SYSTEM ONrn",15); while (1) { if(receive_len!=0) { CDC_Transmit_FS(receivebuf,receive_len); receive_len = 0; memset(receivebuf,0,sizeof(receivebuf)); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 运行测试: PC往STM32 USB虚拟口输入什么,则STM32通过USB返回刚刚收到的内容。试验成功。 小结: CubeMX确实是个挺好的工具。给大家提供了更多更简单的使用选项。 |
|
|
|
只有小组成员才能发言,加入小组>>
3310 浏览 9 评论
2991 浏览 16 评论
3492 浏览 1 评论
9057 浏览 16 评论
4086 浏览 18 评论
1175浏览 3评论
603浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
596浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2333浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1894浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 10:58 , Processed in 1.047403 second(s), Total 46, Slave 37 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号