国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

激光飛秒手勢(shì)識(shí)別算法建模及其簡(jiǎn)易導(dǎo)航微系統(tǒng)實(shí)現(xiàn)

2022-08-02 11:01怯肇乾史繼峰
關(guān)鍵詞:視窗中斷手勢(shì)

怯肇乾,史繼峰

(南昌職業(yè)大學(xué) 信息技術(shù)學(xué)院,南昌 330500)

0 引言

現(xiàn)有手勢(shì)識(shí)別導(dǎo)航,最常見(jiàn)的是紅外收發(fā)/分析識(shí)別,雖然經(jīng)典,但距離短,通常最遠(yuǎn)只有150 mm,若作為論壇、會(huì)展、會(huì)議等演示場(chǎng)合應(yīng)用,使用局限,不現(xiàn)實(shí)際;更有傳統(tǒng)的激光筆導(dǎo)航,雖然簡(jiǎn)便,但需要正對(duì)接收操作,客戶體驗(yàn)不佳;還有重大國(guó)際/國(guó)家類論壇、會(huì)展中運(yùn)用的攝像識(shí)別,盡管操控便捷而且技術(shù)高大上,但價(jià)格不匪,難以拓展應(yīng)用到廣泛的課堂教學(xué)等尋常場(chǎng)景。

教學(xué)、論壇、會(huì)展、會(huì)議市場(chǎng)需求空間巨大,尋找和建立更為可靠、準(zhǔn)確、高效、廉價(jià)的檢測(cè)傳感器和手勢(shì)識(shí)別算法模型意義重大。經(jīng)反復(fù)查閱和對(duì)比,最終聚焦了激光飛秒測(cè)距ToF(Time of Flight)傳感器和“人工智能AI(Artificial Intelligence)深度學(xué)習(xí)自適應(yīng)”算法建模,于是有了這個(gè)省廳科技項(xiàng)目——激光飛秒手勢(shì)導(dǎo)航簡(jiǎn)易微系統(tǒng)實(shí)現(xiàn)。

1 激光飛秒手勢(shì)識(shí)別算法建模

采用高性價(jià)比的激光飛秒測(cè)距ToF傳感器,得到原始距離數(shù)據(jù)。客戶體驗(yàn)考慮,使用3個(gè)傳感器呈上、左、右布局[避免1個(gè)傳感器不合常規(guī)的特定手勢(shì)定義與強(qiáng)制學(xué)習(xí)],以此3路距離數(shù)據(jù)組成采集數(shù)據(jù)輸入。以最簡(jiǎn)潔的“人工智能AI(Artificial Intelligence)深度學(xué)習(xí)自適應(yīng)”算法模型——“后向反饋神經(jīng)元網(wǎng)絡(luò)BP_NN(Back Propagation Neural Networks)”為核心,輔以“智能模糊控制”和“專家經(jīng)驗(yàn)控制”,構(gòu)成“運(yùn)算處理分析”中心,最終得到并輸出“手勢(shì)數(shù)據(jù)信息”[1-3,18]。整個(gè)“ToF手勢(shì)識(shí)別算法”模型如圖1所示。BP_NN運(yùn)算處理分析框架,主要由適配器和調(diào)整器構(gòu)成;適配器,前向傳輸(Feed Forward),逐層波浪式的傳遞輸出值[左右、上下、前后];調(diào)整器,逆向反饋(Back Propagation),反向逐層調(diào)整權(quán)重和閾值,修正誤差至最小。“智能模糊控制”和“專家經(jīng)驗(yàn)控制”,進(jìn)行前級(jí)“預(yù)處理”和后級(jí)“結(jié)果識(shí)別”;前級(jí)“預(yù)處理”,通過(guò)“濾波”,得到50~600 mm內(nèi)的傳感器“視場(chǎng)出入及其運(yùn)動(dòng)的距離和時(shí)刻數(shù)據(jù)”,并對(duì)快速移動(dòng)情形完成數(shù)據(jù)插入,便利BP_NN更加有效運(yùn)算;后級(jí)“結(jié)果識(shí)別”處理,即后處理,對(duì)BP_NN運(yùn)算得到的左右、上下、前后數(shù)據(jù)進(jìn)一步處理分析,得到左右、上下、點(diǎn)擊等手勢(shì)直接數(shù)據(jù)。借助專家經(jīng)驗(yàn),可以把實(shí)際操控中多數(shù)習(xí)慣的“斜上再斜下”的動(dòng)作解釋為前后運(yùn)動(dòng)的“點(diǎn)擊”。

圖1 激光飛秒手勢(shì)識(shí)別算法模型框圖

BP_NN框架,選用3-4-3層次,如圖2所示,3個(gè)輸入層,4個(gè)隱藏層,3個(gè)輸出層,便于常用的Cortex-Mx/RISC-V類型的微控制器MCU (Microcontroller Unit)在軟件層次上進(jìn)行快速高效的實(shí)現(xiàn)[MCU,優(yōu)勢(shì)在控制,數(shù)字信號(hào)處理是弱勢(shì)]。BP_NN運(yùn)算,經(jīng)典成熟,不再贅述相關(guān)過(guò)程的各個(gè)離散處理公式,其關(guān)鍵是誤差計(jì)算及其對(duì)各層權(quán)值和閥值的修正,盡管已經(jīng)采用最簡(jiǎn)層次框架,放在MCU上實(shí)現(xiàn)仍然運(yùn)算繁鎖、耗時(shí)、耗資源,便于MCU硬軟件進(jìn)一步最簡(jiǎn)化及其成本最少考慮起見(jiàn),借助Mablib、Maple等的NN工具函數(shù)和仿真功能,針對(duì)實(shí)際測(cè)量數(shù)據(jù),訓(xùn)練各層的權(quán)值和閥值,形成表格,縮短訓(xùn)練和學(xué)習(xí)時(shí)間,即采用Mablib實(shí)現(xiàn)適配器,MCU僅做調(diào)整器實(shí)現(xiàn)。環(huán)境光的變化是手勢(shì)準(zhǔn)確度的最大影響因素,從系統(tǒng)實(shí)用和精簡(jiǎn)方面考慮,訓(xùn)練4種常用光環(huán)境:夜晚、白熾燈、日光燈、太陽(yáng)光,MCU系統(tǒng)在硬件上采用以光敏電阻-模數(shù)轉(zhuǎn)換ADC(Analog-to-Digital Converter)電路進(jìn)行選擇識(shí)別。

