完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:alientek NANO STM32F411 V1开发板
2)摘自《正点原子STM32F4 开发指南(HAL 库版》关注官方微信号公众号,获取更多资料:正点原子 第三十五章 USB 虚拟串口(Slave)实验 上一章我们向大家介绍了如何利用 NANO STM32F4 的 USB 接口来做一个 USB 读卡器,本章我们将利用 STM32F411 的 USB 来做一个虚拟串口(VCP)。本章分为如下几个部分: 35.1 USB 虚拟串口简介 35.2 硬件设计 35.3 软件设计 35.4 下载验证 35.1 USB 虚拟串口简介 USB 虚拟串口,简称 VCP,是 Virtual COM Port 的简写,它是利用 USB 的 CDC 类来实现的一种通信接口。 我们可以利用 STM32 自带的 USB 功能,来实现一个 USB 虚拟串口,从而通过 USB,实现电脑与 STM32 的数据互传。上位机无需编写专门的 USB 程序,只需要一个串口调试助手即可调试,非常实用。 同上一章一样,我们直接移植官方的 USB VCP 例程,官方例程路径:7,STM32 参考资料 STM32 USB 学习资料STM32_USB-Host-Device_Lib_V2.1.0ProjectUSB_Device_ExamplesVCP,该例程采用 USB CDC 类来实现,利用 STM32 的 USB 接口,实现一个 USB转串口的功能。 35.2 硬件设计 本章实验功能简介:本实验利用 STM32 自带的 USB 功能,连接电脑 USB,虚拟出一个 USB串口,实现电脑和开发板的数据通信。本例程功能完全同实验 4(串口实验),只不过串口变成了 STM32 的 USB 虚拟串口。当 USB 连接电脑(USB 线插入 USB_SLAVE 接口),开发板将通过 USB 和电脑建立连接虚拟出一个串口(注意:需要先安装:光盘5,软件资料1,软件STM32 USB 虚拟串口驱动VCP_V1.4.0_Setup.exe 这个驱动软件),USB 和电脑连接成功后,DS1 常亮。 在找到虚拟串口后,即可打开串口调试助手,实现同实验 4 一样的功能,即:STM32 通过 USB 虚拟串口和上位机对话,STM32 在收到上位机发过来的字符串(以回车换行结束)后,原原本本的返回给上位机。下载后,DS0 闪烁,提示程序在运行,同时每隔一定时间,通过USB 虚拟串口输出一段信息到电脑。所要用到的硬件资源如下: 1)指示灯 DS0 、DS1 2)串口 3)USB SLAVE 接口 前面 3 部分,在之前的实例中都介绍过了,我们在此就不介绍了。接下来看看我们电脑 USB 与 STM32 的 USB SLAVE 连接口。ALIENTEK NANO STM32F4 采用的是 5PIN 的 MicroUSB 接头,用来和电脑的 USB 相连接,连接电路如图 35.2.1 所示: 图 35.2.1 MicroUSB 接口与 STM32 的连接电路图 35.3 软件设计 本章,我们在:实验 4 串口通信实验的基础上修改,先打开实验 4 的工程,在 HARDWARE 文件夹所在文件件下新建一个 USB 的文件夹,同上一章一样,对照官方 VCP 例子,将相关文 件拷贝到 USB 文件夹下。 然后,我们在工程里面去掉一些不必要的代码,并添加 USB 相关代码,最终得到如图 35.3.1 所示的工程: 图 35.3.1 USB 虚拟串口工程截图 可以看到,USB 部分代码,同上一章的在结构上是一模一样的,只是.c 文件稍微有些变化。 同样,我们移植需要修改的代码,就是 USB_APP 里面的这四个.c 文件了。 其中 u***_bsp.c 和 u***d_usr.c 的代码,和上一章基本一样,可以用上一章的代码直接替换即 可正常使用。 u***_desc.c 代码,同上一章不一样,上一章描述符是大容量存储设备,本章变成了 USB 虚 拟串口,所以直接用 ST 官方的就行。 最后 u***d_cdc_vcp.c,这里面的代码,是重点要修改的,修改后代码如下: //USB 虚拟串口相关配置参数 LINE_CODING linecoding = { 115200, //波特率 0x00, //停止位,默认 1 位 0x00, //校验位,默认无 0x08 //数据位,默认 8 位 }; u8 USART_PRINTF_Buffer[USB_USART_REC_LEN]; //u***_printf 发送缓冲区 //用类似串口 1 接收数据的方法,来处理 USB 虚拟串口接收到的数据. u8 USB_USART_RX_BUF[USB_USART_REC_LEN]; //接收缓冲,最大 USART_REC_LEN 个字节. //接收状态 //bit15, 接收完成标志 //bit14, 接收到 0x0d //bit13~0, 接收到的有效字节数目 u16 USB_USART_RX_STA=0; //接收状态标记 extern uint8_t APP_Rx_Buffer []; //虚拟串口发送缓冲区(发给电脑) extern uint32_t APP_Rx_ptr_in; //虚拟串口接收缓冲区(接收来自电脑的数据) //虚拟串口配置函数(供 USB 内核调用) CDC_IF_Prop_TypeDef VCP_fops = { VCP_Init, VCP_DeInit, VCP_Ctrl, VCP_DataTx, VCP_DataRx }; //初始化 VCP //返回值:USBD_OK uint16_t VCP_Init(void) { return USBD_OK; } //复位 VCP //返回值:USBD_OK uint16_t VCP_DeInit(void) { return USBD_OK; } //控制 VCP 的设置 //buf:命令数据缓冲区/参数保存缓冲区 //len:数据长度 //返回值:USBD_OK uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len) { switch (Cmd) { case SEND_ENCAPSULATED_COMMAND:break; case GET_ENCAPSULATED_RESPONSE:break; case SET_COMM_FEATURE:break; case GET_COMM_FEATURE:break; case CLEAR_COMM_FEATURE:break; case SET_LINE_CODING: linecoding.bitrate = (uint32_t)(Buf[0] | (Buf[1] << 8) | (Buf[2] << 16) | (Buf[3] << 24)); linecoding.format = Buf[4]; linecoding.paritytype = Buf[5]; linecoding.datatype = Buf[6]; //打印配置参数 printf("linecoding.format:%drn",linecoding.format); printf("linecoding.paritytype:%drn",linecoding.paritytype); printf("linecoding.datatype:%drn",linecoding.datatype); printf("linecoding.bitrate:%drn",linecoding.bitrate); break; case GET_LINE_CODING: Buf[0] = (uint8_t)(linecoding.bitrate); Buf[1] = (uint8_t)(linecoding.bitrate >> 8); Buf[2] = (uint8_t)(linecoding.bitrate >> 16); Buf[3] = (uint8_t)(linecoding.bitrate >> 24); Buf[4] = linecoding.format; Buf[5] = linecoding.paritytype; Buf[6] = linecoding.datatype; break; case SET_CONTROL_LINE_STATE:break; case SEND_BREAK:break; default:break; } return USBD_OK; } //发送一个字节给虚拟串口(发给电脑) //data:要发送的数据 //返回值:USBD_OK uint16_t VCP_DataTx (uint8_t data) { APP_Rx_Buffer[APP_Rx_ptr_in]=data; //写入发送 buf APP_Rx_ptr_in++; //写位置加 1 if(APP_Rx_ptr_in==APP_RX_DATA_SIZE) //超过 buf 大小了,归零. { APP_Rx_ptr_in = 0; } return USBD_OK; } //处理从 USB 虚拟串口接收到的数据 //databuffer:数据缓存区 //Nb_bytes:接收到的字节数. //返回值:USBD_OK uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len) { u8 i; u8 res; for(i=0;i res=Buf; if((USB_USART_RX_STA&0x8000)==0) //接收未完成 { if(USB_USART_RX_STA&0x4000) //接收到了 0x0d { if(res!=0x0a)USB_USART_RX_STA=0;//接收错误,重新开始 else USB_USART_RX_STA|=0x8000; //接收完成了 }else //还没收到 0X0D { if(res==0x0d)USB_USART_RX_STA|=0x4000; else { USB_USART_RX_BUF[USB_USART_RX_STA&0X3FFF]=res; USB_USART_RX_STA++; if(USB_USART_RX_STA>(USB_USART_REC_LEN-1)) USB_USART_RX_STA=0;//接收数据错误,重新开始接收 } } } } return USBD_OK; } //u*** 虚拟串口,printf 函数 //确保一次发送数据不超 USB_USART_REC_LEN 字节 void u***_printf(char* fmt,...) { u16 i,j; va_list ap; va_start(ap,fmt); vsprintf((char*)USART_PRINTF_Buffer,fmt,ap); va_end(ap); i=strlen((const char*)USART_PRINTF_Buffer);//此次发送数据的长度 for(j=0;j { VCP_DataTx(USART_PRINTF_Buffer[j]); } } 此部分总共 6 个函数,其中前 5 个函数,用于初始化 VCP_fops 结构体,给 USB 内核调用, 以实现相关功能。接下来我们分别介绍这几个函数。 VCP_Init 用于初始化 VCP,在初始化的时候由 USB 内核调用,这里我们无需任何操作, 所以直接范围 USBD_OK 即可。 VCP_DeInit 用于复位 VCP,我们用不到,所以直接返回 USBD_OK 即可。 VCP_Ctrl 用于控制 VCP 的相关参数,根据 cmd 的不同,执行不同的操作,这里主要用到 SET_LINE_CODING 命令,该命令用于设置 VCP 的相关参数,比如波特率、数据类型(位数)、 校验类型(奇偶校验)等,保存在 linecoding 结构体里面,在需要的时候,应用程序可以读取 linecoding 结构体里面的参数,以获得当前 VCP 的相关信息。 VCP_DataTx 用于发送一个字节的数据给 VCP,应用程序每调用一次该函数,就可以发送 一个字节给 VCP,由 VCP 通过 USB 传输给电脑,实现 VCP 的数据发送。 VCP_DataRx 用于 VCP 的数据接收,当 STM32 的 USB 接收到电脑端串口发送过来的数据 时,由 USB 内核程序调用该函数,实现 VCP 的数据接收。我们只需要在该函数里面,将接收 到的数据,保存起来即可,接收的原理同第八章(实验 3 串口通信实验)完全一样。 u***_printf 用于实现和普通串口一样的 printf 操作,该函数将数据格式化输出到 USB VCP, 功能完全同 printf,方便大家使用。 USB VCP 相关代码,就给大家介绍到这里,详细的介绍,请大家参考:CD00289278.pdf 这个文档。 最后在 test.c 里面,我们修改 main 函数如下: USB_OTG_CORE_HANDLE USB_OTG_dev; extern vu8 bDeviceState; //USB 连接 情况 int main(void) { u8 t; u8 len; u16 times=0; u8 u***status=0; HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(96,4,2,4); //设置时钟,96Mhz delay_init(96); //初始化延时函数 LED_Init(); //初始化 LED uart_init(115200); //初始化 USART printf("NANO STM32rn"); printf("USB Virtual USART TESTrn"); USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID, &USR_desc,&USBD_CDC_cb,&USR_cb); while(1) { if(u***status!=bDeviceState)//USB 连接状态发生了改变. { u***status=bDeviceState;//记录新的状态 if(u***status==1) { printf("USB Connectedrn");//提示 USB 连接成功 LED1=0;//DS1 亮 }else { printf("USB disConnectedrn");//提示 USB 断开 LED1=1;//DS1 灭 } } if(USB_USART_RX_STA&0x8000) { len=USB_USART_RX_STA&0x3FFF;//得到此次接收到的数据长度 u***_printf("rn 您发送的消息为:%drnrn",len); for(t=0;t VCP_DataTx(USB_USART_RX_BUF[t]);//以字节方式,发送给 USB } u***_printf("rnrn");//插入换行 USB_USART_RX_STA=0; }else { times++; if(times%5000==0) { u***_printf("rnNANO STM32 开发板 USB 虚拟串口实验rn"); u***_printf("正点原子@ALIENTEKrnrn"); } if(times%200==0)u***_printf("请输入数据,以回车键结束rn"); if(times%30==0)LED0=!LED0;//闪烁 LED,提示系统正在运行. delay_ms(10); } } } 此部分代码比较简单,同上一章一样定义了 USB_OTG_dev 结构体,然后通过 USBD_Init 初始化 USB,不过本章实现的是 USB 虚拟串口的功能。然后在死循环里面轮询 USB 状态并检 查是否接收到数据,如果接收到了数据,则通过 VCP_DataTx 将数据通过 VCP 原原本本的返回 给电脑端串口调试助手。 35.4 下载验证 本例程的测试,需要在电脑上先安装 ST 提供的 USB 虚拟串口驱动软件,该软件路径:光 盘5,软件资料1,软件STM32 USB 虚拟串口驱动 VCP_V1.4.0_Setup.exe,双击安装即 可。 然后,在代码编译成功之后,我们下载代码到 NANO STM32F4 V1 上,然后将 USB 数据 线,插入 USB_SLAVE 口,连接电脑和开发板(注意:不是插 USB_JTAG 端口!),此时电 脑会提示找到新硬件,并自动安装驱动。不过,如果自动安装不成功(有惊叹号),如图 35.4.1所示: 图 35.4.1 自动安装失败 此时,我们可手动选择驱动(以 WIN7 为例),进行安装,在如图 35.4.1 所示的条目上面, 右键更新驱动程序软件浏览计算机以查找驱动程序软件浏览,选择 STM32 虚拟串口的驱 动的路径为:C:Program Files (x86)STMicroelectronicsSoftwareVirtual comport driverWIN7,然 后点击下一步,即可完成安装。安装完成后,可以看到设备管理器里面多出了一个 STM32 的 虚拟串口,如图 35.4.2 所示: 图 35.4.2 发现 STM32 USB 虚拟串口 如图 35.4.2,STM32 通过 USB 虚拟的串口,被电脑识别了,端口号为:COM60(可变), 字符串名字为:STMicroelectronics Virtual COM Port(固定)。此时,开发板的 DS1 常亮,以 表示 USB 已连接,同时开发板串口 1 会打印 USB 连接的状态信息,如图 35.4.3 所示: 图 35.4.3 USB 虚拟串口连接成功 我们另外打开多一个 XCOM,选择 USB 的虚拟串口,这里选择 COM60(需根据自己的电 脑识别到的串口号选择),并打开串口(注意:波特率可以随意设置),就可以进行测试了, 如图 35.4.4 所示: 图 35.4.4 STM32 虚拟串口通信测试 可以看到,我们的串口调试助手,收到了来自 STM32 开发板的数据,同时,按发送按钮 (串口助手必须勾选:发送新行),也可以收到电脑发送给 STM32 的数据(原样返回),说 明我们的实验是成功的。实验现象同第九章完全一样。 至此,USB 虚拟串口实验就完成了,通过本实验,我们就可以利用 STM32 的 USB,直接 和电脑进行数据互传了,具有广泛的应用前景。 |
|
相关推荐
|
|
STM32配合可编程加密芯片SMEC88ST的防抄板加密方案设计
1138 浏览 0 评论
2483 浏览 1 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
2273 浏览 3 评论
4916 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
2419 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-3 02:39 , Processed in 0.337094 second(s), Total 31, Slave 25 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号