動(dòng)AS608指紋模塊實(shí)戰(zhàn):從硬件選型到識(shí)別優(yōu)化)
1. 項(xiàng)目緣起與整體方案設(shè)計(jì)1.1 為什么選STM32F103C8T6加AS608這個(gè)組合手頭這個(gè)指紋識(shí)別項(xiàng)目其實(shí)最早是給一個(gè)做考勤機(jī)的小團(tuán)隊(duì)做的原型驗(yàn)證。他們?cè)居玫氖悄晨顜е讣y功能的專用芯片但開發(fā)自由度太低想改個(gè)UI或者加個(gè)聯(lián)網(wǎng)功能都束手束腳。后來聊下來大家一致覺得用STM32F103C8T6配AS608指紋模塊是最務(wù)實(shí)的路子——前者是嵌入式圈子里公認(rèn)的“國民MCU”資料多、價(jià)格低、供貨穩(wěn)后者是光學(xué)指紋模塊里性價(jià)比極高的一款串口通信協(xié)議簡(jiǎn)單識(shí)別率也夠用。STM32F103C8T6這顆芯片72MHz主頻、64KB Flash、20KB SRAM對(duì)于指紋識(shí)別這種任務(wù)來說綽綽有余。它有三個(gè)USART其中一個(gè)用來跟AS608通信另一個(gè)可以接串口屏或者調(diào)試輸出剩下的還能擴(kuò)展別的外設(shè)。AS608模塊內(nèi)部自帶DSP運(yùn)算單元指紋錄入、比對(duì)、搜索這些重活它自己就干了STM32只需要發(fā)命令、收結(jié)果就行CPU占用率極低。這個(gè)分工很關(guān)鍵——很多新手容易犯一個(gè)錯(cuò)誤試圖在MCU上跑指紋算法那基本是給自己找不痛快。OLED顯示屏我選的是0.96寸I2C接口的SSD1306原因很簡(jiǎn)單接線少。I2C只需要兩根線SCL和SDA加上電源和地四根線搞定。相比SPI接口的OLED省了CS、DC、RES三根線對(duì)于F103C8T6這種引腳不算特別富裕的芯片來說能省一根是一根。而且I2C速率設(shè)到400kHz刷一屏指紋狀態(tài)信息完全感覺不到延遲。整個(gè)系統(tǒng)的數(shù)據(jù)流是這樣的手指按下→AS608采集圖像并提取特征→與模塊內(nèi)存儲(chǔ)的指紋模板比對(duì)→通過串口返回比對(duì)結(jié)果給STM32→STM32解析結(jié)果→在OLED上顯示“識(shí)別成功”或“識(shí)別失敗”→如果成功則驅(qū)動(dòng)繼電器或其他執(zhí)行機(jī)構(gòu)。這個(gè)鏈路里STM32扮演的是“指揮官”角色AS608是“專業(yè)執(zhí)行者”O(jiān)LED是“信息窗口”。1.2 硬件選型背后的成本與性能權(quán)衡先說說為什么沒選ZW101。ZW101確實(shí)更小、功耗更低但它的通信協(xié)議跟AS608不兼容而且開發(fā)資料相對(duì)少一些。對(duì)于第一次做指紋項(xiàng)目的朋友來說AS608的文檔更全社區(qū)里踩坑記錄也多遇到問題更容易搜到答案。另外AS608的光學(xué)傳感器對(duì)干手指、濕手指的適應(yīng)性比電容式的好一些雖然體積大點(diǎn)但放在考勤機(jī)、門禁這種場(chǎng)景里完全不是問題。STM32F103C8T6的國產(chǎn)替代問題也值得提一句?,F(xiàn)在市面上有很多Pin-to-Pin兼容的國產(chǎn)芯片比如GD32F103、CH32F103等。如果你的項(xiàng)目對(duì)成本極度敏感可以考慮這些替代品但要注意一點(diǎn)國產(chǎn)替代品的Flash等待周期、ADC精度、USB外設(shè)兼容性可能有細(xì)微差異。我實(shí)測(cè)過GD32F103在跑AS608串口通信時(shí)完全沒問題但如果你用了USB DFU升級(jí)功能可能就需要額外調(diào)試。所以建議第一版還是用原廠STM32F103C8T6把邏輯跑通后面再考慮換國產(chǎn)降本。OLED模塊這里有個(gè)坑要提前說市面上0.96寸OLED有I2C和SPI兩種I2C版本又分地址0x78和0x7A兩種。買的時(shí)候一定要問清楚或者自己用I2C掃描程序確認(rèn)地址。我遇到過一批模塊標(biāo)稱0x78實(shí)際是0x7A的調(diào)了半天以為是驅(qū)動(dòng)問題結(jié)果是地址錯(cuò)了。另外OLED的供電電壓一般是3.3V但有些模塊標(biāo)稱5V tolerant實(shí)際接5V時(shí)間長了會(huì)燒建議統(tǒng)一用3.3V供電。1.3 軟件架構(gòu)HAL庫還是標(biāo)準(zhǔn)庫這個(gè)問題在STM32社區(qū)里爭(zhēng)論了很多年。我的建議很明確新項(xiàng)目一律用HAL庫。原因有三第一ST現(xiàn)在主推HAL新芯片只提供HAL支持第二HAL的抽象層讓代碼在不同F(xiàn)1、F4、H7系列之間移植變得容易第三CubeMX工具可以自動(dòng)生成初始化代碼省去大量查手冊(cè)配寄存器的時(shí)間。但HAL庫也有它的代價(jià)——代碼體積大、執(zhí)行效率略低。對(duì)于F103C8T6這種64KB Flash的芯片如果全用HAL庫加上OLED驅(qū)動(dòng)和AS608協(xié)議棧編譯出來大概占30-40KB還剩一半空間夠用。如果你實(shí)在在意那點(diǎn)效率可以在關(guān)鍵路徑上直接用寄存器操作比如串口中斷里的數(shù)據(jù)搬運(yùn)。但整體架構(gòu)還是建議HAL搭臺(tái)局部優(yōu)化。FreeRTOS要不要上對(duì)于這個(gè)項(xiàng)目我的看法是如果你只是做指紋錄入和識(shí)別裸機(jī)跑前后臺(tái)架構(gòu)完全夠用。主循環(huán)里輪詢AS608狀態(tài)、刷新OLED、檢測(cè)按鍵邏輯簡(jiǎn)單清晰。但如果你后續(xù)要加聯(lián)網(wǎng)、加多用戶管理、加日志存儲(chǔ)那FreeRTOS就值得上了。任務(wù)劃分可以這樣一個(gè)任務(wù)專門處理AS608通信阻塞式收發(fā)一個(gè)任務(wù)刷OLED定時(shí)刷新一個(gè)任務(wù)處理按鍵和業(yè)務(wù)邏輯。任務(wù)間用消息隊(duì)列傳遞指紋ID和識(shí)別結(jié)果。2. 核心硬件連接與底層驅(qū)動(dòng)要點(diǎn)2.1 STM32F103C8T6最小系統(tǒng)板引腳分配先把手上的板子理清楚。F103C8T6最小系統(tǒng)板通常引出所有GPIO但有些板子會(huì)把PB3、PB4、PA15這幾個(gè)JTAG引腳默認(rèn)占用如果你要用它們做普通IO需要先禁用JTAG功能。我一般習(xí)慣這樣分配USART1PA9/PA10接AS608模塊。PA9是TX接模塊的RXPA10是RX接模塊的TX。注意交叉連接TX對(duì)RXRX對(duì)TX這是串口通信最基本的規(guī)則但新手經(jīng)常接錯(cuò)。I2C1PB6/PB7接OLED。PB6是SCLPB7是SDA。這兩個(gè)引腳需要外接4.7kΩ上拉電阻到3.3V。有些OLED模塊自帶上拉但為了穩(wěn)定我建議還是在MCU端加上。PA0接一個(gè)按鍵用于觸發(fā)指紋錄入模式。按鍵另一端接地PA0配置為上拉輸入按下時(shí)讀到低電平。PC13板載LED用于指示系統(tǒng)運(yùn)行狀態(tài)。這個(gè)引腳在最小系統(tǒng)板上通常已經(jīng)焊好LED低電平點(diǎn)亮。PA2/PA3預(yù)留作為調(diào)試串口接USB轉(zhuǎn)TTL模塊方便打印日志。這里有個(gè)細(xì)節(jié)AS608模塊的供電是3.3V但它的邏輯電平也是3.3V所以直接跟STM32的串口對(duì)接沒問題。如果你用的是5V的AS608模塊有些老版本是5V供電那TX/RX需要電平轉(zhuǎn)換否則可能燒掉STM32的串口引腳。買模塊的時(shí)候一定要確認(rèn)供電電壓。2.2 AS608串口通信協(xié)議拆解AS608的通信協(xié)議說簡(jiǎn)單也簡(jiǎn)單說復(fù)雜也復(fù)雜。簡(jiǎn)單在于它就是一個(gè)標(biāo)準(zhǔn)的串口命令-應(yīng)答模式復(fù)雜在于它的數(shù)據(jù)包格式有嚴(yán)格的校驗(yàn)和而且不同命令的應(yīng)答長度不一樣。一個(gè)完整的命令包格式是這樣的字段長度說明包頭2字節(jié)固定為0xEF01芯片地址4字節(jié)默認(rèn)0xFFFFFFFF包標(biāo)識(shí)1字節(jié)0x01表示命令0x02表示數(shù)據(jù)0x08表示結(jié)束包長度2字節(jié)從包標(biāo)識(shí)到校驗(yàn)和的總長度指令/數(shù)據(jù)N字節(jié)具體命令碼和參數(shù)校驗(yàn)和2字節(jié)從包標(biāo)識(shí)到數(shù)據(jù)末尾的累加和舉個(gè)例子讓AS608模塊自動(dòng)采集指紋并生成特征命令碼是0x01后面跟一個(gè)參數(shù)0x01表示采集到緩沖區(qū)1。整個(gè)包就是EF01 FFFFFFFF 01 0004 01 01 0005。最后兩個(gè)字節(jié)0005是校驗(yàn)和計(jì)算方法是0100040101 07不對(duì)這里要仔細(xì)算。實(shí)際計(jì)算包標(biāo)識(shí)0x01 包長度高字節(jié)0x00 包長度低字節(jié)0x04 指令0x01 參數(shù)0x01 0x07。但校驗(yàn)和是兩個(gè)字節(jié)高字節(jié)是0x00低字節(jié)是0x07。所以完整包是EF01 FFFFFFFF 01 0004 01 01 0007。這個(gè)校驗(yàn)和計(jì)算是新手最容易出錯(cuò)的地方。我建議寫一個(gè)專門的函數(shù)來處理打包和校驗(yàn)不要每次手動(dòng)算。下面是一個(gè)參考實(shí)現(xiàn)void AS608_SendCmd(uint8_t cmd, uint8_t *param, uint16_t paramLen) { uint8_t buf[64]; uint16_t idx 0; uint16_t sum 0; buf[idx] 0xEF; buf[idx] 0x01; buf[idx] 0xFF; buf[idx] 0xFF; buf[idx] 0xFF; buf[idx] 0xFF; buf[idx] 0x01; // 包標(biāo)識(shí)命令 uint16_t pkgLen paramLen 3; // 包標(biāo)識(shí)包長度指令參數(shù)校驗(yàn)和 buf[idx] (pkgLen 8) 0xFF; buf[idx] pkgLen 0xFF; buf[idx] cmd; for (uint16_t i 0; i paramLen; i) { buf[idx] param[i]; } // 計(jì)算校驗(yàn)和從包標(biāo)識(shí)開始到參數(shù)末尾 for (uint16_t i 6; i idx; i) { sum buf[i]; } buf[idx] (sum 8) 0xFF; buf[idx] sum 0xFF; HAL_UART_Transmit(huart1, buf, idx, 1000); }接收解析稍微麻煩一點(diǎn)因?yàn)锳S608的應(yīng)答包長度不固定。我的做法是先等包頭0xEF01然后收完剩下的字節(jié)根據(jù)包長度字段確定總長度最后校驗(yàn)。接收可以用中斷環(huán)形緩沖區(qū)的方式也可以用DMA空閑中斷。對(duì)于F103C8T6我推薦DMA空閑中斷效率高且不占CPU。2.3 OLED I2C驅(qū)動(dòng)移植與漢字顯示OLED驅(qū)動(dòng)這塊網(wǎng)上有很多現(xiàn)成的代碼但質(zhì)量參差不齊。我建議自己移植一份干凈的SSD1306驅(qū)動(dòng)核心函數(shù)就幾個(gè)初始化、寫命令、寫數(shù)據(jù)、刷屏、清屏。I2C通信可以用HAL庫的HAL_I2C_Mem_Write也可以用軟件模擬I2C。硬件I2C在F103上有個(gè)歷史遺留問題——某些批次的芯片I2C外設(shè)有bug容易卡死。如果你遇到了別懷疑自己換軟件I2C就行。軟件I2C的代碼很簡(jiǎn)單就是手動(dòng)翻轉(zhuǎn)SCL和SDAvoid I2C_Start(void) { SDA_HIGH(); SCL_HIGH(); delay_us(2); SDA_LOW(); delay_us(2); SCL_LOW(); delay_us(2); }OLED顯示漢字需要取模。常用的取模軟件是PCtoLCD2002設(shè)置方式陰碼、逐列式、順向、C51格式。取出來的數(shù)組直接放到代碼里用OLED_ShowChinese函數(shù)顯示。注意漢字是16x16像素一個(gè)漢字占32字節(jié)。如果你要顯示多個(gè)漢字建議做一個(gè)漢字索引表用Unicode碼或者自定義編碼來查找不然代碼里全是硬編碼的數(shù)組維護(hù)起來很痛苦。注意OLED初始化之前一定要給足延時(shí)特別是上電后的復(fù)位時(shí)間。我遇到過一批模塊上電后立刻發(fā)命令沒反應(yīng)延時(shí)100ms后就正常了。SSD1306數(shù)據(jù)手冊(cè)里寫的是VCC穩(wěn)定后至少延時(shí)100ms再發(fā)命令。3. 指紋錄入與識(shí)別完整實(shí)現(xiàn)3.1 指紋錄入流程的每一步拆解指紋錄入不是一步完成的AS608的流程是采集圖像→生成特征→與緩沖區(qū)比對(duì)→存儲(chǔ)到指定ID。每一步都是一個(gè)獨(dú)立的串口命令需要等上一步成功后才能進(jìn)行下一步。第一步采集圖像。發(fā)送命令0x01參數(shù)0x01表示采集到緩沖區(qū)1。模塊返回0x00表示成功返回0x02表示傳感器上沒有手指返回0x03表示圖像太干或太濕。這里有個(gè)實(shí)操技巧手指按下去之后不要馬上松開保持1-2秒讓模塊有足夠時(shí)間采集到清晰的圖像。AS608的采集時(shí)間大概在0.5秒左右但如果你手指抖動(dòng)可能需要重試。第二步生成特征。發(fā)送命令0x02參數(shù)0x01表示從緩沖區(qū)1生成特征。模塊返回0x00表示成功返回0x06表示圖像太亂無法生成特征返回0x07表示特征點(diǎn)太少。這一步失敗通常是因?yàn)槭种柑苫蛘甙吹锰p讓用戶重新按一次就行。第三步再次采集并生成特征到緩沖區(qū)2。為什么要采兩次因?yàn)锳S608需要比對(duì)兩次采集的特征是否一致確保錄入的指紋質(zhì)量可靠。這一步跟第一步、第二步一樣只是緩沖區(qū)換成2。第四步比對(duì)兩個(gè)緩沖區(qū)的特征。發(fā)送命令0x03模塊返回0x00表示兩個(gè)特征匹配返回0x08表示不匹配。如果不匹配說明兩次按的手指位置差異太大需要重新錄入。第五步存儲(chǔ)模板。發(fā)送命令0x06參數(shù)是緩沖區(qū)編號(hào)和要存儲(chǔ)的ID號(hào)。比如存儲(chǔ)到ID 1參數(shù)就是0x01 0x00 0x01緩沖區(qū)1ID高字節(jié)0x00ID低字節(jié)0x01。模塊返回0x00表示存儲(chǔ)成功返回0x01表示ID已存在返回0x0B表示ID超出范圍。整個(gè)流程走下來如果一切順利大概需要3-5秒。如果中間某一步失敗需要從失敗的那一步重新開始而不是從頭再來。我建議在代碼里用一個(gè)狀態(tài)機(jī)來管理這個(gè)流程每個(gè)狀態(tài)對(duì)應(yīng)一個(gè)命令收到成功應(yīng)答就跳到下一個(gè)狀態(tài)收到失敗應(yīng)答就回到指定狀態(tài)重試。3.2 指紋識(shí)別與搜索的代碼實(shí)現(xiàn)識(shí)別流程比錄入簡(jiǎn)單采集圖像→生成特征→在指紋庫中搜索。搜索命令是0x04參數(shù)是緩沖區(qū)編號(hào)和搜索起始ID、搜索數(shù)量。模塊返回0x00表示搜索到匹配指紋同時(shí)返回匹配的ID號(hào)返回0x09表示沒搜索到。這里有個(gè)性能問題如果指紋庫里存了很多指紋搜索時(shí)間會(huì)變長。AS608的搜索速度大概是每枚指紋10ms左右100枚指紋就是1秒。對(duì)于考勤機(jī)這種場(chǎng)景1秒的等待是可以接受的但如果你要做得更流暢可以考慮把常用指紋放在前面或者用1:N識(shí)別加1:1驗(yàn)證的組合方式。代碼實(shí)現(xiàn)上我建議把指紋操作封裝成幾個(gè)獨(dú)立函數(shù)uint8_t AS608_GenChar(uint8_t bufferId); uint8_t AS608_Search(uint8_t bufferId, uint16_t startId, uint16_t count, uint16_t *matchId); uint8_t AS608_Store(uint8_t bufferId, uint16_t id); uint8_t AS608_Delete(uint16_t id);每個(gè)函數(shù)內(nèi)部負(fù)責(zé)發(fā)送命令、等待應(yīng)答、解析結(jié)果。返回值統(tǒng)一用0x00表示成功其他值表示錯(cuò)誤碼。這樣上層業(yè)務(wù)邏輯就很清晰如果AS608_Search返回0x00就從matchId里取匹配的ID然后執(zhí)行開鎖動(dòng)作。實(shí)操心得AS608的串口波特率默認(rèn)是57600但你可以通過命令改成115200甚至更高。我實(shí)測(cè)115200下通信很穩(wěn)定搜索響應(yīng)也更快。改波特率之后記得把STM32的串口配置也改掉否則就通信不上了。3.3 OLED界面設(shè)計(jì)與交互邏輯OLED界面不需要花哨但要清晰。我一般設(shè)計(jì)三個(gè)頁面待機(jī)頁面、錄入頁面、識(shí)別結(jié)果頁面。待機(jī)頁面顯示“請(qǐng)按手指”和當(dāng)前指紋庫容量比如“已錄入5枚”。錄入頁面顯示當(dāng)前錄入步驟比如“請(qǐng)按手指...”、“請(qǐng)?jiān)侔匆淮?..”、“錄入成功”。識(shí)別結(jié)果頁面顯示“識(shí)別成功 ID:1”或“識(shí)別失敗”。按鍵交互方面PA0按鍵短按進(jìn)入錄入模式長按3秒刪除所有指紋。刪除所有指紋的命令是0x05參數(shù)是0x00 0x00 0x00 0x64起始ID 0數(shù)量100。這個(gè)操作要加確認(rèn)機(jī)制不然誤觸就麻煩了。OLED刷新頻率不需要太高200ms刷一次就夠了。刷太快反而可能導(dǎo)致I2C總線繁忙影響AS608的串口通信。我試過在中斷里刷OLED結(jié)果串口數(shù)據(jù)丟了后來改成主循環(huán)里定時(shí)刷就穩(wěn)定了。4. 調(diào)試過程中踩過的坑與排查技巧4.1 串口通信不穩(wěn)定的常見原因第一個(gè)坑串口接收丟數(shù)據(jù)。AS608返回的應(yīng)答包有時(shí)候比較長比如搜索成功的應(yīng)答有十幾字節(jié)。如果你用HAL_UART_Receive阻塞接收指定長度不對(duì)就會(huì)超時(shí)或者丟包。我的做法是用DMA接收配合空閑中斷判斷一幀結(jié)束。具體配置開啟USART1的DMA接收緩沖區(qū)設(shè)64字節(jié)在HAL_UARTEx_RxEventCallback里處理完整幀。第二個(gè)坑校驗(yàn)和計(jì)算錯(cuò)誤。前面說過校驗(yàn)和是從包標(biāo)識(shí)開始累加不包括包頭和芯片地址。我見過有人從包頭開始算結(jié)果怎么都不對(duì)。還有一個(gè)細(xì)節(jié)校驗(yàn)和是兩個(gè)字節(jié)高字節(jié)在前低字節(jié)在后。如果你只發(fā)一個(gè)字節(jié)的校驗(yàn)和模塊會(huì)認(rèn)為包不完整。第三個(gè)坑波特率不匹配。AS608出廠默認(rèn)57600但有些商家發(fā)貨前會(huì)改成9600或115200。如果你發(fā)現(xiàn)發(fā)命令沒反應(yīng)先用示波器或者邏輯分析儀看一下TX線上的波形確認(rèn)波特率。沒有儀器的話寫個(gè)簡(jiǎn)單的串口回環(huán)測(cè)試發(fā)什么收什么確認(rèn)STM32的串口配置是對(duì)的。4.2 OLED點(diǎn)不亮的排查思路OLED點(diǎn)不亮的原因太多了我按概率從高到低列一下供電問題3.3V有沒有電流夠不夠OLED全亮?xí)r大概20mA有些最小系統(tǒng)板的3.3V LDO帶不動(dòng)電壓會(huì)掉到2.8V以下OLED就不亮了。用萬用表量一下OLED的VCC引腳。I2C地址錯(cuò)誤0x78還是0x7A寫個(gè)I2C掃描程序把總線上所有應(yīng)答的地址打印出來。初始化序列不對(duì)不同批次的SSD1306初始化序列可能有差異。如果點(diǎn)不亮試試通用的初始化序列或者用賣家提供的例程。接線錯(cuò)誤SCL和SDA接反了這個(gè)錯(cuò)誤太常見了我至少犯過三次。I2C的SCL是時(shí)鐘線SDA是數(shù)據(jù)線別搞混。上拉電阻缺失I2C總線需要上拉電阻一般是4.7kΩ。有些模塊自帶有些不帶。用萬用表量一下SCL和SDA對(duì)VCC的電阻如果是無窮大說明沒上拉。4.3 指紋識(shí)別率低的優(yōu)化方法識(shí)別率低通常不是模塊的問題而是使用方式的問題。我總結(jié)了幾條經(jīng)驗(yàn)第一手指要干凈。油污、水漬、灰塵都會(huì)影響光學(xué)采集。讓用戶在識(shí)別前擦一下手指識(shí)別率能提升不少。第二按壓力度要適中。太輕了采集不到足夠的特征點(diǎn)太重了手指變形也會(huì)影響。一般按到指紋紋路清晰可見就行。第三錄入時(shí)多采幾個(gè)角度。同一個(gè)手指正面按一次稍微左偏按一次稍微右偏按一次這樣生成的模板適應(yīng)性更強(qiáng)。AS608支持同一ID存儲(chǔ)多個(gè)模板你可以把三個(gè)角度的特征都存到同一個(gè)ID下。第四定期清理傳感器表面。光學(xué)傳感器表面容易積灰用眼鏡布擦一下就行。如果表面有劃痕識(shí)別率會(huì)明顯下降那就只能換模塊了。4.4 常見問題速查表現(xiàn)象可能原因排查方法發(fā)命令無應(yīng)答波特率不對(duì)、接線錯(cuò)誤、模塊未供電檢查TX/RX是否交叉、量模塊VCC電壓、試不同波特率應(yīng)答校驗(yàn)和錯(cuò)誤校驗(yàn)和計(jì)算范圍不對(duì)確認(rèn)從包標(biāo)識(shí)開始累加高字節(jié)在前指紋錄入總是失敗手指太干/太濕、按壓力度不對(duì)讓用戶哈口氣再按、調(diào)整按壓位置OLED顯示亂碼取模方式不對(duì)、I2C速率太高確認(rèn)取模設(shè)置為陰碼逐列順向、降低I2C速率到100kHz識(shí)別成功但繼電器不動(dòng)作GPIO配置錯(cuò)誤、繼電器驅(qū)動(dòng)電路問題量GPIO輸出電平、檢查繼電器線圈電壓系統(tǒng)運(yùn)行一段時(shí)間后死機(jī)堆棧溢出、看門狗未喂增大??臻g、檢查HardFault、加獨(dú)立看門狗5. 項(xiàng)目擴(kuò)展與進(jìn)階方向5.1 加聯(lián)網(wǎng)功能ESP8266或ESP32做WiFi網(wǎng)關(guān)指紋識(shí)別只是入口數(shù)據(jù)上傳才是價(jià)值。加一個(gè)ESP8266模塊通過AT指令跟STM32串口通信把識(shí)別記錄上傳到服務(wù)器。STM32這邊只需要在識(shí)別成功后往另一個(gè)串口發(fā)一條JSON格式的記錄ESP8266負(fù)責(zé)轉(zhuǎn)發(fā)。注意ESP8266的AT指令響應(yīng)時(shí)間不確定建議用狀態(tài)機(jī)超時(shí)重試的方式不要阻塞主循環(huán)。5.2 加FreeRTOS做多任務(wù)管理如果項(xiàng)目功能變復(fù)雜裸機(jī)的前后臺(tái)架構(gòu)會(huì)越來越難維護(hù)。上FreeRTOS之后可以這樣劃分任務(wù)Task_AS608優(yōu)先級(jí)最高負(fù)責(zé)指紋模塊的收發(fā)和狀態(tài)機(jī)。Task_OLED優(yōu)先級(jí)中等每200ms刷新一次顯示。Task_Key優(yōu)先級(jí)中等檢測(cè)按鍵發(fā)送事件到隊(duì)列。Task_Logic優(yōu)先級(jí)最低處理業(yè)務(wù)邏輯比如識(shí)別成功后開鎖、記錄日志。任務(wù)間用消息隊(duì)列傳遞指紋ID和事件類型用信號(hào)量保護(hù)共享資源比如OLED顯示緩沖區(qū)。FreeRTOS在F103C8T6上跑完全沒問題20KB SRAM夠用但要注意每個(gè)任務(wù)的??臻g不要設(shè)太大128字512字節(jié)起步根據(jù)實(shí)際使用調(diào)整。5.3 低功耗設(shè)計(jì)電池供電場(chǎng)景如果要做電池供電的指紋鎖低功耗就是剛需。F103C8T6有睡眠、停止、待機(jī)三種低功耗模式。指紋模塊不工作時(shí)可以發(fā)命令讓它進(jìn)入休眠OLED也可以關(guān)閉顯示。STM32本身在停止模式下功耗大概20uA喚醒源可以配置為按鍵中斷或串口接收中斷。具體做法主循環(huán)里如果沒有任務(wù)就調(diào)用__WFI()進(jìn)入睡眠。AS608模塊在空閑時(shí)發(fā)0x00命令進(jìn)入休眠需要識(shí)別時(shí)再發(fā)命令喚醒。OLED用命令0xAE關(guān)閉顯示0xAF打開顯示。這樣整機(jī)待機(jī)電流可以做到1mA以下用2000mAh電池能撐好幾個(gè)月。5.4 指紋數(shù)據(jù)加密存儲(chǔ)的考慮如果項(xiàng)目涉及多用戶指紋數(shù)據(jù)安全就不能忽視。AS608模塊內(nèi)部存儲(chǔ)的指紋模板是特征數(shù)據(jù)不是原始圖像泄露風(fēng)險(xiǎn)相對(duì)較低。但如果你把指紋ID和用戶信息存在STM32的Flash里建議做簡(jiǎn)單的加密比如AES-128。STM32F103C8T6沒有硬件加密引擎軟件AES大概占2KB Flash速度也夠用。密鑰可以存在芯片的選項(xiàng)字節(jié)里或者用外部加密芯片。注意指紋數(shù)據(jù)屬于個(gè)人生物特征信息在項(xiàng)目落地時(shí)務(wù)必遵守相關(guān)數(shù)據(jù)保護(hù)規(guī)范做好告知和授權(quán)不要隨意上傳或共享原始數(shù)據(jù)。6. 寫在最后的一些個(gè)人體會(huì)這個(gè)項(xiàng)目我從畫原理圖到跑通完整流程大概花了一周時(shí)間其中調(diào)試串口通信和OLED顯示占了大半。最大的感受是嵌入式開發(fā)里硬件問題往往比軟件問題更難查。軟件錯(cuò)了可以單步調(diào)試硬件錯(cuò)了只能靠示波器和萬用表一點(diǎn)點(diǎn)量。另外AS608這個(gè)模塊雖然資料多但不同批次的固件版本有差異有些命令的返回值可能跟手冊(cè)不完全一致。遇到這種情況別死磕手冊(cè)用串口助手發(fā)命令實(shí)測(cè)一下以實(shí)際返回為準(zhǔn)。我遇到過一批模塊搜索命令返回的ID號(hào)字節(jié)序跟手冊(cè)相反后來在代碼里做了兼容處理才搞定。最后說一句指紋識(shí)別這個(gè)方向技術(shù)本身已經(jīng)很成熟了難點(diǎn)不在算法而在工程細(xì)節(jié)——怎么讓用戶按得舒服、怎么讓識(shí)別率穩(wěn)定、怎么讓系統(tǒng)長時(shí)間運(yùn)行不出問題。這些經(jīng)驗(yàn)只有真正動(dòng)手做過才能積累下來。