圖2 后向反饋神經(jīng)元網(wǎng)絡(luò)層次構(gòu)成示意圖

MCU在BP_NN中執(zhí)行前向輸出的運(yùn)算公式如下,這里激勵(lì)函數(shù)采用修正線性單元ReLU(Rectified Linear Unit),其中x/h/y分別對(duì)應(yīng)輸入/隱藏/輸出各層神經(jīng)元節(jié)點(diǎn),w/θ表示相應(yīng)前級(jí)的權(quán)重和閥值。

2 激光飛秒手勢(shì)導(dǎo)航微系統(tǒng)構(gòu)造

系統(tǒng)由三部分組成:信號(hào)采集識(shí)別發(fā)送終端(以下簡(jiǎn)稱采發(fā)終端)、手勢(shì)數(shù)據(jù)收集轉(zhuǎn)發(fā)終端(以下簡(jiǎn)稱收轉(zhuǎn)終端)和視窗展示服務(wù)軟件(以下簡(jiǎn)稱視窗展示軟件)。短距離無(wú)線通信采用抗干擾強(qiáng)、傳輸距離大、穿墻能力強(qiáng)、功耗低(發(fā)射最大功耗35 mA)的遠(yuǎn)距無(wú)線LoRa通信(Long Range Radio)形式。由于系統(tǒng)主要工作在Windows、UOS等通用操作系統(tǒng)下,并且服務(wù)以優(yōu)秀的微軟office等辦公軟件,轉(zhuǎn)換接口采用精簡(jiǎn)易用的WinUSB形式。終端微控制核心MCU,選用高性價(jià)比的32位的GD32F103TB(Cortex-M3內(nèi)核)或GD32VF103TB(RISC-V內(nèi)核),以C語(yǔ)言編程實(shí)現(xiàn)BP_NN適配器及其TOF數(shù)據(jù)采集與LoRa、USB傳輸通信。視窗展示軟件,以C++語(yǔ)言編程實(shí)現(xiàn)WinUSB驅(qū)動(dòng),以C++或Python語(yǔ)言編程實(shí)現(xiàn)手勢(shì)隨動(dòng)的各個(gè)視窗切換,伴隨視窗上隱含的微透明動(dòng)態(tài)指示,既可完成基本的PPT幻燈選擇播放,也可完成包括office(word、excel、ppt等)、acrobat(pdf電子文檔)在內(nèi)常用辦公軟件的遠(yuǎn)程切換翻頁(yè)操作,更可完成涵蓋辦公軟件在內(nèi)包括eclipse、notepad等集成開(kāi)發(fā)環(huán)境的遠(yuǎn)程研發(fā)演示,即3個(gè)版本:幻燈播放版、辦公播控版和開(kāi)發(fā)播控版[4-5,17]。完整的系統(tǒng)構(gòu)成及其核心算法模型與語(yǔ)言編程實(shí)現(xiàn),如圖3所示,詳細(xì)的微產(chǎn)品系統(tǒng)如圖4演示PPT截圖所示,圖4還示意了產(chǎn)品系統(tǒng)化的生產(chǎn)測(cè)試與配置的演示軟件。

圖3 微系統(tǒng)構(gòu)成及其核心技術(shù)手段示意圖

圖4 微產(chǎn)品系統(tǒng)應(yīng)用及其測(cè)試與配置示意圖

3 激光飛秒手勢(shì)導(dǎo)航微系統(tǒng)設(shè)計(jì)

3.1 采集識(shí)別發(fā)送電子終端構(gòu)造

3.1.1 電子電路設(shè)計(jì)

