Visual Studio 开发STM32实现USB虚拟串口功能——方法3 Keil工程移植到Visual Studio

时间:2024-03-09 21:55:44
  • 方法2的方法是visual studio直接导进来keil工程,这样做的一个缺点就是:
  • 1、生成是vs工程目录太乱;
  • 2、keil在编译后.c文件下都会包括用到的.h文件,可以查看到.h文件的内容,但是vs编译后.c文件下并不会包括.h文件,这样在vs里是看不到导进来的.h文件。而且在.h路径方面,vs跟keil设置的路径是一样的,导致vs工程不能单独移动,得带着整个CubeMX工程一起移动,岂不是麻烦。如果想可以单独移动vs,得重新添加.h路径以及.c文件。

  • 从CubeMX生成的工程目录下拷贝出我们需要的文件,最好放在另一个路径下,不要跟CubeMX工程在同一路径下,我第一次是放在了同一路径下,当我单独移动VS project后,vs projcet里的那些.c/.h都打不开,提示找不到该文件,所以还是建议拷贝出来的文件放在不同路径下再接着下面的操作.

  • 1、用VS新建一个USB CDC通信Project模板,备用,参照方法一

  • 2、从CubeMX生成配置好的USB虚拟串口通信配置工程目录中拷贝出需要的文件夹。CubeMX配置参照方法二

  •  

  • 3、将vs模板中不用的文件移除,加入我们拷贝出来的文件 

  •  4、按下图方式添加文件:(vcp.h,vcp.c是自己创建的)

  • 5、下面设置.h的路径

  • 6、到此完成。编译下没有错误,下载,发现PC可以识别USBcom口。

  • 7、自带的收发函数能用但不好用,搞一下它。

  •    在usbd_cdc_if.c中添加代码:

static struct
{
	uint8_t Buffer[CDC_DATA_HS_OUT_PACKET_SIZE];
	int Position, Size;
	char ReadDone;
} s_RxBuffer;

char g_VCPInitialized;
  • 修改自带的CDC_Receive_FS()函数如下:

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

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

	s_RxBuffer.Position = 0;
	s_RxBuffer.Size = *Len;
	s_RxBuffer.ReadDone = 1;
	return (USBD_OK);
}
  • 添加新函数:VCP_read()和VCP_write()用于数据收发:

int VCP_read(void *pBuffer, int size)
{
	if (!s_RxBuffer.ReadDone)
		return 0;

	int remaining = s_RxBuffer.Size - s_RxBuffer.Position;
	int todo = MIN(remaining, size);
	if (todo <= 0)
		return 0;

	memcpy(pBuffer, s_RxBuffer.Buffer + s_RxBuffer.Position, todo);
	s_RxBuffer.Position += todo;
	if (s_RxBuffer.Position >= s_RxBuffer.Size)
	{
		s_RxBuffer.ReadDone = 0;
		USBD_CDC_ReceivePacket(&hUsbDeviceFS);
	}

	return todo;
}
int VCP_write(const void *pBuffer, int size)
{
	if (size > CDC_DATA_FS_OUT_PACKET_SIZE)
	{
		int offset;
		int done = 0;
		for (offset = 0; offset < size; offset += done)
		{
			int todo = MIN(CDC_DATA_FS_OUT_PACKET_SIZE, size - offset);
			done = VCP_write(((char *)pBuffer) + offset, todo);
			if (done != todo)
				return offset + done;
		}

		return size;
	}
/*
	USBD_CDC_HandleTypeDef *pCDC =
	        (USBD_CDC_HandleTypeDef *)hUsbDeviceFS.pClassData;
	while (pCDC->TxState) {} //Wait for previous transfer

	USBD_CDC_SetTxBuffer(&hUsbDeviceFS, (uint8_t *)pBuffer, size);
	if (USBD_CDC_TransmitPacket(&hUsbDeviceFS) != USBD_OK)
		return 0;

	while (pCDC->TxState) {} //Wait until transfer is done
	return size;
	*/
	uint8_t result = USBD_OK;
	USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
	if (hcdc->TxState != 0) {
		return USBD_BUSY;
	}
	USBD_CDC_SetTxBuffer(&hUsbDeviceFS, (uint8_t *)pBuffer, size);
	result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);

	return result;
}
  • 在usbd_cdc_if.h文件中声明新的函数:

int VCP_read(void *pBuffer, int size);
int VCP_write(const void *pBuffer, int size);
extern char g_VCPInitialized;
  • 做了一个vcp.c和vcp.h,创建一个print函数,用来向PC打印调试信息,vcp.c文件如下:

#include "vcp.h"
#include "usbd_cdc_if.h"

void print(const char *buffer)
{
	int length = strlen(buffer);
	//CDC_Transmit_FS((uint8_t*)buffer, length);
	VCP_write((uint8_t*)buffer, length);
}
  • main函数测试下print函数:

int main(void)
{

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  char byte[3];
  while (1)
  {

	  //VCP_read(byte,3);
	  //VCP_write(byte, sizeof(byte));
	  print("Yours VCP is  success!\n");
	  HAL_Delay(500);
  }

}

  • main函数中测试下收发函数,串口助手发给MCU后,MCU再发回给串口助手:

int main(void)
{

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  char byte[3];            //只定义了收发字节数最大是3字节
  while (1)
  {

	  VCP_read(byte,3);            
	  VCP_write(byte, sizeof(byte));
	  //print("Yours VCP is  success!\n");
	 HAL_Delay(1000);
  }

}