利用STM32CUBE创建一个虚拟串口

更新时间:2024-01-21 01:57:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

利用STM32CUBE创建一个虚拟串口

由于现在的PC机大多都没有串口了,但PC机上的很多应用程序却使用串口,为了让PC机与STM32处理器进行通信,可以让STM32处理器,以串行方式与外界进行通信,再用CH340等芯片,实现USB转串口的功能,实现虚拟串口。不过这样做需要额外的芯片和相关电路,不很理想。

利用STM32处理器自身的USB功能,就可以实现虚拟串口。由于USB是一个很复杂的东西,所对应的代码很多,如果采用操作寄存器或标准库的方式,都要编写很多代码,也容易出错,而采用STM32CUBE就方便多了。

首先要利用STM32CUBE,选择芯片,比如芯片型号为STM32F103ZET6,如下图所示:

然后在Pinout选项页中,先选择“RCC”项,按下图设置:

再选择“USB”选项,按下图设置:

这一步的最后再选择“USB_DEBICE”,按下图设置:

下面要设置时钟,进入“Clock Configuration”选项页,按下图设置:

请注意:上图的设置必须保障给USB模块的时钟信号是精准的48MHz,不允许有偏差。

然后进行工程设置,点击菜单项“Porject→Settings...”,这时将弹出一个对话框窗口如下:

在该对话框窗口上,输入工程名、工程存放的文件夹、所用的开发工具之后,点击“OK”按键,关闭该对话框。

最后点击菜单项“Porject→Generate Code”,生成工程。本人用的开发工具是IAR,打开该工程,如下图所示:

这个工程已经包含了不少文件,建立了基本的程序框架和初始化代码,只要进一步添加应用程序代码就可以了。下面将围绕虚拟串口进一步编写程序: 在这个工程中,有一个“usbd_cdc_if.c”文件,进行USB虚拟串口进行数据的发送和接收时,首先要在usbd_cdc_if.c文件中修改“APP_RX_DATA_SIZE”、“APP_TX_DATA_SIZE”两个宏,它们用于数据的接收和发送缓冲区的大小;然后要声明一个结构体(并初始化),其代码如下: USBD_CDC_LineCodingTypeDef LineCoding = { 115200, /*baud rate*/ 0x00, /*stop bits - 1*/ 0x00, /*parity - none*/ 0x08, /*nb. of bits 8*/ };

这段代码用于指示串口的基本设置。

在该文件的“CDC_Control_FS”函数中,在“CDC_SET_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;

这样之后,就可以使用虚拟串口了!

当需要发送数据时,先将要发送的数据放入一个数组中(假设该数组名为a,要发送的n个字节),然后用如下代码就可以发送数据: CDC_Transmit_FS(a, n);

如果还需要读取上位机传来的数据,要修改usbd_cdc_if.c文件中的CDC_Receive_FS函数,该函数原本为:

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)

{

/* USER CODE BEGIN 6 */

USBD_CDC_SetRxBuffer(hUsbDevice_0, &Buf[0]); USBD_CDC_ReceivePacket(hUsbDevice_0); return (USBD_OK);

/* USER CODE END 6 */ }

该函数在收到数据时,将被系统调用,它的两个参数分别指向接收缓冲区和接收到的数据字节长度。显然我们可以编写一段代码,将接收到的数据送到应用程序指定的内存区,比如进行如下修改:

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) {

/* USER CODE BEGIN 6 */ uint8_t i;

USBD_CDC_SetRxBuffer(hUsbDevice_0, &Buf[0]); USBD_CDC_ReceivePacket(hUsbDevice_0); for(i = 0; i < *Len; i++)

app_rx_buf[i] = Buf[i];//将收到的数据转移到app_rx_buf数组中 rx_f = TRUE;//将收到数据标志位置位,用以通知应用程序 return (USBD_OK);

/* USER CODE END 6 */ }

这样就可以进行数据的上传和下传了。

{

/* USER CODE BEGIN 6 */

USBD_CDC_SetRxBuffer(hUsbDevice_0, &Buf[0]); USBD_CDC_ReceivePacket(hUsbDevice_0); return (USBD_OK);

/* USER CODE END 6 */ }

该函数在收到数据时,将被系统调用,它的两个参数分别指向接收缓冲区和接收到的数据字节长度。显然我们可以编写一段代码,将接收到的数据送到应用程序指定的内存区,比如进行如下修改:

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) {

/* USER CODE BEGIN 6 */ uint8_t i;

USBD_CDC_SetRxBuffer(hUsbDevice_0, &Buf[0]); USBD_CDC_ReceivePacket(hUsbDevice_0); for(i = 0; i < *Len; i++)

app_rx_buf[i] = Buf[i];//将收到的数据转移到app_rx_buf数组中 rx_f = TRUE;//将收到数据标志位置位,用以通知应用程序 return (USBD_OK);

/* USER CODE END 6 */ }

这样就可以进行数据的上传和下传了。

本文来源:https://www.bwwdw.com/article/o6ao.html

Top