核心功能實(shí)現(xiàn),以MCU片上接口——內(nèi)部集成電路IIC(Inter-Integrated Circuit)掛接ToF傳感器、異同步串行收發(fā)器USART(Universal Synchronous/Asynchronous Receiver/Transmitter)掛接LoRa無(wú)線模塊和ADC片上外設(shè)連接光敏電阻,同時(shí)以其片內(nèi)實(shí)時(shí)時(shí)鐘RTC(Real_Time Clock)完成ToF測(cè)距時(shí)刻記錄。便攜低功耗設(shè)計(jì)考慮,采用1 000~2 500 mA扁平鋰電池供電,以高性價(jià)比的ETA7640芯片作為充供電管理,同時(shí)設(shè)置按鈕喚醒重啟電路。ToF激光發(fā)射測(cè)距和LoRa數(shù)據(jù)發(fā)送,最大功耗達(dá)100 mA,供電轉(zhuǎn)換電路選用性能優(yōu)良的大功率LM1117_3V3,無(wú)檢測(cè)傳感時(shí)必須預(yù)以關(guān)斷,因而設(shè)計(jì)10 min內(nèi)無(wú)動(dòng)作時(shí)通過(guò)軟件關(guān)閉系統(tǒng),再次使用時(shí)以上述按鈕喚醒重啟。由于采用QFN36最小MCU封裝,此類MCU無(wú)VB電池待機(jī)/休眠管理腳,則控制關(guān)斷時(shí)直接切斷LM117供電電路。電源開(kāi)關(guān)選用P溝通MOS場(chǎng)效應(yīng)管PDN304P。ToF傳感器2.8 V供電時(shí)性能最佳,選用XC6206P28MR為其集群獨(dú)立供電,3.3 V與2.8 V之間的IIC總線采用N溝通MOS場(chǎng)效應(yīng)管2N7002過(guò)渡。模塊化電路設(shè)計(jì),MCU與ToF傳感器及其喚醒按鈕構(gòu)成小頂板,大底板攜帶鋰電池及其充供電路,并背附LoRa無(wú)線通信模塊。一大一小兩板在兩側(cè)通過(guò)“信號(hào)排針”連通[5,11,17]。終端平面大小不超過(guò)鋰電池大小35 mm×50 mm,包括鋰電池在內(nèi)整體厚度控制在8 mm內(nèi),“胸針”或“別針”形式,供胸前佩帶,充分體現(xiàn)“便攜”。選用透明熱縮管外封,既時(shí)尚大方又可免去昂貴的模具設(shè)制費(fèi)用。識(shí)別模塊設(shè)計(jì)最大持續(xù)工作時(shí)間不低于8h@1 000 mA,總體重量控制在250 gf內(nèi)。電路原理及其整體外觀造型如圖5所示。

圖5 采發(fā)終端電路原理及其整體造型示意圖

3.1.2 軟件體系構(gòu)造及其編制

穩(wěn)定高效設(shè)計(jì)及其開(kāi)發(fā)考慮,基于MCU寄存器和多中斷處理機(jī)制,構(gòu)造嵌入式軟件應(yīng)用體系,這里采用項(xiàng)目主持人的發(fā)明專利——ARM/RISC-V系列微控制處理器軟件架構(gòu)工具,快速得到包括啟動(dòng)代碼、系統(tǒng)時(shí)鐘變換配置、片內(nèi)接口/外設(shè)驅(qū)動(dòng)程序、中斷分配及其處理程序、多任務(wù)調(diào)度程序等的基本框架代碼,直接在此基礎(chǔ)上展開(kāi)填空式的功能代碼設(shè)計(jì)。

3.1.2.1 TOF測(cè)距及其BP_NN手勢(shì)識(shí)別

TOF測(cè)距,采用意法半的VL53L0X模塊,需要兩級(jí)驅(qū)動(dòng),一級(jí)驅(qū)動(dòng)IIC傳輸完成數(shù)據(jù)讀寫(xiě),二級(jí)驅(qū)動(dòng),移植相應(yīng)的應(yīng)用程序接口API(Application Programming Interface),配合模塊內(nèi)嵌算法處理得到最終距離數(shù)據(jù)。采用兩個(gè)中斷處理完成核心操作:IIC中斷和距離獲取事件中斷,優(yōu)先級(jí)最高,僅次任務(wù)調(diào)度的時(shí)鐘節(jié)拍中斷。兩級(jí)中斷的使用,把單次測(cè)距時(shí)間提升了18 ms內(nèi)(廠家提供的最小值為22 ms)。

中斷處理IIC操作,效率最優(yōu),但時(shí)序節(jié)點(diǎn)把握要求苛刻,特別是單字節(jié)的讀操作,很難駕馭,常常因此造成系統(tǒng)停滯,多采用通用輸入輸出GPIO(General-Purpose Input/Output)模擬實(shí)現(xiàn),軟件架構(gòu)工具得到的IIC驅(qū)動(dòng)程序,很好解決了這個(gè)問(wèn)題[19-21]。核心的底層IIC驅(qū)動(dòng)程序流程如圖6所示。

圖6 IIC中斷收發(fā)驅(qū)動(dòng)程序流程圖

關(guān)鍵的單字節(jié)讀取IIC操控時(shí)序如圖7所示,先寫(xiě)指定寄存器地址,再?gòu)闹凶x出數(shù)據(jù)。

圖7 恰當(dāng)?shù)钠瑑?nèi)IIC驅(qū)動(dòng)程序流程圖

距離獲取事件中斷,設(shè)置任務(wù)啟動(dòng)標(biāo)識(shí),處理程序在濾波插值、BP_NN適配輸出、手勢(shì)識(shí)別3個(gè)順序任務(wù)中實(shí)現(xiàn),首先是濾波插值,依據(jù)專家經(jīng)驗(yàn),只取連續(xù)(最大時(shí)間間隔100 ms)有效手勢(shì)距離(110~550 mm內(nèi))構(gòu)成原始數(shù)據(jù)隊(duì)列(長(zhǎng)度30內(nèi)),且每個(gè)傳感器應(yīng)用至少3個(gè)數(shù)據(jù),數(shù)量不足按照進(jìn)出計(jì)量場(chǎng)的數(shù)據(jù)變化規(guī)律插入,然后是BP_NN適配和手勢(shì)識(shí)別[8-9,19-21],核心的處理函數(shù)代碼如下:

char vldDtLgth = 0, vldDtFlg = 0, lstGst =‘z’; // 有效數(shù)據(jù)數(shù)量、標(biāo)識(shí)、上次手勢(shì)值

