這段時間學(xué)習(xí)STM32的USB通信,今天分享USB模擬串口,先上最小系統(tǒng)板和原理圖
我們先來了解一下USB模擬串口方面的知識,記得D+要上拉1.5K電阻
1.stm32的USB固件庫
移植時,重點要修改USB_CONFIG文件夾下的代碼,USB_CORE下的代碼一般不用修改。
1.USB_CORE下的文件介紹
2.USB_CONFIG下的文件介紹
3.中斷
再看USB如何初始化
USB的配置通過上面三個函數(shù)完成:
Set_USBClock(); //配置USB時鐘,即從72M主頻得到48M的USB時鐘(1.5分頻)
USB_Interrupts_Config(); //設(shè)置USB喚醒中斷和USB低優(yōu)先級數(shù)據(jù)處理中斷
USB_Init(); //初始化USB,主要是調(diào)用Virtual_Com_Port_init函數(shù),開啟USB部分的電源等
一、USB虛擬串口數(shù)據(jù)發(fā)送:
//發(fā)送一個字節(jié)數(shù)據(jù)到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;
}
}
該函數(shù)實現(xiàn)發(fā)送1字節(jié)數(shù)據(jù)到虛擬串口中。
這里用到了一個uu_txfifo結(jié)構(gòu)體,該結(jié)構(gòu)體是一個USB虛擬串口發(fā)送數(shù)據(jù)FIFO結(jié)構(gòu)體,定義如下:
//定義一個USB USART FIFO結(jié)構(gòu)體
typedef struct
{
u8 buffer[USB_USART_TXFIFO_SIZE]; //buffer
vu16 writeptr; //寫指針
vu16 readptr; //讀指針
}_usb_usart_fifo;
extern _usb_usart_fifo uu_txfifo; //USB串口發(fā)送FIFO
該結(jié)構(gòu)體用于處理USB串口要發(fā)送的數(shù)據(jù),所以通過USB串口發(fā)送的數(shù)據(jù),都將先存到結(jié)構(gòu)體的buffer數(shù)組(FIFO緩存區(qū))里面,USB_USART_TXFIFO_SIZE定義了該數(shù)組的大小,通過writeptr和readptr來控制FIFO的寫入和讀出。該結(jié)構(gòu)體buffer數(shù)據(jù)的寫入,是通過USB_USART_SendData()函數(shù)實現(xiàn)的。buffer數(shù)據(jù)的讀出(然后發(fā)送到USB)則是通過端點1的回調(diào)函數(shù)EP1_IN_Callback()函數(shù)實現(xiàn)的。
該函數(shù)在usb_endp.c中。代碼如下:
void EP1_IN_Callback (void)
{
u16 USB_Tx_ptr;
u16 USB_Tx_length;
if(uu_txfifo.readptr==uu_txfifo.writeptr) //無任何數(shù)據(jù)要發(fā)送,直接退出
{
return;
}
if(uu_txfifo.readptr<uu_txfifo.writeptr) //沒有超過數(shù)組,讀指針<寫指針
{
USB_Tx_length=uu_txfifo.writeptr-uu_txfifo.readptr;//得到要發(fā)送的數(shù)據(jù)長度
}else //超過數(shù)組了 讀指針>寫指針
{
USB_Tx_length=USB_USART_TXFIFO_SIZE-uu_txfifo.readptr;//得到要發(fā)送的數(shù)據(jù)長度
}
if(USB_Tx_length>VIRTUAL_COM_PORT_DATA_SIZE) //超過64字節(jié)?
{
USB_Tx_length=VIRTUAL_COM_PORT_DATA_SIZE; //此次發(fā)送數(shù)據(jù)量
}
USB_Tx_ptr=uu_txfifo.readptr; //發(fā)送起始地址
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);
}
這個函數(shù)由USB中斷處理相關(guān)函數(shù)調(diào)用,將通過USB發(fā)送給電腦的數(shù)據(jù)拷貝到端點1的發(fā)送區(qū),然后通過USB發(fā)送給電腦,從而實現(xiàn)串口數(shù)據(jù)的發(fā)送。
因為每次傳輸數(shù)據(jù)長度不超過VIRTUAL_COM_PORT_DATA_SIZE,所以USB的發(fā)送數(shù)據(jù)長度:USB_Tx_length的最大值,只能是VIRTUAL_COM_PORT_DATA_SIZE。
以上就是USB虛擬串口數(shù)據(jù)發(fā)送過程。
二、我們看看USB虛擬串口數(shù)據(jù)接收:
USB虛擬串口的接收,通過端點3來實現(xiàn),端點3的回調(diào)函數(shù)為EP3_OUT_Callback(),該函數(shù)也在usb_endp.c中,代碼如下:
void EP3_OUT_Callback(void)
{
u16 USB_Rx_Cnt;
USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, USB_Rx_Buffer); //得到USB接收到的數(shù)據(jù)及其長度
USB_To_USART_Send_Data(USB_Rx_Buffer, USB_Rx_Cnt); //處理數(shù)據(jù)(其實就是保存數(shù)據(jù))
SetEPRxValid(ENDP3); //時能端點3的數(shù)據(jù)接收
}
該函數(shù)也是由USB中斷處理相關(guān)函數(shù)調(diào)用,該函數(shù)通過調(diào)用USB_To_USART_Send_Data函數(shù),實現(xiàn)USB接收數(shù)據(jù)的保存,
該函數(shù)在hw_config.c中實現(xiàn),代碼如下:
//處理從USB虛擬串口接收到的數(shù)據(jù)
//databuffer:數(shù)據(jù)緩存區(qū)
//Nb_bytes:接收到的字節(jié)數(shù).
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;//接收數(shù)據(jù)錯誤,重新開始接收
}
}
}
}
}
最后下載驗證
發(fā)送和接受一致