一、項目名稱:
NFC門鎖
二、項目概述:
本系統(tǒng)是基于雙核LPC55S69為主控芯片的NFC門鎖,采用I2C端口讀取NFC讀卡器的數(shù)據(jù),經(jīng)過身份驗證后,啟動伺服電機(jī)控制門鎖開鎖。延時后再次掃描讀卡器,如果沒有更新并保持的最新讀卡器數(shù)據(jù)后,控制伺服電機(jī)返回,關(guān)閉門鎖。
補充說明:原計劃的門鎖是采用Tensorflow Lite的智能門鎖項目,用攝像頭掃描,捕捉人體接近并啟動圖片識別功能,符合安全身份認(rèn)證后,開啟門鎖。原計劃中,NFC門鎖是其中的一個多重身份驗證工具,運行在Core0在低功耗運行。CV識別運行在core1,高速執(zhí)行。
LPC55S69本身功能強大,可以勝任告訴圖片讀取的功能,但是在導(dǎo)入tensorflow lite的過程中,發(fā)現(xiàn)了公版model的問題,就是這個系統(tǒng)太大,不能支持MCU的運行。tensorflow lite對于內(nèi)存的最小要求是1M內(nèi)存,680k閃存已經(jīng)足夠大,但是不能支持經(jīng)過測試的公版model(如mobileNet-0.25x0.25執(zhí)行flatten后仍然有1.68M)。
自行設(shè)計model并訓(xùn)練更小的模型,在性能上不能得到驗證,所以在提交截止期之前,只能實現(xiàn)現(xiàn)有的功能。
感謝本次挑戰(zhàn)賽的開發(fā)過程,引出了一個有趣的新題目,就是如何在高性能MCU上執(zhí)行大的模型運行,如VGG這樣的深度網(wǎng)絡(luò)模型,后續(xù)仍然繼續(xù)沿著這個思路開發(fā),力爭在這個板子上實現(xiàn)公版模型的適用。
經(jīng)過多次實驗,已經(jīng)有了初步的設(shè)計框架:在不啟動MMU功能的情況下,如何構(gòu)建一個SWAP空間,仍然能夠快速實現(xiàn)擴(kuò)址訪問,只需要再做一個overlay的內(nèi)存管理庫就可以了。
三、作品實物圖
NFC讀卡器的鏈接I2C
NFC讀卡器的型號
鏈接9G伺服電機(jī)
讀卡器讀取NFC卡的ID信息
四、演示視頻
動態(tài)演示這個程序執(zhí)行過程
五、項目文檔
5.1 使用的硬件包括
-??LPC55S69 dev board
- NFC tag reader ID-12LA,
5.2 主要的代碼如下:其中實現(xiàn)servo控制使用了ctime庫,定義一個50Hz的占空比再2.5%~12.5%可調(diào)的PWM信號來控制伺服電機(jī)。
int main(void)
{
i2c_master_config_t masterConfig;
status_t reVal = kStatus_Fail;
uint8_t deviceAddress = 0x01U;
ctimer_config_t config;
uint32_t srcClock_Hz;
uint32_t timerClock;
uint8_t updatedutyCyclePercent;
/* attach 12 MHz clock to FLEXCOMM0 (debug console) */
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
/* attach 12 MHz clock to FLEXCOMM8 (I2C master) */
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
/* Use 12 MHz clock for some of the Ctimers */
CLOCK_AttachClk(kFRO_HF_to_CTIMER2);
/* reset FLEXCOMM for I2C */
RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn);
BOARD_InitPins();
BOARD_BootClockPLL150M();
BOARD_InitDebugConsole();
/* CTimer0 counter uses the AHB clock, some CTimer1 modules use the Aysnc clock */
srcClock_Hz = CTIMER_CLK_FREQ;
PRINTF("CTimer example to generate a PWM signalrn");
CTIMER_GetDefaultConfig(&config);
timerClock = srcClock_Hz / (config.prescale + 1);
CTIMER_Init(CTIMER, &config);
/* Get the PWM period match value and pulse width match value of 50hz PWM signal with 2.5%~12.5% dutycycle , 20ms peoriod*/
CTIMER_GetPwmPeriodValue(50, 10, timerClock);
CTIMER_SetupPwmPeriod(CTIMER, CTIMER_MAT_OUT, g_pwmPeriod, g_pulsePeriod, false);
CTIMER_StartTimer(CTIMER);
//CTIMER_UpdatePwmDutycycle(CTIMER_Type *base, ctimer_match_t matchChannel, uint8_t dutyCyclePercent);
PRINTF("rnI2C board2board polling -- Master transfer.rn");
g_master_txBuff[0] = I2C_DATA_LENGTH - 1U;
for (uint32_t i = 1U; i < I2C_DATA_LENGTH; i++)
{
g_master_txBuff[i] = i - 1;
}
I2C_MasterGetDefaultConfig(&masterConfig);
/* Change the default baudrate configuration */
masterConfig.baudRate_Bps = I2C_BAUDRATE;
/* Initialize the I2C master peripheral */
I2C_MasterInit(EXAMPLE_I2C_MASTER, &masterConfig, I2C_MASTER_CLOCK_FREQUENCY);
/* Wait until the slave is ready for transmit, wait time depend on user's case.
Slave devices that need some time to process received byte or are not ready yet to
send the next byte, can pull the clock low to signal to the master that it should wait.*/
for (uint32_t i = 0U; i < WAIT_TIME; i++)
{
__NOP();
}
PRINTF("Receive sent data from slave :");
while (1)
{
for (uint32_t i = 0U; i < WAIT_TIME; i++)
{ __NOP(); }
/* Receive blocking data from slave */
if (kStatus_Success == I2C_MasterStart(EXAMPLE_I2C_MASTER, I2C_MASTER_SLAVE_ADDR_7BIT, kI2C_Write))
{
reVal = I2C_MasterReadBlocking(EXAMPLE_I2C_MASTER, g_master_rxBuff, I2C_DATA_LENGTH - 1, kI2C_TransferDefaultFlag);
if (reVal != kStatus_Success)
{
return -1;
}
reVal = I2C_MasterStop(EXAMPLE_I2C_MASTER);
if (reVal != kStatus_Success)
{
return -1;
}
}
for (uint32_t i = 0U; i < 4; i++)
//for (uint32_t i = 0U; i < I2C_DATA_LENGTH - 1; i++)
{
if (i % 8 == 0)
{
PRINTF("rn");
}
PRINTF("0x%2x ", g_master_rxBuff[i]);
if (g_master_rxBuff[i]== g_match_id[i] ){g_master_rxBuff[I2C_DATA_LENGTH-1]=127;}
}
PRINTF("rnrn");
// LOCK_UNLOCK, refreshed every loop and return to LOCK off status,
updatedutyCyclePercent= LOCK_ON ? (g_master_rxBuff[I2C_DATA_LENGTH-1]==127):LOCK_OFF;
g_pulsePeriod = (g_pwmPeriod * (100 - updatedutyCyclePercent)) / 100;
CTIMER_UpdatePwmDutycycle(CTIMER, CTIMER_MAT_OUT, g_pulsePeriod);
}
// PRINTF("rnEnd of I2C example .rn");
}