VL53L0X_RangingPoint vldDt[30] = {0}; // 有效數(shù)據(jù)存儲(chǔ)

unsigned int lstTs = 0; // 最近測(cè)量活動(dòng)時(shí)間記錄

void tof_bpnn_process(char maxNum) { // ToF數(shù)據(jù)分析處理[傳感器最大數(shù)量]

uint8_t i, m; unsigned short v; unsigned int ts;

VL53L0X_RangingMeasurementData_t msData[maxNum];

for(i=0; i

if(((alarm_flag>>i)&1) 1) { alarm_flag &= ~(1 << i);

VL53L0X_GetRangingMeasurementData(&vl53l0x_dev[i], &msData[i]); // 獲取測(cè)量距離

msData[i].TimeStamp = RTC_GetCounter();

ts = msData[i].TimeStamp;

v = msData[i].RangeMilliMeter;

if((v>110)&&(v<550)) {

if((vldDtLgth 0)&&(vldDtFlg 0)) {

vldDt[vldDtLgth].dvcNum = i;

vldDt[vldDtLgth].TimeStamp = msData[i].TimeStamp;

vldDt[vldDtLgth].RangeMilliMeter = msData[i].RangeMilliMeter;

vldDtLgth += 1; lstTs = ts; vldDtFlg = 1;

if((optFlg>>1)&1)

printf("**%d-%d: %4dmm,%8d; ",vldDtLgth, i, v, ts);

}

else {

if(((ts-lstTs)<10)&&(vldDtLgth<30)&&(vldDtFlg 1)) {

vldDt[vldDtLgth].dvcNum = i;

vldDt[vldDtLgth].TimeStamp = msData[i].TimeStamp;

vldDt[vldDtLgth].RangeMilliMeter = msData[i].RangeMilliMeter;

vldDtLgth += 1; lstTs = ts;

if((optFlg>>1)&1)

printf("**%d-%d: %4dmm,%8d; ",vldDtLgth, i, v, ts);

}

else vldDtFlg = 2;

}

}

VL53L0X_ClearInterruptMask(&vl53l0x_dev[i],0); // 清除VL53L0X中斷標(biāo)志位

}

}

if((vldDtFlg 1)&&((RTC_GetCounter()-lstTs)>53)) vldDtFlg = 2;

if(vldDtFlg 2) { // 手勢(shì)分析識(shí)別

VL53L0X_DtSetInterpolation (); // 插值

VL53L0X_BpNnAdepter(); // BP_NN適配輸出

VL53L0X_gestureRecognition(); // 手勢(shì)識(shí)別

if(gestureFlg) { // Lora外傳

printf(" gesture:%d ", m);

gesture[5] = m | 0x30;

USART1_SendData(gesture, 6);

}

}

}

3.1.2.2 LoRa配置及其有效數(shù)據(jù)無(wú)線發(fā)送

配置包括LoRa地址、通道、升級(jí)通信速率,并進(jìn)入易用的透明傳輸方式,需要反復(fù)寫(xiě)入驗(yàn)證特別耗時(shí),僅做一次即可,無(wú)需每次啟動(dòng)時(shí)都執(zhí)行,設(shè)計(jì)快速啟動(dòng)運(yùn)行,運(yùn)行中需要修改時(shí)通過(guò)UART串口或USB接口通信實(shí)現(xiàn),盡管耗時(shí),卻一勞永逸,相關(guān)操控函數(shù)代碼如下:

void Lora2G4_smpInit(void) { // Lora2G4模塊快速常規(guī)初始化

PIO_DataOutput(0, 5, 1); // 設(shè)置進(jìn)入連續(xù)透?jìng)鞴ぷ髂J?/p>

PIO_DataOutput(0, 6, 0);

PIO_DataOutput(0, 7, 0);

while(PIO_DataInput(0, 4) 0); // 等待模塊有效

}

void Lora2G4_vInit(void) { // Lora2G4模塊配置初始化

unsigned char i, b[15] = {0};

unsigned char a[6] = { 0xC0, // 工作模式: 參數(shù)掉電保存

{0x30, 0x31}, 0x28, 0x03, 0x04 }; // 地址, 波特率, 通道號(hào),透?jìng)?功耗

inFlshByteRead(0, AddrChnl, 3); // Lora地址通道號(hào)

a[1] = AddrChnl[0]; a[2] = AddrChnl[1]; // Lora地址通道號(hào)

a[4] = AddrChnl[2];

PIO_DataOutput(0, 5, 1); // 設(shè)置模塊進(jìn)入配置模式

PIO_DataOutput(0, 6, 1);

PIO_DataOutput(0, 7, 1);

while(PIO_DataInput(0, 4) 0); // 等待模塊有效

do { // 配置參數(shù)及其驗(yàn)證

Delay(300); USART1_SendData(a, 6); // 發(fā)送配置參數(shù)

Delay(300); b[0] = b[1] = b[2] = 0xC1; // 驗(yàn)證配置

USART1_SendData(b, 3);

Delay(100); i = USART1_QueueRcvData(b);

}while((b[0]!=a[0]) || (b[1]!=a[1]) || (b[2]!=a[2]) || (b[3]!=a[3]) ||

(b[4]!=a[4]) || (b[5]!=a[5]) || (i!=6) );

PIO_DataOutput(0, 6, 0); // 設(shè)置進(jìn)入連續(xù)透?jìng)髂J?/p>

PIO_DataOutput(0, 7, 0);

USART1_CR1 &= ~6; // USART波特率調(diào)整: 禁止收發(fā)

USART1_BRR = 0x00000138; // 波特率115200

USART1_CR1 |= 6; // 收發(fā)使能

while(PIO_DataInput(0, 4) 0); // 等待模塊有效

}

