当前位置:首页 > 消费电子 > 消费电子
[导读]智能门锁不是“指纹任务+密码任务+蓝牙任务各管各的”,那样必出三源同时触发、电机被重复驱动、蓝牙指令重放。正确架构是输入源只产生认证事件,调度器统一仲裁,执行层只认一条开锁指令。指纹、键盘、BLE都别直接碰电机。


智能门锁不是“指纹任务+密码任务+蓝牙任务各管各的”,那样必出三源同时触发、电机被重复驱动、蓝牙指令重放。正确架构是输入源只产生认证事件,调度器统一仲裁,执行层只认一条开锁指令。指纹、键盘、BLE都别直接碰电机。

一、三层解耦

采集层:指纹UART、矩阵键盘、BLE GATT

认证层:匹配/比对/解密,产出auth_event

调度层:状态机+队列,判断是否允许开锁

执行层:电机驱动+锁舌反馈+日志

各任务通过消息队列发给主锁控任务,谁先合法谁触发,触发后进入“已处理”窗口,别源重复计。

二、指纹:UART只收结果

AS608/ZW101类模块内部完成采图匹配,主控别去解析图像,只发指令收确认码。

typedef enum {

   AUTH_NONE, AUTH_FP_OK, AUTH_PWD_OK,

   AUTH_BLE_OK, AUTH_FAIL

} auth_src_t;


void fp_task(void*p){

   uint8_t rsp[32];

   if(fp_wait_finger()){                  // TOUCH中断唤醒

       fp_send_cmd(CMD_GET_IMAGE);

       fp_send_cmd(CMD_GEN_CHAR);

       uint8_t code = fp_search(rsp);     // 0x00成功

       if(code==0x00)

           lock_post_event(AUTH_FP_OK, rsp[2]); // 匹配ID

       else

           lock_post_event(AUTH_FAIL, 0);

   }

}

坑点:UART接收放任务里,别在串口中断里解帧;模块供电要独立,采图瞬间电流抖动会让主控复位。

三、密码:虚位+错误计数掉电保持

密码输入别只比“等于”,做子串匹配:输入缓冲里包含真实密码连续序列即过,前后可加干扰数字。

int pwd_check(const uint8_t*buf,int len,const uint8_t*pwd,int plen){

   for(int i=0;i+plen<=len;i++)

       if(memcmp(buf+i,pwd,plen)==0) return 1;

   return 0;

}

错误计数不能放RAM,断电归零等于没锁。写Backup SRAM或EEPROM,带RTC时间戳:

void pwd_fail_record(void){

   fail_cnt++;

   last_fail_ts = rtc_sec();

   bkp_write(FAIL_ADDR, fail_cnt);

   if(fail_cnt>=5){

       lock_state = LOCK_FROZEN;

       freeze_release_ts = rtc_sec()+60;   // 锁1分钟

   }

}

虚位密码要限总长,避免无限输入蹭缓冲;确认键#收尾,超时15s回IDLE清缓冲。

四、蓝牙:BLE指令必须防重放

HC-06明文配对别上量;正经方案走BLE LESC配对+应用层再验一次。

开锁指令结构:

typedef struct {

   uint8_t cmd;

   uint32_t ts;        // 时间戳

   uint32_t nonce;     // 随机数

   uint8_t  mac[8];    // HMAC

} ble_unlock_t;

校验顺序:

链路层已加密(LTK)

ts与本地偏差<5s → 否则丢(防重放)

nonce大于上次记录

HMAC用主密钥验

再判断用户权限

void ble_task(void*p){

   ble_unlock_t u;

   if(ble_recv((uint8_t*)&u,sizeof(u))){

       if(abs(u.ts-rtc_sec())>5) return;

       if(!hmac_ok(&u)) return;

       if(u.cmd==CMD_UNLOCK)

           lock_post_event(AUTH_BLE_OK, 0);

   }

}

Just Works配对不够,门锁用Numeric Comparison或带外密钥。

五、调度器:单点仲裁

所有认证源都调lock_post_event,主状态机决定做不做:

typedef enum { LS_IDLE, LS_VERIFYING,

             LS_OPENING, LS_FROZEN } lock_st_t;

static lock_st_t ls = LS_IDLE;


void lock_post_event(auth_src_t s, uint8_t id){

   static uint32_t open_guard;

   if(ls==LS_OPENING) return;          // 正在开,去重

   if(ls==LS_FROZEN){

       if(rtc_sec()>=freeze_release_ts){ ls=LS_IDLE; }

       else return;

   }

   if(s==AUTH_FP_OK||s==AUTH_PWD_OK||s==AUTH_BLE_OK){

       motor_open();                   // 只这里动电机

       log_access(s,id);

       ls = LS_OPENING;

   }else{

       pwd_fail_record();

   }

}

规则:

指纹/密码/蓝牙任一合法即可开(单因子)

高安全模式要求双因子:先指纹再BLE确认

同一次按压/一次连接只开一次

电机动作期间屏蔽新事件

六、电机执行防卡死

开锁不是“IN1=1转两秒”。要带超时+过流+位置反馈:

void motor_open(void){

   uint32_t t0=systick();

   motor_set(FWD);

   while(!hall_locked() && systick()-t0 < 800); // 等锁舌到位

   motor_set(BRAKE);

   if(systick()-t0>=800) log_err(E_MECH); // 卡死记录

}

驱动加OCP,电流超阈值切输出;半锁状态别硬顶,回退重试一次;霍尔/微动开关确认到位再回IDLE。

七、落坑清单

指纹任务里直接motor_open()→蓝牙又触发重复开

密码错误计数放局部变量→断电清零

虚位密码不限长→缓冲溢出

BLE只比cmd==1→重放包照开

Just Works配对→中间人伪造

串口中断里解帧→阻塞卡死

电机无超时→指纹识别后卡死不回弹

三任务同写全局状态→竞态

开锁中不关中断事件→连发抖动

八、落地顺序

建锁控状态机LS_IDLE/VERIFYING/OPENING/FROZEN

指纹UART任务只发事件

键盘任务做虚位匹配+Backup SRAM错误计数

BLE任务做LESC+时间戳+nonce+HMAC

统一lock_post_event入队

主任务唯一调用motor_open

电机带霍尔反馈+800ms超时+过流保护

每次开锁写日志(源/ID/时间)

智能门锁多逻辑调度的本质不是“三个功能都能开”,是三个输入源都不能绕过调度器。指纹快、密码稳、蓝牙远控,但执行出口只有一个;事件队列隔开中断和驱动,状态机隔开多源冲突,防重放和错误冻结补上安全底线。代码不复杂,乱的是把认证和驱动耦合在一起——谁直接碰电机,谁就是bug源头。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