在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结

    STM32F103 系列芯片都自带了 USB,不过 STM32F103 USB 都只能用来做设备,而不能用作主机。既便如此,对于一般应用来说已经足够了。 下面利用 STM32 自生的 USB 功能实现一个虚拟串口 。

USB简介:    

    USB ,是英文 Universal Serial BUS(通用串行总线)的缩写,而其中文简称为“通串线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。 标准 USB 共四根线组成,VCC/GND ,另外为 D+,D-; 这两根数据线采用的是差分电压的方式进行数据传输的。在 USB 主机上, D-D+都是接了 15K 的电阻到低的,所以在没有设备接入的时候, D+D-均是低电平。而在 USB 设备中,如果是高速设备,则会在 D+上接一1.5K 的电阻到 VCC,而如果是低速设备,则会在 D-上接一个 1.5K 的电阻到 VCC。这样当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。 

    ST 提供了我们一套完整的 USB 驱动库,通过这个库,我们可以很方便的实现我们所要的功能,而不需要详细了解 USB 的整个驱动,大大缩短了我们的开发时间和精力。 本实验的 USB 部分就是移植 ST Virtual_COM_Port 例程相关部分而来,完成一个 USB 虚拟串口的功能。

移植过程:

在官方网站上下载源文件。

在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第1张图片


    新建USB文件夹

在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第2张图片


   USB 文件夹下,新建 CONFIG 文件夹存放 Virtual COM 实现相关代码,即:STM32_USB-FS-Device_Lib_V4.0.0/Projects/Virtual_COM_Port/src 文件夹下的部分代码:hw_config.cusb_desc.cusb_endp.cusb_istr.cusb_prop.c usb_pwr.c 6 .c 文件,同时拷贝: STM32_USB-FS-Device_Lib_V4.0.0/Projects/Virtual_COM_Port/inc 文件夹下面的:hw_config.hplatform_config.husb_conf.husb_desc.husb_istr.husb_prop.h usb_pwr.h 7 个头文件到 CONFIG 文件夹下,最后 CONFIG 文件夹下的文件如图所示:在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第3张图片
在源代码基础上新建分组添加相关代码,具体细节,这里就不详细介绍了,添加好之后,如图 所示:
在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第4张图片

CONFIG 文件夹里面的几个.c 文件。
hw_config.c 文件,该文件用于硬件的配置,比如初始化 USB 时钟、 USB 中断、低功耗模式处理等。
usb_desc.c 文件,该文件用于 Virtual Com 描述符的处理。
usb_endp.c 文件,该文件用于非控制传输,处理正确传输中断回调函数。
usb_pwr.c 文件,该文件用于 USB 控制器的电源管理;
usb_istr.c
文件,该文件用于处理 USB 中断。
usb_prop.c 文件,该文件用于处理所有 Virtual Com 的相关事件,包括 Virtual Com 的初始化、复位等等操作。

   移植时,我们重点要修改的就是 CONFIG 文件夹下面的代码, USB_CORE 文件夹下的代码一般不用修改。另外官方例程用到 stm32_it.c 来处理 USB 相关中断,包括两个中断服务函数,第一个是:USB_LP_CAN1_RX0_IRQHandler 函数,我们在该函数里面调用 USB_Istr 函数,用于处理 USB发生的各种中断。另外一个就是 USBWakeUp_IRQHandler 函数,我们在该函数就做了一件事:清除中断标志。为了方便,我们直接将 USB 中断相关代码,全部放到 hw_config.c 里面,所以,本例程直接用不到 stm32_it.c

我们新建一个封装函数,用来完成USB的所有初始化

void USB_Run_Init(void)
{
	USB_Port_Set(0); 	//USB断开
	delayUs(7000);
	USB_Port_Set(1);	//USB连接
 	Set_USBClock();   
 	USB_Interrupts_Config();    
 	USB_Init();
}

    其中,USB 的配置通过三个函数完成:USB_Interrupts_Config()Set_USBClock()USB_Init(),第一个函数用于设置 USB 唤醒中断和USB 低优先级数据处理中断, Set_USBClock 函数用于 配置 USB 时钟,也就是72M 的主频得到 48M USB时钟1.5 分频)(移植过程中一定要注意,USB的时钟必须为48M,本人在移植过程中没注意,卡住了!因为公司源码用的是24Mhz主频,我在移植的过程中没注意,24*1.5=36不等于48Mhz,所以出问题了)

