這段時間學習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;//接收數據錯誤,重新開始接收
}
}
}
}
}
最后下載驗證
發送和接受一致