一、項目背景
門禁系統(tǒng)是現(xiàn)代社會中非常重要的安全控制系統(tǒng)之一,其功能是在保障建筑物安全的同時,為合法用戶提供便利。當(dāng)前設(shè)計一種基于STM32+RC522的門禁系統(tǒng)設(shè)計方案,通過RFID-RC522模塊實現(xiàn)了對用戶卡的注冊、識別及身份驗證,通過控制SG90舵機(jī)實現(xiàn)門鎖的開關(guān),具有較高的安全性和可靠性。實驗結(jié)果表明,該門禁系統(tǒng)可以有效地保障建筑物的安全性。
門禁系統(tǒng)廣泛應(yīng)用于各種建筑物、企事業(yè)單位,用于管理人員的進(jìn)出、控制人員活動范圍、實現(xiàn)安全監(jiān)控等功能。傳統(tǒng)的門禁系統(tǒng)采用密碼輸入或刷卡的方式進(jìn)行身份驗證,但存在易被破解的風(fēng)險。基于RFID的門禁系統(tǒng)已經(jīng)成為一種相對先進(jìn)的安全控制方案。
本次設(shè)計的STM32+RC522門禁系統(tǒng),通過RFID-RC522模塊對用戶的卡進(jìn)行注冊、識別完成身份識別,對門鎖進(jìn)行開關(guān)。系統(tǒng)帶了OLED顯示屏,輸入用戶密碼登錄之后,可以對新卡片進(jìn)行注冊,添加新卡片,對不使用的卡片進(jìn)行注銷。在系統(tǒng)里,IC卡的數(shù)據(jù)都存儲在卡的內(nèi)部扇區(qū)里,通過卡的內(nèi)部空間進(jìn)行管理。
采用5V-步進(jìn)電機(jī)的版本:
二、系統(tǒng)設(shè)計
門禁系統(tǒng)由STM32F103C8T6單片機(jī)、RFID-RC522模塊、SG90舵機(jī)、LCD1602液晶顯示屏、鍵盤模塊等組成。其中,STM32F103C8T6單片機(jī)作為系統(tǒng)的核心控制器,控制程序的執(zhí)行;RFID-RC522模塊作為識別用戶卡片的設(shè)備;SG90舵機(jī)作為門鎖控制設(shè)備;OLED顯示屏提供用戶輸入信息和系統(tǒng)信息的顯示;鍵盤模塊方便用戶進(jìn)行密碼和卡片信息的輸入。
2.1 軟件設(shè)計
【1】RFID卡信息管理
本系統(tǒng)采用卡的內(nèi)部空間進(jìn)行IC卡信息的管理。每個IC卡可以分為多個扇區(qū),每個扇區(qū)包含多個塊,每個塊包含16個字節(jié)。扇區(qū)0是廠家已經(jīng)預(yù)留好的,用于存儲卡片的序列號,扇區(qū)1-15可以由用戶自己配置,用于存儲一些私有數(shù)據(jù),如用戶身份、車牌號、員工編號等。
在本系統(tǒng)中,IC卡信息的管理主要包括三個方面:新卡片注冊、卡片識別和注銷卡片。
對于新卡片的注冊,用戶需要按下鍵盤上的“#”鍵進(jìn)入注冊模式,接著輸入管理員密碼,然后將新卡放到RFID讀寫器上,系統(tǒng)將讀取卡片序列號,并在卡片的扇區(qū)中存儲用戶名和密碼信息等。
對于卡片的識別,當(dāng)用戶按下門禁系統(tǒng)的確認(rèn)鍵時,系統(tǒng)將讀取RFID模塊中讀取的卡片序列號,并去卡片扇區(qū)中查詢用戶名和密碼信息,進(jìn)行身份驗證。如果卡片識別成功,系統(tǒng)將控制舵機(jī)旋轉(zhuǎn)一圈實現(xiàn)開鎖功能。
對于注銷卡片,管理員需要輸入密碼進(jìn)行身份驗證后,再將要注銷的卡片放到RFID讀寫器上,系統(tǒng)將清空該卡片的扇區(qū)內(nèi)所有數(shù)據(jù)。
【2】門禁系統(tǒng)安全控制
本門禁系統(tǒng)采用密碼驗證和卡片識別相結(jié)合的方式,提高了系統(tǒng)的安全性。具體來說,系統(tǒng)要求用戶輸入密碼或刷卡進(jìn)行身份驗證,只有在驗證成功后才能控制門鎖進(jìn)行開關(guān)操作。同時,系統(tǒng)還可以記錄每一次開啟門鎖的時間和用戶信息,以便管理員進(jìn)行安全監(jiān)控。
【3】門鎖控制
本門禁系統(tǒng)采用SG90舵機(jī)控制門鎖的開關(guān),具有結(jié)構(gòu)簡單,控制方便的優(yōu)點。在門鎖控制過程中,系統(tǒng)對舵機(jī)控制信號的頻率和占空比進(jìn)行精細(xì)控制,以實現(xiàn)門鎖的準(zhǔn)確開關(guān)。
2.2 硬件設(shè)計
【1】STM32F103C8T6單片機(jī)
STM32F103C8T6單片機(jī)是ST公司推出的一款基于Cortex-M3內(nèi)核的可編程32位單片機(jī),常常被廣泛應(yīng)用于工業(yè)控制、智能家居、嵌入式控制等領(lǐng)域。
它的主要特點包括:
?
?1. Cortex-M3內(nèi)核:STM32F103C8T6使用Cortex-M3內(nèi)核,具有高性能、低功耗、硬實時等特點,可支持多個串口、I2C、SPI、USB等外設(shè),為使用者帶來更大的靈活性。 ?2. 32位處理能力:STM32F103C8T6是一款32位單片機(jī),具有比8位、16位單片機(jī)更高的數(shù)據(jù)運(yùn)算能力、編程靈活度和計算精度。 ?3. 較強(qiáng)的系統(tǒng)時間管理能力:STM32F103C8T6內(nèi)部具備RTC實時時鐘模塊,可實現(xiàn)精準(zhǔn)的時間管理和時間標(biāo)記功能,在一些需要時間同步的應(yīng)用場景下具有較大的優(yōu)勢。 ?4. 大存儲容量:STM32F103C8T6內(nèi)置64K字節(jié)的閃存和20K字節(jié)的SRAM,能夠滿足大型嵌入式應(yīng)用的存儲需求。 ?5. 豐富的外設(shè)接口:STM32F103C8T6支持多個外設(shè)接口,如SPI、I2C、CAN總線等,方便開發(fā)者擴(kuò)展相關(guān)應(yīng)用場景。 ?6. 代碼可移植性強(qiáng):由于該芯片應(yīng)用廣泛,可以使用多種開發(fā)工具進(jìn)行開發(fā),例如Keil、STM32CubeMX等,而且支持多種編程語言,如C語言、C++等,因此優(yōu)點很容易在不同的平臺、不同開發(fā)者之間實現(xiàn)代碼的移植。
?
【2】RFID-RC522模塊
RFID-RC522模塊是一種低成本、高性價比的RFID讀寫模塊。它具有高精度、快速讀取等特點,廣泛應(yīng)用于門禁系統(tǒng)、智能卡管理、物流追蹤等領(lǐng)域。
RFID-RC522模塊的特點如下:
?
?1. 高精度:RFID-RC522模塊采用射頻感應(yīng)技術(shù)進(jìn)行信號傳輸和讀寫,具有高精度、穩(wěn)定性強(qiáng)等優(yōu)點。 ?2. 快速讀取:RFID-RC522模塊讀取速度快,一般只需0.1秒左右就可以完成讀取操作。 ?3. 支持多種協(xié)議:RFID-RC522模塊支持ISO14443A/B、FeliCa等多種RFID協(xié)議,可滿足不同應(yīng)用場合的需求。 ?4. 低功耗:RFID-RC522模塊功耗低,工作電流為13-26mA,待機(jī)電流為10A。 ?5. 接口簡單:RFID-RC522模塊采用SPI接口進(jìn)行通信,模塊上的引腳有7個,具有很好的兼容性。 ?6. 支持多種開發(fā)語言:RFID-RC522模塊支持多種開發(fā)語言,如C++、Python等,方便開發(fā)者進(jìn)行二次開發(fā)。
?
RFID-RC522模塊的使用需要配合相關(guān)的庫文件,在Arduino、Raspberry Pi等開發(fā)板上進(jìn)行代碼編寫和開發(fā)。常見的使用場景包括門禁系統(tǒng)、智能卡管理、出入庫管理、物流追蹤等領(lǐng)域。
【3】SG90舵機(jī)
該舵機(jī)小巧耐用,可以精確地控制門鎖的開關(guān)。
SG90舵機(jī)是一種小型舵機(jī),體積小、重量輕、價格低廉,常常被用于模型飛機(jī)、小型機(jī)械臂、玩具模型等領(lǐng)域。它采用了直流電機(jī),利用PID控制技術(shù),以及精密的小齒輪減速箱實現(xiàn)轉(zhuǎn)向角的控制。
SG90舵機(jī)的特點如下:
?
1. 采用IIC總線通信:IIC接口的4x4電容矩陣鍵盤模塊通過IIC總線通信連接到MCU,簡化了連接方式,方便使用。 2. 采用電容式按鍵設(shè)計:每個按鍵上放置一個電容器,當(dāng)手指觸摸到按鍵時,電容器的電容值發(fā)生變化,通過檢測電容的變化實現(xiàn)按鍵檢測。 3. 4x4矩陣排列式設(shè)計:4x4電容矩陣鍵盤模塊采用矩陣排列式設(shè)計,一共有16個按鍵,可以滿足較為復(fù)雜的應(yīng)用場景。 4. 接口簡單:IIC接口的4x4電容矩陣鍵盤模塊只需要SCL和SDA兩條線連接到MCU即可。 5. 高靈敏度:電容式按鍵設(shè)計使得按鍵檢測更加靈敏,而且不會產(chǎn)生按鍵輕微彈起的誤觸情況,使用更加舒適。 6. 代碼簡潔:使用該模塊并不需要編寫復(fù)雜的按鍵掃描程序,只需要通過讀取IIC總線上的按鍵值即可。
?
SG90舵機(jī)在使用時需要通過PWM信號進(jìn)行控制。
【4】0.96寸OLED顯示屏
0.96寸SPI接口OLED顯示屏是一種小型化的屏幕,屬于OLED顯示技術(shù),采用SPI接口連接,外觀尺寸約為12mm * 12mm,分辨率一般為128 * 64或者128 * 32。它可以用于各種小型電子設(shè)備,例如手持設(shè)備、小型儀器、智能家居控制面板等等。
OLED即有機(jī)發(fā)光二極管,與傳統(tǒng)的液晶顯示屏相比,OLED具有響應(yīng)速度快、視角范圍廣、色彩鮮艷、亮度高等優(yōu)勢。SPI接口則是一種串行外設(shè)接口,具有簡單、靈活、高速等特點。
0.96寸SPI接口OLED顯示屏的驅(qū)動芯片一般為SSD1306,有128個列和64個行的像素,還有一些有128個列和32個行的像素。其中,128 * 64像素的屏幕顯示面積較大,在顯示圖像和文字時更加清晰和細(xì)膩。0.96寸SPI接口OLED顯示屏具有小巧、高清、高速等優(yōu)點,被廣泛使用在各種小型電子設(shè)備中。
【5】鍵盤模塊
該模塊可以方便地輸入密碼和卡片信息。
IIC接口的4x4電容矩陣鍵盤模塊是一種基于IIC總線通信的電容式按鍵模塊,常常被應(yīng)用在工控、家電、醫(yī)療器械等領(lǐng)域。
它的主要特點包括:
?1. 采用IIC總線通信:IIC接口的4x4電容矩陣鍵盤模塊通過IIC總線通信連接到MCU,簡化了連接方式,方便使用。 ?2. 采用電容式按鍵設(shè)計:每個按鍵上放置一個電容器,當(dāng)手指觸摸到按鍵時,電容器的電容值發(fā)生變化,通過檢測電容的變化實現(xiàn)按鍵檢測。 ?3. 4x4矩陣排列式設(shè)計:4x4電容矩陣鍵盤模塊采用矩陣排列式設(shè)計,一共有16個按鍵,可以滿足較為復(fù)雜的應(yīng)用場景。 ?4. 接口簡單:IIC接口的4x4電容矩陣鍵盤模塊只需要SCL和SDA兩條線連接到MCU即可。 ?5. 高靈敏度:電容式按鍵設(shè)計使得按鍵檢測更加靈敏,而且不會產(chǎn)生按鍵輕微彈起的誤觸情況,使用更加舒適。 ?6. 代碼簡潔:使用該模塊并不需要編寫復(fù)雜的按鍵掃描程序,只需要通過讀取IIC總線上的按鍵值即可。
IIC接口的4x4電容矩陣鍵盤模塊是一種方便易用、高靈敏度的按鍵模塊,通過電容式按鍵設(shè)計實現(xiàn)按鍵的檢測和響應(yīng),并且通過IIC總線通信簡化了連接方式。它適合于應(yīng)用于許多領(lǐng)域,如工控、家電和醫(yī)療器械等,能夠為使用者的產(chǎn)品帶來更為方便和高效的控制方式。
三、核心代碼
3.1 SG90舵機(jī)控制代碼
下面是基于GPIO模擬時序控制STM32F103C8T6驅(qū)動SG90舵機(jī)旋轉(zhuǎn)指定的角度的代碼,并封裝成子函數(shù)調(diào)用。
?
#include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "delay.h" ? #define Servo_pin GPIO_Pin_5 #define Servo_port GPIOA ? void SG90_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); ? GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = Servo_pin; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Servo_port, &GPIO_InitStructure); } ? void SG90_SetAngle(uint8_t angle) { if(angle>180) angle=180; if(angle<0) angle = 0; ? uint8_t temp = angle/2 + 15; ? for(int i=0;i<5;i++) { GPIO_SetBits(Servo_port, Servo_pin); delay_us(temp); GPIO_ResetBits(Servo_port, Servo_pin); delay_us(20000-temp); } } ? int main(void) { SystemInit(); ? delay_init(); ? SG90_Init(); ? while(1) { for(int i=0;i<=180;i+=10) { SG90_SetAngle(i); delay_ms(500); } } }
?
其中,SG90_Init()函數(shù)用于初始化PA5口,并將其配置為輸出模式。SG90_SetAngle()函數(shù)用于驅(qū)動舵機(jī)旋轉(zhuǎn)到指定角度。在該函數(shù)中,首先根據(jù)所給的角度值計算出延時的時間temp(單位為微秒),然后使用GPIO口控制SG90舵機(jī)在temp延時時間內(nèi)輸出高電平,其余時間輸出低電平。通過調(diào)整延時時間和按角度分配脈沖寬度,達(dá)到驅(qū)動SG90舵機(jī)旋轉(zhuǎn)的目的。
main()函數(shù)中的for循環(huán)控制舵機(jī)從0度到180度的循環(huán)旋轉(zhuǎn)。代碼中用到了delay_init()函數(shù)和delay_ms()、delay_us()函數(shù)。它們是自行編寫的延時函數(shù),可以實現(xiàn)毫秒和微秒級別的延時,具體代碼如下:
?
#include "stm32f10x.h" ? void delay_init(void) { if (SysTick_Config(SystemCoreClock / 1000000)){ while(1); } } ? static __IO uint32_t delay_us_tick; void delay_us(uint32_t nUs) { delay_us_tick = nUs; while (delay_us_tick); } ? static __IO uint32_t delay_ms_tick; void delay_ms(uint32_t nMs) { delay_ms_tick = nMs; while (delay_ms_tick); } ? void SysTick_Handler(void) { if (delay_us_tick > 0){ delay_us_tick--; } ? if (delay_ms_tick > 0){ delay_ms_tick--; } }
?
其中,delay_init()函數(shù)用于配置系統(tǒng)時鐘源和SysTick定時器,實現(xiàn)每個SysTick時鐘產(chǎn)生一個中斷的功能。delay_us()函數(shù)和delay_ms()函數(shù)分別用于實現(xiàn)微秒級別和毫秒級別的延時,通過限制delay_us_tick和delay_ms_tick的值實現(xiàn)延時的效果。SysTick_Handler()為中斷處理函數(shù),每次SysTick定時器計數(shù)減1,當(dāng)減到0時,相應(yīng)的delay_us_tick或delay_ms_tick也減1,通過循環(huán)等待該值為0實現(xiàn)延時。
在代碼中的SG90_SetAngle()函數(shù)中,需要精確控制GPIO的電平時間,使其產(chǎn)生相應(yīng)的脈沖寬度,從而控制舵機(jī)轉(zhuǎn)動角度。因此,需要配置GPIO口的輸出模式和速度、設(shè)定delay_us()函數(shù)中根據(jù)角度計算的電平時間,使得舵機(jī)能夠準(zhǔn)確地執(zhí)行旋轉(zhuǎn)。
3.2 RC522讀寫代碼
下面是基于SPI接口控制STM32F103C8T6驅(qū)動RFID-RC522模塊完成卡片識別和扇區(qū)讀寫的代碼示例。在該代碼中,使用的是SPI1的接口,RFID-RC522模塊通過SPI1接口連接到STM32F103C8T6。
代碼中通過封裝SPI相關(guān)操作和MFRC522庫函數(shù),實現(xiàn)了讀取卡片信息和完成扇區(qū)讀寫的功能。
?
#include "stm32f10x.h" #include "stm32f10x_spi.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "delay.h" #include "mfrc522.h" #include "stdio.h" #define SPI_CE_LOW() GPIO_ResetBits(GPIOA,GPIO_Pin_4) #define SPI_CE_HIGH() GPIO_SetBits(GPIOA,GPIO_Pin_4) void SPI1_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); } uint8_t SPI1_SendByte(uint8_t byte) { while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, byte); while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); } void MFRC522_Reset(void) { SPI_CE_LOW(); SPI1_SendByte(0x1B); SPI_CE_HIGH(); } uint8_t MFRC522_ReadRegister(uint8_t addr) { SPI_CE_LOW(); uint8_t data; SPI1_SendByte(0x80 | addr); data = SPI1_SendByte(0x00); SPI_CE_HIGH(); return data; } void MFRC522_WriteRegister(uint8_t addr, uint8_t val) { SPI_CE_LOW(); SPI1_SendByte(0x7F & addr); SPI1_SendByte(val); SPI_CE_HIGH(); } void MFRC522_ReadRegisters(uint8_t addr, uint8_t count, uint8_t *values) { SPI_CE_LOW(); SPI1_SendByte(0x80 | addr); for(uint8_t i=0;i
?
測試。。。
詳細(xì)流程:
1. 創(chuàng)建 RtcEngine 對象
該對象管理了整個的視頻等場景,是一個非常核心的對象。
?
try { RtcEngineConfig config = new RtcEngineConfig(); config.mContext = getBaseContext(); config.mAppId = appId; config.mEventHandler = mRtcEventHandler; config.mAudioScenario = Constants.AudioScenario.getValue(Constants.AudioScenario.DEFAULT); mRtcEngine = RtcEngine.create(config); } catch (Exception e) { throw new RuntimeException("Check the error."); }
?
2. 創(chuàng)建 RtcEngine 屬性
?
// 視頻默認(rèn)禁用,你需要調(diào)用 enableVideo 啟用視頻流。 mRtcEngine.enableVideo(); // 錄音默認(rèn)禁用,你需要調(diào)用 enableAudio 啟用錄音。 mRtcEngine.enableAudio(); // 開啟本地視頻預(yù)覽。 mRtcEngine.startPreview();
?
3. 將本地攝像頭內(nèi)容顯示到 local_video_view_container 上
?
FrameLayout container = findViewById(R.id.local_video_view_container); // 創(chuàng)建一個 SurfaceView 對象,并將其作為 FrameLayout 的子對象。 SurfaceView surfaceView = new SurfaceView (getBaseContext()); container.addView(surfaceView); // 將 SurfaceView 對象傳入聲網(wǎng),以渲染本地視頻。 mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, KeyCenter.RTC_UID));
?
4. 設(shè)置當(dāng)前的模式
?
ChannelMediaOptions options = new ChannelMediaOptions(); // 將用戶角色設(shè)置為 BROADCASTER。 options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER; // 視頻通話場景下,設(shè)置頻道場景為 BROADCASTING。 options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
?
其中 clientRoleType 有兩種,如果是 CLIENT_ROLE_BROADCASTER 就是可以播和收,如果是 CLIENT_ROLE_AUDIENCE 就只能收看,當(dāng)前就成了主播模式。
5. 加入頻道
?
// 使用臨時 Token 加入頻道。 // 你需要自行指定用戶 ID,并確保其在頻道內(nèi)的唯一性。 int res = mRtcEngine.joinChannel(token, channelName, KeyCenter.RTC_UID, options); if (res != 0) { // Usually happens with invalid parameters // Error code description can be found at: // en: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html // cn: https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html Log.e("video","join err:"+RtcEngine.getErrorDescription(Math.abs(res))); }
?
joinChannel 方法有返回值,可以看到我們加入頻道是否成功了,如果不成功的話,我們可以看下錯誤原因,并對照解決;如果成功了,就可以觀察 IRtcEngineEventHandler 對象的回調(diào)方法,重點關(guān)注下 onError (int err) 和 onJoinChannelSuccess (String channel, int uid, int elapsed) 如果收到 onJoinChannelSuccess 方法的回調(diào),我們就可以關(guān)注 onUserJoined (int uid, int elapsed) 方法,我們可以在這個方法里開始顯示遠(yuǎn)端內(nèi)容。
6. 顯示遠(yuǎn)端內(nèi)容
?
@Override // 監(jiān)聽頻道內(nèi)的遠(yuǎn)端主播,獲取主播的 uid 信息。 public void onUserJoined(int uid, int elapsed) { Log.e(TAG, "onUserJoined->" + uid); runOnUiThread(new Runnable() { @Override public void run() { // 從 onUserJoined 回調(diào)獲取 uid 后,調(diào)用 setupRemoteVideo,設(shè)置遠(yuǎn)端視頻視圖。 setupRemoteVideo(uid); } }); } private void setupRemoteVideo(int uid) { FrameLayout container = findViewById(R.id.remote_video_view_container); SurfaceView surfaceView = new SurfaceView (getBaseContext()); surfaceView.setZOrderMediaOverlay(true); container.addView(surfaceView); mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid)); }
?
最終,遠(yuǎn)端的視頻會顯示在 remote_video_view_container 上。
1、接口遺漏
通過精準(zhǔn)平臺確認(rèn)通過商家用戶 id 查詢退貨地址接口也存在對應(yīng)的改動,開發(fā)少梳理了一個,并同步開發(fā)在清單中進(jìn)行補(bǔ)充。
2、代碼分支合并
商家核心服務(wù)識別出了一個非地址相關(guān)的改動,跟開發(fā)確認(rèn)之后發(fā)現(xiàn)是因為當(dāng)前提測分支沒有合并當(dāng)前線上最新的 master 分支,導(dǎo)致跑出了非地址相關(guān)的功能數(shù)據(jù)。告知開發(fā)進(jìn)行對應(yīng)代碼合并之后,QA 需要重新部署重新拉取接口再次確認(rèn)。
3、接口重載
商家核心服務(wù)有一個重載方法精準(zhǔn)平臺沒有識別出這個根據(jù)商家 id 查詢商家地址的接口,跟開發(fā)進(jìn)行確認(rèn),最終結(jié)論是根據(jù)商家 id 查詢商家地址的 V2 接口是重載了以下接口:平臺沒有看到重載的方法名,最終確認(rèn)重載方法還是原來的方法名,只是在入?yún)⑸献鲄^(qū)分,一個只有商家 ID,一個需要傳商家 ID、訂單類型、商品 ID。最終在精準(zhǔn)平臺確認(rèn)了對應(yīng)的入?yún)^(qū)別,平臺沒有作為兩個接口進(jìn)行識別。
4、內(nèi)部調(diào)用方法也被識別
在使用精準(zhǔn)平臺進(jìn)行新增接口拉取的時候,發(fā)現(xiàn)平臺會將一些私有方法識別出來,這些方法是內(nèi)部調(diào)用,沒有注冊,接口測試平臺也看不到對應(yīng)的接口信息,無法覆蓋。
3.6 最終接口確認(rèn)
1、商家拆分服務(wù)
本次涉及 8 個改動接口,并補(bǔ)充缺少的 4 個接口的自動化之后,正常識別且狀態(tài)正常,說明此服務(wù)接口都正常覆蓋。
2、商家核心服務(wù)
本次涉及 10 個接口改動,并補(bǔ)充缺少的接口自動化之后,對應(yīng)接口都能正常識別且狀態(tài)正常,說明此服務(wù)接口都正常覆蓋。
3、商家下單鏈路服務(wù)
本次涉及 4 個接口改動,并補(bǔ)充缺少的 2 個接口自動化之后,對應(yīng)接口都能正常識別且狀態(tài)正常,說明此服務(wù)接口都正常覆蓋。
四、結(jié)果
4.1 各個服務(wù)觸發(fā)自動化結(jié)果
1、商家拆分服務(wù)
2、商家核心服務(wù)
3、商家下單鏈路服務(wù)
五、探索心得
5.1 總結(jié)
借助于精準(zhǔn)測試平臺,發(fā)現(xiàn)一個開發(fā)梳理遺漏的接口,有效避免了梳理遺漏導(dǎo)致的測試遺漏,一定程度上規(guī)避了風(fēng)險,是 QA 從經(jīng)驗型的主觀判斷向精準(zhǔn)的數(shù)據(jù)可視化轉(zhuǎn)變。
借助精準(zhǔn)平臺識別出一些沒有進(jìn)行自動化覆蓋的接口,讓 QA 能針對這些清單進(jìn)行接口自動化的查缺補(bǔ)漏,從另一層面提升了自動化用例集的完整性。
精準(zhǔn)平臺與自動化平臺、測試用例平臺、覆蓋率平臺打通,從正向追溯和逆向追溯兩個核心進(jìn)行測試,確保數(shù)據(jù)的準(zhǔn)確性、完整性,方便 QA 持續(xù)跟蹤,提高測試效率。
5.2 優(yōu)化
在接入精準(zhǔn)測試平臺的過程中,對平臺有了進(jìn)一步的了解,當(dāng)然在使用的過程中也發(fā)現(xiàn)一些問題,并給開發(fā)提了相關(guān)建議,從而不斷完善精準(zhǔn)測試平臺開發(fā),也幫助 QA 更好更高效得完成質(zhì)量保障工作。
評論