void USART0_Process(void) // USART0數(shù)據(jù)收發(fā)處理

{ unsigned int status = USART0_SR;

if(status&15) return; // 異常處理: 校驗(yàn)錯(cuò), 幀錯(cuò), 噪聲, 溢出

else if((status>>5)&1) // 數(shù)據(jù)接收(環(huán)形隊(duì)列存放, 隊(duì)列滿則拋掉)

{ status = Usart0RcvPrt + 1;

if(status>Usart0QueueLth) status = 0;

if(status!=Usart0AppPrt) { status = USART0_DR;

switch(Usart0RcvFlg) {

case 0: if(status '*') Usart0RcvFlg += 1; break;

case 1: if(status ' ') Usart0RcvFlg += 1;

else Usart0RcvFlg = 0; break;

case 2: case 3: case 4: Usart0RcvFlg += 1; break;

default: break;

}

Usart0RcvQueue[Usart0RcvPrt++] = status;

if(Usart0RcvPrt>=Usart0QueueLth) Usart0RcvPrt = 0;

}

else USART0_DR;

}

}

3.2 接收轉(zhuǎn)換傳輸電子終端構(gòu)造

3.2.1 電子電路設(shè)計(jì)

收轉(zhuǎn)終端,USART串口無(wú)線LoRa接收,通用串行總線USB(Universal Serial Bus )“二傳”并供電,采用MCU片內(nèi)外設(shè)——USB2.0全速模塊[5-8][10-12],電路原理及其正反面mini造型如圖8所示。

圖8 收轉(zhuǎn)終端原理及其正反面mini造型圖

3.2.2 軟件體系構(gòu)造及其編制

仍然采用項(xiàng)目主持人的發(fā)明專利——ARM/RISC-V系列微控制處理器軟件架構(gòu)工具,快速得到基本框架代碼(包括USB驅(qū)動(dòng)程序),在此基礎(chǔ)上展開(kāi)填空式的功能代碼設(shè)計(jì)。采用USART中斷和USB中斷進(jìn)行LoRa無(wú)線透?jìng)餍畔⒔邮蘸蚒SB收發(fā)通信,中斷里接收,相應(yīng)任務(wù)中分析處理[17,22]。

LoRa手勢(shì)信息接收,在中斷處理程序中設(shè)置環(huán)形隊(duì)列高效接收識(shí)別,相應(yīng)任務(wù)中轉(zhuǎn)包調(diào)用USB發(fā)送任務(wù)上傳,關(guān)鍵程序代碼如下:

int USART1_QueueRcvData(unsigned char *Data) // 環(huán)形隊(duì)列中斷數(shù)據(jù)接收

