这段时间学习STM32的USB通信,今天分享USB模拟串口,先上最小系统板和原理图
我们先来了解一下USB模拟串口方面的知识,记得D+要上拉1.5K电阻
1.stm32的USB固件库
移植时,重点要修改USB_CONFIG文件夹下的代码,USB_CORE下的代码一般不用修改。
1.USB_CORE下的文件介绍
2.USB_CONFIG下的文件介绍
3.中断
再看USB如何初始化
USB的配置通过上面三个函数完成:
Set_USBClock(); //配置USB时钟,即从72M主频得到48M的USB时钟(1.5分频)
USB_Interrupts_Config(); //设置USB唤醒中断和USB低优先级数据处理中断
USB_Init(); //初始化USB,主要是调用Virtual_Com_Port_init函数,开启USB部分的电源等
一、USB虚拟串口数据发送:
//发送一个字节数据到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)//超过buf大小了,归零.
{
uu_txfifo.writeptr=0;
}
}
该函数实现发送1字节数据到虚拟串口中。
这里用到了一个uu_txfifo结构体,该结构体是一个USB虚拟串口发送数据FIFO结构体,定义如下:
//定义一个USB USART 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中。代码如下:
void EP1_IN_Callback (void)
{
u16 USB_Tx_ptr;
u16 USB_Tx_length;
if(uu_txfifo.readptr==uu_txfifo.writeptr) //无任何数据要发送,直接退出
{
return;
}
if(uu_txfifo.readptr<uu_txfifo.writeptr) //没有超过数组,读指针<写指针
{
USB_Tx_length=uu_txfifo.writeptr-uu_txfifo.readptr;//得到要发送的数据长度
}else //超过数组了 读指针>写指针
{
USB_Tx_length=USB_USART_TXFIFO_SIZE-uu_txfifo.readptr;//得到要发送的数据长度
}
if(USB_Tx_length>VIRTUAL_COM_PORT_DATA_SIZE) //超过64字节?
{
USB_Tx_length=VIRTUAL_COM_PORT_DATA_SIZE; //此次发送数据量
}
USB_Tx_ptr=uu_txfifo.readptr; //发送起始地址
uu_txfifo.readptr+=USB_Tx_length; //读指针偏移
if(uu_txfifo.readptr>=USB_USART_TXFIFO_SIZE) //读指针归零
{
uu_txfifo.readptr=0;
}
UserToPMABufferCopy(&uu_txfifo.buffer[USB_Tx_ptr], ENDP1_TXADDR, USB_Tx_length);
SetEPTxCount(ENDP1, USB_Tx_length);
SetEPTxValid(ENDP1);
}
这个函数由USB中断处理相关函数调用,将通过USB发送给电脑的数据拷贝到端点1的发送区,然后通过USB发送给电脑,从而实现串口数据的发送。
因为每次传输数据长度不超过VIRTUAL_COM_PORT_DATA_SIZE,所以USB的发送数据长度:USB_Tx_length的最大值,只能是VIRTUAL_COM_PORT_DATA_SIZE。
以上就是USB虚拟串口数据发送过程。
二、我们看看USB虚拟串口数据接收:
USB虚拟串口的接收,通过端点3来实现,端点3的回调函数为EP3_OUT_Callback(),该函数也在usb_endp.c中,代码如下:
void EP3_OUT_Callback(void)
{
u16 USB_Rx_Cnt;
USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, USB_Rx_Buffer); //得到USB接收到的数据及其长度
USB_To_USART_Send_Data(USB_Rx_Buffer, USB_Rx_Cnt); //处理数据(其实就是保存数据)
SetEPRxValid(ENDP3); //时能端点3的数据接收
}
该函数也是由USB中断处理相关函数调用,该函数通过调用USB_To_USART_Send_Data函数,实现USB接收数据的保存,
该函数在hw_config.c中实现,代码如下:
//处理从USB虚拟串口接收到的数据
//databuffer:数据缓存区
//Nb_bytes:接收到的字节数.
void USB_To_USART_Send_Data(u8* data_buffer, u8 Nb_bytes)
{
u8 i;
u8 res;
for(i=0;i<Nb_bytes;i++)
{
res=data_buffer[i];
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;//接收数据错误,重新开始接收
}
}
}
}
}
最后下载验证
发送和接受一致