本教程來至 FlexLua 官網(wǎng) ShineBlink 開發(fā)板教程,即使不懂單片機開發(fā)也可很容易用FlexLua零門檻開發(fā)各種 IoT 硬件。
本篇章所實現(xiàn)的功能是將Core(ShineBlink Mini 開發(fā)板)的USB口通過 Lua 代碼配置成虛擬串口,這樣和電腦通過USB線連接好后,電腦就會發(fā)現(xiàn)一個新的串口設(shè)備,我們通過在電腦上運行的串口調(diào)試終端(sscom,putty,minicom,etc..)打開這個串口后,每隔300毫秒向Core發(fā)送一包10個字節(jié)的數(shù)據(jù),Core收到這10個字節(jié)后將這個10個字節(jié)的數(shù)據(jù)每個都加1后再返回給電腦。
注意: 在 C1 開發(fā)板中,如果您的項目中同時用到Ble藍牙功能時,一定要先初始化Ble藍牙之后,再調(diào)用LIB_UsbConfig函數(shù)初始化USB功能。
--配置Core的USB接口以USB轉(zhuǎn)串口模式工作,注意:配置成CDC_PD后print函數(shù)并不會打印輸出到電腦上
LIB_UsbConfig("CDC_PD")
--開始大循環(huán)
while(GC(1)==true)
do
--如果Core和電腦通過USB線連好了,且電腦端打開了該串口
if LIB_UsbCommPortOpenQuery()==1 then
--查詢是否收到電腦發(fā)來的串口數(shù)據(jù)
recv_flag,recv_tab=LIB_UsbCdcRecv()
if recv_flag==1 then
--將收到的數(shù)據(jù)每個都加1,再返送給電腦
for i=1, #recv_tab do
recv_tab[i]=recv_tab[i] + 1
end
LIB_UsbCdcSend(recv_tab)
end
end
end
如果感興趣,上面代碼中出現(xiàn)的LIB開頭的庫函數(shù)可以在 API文檔 中通過Ctrl+F查詢。
如果您的電腦是win10系統(tǒng),當和Core通過USB線連接好了會自動裝好驅(qū)動,如果是Win7系統(tǒng)請用baidu或google搜索 “nRF52 USB CDC ACM驅(qū)動” 關(guān)鍵詞來完成驅(qū)動安裝的工作。
接下來在串口調(diào)試終端軟件上按照 N, 8, 1, 115200 設(shè)置,并找到正確的com口打開,這里我設(shè)置每300毫秒發(fā)送
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09十個數(shù)據(jù)。
下圖是實際運行效果:
通常我們使用STM32進行串口通信會選擇其硬件串口,但在某些情況下串口會不夠用,這個時候就可以選擇USB的虛擬串口,這樣可以增加一個串口。
USB是非常復雜的一個設(shè)備,要想完全搞懂它需要花費不少時間和精力。但去使用它卻相對簡單。這里我們使用STM32CubeMX構(gòu)建一個初始工程,然后實現(xiàn)將我們從電腦發(fā)下來的東西原封不動地發(fā)回電腦,使用的芯片是STM32F103zet6。
USB需要配置兩個地方,一個是Connectivity下勾選USB,在Mode下勾選Device,下面的參數(shù)保持默認即可。其他芯片類型的選項可能不同,選擇有Device字樣的就OK。
第二在Middleware下選擇USB_DEVICE,在右邊的下拉菜單選擇Communication Device Class(Virtual Port Com),下面的參數(shù)設(shè)置可以保持默認,除非你了解各個參數(shù)是干什么的,否則不建議修改。這些參數(shù)涉及到了USB的設(shè)備描述符、字符串描述符、緩存等等。
其他配置包括時鐘、工程路徑、工具鏈、驅(qū)動設(shè)置等等就不羅嗦了,配置好后點擊生成代碼,我使用gcc編譯。
USB虛擬串口涉及的文件有下面三類:
實際使用的時候只需要關(guān)心應(yīng)用層即可。
在編譯下載之前,我們需要在電腦安裝STM32提供的虛擬串口驅(qū)動,這在他們的官網(wǎng)可以下載到。
驅(qū)動安裝好后,接下來看看如何實現(xiàn)數(shù)據(jù)的收發(fā)。
在usb_device.c文件下實現(xiàn)了USB設(shè)備的初始化,只需要調(diào)用它就完成了所有的USB初始化工作。
通過在main中調(diào)用這個函數(shù),電腦就已經(jīng)可以將芯片的USB識別為一個串口了。進一步詳細內(nèi)容就不展開了,以后會專門發(fā)文介紹USB。
上面的VID和PID可以在文件usbd_desc.c中找到,設(shè)備描述符就在這個文件中。
OK,現(xiàn)在虛擬串口正確識別了,下面就是數(shù)據(jù)的收發(fā)了。
數(shù)據(jù)收發(fā)的接口在usbd_cdc_if.c文件下。
這里可以看到接收用了static關(guān)鍵字,說明它只能在本文件中使用,不可以外部調(diào)用。發(fā)送我們可以直接調(diào)用。這里先介紹發(fā)送吧。
發(fā)送
如果是發(fā)送原始數(shù)據(jù),可以直接將數(shù)據(jù)打包成數(shù)組,然后調(diào)用函數(shù)發(fā)送即可。但通常我們用串口打log,所以這里可以構(gòu)造一個printf函數(shù)。
這樣使用USB虛擬串口打印東西就非常方便了。這里要注意buff要夠大,否則會出現(xiàn)發(fā)送亂碼或不全的問題。
接收
USB虛擬串口的接收采用了中斷方式,芯片接收到數(shù)據(jù)后中斷回調(diào)函數(shù)會調(diào)用CDC_Receive_FS()函數(shù)接收數(shù)據(jù),然后將數(shù)據(jù)放到接收緩存中。但是軟件沒有提供直接獲得數(shù)據(jù)和個數(shù)的接口。所以我采取了一種簡單暴力的方式來獲取數(shù)據(jù)和數(shù)據(jù)個數(shù)。
收到數(shù)據(jù)后,數(shù)據(jù)的緩存指針通過參數(shù)Buf傳進來,數(shù)據(jù)個數(shù)通過參數(shù)Len傳進來。上面三個extern的變量在main文件中定義,get_data_flag標志是否收到數(shù)據(jù),buf存放數(shù)據(jù),data_nums存放數(shù)據(jù)個數(shù)。由于USB虛擬串口一次最多接收64字節(jié),如果收到的數(shù)據(jù)多于64字節(jié),會連續(xù)調(diào)用多次接收函數(shù),上圖中的方法理論上可以任意接收不超過buf大小個字節(jié)。
在main.c中的情況如下所示:
運行效果如下圖所示:
使用虛擬串口波特率不起作用,任何波特率都可以用。
在main中我們還發(fā)現(xiàn)有一個USB_Status_Init()函數(shù),這個函數(shù)用來復位USB口。如果沒有這個函數(shù),每次下載完程序后需要重新插拔usb線電腦才能識別到,有了它就可以不用拔插線了。
原理也很簡單,就是讓USB的兩個Pin都是低電平持續(xù)幾個毫秒即可。
OK,關(guān)于STM32的USB虛擬串口就介紹到這里了,很多細節(jié)我也不甚了解,希望看到本文的小伙伴能指正補充。