{ int i = 0;

USART1_CR1 |= 1 << 2; // 使能啟動(dòng)接收

if(Usart1AppPrt

{ do { i++;

*Data++ = Usart1RcvQueue[Usart1AppPrt++];

} while(Usart1AppPrt!=Usart1RcvPrt);

}

else if(Usart1AppPrt>Usart1RcvPrt) // 隊(duì)列反向增長(zhǎng)數(shù)據(jù)接收

{ do

{ *Data++ = Usart1RcvQueue[Usart1AppPrt++]; i++;

if(Usart1AppPrt Usart1QueueLth) Usart1AppPrt = 0;

} while(Usart1AppPrt!=Usart1RcvPrt);

}

return i; // 返回?cái)?shù)據(jù)接收量

}

void USART1_Process(void) // USART1數(shù)據(jù)收發(fā)處理

{ unsigned int status = USART1_SR;

if(status&15) return; // 異常處理: 校驗(yàn)錯(cuò), 幀錯(cuò), 噪聲

if((status>>5)&1) // 數(shù)據(jù)接收(環(huán)形隊(duì)列存放,滿則拋掉)

{ status = Usart1RcvPrt + 1;

if(status>Usart1QueueLth) status = 0;

if(status!=Usart1AppPrt) {

status = USART1_DR;

switch(Usart1RcvFlg) {

case 0: if(status '*') Usart1RcvFlg += 1; break;

case 1: if(status '&') Usart1RcvFlg += 1;

else Usart1RcvFlg = 0; break;

case 2: if(status '^') Usart1RcvFlg += 1;

else Usart1RcvFlg = 0; break;

case 3: if(status ' ') Usart1RcvFlg += 1;

else Usart1RcvFlg = 0; break;

case 4: if(status '@') Usart1RcvFlg += 1;

else Usart1RcvFlg = 0; break;

case 5: Usart1RcvFlg += 1; break;

default: break;

}

Usart1RcvQueue[Usart1RcvPrt++] = status;

if(Usart1RcvPrt>=Usart1QueueLth) Usart1RcvPrt = 0;

}

else USART1_DR;

}

}

while(1) {

m = DrvUSB_EpRead(2, tmp, 6); // USB接收數(shù)據(jù)處理

if(m 0) {

DrvUSB_EpWrite(1, tmp, 5); // 通過(guò)USB上傳

if((tmp[0] '*')&&(tmp[1] ' ')) { // Lora地址通道號(hào)變更

AddrChnl[0] = tmp[2] & 0x0F;

AddrChnl[1] = tmp[3] & 0x0F;

AddrChnl[2] = tmp[4] & 0x0F;

inFlshPageErase(); // 閃存記錄修正

inFlshByteWrite(0, AddrChnl, 3);

USART1_CR1 &= ~6; // USART波特率調(diào)整

USART1_BRR = 0x00000E98; // 波特率9600

USART1_CR1 |= 6;

Lora2G4_vInit(); // Lora重新初始化

}

}

if(Usart1RcvFlg 6) { // Lora收到有效數(shù)據(jù)

m = USART1_QueueRcvData(tmp);

Usart1RcvFlg = 0;

if(m 6) DrvUSB_EpWrite(1, tmp, 6); // 通過(guò)USB上傳

}

}

USB收發(fā)傳輸,不以傳統(tǒng)的人機(jī)接口設(shè)備HID(Human Interface Device)/配合主機(jī)USART轉(zhuǎn)USB做“借尸還魂”,直接采用高效的WinUSB格式,增加特定的操作系統(tǒng)描述、兼容ID特征描述和設(shè)備接口GUID描述符,并對(duì)收發(fā)任務(wù)函數(shù)做超時(shí)處理以避免程序阻塞,主要程序代碼如下:

const unsigned char OsDscrptStr[] = // 操作系統(tǒng)描述字符串

{ USBStrDscrpt_Lth(8), 3,

USBStrDscrpt_Uncd('M'), USBStrDscrpt_Uncd('S'),

USBStrDscrpt_Uncd('F'), USBStrDscrpt_Uncd('T'),

USBStrDscrpt_Uncd('1'), USBStrDscrpt_Uncd('0'),

USBStrDscrpt_Uncd('0'), USBStrDscrpt_Uncd(1)

};

const CptbIdDscrpt cptbIdDscrpt = // 兼容ID特征描述符

{0x28, 0x100, 4, 1, // dwLength, bcdVersion, wIndex, wCount

{0, 0, 0, 0, 0, 0, 0}, // Reserved[7]

0, 1, // bFirstInterfaceNumber, RESERVED

{'W', 'I', 'N', 'U', 'S', 'B', 0, 0}, // compactiableID[8]

{0, 0, 0, 0, 0, 0, 0, 0}, // subCompactiableID[8]

{0, 0, 0, 0, 0, 0} // Reserved[6]

};

const ItfcGuidDscrpt itfcGuidDscrpt = // 設(shè)備接口GUID描述符

{ 0x8E, 0x100, 5, 1, // dwTotalSize, bcdVersion, wIndex, wCount

0x84, 1, 0x28, // dwSize, dwPropertyDataType, wPropertyNameLength

USBStrDscrpt_Uncd('DeviceInterfaceGUID'), // bProperytName

0x4E, // dwPropertyDataLength

USBStrDscrpt_Uncd('{12345678-1234-1344-1234-12345678ABCD}0') // bPropertyData

};

// 單緩端點(diǎn)數(shù)據(jù)發(fā)送(查詢激發(fā)中斷發(fā)出), 參數(shù): 端點(diǎn)號(hào)1-7, 預(yù)發(fā)數(shù)據(jù), 數(shù)量, 返回[0-正確/-1超時(shí)]

char DrvUSB_EpWrite(char EpNum, unsigned char* data, unsigned int counts) {

unsigned int i; short sz;

if(EpNum 1) sz = CfgDscrpts.EpIn1.wMaxPcktSz;

while(counts) { i = 0;

do { i++;

if(i>maxTmOut) return 0xFF; // 超時(shí)退出

} while((EpDtSts>>EpNum)&1); // 時(shí)機(jī)查詢: 等待USBD空閑

if(counts>sz) // 超過(guò)最大包尺寸的發(fā)送

{ USBD_BasicWrite(EpNum, 0, data, sz);

data += sz; counts -= sz;

}

else // 最大包尺寸內(nèi)的發(fā)送

{ USBD_BasicWrite(EpNum, 0, data, counts);

counts = 0;

}

EpDtSts |= 1 << EpNum; // 標(biāo)識(shí)需要數(shù)據(jù)發(fā)送

}

return 0;

}

// 端點(diǎn)數(shù)據(jù)接收, 參數(shù): 端點(diǎn)號(hào)1-7, 預(yù)發(fā)數(shù)據(jù), 數(shù)量, 返回[0-正確/-1超時(shí)]

char DrvUSB_EpRead(char EpNum, unsigned char* data, unsigned int counts) {

unsigned int i; RcvPt = data;

while(counts) { i = 0;

do { i++;

if(i>maxTmOut) return 0xFF; // 超時(shí)退出

} while(!((EpDtSts>>EpNum)&1)); // 等待USB數(shù)據(jù)到來(lái)

counts -= RcvCnt;

EpDtSts &= ~(1 << EpNum); // 標(biāo)識(shí)已經(jīng)取得USBD收到數(shù)據(jù)

}

return 0;

}

3.3 WinUSB接收及其視窗展示控制實(shí)現(xiàn)

3.3.1 WinUSB驅(qū)動(dòng)及其數(shù)據(jù)接收實(shí)現(xiàn)

針對(duì)常規(guī)Windows、UOS操作系統(tǒng)應(yīng)用,直接調(diào)用Win7以上內(nèi)嵌的WinUSB.dll動(dòng)態(tài)庫(kù)實(shí)現(xiàn),主要是操控句柄的開(kāi)關(guān)和接收監(jiān)聽(tīng),采用兩個(gè)定時(shí)器分別開(kāi)關(guān)線程實(shí)現(xiàn)收轉(zhuǎn)USB終端的即插即用和動(dòng)態(tài)接收監(jiān)聽(tīng)。只要底層嵌入式應(yīng)用軟件中添加特定描述支持,Windows就可以自動(dòng)識(shí)其為WinUSB設(shè)備,上層可視化測(cè)試/應(yīng)用程序就可以通過(guò)WinUSB.dll與其進(jìn)行USB數(shù)據(jù)傳輸通信。這樣, USB設(shè)備的數(shù)據(jù)采集、監(jiān)視控制、配置參數(shù)、軟件刷新等編程操控,就同傳統(tǒng)的“RS-232C通信”一樣了,無(wú)需USB轉(zhuǎn)串口作硬軟件轉(zhuǎn)接,而且速度快、實(shí)時(shí)性強(qiáng),直截了當(dāng)[6][10-15]。相關(guān)關(guān)鍵代碼如下:

HANDLE hDeviceHandle = INVALID_HANDLE_VALUE; // 設(shè)備文件句柄

WINUSB_INTERFACE_HANDLE hWinUSBHandle // WinUSB操作句柄

= INVALID_HANDLE_VALUE;

OVERLAPPED overlapped; // 異步收發(fā)緩存結(jié)構(gòu)變量

BOOL flgWinUSB = false; // WinUSB設(shè)備存在與否[true存在]

char thrdStt = 0; // 線程建立標(biāo)識(shí)狀態(tài)[0-無(wú)/1-建]

void __fastcall TfmShow::SystemInit(void) { // 系統(tǒng)初始化

static const GUID stm32F1xxDvcItfc = { 0x12345678, 0x1234, 0x1344,

{ 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC } };

GUID guidDeviceInterface = stm32F1xxDvcItfc;

BOOL bResult = TRUE; AnsiString str;

bResult = GetDeviceHandle(guidDeviceInterface, &hDeviceHandle);

if (!bResult) { inOutTmr->Enabled = true;

sttFlg->Font->Color = clGray; return;

}

bResult = GetWinUSBHandle(hDeviceHandle, &hWinUSBHandle);

if (!bResult) { inOutTmr->Enabled = true;

sttFlg->Font->Color = clGray; return;

}

flgWinUSB = true; // 設(shè)備已經(jīng)正常尋址到

inOutTmr->Enabled = false;

sttFlg->Font->Color = clRed;

if(thrdStt 0) { // 啟動(dòng)并運(yùn)行線程

rcvThrdDt = new rcvThrd(true, imgDrct,

sttFlg, spcTmr, inOutTmr); thrdStt = 1;

}

rcvThrdDt->FreeOnTerminate = true;

rcvThrdDt->Resume(); UINT timeout = 100; // 最大傳輸時(shí)間[ms]

bResult = WinUsb_SetPipePolicy(hWinUSBHandle,

0x81, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout);

if(!bResult)

{ str = "設(shè)置超時(shí)錯(cuò)誤:"; str += GetLastError();

ShowMessage(str); return;

}

ZeroMemory(&overlapped, sizeof(overlapped));

overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

}

void __fastcall rcvThrd::RcvDt()

{ if(hWinUSBHandle INVALID_HANDLE_VALUE) return;

ULONG cbRead = 0; UCHAR szBffr[20] = {'0'}; AnsiString str;

BOOL bResult = WinUsb_ReadPipe(hWinUSBHandle, 0x81,

szBffr, 15, &cbRead, &overlapped);

if(bResult) { const char* t = szBffr; str = t; windowChange(str); }

else if(ERROR_IO_PENDING GetLastError())

{ bResult = WinUsb_GetOverlappedResult(hWinUSBHandle,

&overlapped, &cbRead, true);

if(NULL != cbRead)

{ int m = cbRead; cbRead = 0;

if(bResult)

{ const char* d = szBffr; str = d;

char i = 0; windowChange(str);

}

}

}

else if(22 GetLastError()) inOutTmr->Enabled = true; // 設(shè)備撥出

}

3.3.2 視窗動(dòng)態(tài)展現(xiàn)及其控制軟件編制

開(kāi)發(fā)之初,設(shè)想用通用流行的Python語(yǔ)言開(kāi)發(fā),擬用PyUSB、Kivy/Tkinter、python-pptx/word/excel/acrobat,PyKeyboard/PyMouse等庫(kù),深入之后發(fā)現(xiàn)這些庫(kù)多是用C++開(kāi)發(fā)打包的,多是針對(duì)WinAPI的包,而且不新、不全面,作為解釋語(yǔ)言也沒(méi)有編譯語(yǔ)言C++運(yùn)行效率高,與其特制一些把C++庫(kù)彌補(bǔ)Python應(yīng)用,倒不如與底層合二為一,直接嵌入其監(jiān)聽(tīng)線物程中實(shí)現(xiàn),更為經(jīng)典直接,于是回到了C++開(kāi)發(fā)實(shí)現(xiàn)。這里選用Enbarcadero的RadStudio開(kāi)發(fā)環(huán)境,主要是兩類窗口:引導(dǎo)窗口和展示窗口。引導(dǎo)窗口,小視野透明暗標(biāo)動(dòng)態(tài)圖文指示,控制展示窗口切換和翻頁(yè)。展示窗口,展示常規(guī)辦公軟件和特定開(kāi)發(fā)軟件的窗口,主要通過(guò)調(diào)用Windows視窗變換和鍵盤(pán)模擬操控API函數(shù)實(shí)現(xiàn)[6][10-15]。核心程序函數(shù)代碼如下:

BOOL SetTopWindow(HWND hWnd) { // 設(shè)置窗口到最頂層[參數(shù):窗口句柄]

HWND hForeWnd = GetForegroundWindow();

DWORD dwForeID = GetWindowThreadProcessId(hForeWnd, NULL);

DWORD dwCurID = GetCurrentThreadId();

AttachThreadInput(dwCurID, dwForeID, TRUE);

ShowWindow(hWnd, SW_MAXIMIZE);

SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

SetForegroundWindow(hWnd);

AttachThreadInput(dwCurID, dwForeID, FALSE); return TRUE;

}

窗口隨動(dòng)變換展示的程序流程圖如圖9所示。

圖9 窗口隨動(dòng)變換展示的程序流程圖

4 產(chǎn)品系統(tǒng)化測(cè)試及其配置考慮

生產(chǎn)出廠測(cè)試,輸出指示原始的手勢(shì)分析結(jié)果和通信通道的暢通性,配置LoRa無(wú)線通信地址、通道及其是否輸出原始測(cè)距數(shù)據(jù)。設(shè)計(jì)有專用的可視化USB軟件,完成手勢(shì)分析原始數(shù)據(jù)的即時(shí)查看和LoRa無(wú)線通信配置。同時(shí)底層采發(fā)終端還支持使用USB串口助手查看手勢(shì)分析原始數(shù)據(jù)、原始測(cè)距數(shù)據(jù)詳細(xì)查看和LoRa無(wú)線通信配置[6-8]。專用可視化USB軟件和USB串口助手操控界面,如圖10~11所示。

圖10 專用可視化USB軟件實(shí)現(xiàn)的測(cè)試與配置示意圖

圖11 USB串口助手實(shí)現(xiàn)的測(cè)試與配置示意圖

要做到這些,終端軟件中需要添加相應(yīng)支持,采發(fā)終端中相關(guān)的典型實(shí)現(xiàn)函數(shù)代碼如下:

void Lora2G4_chgCfg(void) { // Lora地址通道變更/系統(tǒng)打印信息[配合USART0接收中斷]

unsigned char tmp[10] = {0}, m;

if(Usart0RcvFlg 5) { // 收到有效數(shù)據(jù)

m = USART0_QueueRcvData(tmp);

Usart0RcvFlg = 0;

if(m 5) {

if(tmp[2]<0x41) { // Lora地址通道變更

AddrChnl[0] = tmp[2] & 15;

AddrChnl[1] = tmp[3] & 15;

AddrChnl[2] = tmp[4] & 15;

inFlshPageErase(); // 閃存記錄修正

inFlshByteWrite(0, AddrChnl, 3);

USART1_CR1 &= ~6; // USART波特率調(diào)整

USART1_BRR = 0x00000E98; // 波特率9600

USART1_CR1 |= 6;

Lora2G4_vInit(); // Lora重新初始化

}

else { // 系統(tǒng)輸出指示信息變更

if(((optFlg>>1)&1) 0) optFlg |= 1 <<1; // 詳細(xì)

else optFlg &= ~(1 << 1);

}

}

}

}

5 產(chǎn)品系統(tǒng)的應(yīng)用統(tǒng)計(jì)分析

激光手指飛行導(dǎo)航簡(jiǎn)易微系統(tǒng),試銷以后,以極高的性價(jià)比,滿足了各類學(xué)校、企業(yè)、酒店、機(jī)關(guān)、場(chǎng)所的尋常應(yīng)用需要,內(nèi)外循環(huán)行銷,市場(chǎng)前景頗佳,緊接著就圍繞微型化和低功耗設(shè)計(jì)又推出了二代產(chǎn)品。另外,頂板即主板,還作為獨(dú)立的ToF手勢(shì)或雷達(dá)測(cè)距測(cè)向模塊,單獨(dú)出售,填補(bǔ)遠(yuǎn)距離手勢(shì)導(dǎo)航和低成本雷達(dá)測(cè)距測(cè)向領(lǐng)域的空白。

6 結(jié)束語(yǔ)

激光手指飛行導(dǎo)航簡(jiǎn)易微系統(tǒng),麻雀雖小,五臟俱全,以神經(jīng)元深度學(xué)習(xí)自適應(yīng)人工智能手勢(shì)識(shí)別核心算法數(shù)學(xué)處理模型為中心,既涵蓋了數(shù)電/模電/射電在內(nèi)的低功耗微型電子電路設(shè)計(jì),也包括了嵌入式C語(yǔ)言應(yīng)用軟件設(shè)計(jì)、C++驅(qū)動(dòng)程序設(shè)計(jì)和C++/Python動(dòng)態(tài)視窗切換技術(shù),通用流行的局部長(zhǎng)距離無(wú)線通信和各類局部總線接口技術(shù)一應(yīng)俱全,既是可探索開(kāi)發(fā)項(xiàng)目的過(guò)程研發(fā),也產(chǎn)生了可測(cè)試生產(chǎn)行銷的產(chǎn)品系統(tǒng)。在此基礎(chǔ)上,加大深度學(xué)習(xí)自適應(yīng)人工智能算法處理,實(shí)現(xiàn)鼠標(biāo)功能的“遠(yuǎn)距離移動(dòng)飛鼠”,將有望成為可能,“學(xué)研”應(yīng)用顛覆突破,意義重大,拭目以待,為期不遠(yuǎn)。

猜你喜歡
視窗中斷手勢(shì)
TMS320F28335外部中斷分析與研究
雪后林鳥(niǎo)
挑戰(zhàn)!神秘手勢(shì)
跟蹤導(dǎo)練(二)(5)
勝利的手勢(shì)
環(huán)球視窗
創(chuàng)意視窗
認(rèn)手勢(shì)說(shuō)數(shù)字
新聞浮世繪