//USB,USBclk=48Mhz@HCLK=72Mhz
void Set_USBClock(void)
{
	RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);//USBclk=PLLclk/1.5=48Mhz	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);	 //USB	 
} 

    最后 USB_Init()函数用于初始化 USB,最主要的就是调用了 Virtual_Com_Port_init 函数,开启了 USB 部分的电源等。这里需要特别说明的是, USB 配置并没有对 PA11 PA12 这两个 IO 口进行设置,是因为,一旦开启了 USB 电源(USB_CNTRPDWN 位清零)PA11 PA12 将不再作为其他功能使用,仅供 USB 使用,所以在开启了 USB电源之后不论你怎么配置这两个 IO 口,都是无效的。 

如果提前安装运行STM32 USB 虚拟串口驱动/ VCP_V1.4.0_Setup.exe

代码在调用

void USB_Run_Init(void)

可以在我的电脑设备管理器中看到

在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第5张图片


到这里,USB的移植算是成功了。

软件部分:

    USB 虚拟串口的数据发送,我们通过函数: USB_USART_SendData 来实现,该函数在hw_config.c 里面实现,该函数代码如下:

//发送一个字节到USB虚拟串口
void USB_USART_SendData(u8 data)
{
	uu_txfifo.buffer[uu_txfifo.writeptr]=data;
	uu_txfifo.writeptr++;
	if(uu_txfifo.writeptr==USB_USART_TXFIFO_SIZE)
	{
		uu_txfifo.writeptr=0;
	} 
}

该函数实现发送 1 个字节到虚拟串口,这里,我们用到了一个 uu_txfifo 的结构体,该结构体是我们在 hw_config 里面定义的一个 USB 虚拟串口发送数据 FIFO 结构体,定义如下:

#define USB_USART_TXFIFO_SIZE   1024	//USB虚拟串口发送FIFO		
typedef struct  
{										    
	u8  buffer[USB_USART_TXFIFO_SIZE];	//buffer
	vu16 writeptr;						//写指针
	vu16 readptr;						//读指针
}_usb_usart_fifo; 
extern _usb_usart_fifo uu_txfifo;		//USB串口发送FIFO

    该结构体用于处理 USB 串口要发送的数据,所有要通过 USB 串口发送的数据,都将先存放在该结构体的 buffer 数组(FIFO 缓存区)里面, USB_USART_TXFIFO_SIZE 定义了该数组的大小,通过 writeptr readptr 来控制 FIFO 的写入和读出,该结构体 buffer 数据的写入,是通过 USB_USART_SendData 函数实现,而 buffer 数据的读出(然后发送到 USB)则是通过端点 1 回调函数: EP1_IN_Callback 函数实现,该函数在 usb_endp.c 里面实现,代码如下:

在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第6张图片

    这个函数由 USB 中断处理相关函数调用,将要通过 USB 发送给电脑的数据拷贝到端点 1的发送区,然后通过 USB 发送给电脑,从而实现串口数据的发送。因为 USB 每次传输数据长度不超过 VIRTUAL_COM_PORT_DATA_SIZE,所以 USB 发送数据长度: USB_Tx_length 的最大值只能是 VIRTUAL_COM_PORT_DATA_SIZE

    以上,就是 USB 虚拟串口的数据发送过程,而 USB 虚拟串口数据的接收,则是通过端点3 来实现的,端点 3 的回调函数为 EP3_OUT_Callback,该函数也是在 usb_endp.c 里面定义,代码如下:

在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第7张图片

    该函数也是被 USB 中断处理调用,该函数通过调用 USB_To_USART_Send_Data 函数,实现 USB 接收数据的保存, USB_To_USART_Send_Data 函数在 hw_config.c 里面实现,代码如下:

在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结_第8张图片

    USB_To_USART_Send_Data 函数类似于串口通信实验的串口中断服务函数(USART1_IRQHandler),完成 USB 虚拟串口的数据接收。








你可能感兴趣的:(在STM32F103CB上通过自带USB虚拟串口实现STM32单片机与PC之间的通信(参考原子mini板子资料)自我学习总结)