一 、实验目的:
通过MCU的USB模块加串口模块,实现一个串口助手的功能。具体操作为把USB接收到的数据通过串口发送,同时实现串口接收的数据回传到USB,从而实现从USB到TTL的电平转换。
二、实验环境:
1.mcu: 国芯ccm4202
2.开发环境:Keil
三、操作步骤:
1.USB设置为CDC类
USB CDC类的通信部分主要包含三部分:枚举过程、虚拟串口操作和数据通信。其中虚拟串口操作部分并不一定强制需要,因为若跳过这些虚拟串口的操作,实际上USB依然是可以通信的,这也就是为什么上图中,在操作虚拟串口之前会有两条数据通信的数据。之所以会有虚拟串口操作,主要是我们通常使用PC作为Host端,在PC端使用一个串口工具来与其进行通信,PC端的对应驱动将其虚拟成一个普通串口,这样一来,可以方便PC端软件通过操作串口的方式来与其进行通信,但实际上,Host端与Device端物理上是通过USB总线来进行通信的,与串口没有关系,这一虚拟化过程,起决定性作用的是对应驱动,包含如何将每一条具体的虚拟串口操作对应到实际上的USB操作。需要注意的是,Host端与Device端的USB通信速率并不受所谓的串口波特率影响,它就是标准的USB2.0全速(12Mbps)速度,实际速率取决于总线的实际使用率、驱动访问USB外设有效速率(两边)以及外部环境对通信本身造成的干扰率等因素组成。
2.接口映射
初始化MCU的UART,实现通过UART把USB的数据进行收发。
四、软件实现:
1.USB设置为CDC类
void USB_CDC_Init(void)
{
//USB1.1, 同时配置USB配置项为USB1.1模式
g_usbVer = 0;
//0:internal oscillator; 1:external oscillator
USBC_PHY_Init(0);
CCM->PHYPA |= 0x0e00; //no need to supply VBUS.
/* Global USB Register */
//gUSBC_fifoReg = (USBCFIFO_Reg*)(USBC_BASE_ADDR+0x1A);
gUSBC_fifoReg = (USBCFIFO_Reg*)(USBC_BASE_ADDR+0x60);
gUSBC_ComReg = (USBCCommonReg*)USBC_BASE_ADDR;
gUSBC_IdxReg = (USBCIndexedReg*)(USBC_BASE_ADDR+0x10);
//USB data buffer
g_databuf = USB_BUFFER_ADDR;
//The suspend mode is disable before BULK-Only tranfer start
g_suspendMode = 0;
/* Setup USB register */
//enable usb common interrupt
//0 1 2 3 4 5 6 7 (bit)
//Susp Resume Reset SOF Conn Discon SessReq VBusErr
gUSBC_ComReg->INTRUSBE = USB_INTERRUPT_RESET|USB_INTERRUPT_CONNECT|USB_INTERRUPT_DISCON|USB_INTERRUPT_SUSPEND|USB_INTERRUPT_RESUME;
//enable ep0 and ep1 tx interrupts,clear other tx interrupts
gUSBC_ComReg->INTRTXE_L = USB_INTERRUPT_EP0|(1<<INDEX_EP1)|(1<<INDEX_EP3);
gUSBC_ComReg->INTRRXE_L = (1<<INDEX_EP2);
//ensure ep0 control/status regesters appeare in the memory map.
gUSBC_ComReg->EINDEX = CONTROL_EP;
//Enable Soft connection
if(g_usbVer == 1)
gUSBC_ComReg->UCSR = USB_POWER_SOFT_CONN|USB_POWER_HS_ENAB;
else
gUSBC_ComReg->UCSR = USB_POWER_SOFT_CONN;
g_USBAddrFlag = 0;
g_USBNewAddr = 0;
NVIC_Init(3, 3, USBC_IRQn, 2);
}
2.初始化串口为中断方式
void Usb_UART_init(void)
{
UART_InitTypeDef UART_InitStruct;
UART_InitStruct.UART_BaudRate = LineCoding.bitrate;
UART_InitStruct.UART_Mode = UART_INT_MODE;
UART_InitStruct.UART_Parity = UART_PARITY_NONE;
if( LineCoding.format == 0)
{
UART_InitStruct.UART_FrameLength = UART_DATA_FRAME_LEN_10BIT;
UART_InitStruct.UART_StopBits = 1;
}
else
{
UART_InitStruct.UART_FrameLength = UART_DATA_FRAME_LEN_11BIT;
UART_InitStruct.UART_StopBits = 2;
}
UART_Init(Usb_Uart, &UART_InitStruct);
}
3.串口接收数据,通过USB发送到上位机。当数据间隔大于50毫秒默认为两包数据
ret = UART_RecvByte(Usb_Uart, &temp);
if(STATUS_OK == ret)
{
uart_data_buf_[i++] = temp;
len = i ;
}
else
{
if( Tool_Tc_cnt >= 50)
{
Tool_Tc_cnt = 0 ;
if(len!= 0 )
{
usb_cdc_send(INDEX_EP1, (UINT8*)uart_data_buf_, len);
i = 0 ;
len = 0 ;
}
}
}
4.USB接收数据,并将数据通过UART发出
void USBDev_DoCDCCmd_(void)
{
UINT16 recvLen = 0;
UINT16 len;
len = 64;
memset(cdc_ctl_buf_, 0x00, sizeof(cdc_ctl_buf_));
recvLen = usb_cdc_receive(INDEX_EP2, (UINT8 *)cdc_ctl_buf_);
if (recvLen == 0)
return;
len = recvLen;
UART_SendData(Usb_Uart, cdc_ctl_buf_,len);
}
void usb_cdc_poll_(void)
{
if( (g_uchUSBStatus & BIT1) == BIT1 ) //接收到一包数据
{
g_uchUSBStatus &= ~BIT1;
USBDev_DoCDCCmd_();
}
}
五、实验现象:
如图所示,通过MCU模拟出来的串口助手可以实现USB_TTL芯片相同效果,进行数据收发。
六、注意点
1.串口需要采用中断方式,轮训会造成数据接收转发不完全
2.usb虚拟串口部分,需要设置MCU的波特率,数据位,停止位等信息,否则会导致数据乱码。
|