丁丁生于 1987.07.01 ,30岁,英文ID:newflydd
基于R303电容指纹模块的MCU串口通信详解(NodeJs及51单片机实现)
前期准备
R303电容指纹简介
R303指纹模块采用台湾产电容大面状采集芯片,集成了指纹算法芯片,具有指纹录入、图像处理、特征提取、模板生成、模板存储、指纹比对(1:1)或指纹搜索(1:N)等功能;工作电流低。
R303作为下位机,可以使用UART与上位机通信,可以在9600-115200波特率通信。对于MCU,R303可以直接使用RXD和TXD两个引脚与上位机通信,工作电压5V;上位机为x86架构下的windows时,有dll和lib库封装的SDK,插上USB转接线,可以直接使用,本文不做详细介绍,其本质也是通过USB转TTL后的串口通信。
R303的全部使用方式,可以参考我上传的官方文档资料:
https://share.weiyun.com/b94427dcf3ffa37217d6bb1587b873e7
R303常用功能命令
- ①采集指纹到图像缓冲区
- ②从图像缓冲区生成特征码到N号寄存器(N in [01, 02])
- ③合并1号寄存器和2号寄存中的特征码,并同时复制给1号、2号寄存器
- ④将N号寄存器中的特征码保存到指纹库PAGE位置(PAGE in [0,1028))
- ⑤对指纹库BEGIN-END位置搜索验证第N号寄存器特征码(BEGIN,END in[0,1028); N in [01, 02])
上述命令为最常用的命令,此外,还有一些删除,清空指纹库的命令,读取指纹库有效特征码个数的命令没有写上。
不如要执行录入指纹的操作,就可以按照1->2->1->2->3->4的步骤来实现,要实现验证指纹的操作,就可以按照1->2->5。
指令集
上述所有命令,以及本文中没有列举的命令,R303都对应一系列的串口指令集,同时R303在接受到指令后会给出一个相应的反馈信息,从而实现通信的闭环。
指令集的结构为:包头
+ 收发标志(发01/收07)
+ 2byte的后续包长度
+ 1byte命令码
+ Nbyte参数(N可以等于0)
+ 校验和
包头:如果MCU只挂载一个指纹模块的话,我们可以基本认为16进制的EF 01 FF FF FF FF
是一个包头,后4个字节其实是设备物理地址。
收发标志:发01/收07
2byte后续包长度:指令包从下个字节开始到结束时的长度,如果大于2个byte,高位舍去,2个byte就是16个bit,就是65535个长度,几乎不可能发送或者接受这么长的指令的。
1byte命令码:相当于函数名,对应不同的指令,1byte够了,能表示255种命令。
Nbyte参数:相当于函数参数,调用不同指令时可能会传入参数,也可能没有参数。
校验和:从长度字节开始到最后一个参数之间所有的byte相加,得到校验和。
下面整理罗列一下指令集对应的串口数据:
录入图像
发送:EF 01 FF FF FF FF 01 00 03 01
00 05
接受:EF 01 FF FF FF FF 07 00 03 RE S U M
RE:应答码,1byte,没有错误一般都是0x00,有异常时抛出不同的异常状态码。
SUM:2byte校验和
生成特征码
将ImageBuffer中的图像生成指纹特征,存于cb1或cb2寄存器
发送:EF 01 FF FF FF FF 01 00 04 02
01/02 S U M
接受:EF 01 FF FF FF FF 07 00 03 RE S U M
合并指纹
将cb1和cb2的特征码进行合并,如果指纹出入太大的话有可能合并不成功
发送:EF 01 FF FF FF FF 01 00 03 05
00 09
接受:EF 01 FF FF FF FF 07 00 03 RE S-U-M
搜索指纹
将cb1或者cb2中的特征码与指纹库中的数据进行对比
发送:EF 01 FF FF FF FF 01 00 08 04
CB ST-PG PG-ED S-U-M
接受:EF 01 FF FF FF FF 07 00 07 RE PAGE= =SC== S-U-M
CB: 特征码寄存器
ST-PG: 2byte 搜索起始位
PG-ED: 2byte 搜索截止位
如果想整个指纹库搜索,上面两个可以设置为00 00 03 E7
,代表从0搜到1000位。
RE:0表示找到了,其他值表示找不到
PAGE: 2byte 如果指纹模块搜索到了匹配指纹,则表示找到的位置
SC:匹配得分
存储特征码到指纹库
将cb1或者cb2中的特征码存储到pageID指纹库位置
发送:EF 01 FF FF FF FF 01 00 08 06
CB PAGE= S-U-M
接受:EF 01 FF FF FF FF 07 00 07 RE S-U-M
NodeJS编码测试
在进行R303指纹模块PC端编程测试时,我选择使用刚学的NodeJS。串口通信是一种异步的通信,它的发送和接受是靠RXD和TXD两根线的高低电平变化同时产生的。而NodeJS这个语言,天生可以通过Promis机制非常有序的处理这种异步过程,将这种异步过程通过then堵塞变成同步操作。
下面是我用NodeJS编写的模块测试代码:
const readline = require('readline');
var SerialPort = require("serialport");
var Q = require('q');
var EventEmitter = require('events').EventEmitter;
var fingureEmitter = new EventEmitter(); //指纹接受消息弹射器
var keyboardEmitter = new EventEmitter(); //键盘输入事件的弹射器
var MessageOpenError = 'open port error : '; //串口打开失败的提示
var PackageHeaderBuffer = new Buffer('EF01FFFFFFFF01', 'hex'); //UART发送包包头
var cmdReceiveBuffer = new Buffer(''); //指令串,包含EF01FFFFFFFF07
var packageLength = 0; //接受包长度,不包含长度位,但包含校验和
var waiteCount = 100; //录入指纹时的失败控制次数
var inputFingureTimmer; //控制录入指纹循环定时器
var pos = 0; //读入指纹地址列表的坐标
var fingureAddressList = []; //指纹地址列表
var port = new SerialPort(
"COM3",
{
baudRate: 9600,
parser: SerialPort.parsers.byteLength(1),
autoOpen: false,
}
);
fingureEmitter.on('processEnd', () => showMenu());
port.on('error', err => {console.log(err); rl.close();});
port.on('data', data => {
let dataBuffer = new Buffer(data, 'hex');
//console.log('data received: =========' + dataBuffer.toString('hex'));
cmdReceiveBuffer = Buffer.concat([cmdReceiveBuffer, dataBuffer]);
if (cmdReceiveBuffer.length == 9) {
//提取包长度信息, packageLength = buffer[8,9]
packageLength = (cmdReceiveBuffer[7] << 8) + cmdReceiveBuffer[8];
//console.log('packageLength: ' + packageLength);
} else if (cmdReceiveBuffer.length == 9 + packageLength) {
//结束一轮消息接受,清空buffer,解析命令
//console.log('cmd end.cmd is: ' + cmdReceiveBuffer.toString('hex'));
let checkSum = (cmdReceiveBuffer[7 + packageLength] << 8) + cmdReceiveBuffer[8 + packageLength];
let cfmCode = cmdReceiveBuffer[9];
let params = [];
for (kk = 0; kk < (packageLength - 3) / 2; kk++) {
params.push((cmdReceiveBuffer[10 + kk * 2] << 8) + cmdReceiveBuffer[11 + kk * 2]);
}
//console.log('checkSum is:' + checkSum);
//console.log('cfmCode is:' + cfmCode);
//console.log('params are:' + params.toString());
let tempSum = 0;
for (kk = 6; kk < cmdReceiveBuffer.length - 2; kk++) {
tempSum += cmdReceiveBuffer[kk];
}
if (tempSum == checkSum) {
//校验正确,发射消息响应
fingureEmitter.emit('dataReceived', cfmCode, params);
}
//清空指令buffer
cmdReceiveBuffer = new Buffer('');
}
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
//菜单0:与指纹模块握手
function ackFingure() {
sendCmd('13', '00000000').then(data => {
if (data.cfmCode == 0)
console.log('握手成功');
else
console.log('握手失败');
}).catch(err => { console.log('握手失败') }).finally(() =>{fingureEmitter.emit('processEnd');});
}
//通过输入的权限得到下一个存放位置
function generatePower(answer){
let startPos = (answer - 1) * 100;
while(fingureAddressList.indexOf(startPos) != -1){
startPos++;
if(startPos >= answer * 100){
startPos = -1;
break;
}
}
return startPos;
}
//菜单1:录入指纹
function inputFingure() {
showQuestion('请输入指纹录入者的权限(1-10):').then(answer => {
if (answer < 1 || answer > 10) {
console.log('权限输入有误');
showMenu();
return;
}
let pow = generatePower(answer);
if(pow == -1){
console.log('该权限存储位置已满,无法录入。');
fingureEmitter.emit('processEnd');
}
console.log(`指纹将存放在${pow}位置。`);
waiteCount = 100;
console.log('开始采集第一次指纹,请将手指放到采集器');
inputFingureTimmer = setInterval(() => {
if (waiteCount == 0) {
clearInterval(inputFingureTimmer);
console.log('长时间没有采集到指纹,已终止采集');
fingureEmitter.emit('processEnd');
}
sendCmd('01').then(data => {
if (data.cfmCode == 0) {
clearInterval(inputFingureTimmer);
console.log('指纹采集成功');
console.log('准备生成特征码到cb1');
return sendCmd('02', '01');
} else if (data.cfmCode == 2) {
//console.log('没有指纹,等待录入:' + waiteCount);
waiteCount--;
} else {
console.log('录入失败, 等待继续录入:' + waiteCount);
waiteCount--;
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('生成特征码到cb1成功');
console.log('开始采集第二次指纹,请将手指放到采集器');
waiteCount = 100;
inputFingureTimmer = setInterval(() => {
if (waiteCount == 0) {
clearInterval(inputFingureTimmer);
console.log('长时间没有采集到指纹,已终止采集');
fingureEmitter.emit('processEnd');
}
sendCmd('01').then(data => {
if (data.cfmCode == 0) {
clearInterval(inputFingureTimmer);
console.log('指纹采集成功');
console.log('准备生成特征码到cb2');
return sendCmd('02', '02');
} else if (data.cfmCode == 2) {
//console.log('没有指纹,等待录入:' + waiteCount);
waiteCount--;
} else {
console.log('录入失败, 等待继续录入:' + waiteCount);
waiteCount--;
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('生成特征码到cb2成功');
console.log('准备合并特征码');
return sendCmd('05');
} else {
console.log('生成特征码到cb2失败');
fingureEmitter.emit('processEnd');
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('合并成功');
console.log(`准备将合并后的特征码保存到指纹库${pow}位置`);
let hPow = pow>>8;
let lPow = pow&0x00FF;
return sendCmd('06', '02' + new Buffer([hPow, lPow]).toString('hex'));
} else if (data.cfmCode == 10) {
console.log('合并失败,两个指纹不是同一手指');
fingureEmitter.emit('processEnd');
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('保存成功,流程结束!');
getFingureDBList();
} else {
console.log('保存失败!code:' + data.cfmCode);
fingureEmitter.emit('processEnd');
}
});
}, 1000);
}else {
console.log('生成特征码到cb1失败');
fingureEmitter.emit('processEnd');
}
});
}, 1000);
});
}
//菜单2:检索指纹
function searchFingure() {
console.log('开始采集指纹,请将手指放到采集器');
waiteCount = 100;
inputFingureTimmer = setInterval(() => {
if (waiteCount <= 0) {
clearInterval(inputFingureTimmer);
console.log('长时间没有采集到指纹,已终止采集');
fingureEmitter.emit('processEnd');
}
sendCmd('01')
.then(data => {
if (data.cfmCode == 0) {
clearInterval(inputFingureTimmer);
console.log('指纹采集成功');
console.log('准备生成特征码到cb1');
return sendCmd('02', '01');
} else {
//console.log('没有指纹,等待录入:' + waiteCount);
waiteCount--;
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('生成特征码到cb1成功,准备匹配指纹库');
return sendCmd('1b', '01000003E7');
} else {
console.log('生成特征码到cb1失败');
fingureEmitter.emit('processEnd');
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('比对成功,指纹ID:' + data.params[0] + ' 匹配度:' + data.params[1] + '。流程结束!');
fingureEmitter.emit('processEnd');
} else if (data.cfmCode == 9) {
console.log('没有匹配指纹,流程结束!');
fingureEmitter.emit('processEnd');
} else {
console.log('其他错误,code: ' + data.cfmCode);
fingureEmitter.emit('processEnd');
}
});
}, 1000);
}
//菜单3:获取指纹库有效个数
function getFingureDBCount() {
console.log('正在获取指纹库有效指纹个数');
sendCmd('1d').then(data => {
if (data.cfmCode == 0) {
console.log('指纹库个数提取成功:' + data.params[0]);
} else {
console.log('指纹库个数提取失败。');
}
}).finally(() => {fingureEmitter.emit('processEnd');});
}
function countValue(value) {
let h8 = value >> 8;
let l8 = value;
for (i = 0; i < 8; i++) {
if (h8 & 0x01) {
fingureAddressList.push(pos);
}
h8 >>= 1;
pos++;
}
for (i = 0; i < 8; i++) {
if (l8 & 0x01) {
fingureAddressList.push(pos);
}
l8 >>= 1;
pos++;
}
}
//菜单4:获取指纹库
function getFingureDBList() {
pos = 0;
fingureAddressList.splice(0, fingureAddressList.length); //清空数组
console.log('准备读取指纹库page0页列表');
sendCmd('1F', '00').then(data => {
if (data.cfmCode == 0) {
console.log('page0列表读取完毕:');
data.params.forEach(value => {
countValue(value);
});
console.log('准备读取指纹库page1页列表');
return sendCmd('1F', '01');
} else {
console.log('page0列表读取失败:' + data.cfmCode);
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('page1列表读取完毕:');
data.params.forEach(value => {
countValue(value);
});
console.log('准备读取指纹库page2页列表');
return sendCmd('1F', '02');
} else {
console.log('page1列表读取失败:' + data.cfmCode);
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('page2列表读取完毕:');
data.params.forEach(value => {
countValue(value);
});
console.log('准备读取指纹库page3页列表');
return sendCmd('1F', '03');
} else {
console.log('page2列表读取失败:' + data.cfmCode);
}
}).then(data => {
if (data.cfmCode == 0) {
console.log('page2列表读取完毕:');
data.params.forEach(value => {
countValue(value);
});
console.log('指纹库所有页的数据读取完毕,有效地址列表:');
console.log(fingureAddressList.toString());
} else {
console.log('page3列表读取失败:' + data.cfmCode);
}
}).catch(err => console.trace(err)).finally(() => {fingureEmitter.emit('processEnd');});
}
//键盘输入事件监听
rl.on("line", answer => {
keyboardEmitter.emit('keyboardInputed', answer);
});
//内部发送串口通信函数
function sendCmdFn(cmd, params) {
let cmdBuffer = new Buffer(cmd, 'hex');
let paramsBuffer = null;
if (params && params != '')
paramsBuffer = new Buffer(params, 'hex');
let length = (paramsBuffer ? paramsBuffer.length : 0) + 3; //计算长度,指令1byte + 参数nbyte + 校验和2byte
let checkSum = cmdBuffer[0] + (paramsBuffer ? paramsBuffer.reduce((x, y) => x + y) : 0) + 1 + length; //求校验和,使用了数组的高阶函数reduce
let l1 = length >> 8;
let lengthBuffer = Buffer.from([l1, length]);
let c1 = checkSum >> 8;
let checkSumBuffer = Buffer.from([c1, checkSum]);
let resultBuffer = paramsBuffer ? Buffer.concat([PackageHeaderBuffer, lengthBuffer, cmdBuffer, paramsBuffer, checkSumBuffer]) : Buffer.concat([PackageHeaderBuffer, lengthBuffer, cmdBuffer, checkSumBuffer]);
//console.log('send: ' + resultBuffer.toString('hex'));
port.write(resultBuffer);
}
//对外公开的发送串口指令函数
function sendCmd(cmd, params) {
var deferred = Q.defer();
if (port.isOpen()) {
sendCmdFn(cmd, params);
} else {
port.open(err => {
if (err)
deferred.reject(err);
else
sendCmdFn(cmd, params);
})
}
fingureEmitter.once('dataReceived', (cfmCode, params) => {
//console.log(cfmCode + "\nParams's length:" + params.length);
deferred.resolve({ 'cfmCode': cfmCode, 'params': params });
});
return deferred.promise;
}
function closePort() {
if (port.isOpen())
port.close();
}
function showQuestion(question) {
console.log(question);
rl.prompt();
var keyboardDiferred = Q.defer();
keyboardEmitter.once('keyboardInputed', answer => {
keyboardDiferred.resolve(answer);
});
return keyboardDiferred.promise;
}
function showMenu() {
showQuestion(
`What do you want to do?
0.与指纹模块握手验证.
1.录入指纹.
2.验证指纹.
3.获得数据库特征个数
4.获得数据库特征列表
5.退出\n`
).then(answer => {
switch (answer) {
case '0':
ackFingure();
break;
case '1':
inputFingure();
break;
case '2':
searchFingure();
break;
case '3':
getFingureDBCount();
break;
case '4':
getFingureDBList();
break;
case '5':
closePort();
while (!port.isOpen())
process.exit(0);
default:
showMenu();
}
});
}
getFingureDBList();
51单片机进行MCU移植
指纹模块不可能一直连着x86的PC用,现在我们来将上面的逻辑用51单片机实现:
在编写单片机程序时,我参考借鉴了windows编程中的消息响应机制,在大循环中优先判断是否需要响应消息。
/*
* @CreateTime: Mar 3, 2017 4:25 PM
* @Author: Smith Ding
* @Contact: newflydd@gmail.com
* @Last Modified By: Smith Ding
* @Last Modified Time: Mar 3, 2017 4:46 PM
* @Description: 本软件用来将面板与指纹模块进行通信
* @Company: JIANGSU SAIYANG MECHANICAL & ELECTRICAL TECHNOLOGY CO.,LTD
*/
#include <reg52.h>
#include <intrins.h>
#include "uart.h"
#include "fingure.h"
#include "event.h"
void delay(uint num){
while(num--);
}
//启动初始化
void initMain(){
//初始化发送指令前7个byte
for(ucharTemp = 0; ucharTemp < 7; ucharTemp ++){
sendBuffer[ucharTemp] = sendPackageHeader[ucharTemp];
}
//将串口接受寄存器的数据长度置0
receiveBufferLength = 0;
//接受到了串口通知开关置0
receiveCmdNotify = 0;
//等待串口消息开关置0
waitForReceive = 0;
EA = 1; //总中断开关打开
}
void main(){
uchar fingureReadable = 1; //下位机指纹模块连接性,0时代表可准确连接
delay(65535);
delay(65535);
delay(65535);
delay(65535);
delay(65535);
delay(65535);
delay(65535);
delay(65535);
initPrograme:
initUart();
initMain();
fingureReadable = getAddressListFunction();
if(fingureReadable){
//@TODO: 异常警报
showWarning();
goto initPrograme;
}else{
//P1 = 0x40;
}
//初始化指令为:0x11,向指纹模块发送采集指纹用来验证的命令
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
while(1){
/* 主循环中首先判断是否有串口响应,如果有,则本次循环用来处理消息响应 */
if(receiveCmdNotify == 1){
receiveCmdNotify = 0;
receiveEventFunction(); //接住消息
continue;
}
/*
* 如果没有串口响应
* 首先判断是否在等待下位机反馈,如果在等待,就开始延时计数
*/
if(waitForReceive == 1){
waitForReceive = 0;
if(waitTimes < 3)
waitForReceiveFunction();
else
resetFingureFunction();
continue;
}
/*
* 继续判断P2口有没有录入通知
* 如果有录入通知,并且当前状态为验证状态,则发送录入命令
* 如果没有录入通知,则发送验证命令
*/
inputSignal = checkInputSignal();
if((sendCmdStatus == ACTION_GET_IMAGE_FOR_CHECK) && inputSignal){
newFingureAddressIndex = getNewAddressIndexByPower(inputSignal); //通过权限来构造一个空位置
noFingureTimesWhenInput = 0; //将录入指纹时的重复次数归零
sendCmdStatus = ACTION_GET_IMAGE_FOR_INPUT1;
}
//uartSendByte(sendCmdStatus);
if(receiveCmdNotify == 0)
sendCmdFunction();
delay(2000);
}
}
/**
* 串口中断函数,用来接收下位机数据
*/
void serialInterruptCallback() interrupt 4 {
if(RI){ //本次中断是接受中断
RI = 0; //接受完了清零
//将接受到的字节追加到指令接受缓冲区
receiveByte = SBUF;
receiveBuffer[receiveBufferLength] = receiveByte;
receiveBufferLength++;
if(receiveBufferLength == 1 && receiveByte!=0xEF){
receiveBufferLength = 0;
return;
}
if(receiveBufferLength == 2 && receiveByte!=0x01){
receiveBufferLength = 0;
return;
}
if(receiveBufferLength == 3 && receiveByte!=0xFF){
receiveBufferLength = 0;
return;
}
if(receiveBufferLength == 4 && receiveByte!=0xFF){
receiveBufferLength = 0;
return;
}
if(receiveBufferLength == 5 && receiveByte!=0xFF){
receiveBufferLength = 0;
return;
}
if(receiveBufferLength == 6 && receiveByte!=0xFF){
receiveBufferLength = 0;
return;
}
if(receiveBufferLength == 9){
//如果指令接受到9个byte,这时候包长度信息有了
receivePackageLength = (receiveBuffer[7] << 8) + receiveBuffer[8];
}else if (receiveBufferLength == 9 + receivePackageLength) {
//结束一轮消息接受,清空buffer,解析命令
//获取校验和
receiveCheckSum = (receiveBuffer[7 + receivePackageLength] << 8) + receiveBuffer[8 + receivePackageLength];
//获取确认码
cfmCode = receiveBuffer[9];
//获取参数
for (ucit = 0; ucit < receivePackageLength - 3; ucit++) {
receiveParams[ucit] = receiveBuffer[10 + ucit];
}
//验证校验和
uiit = 0;
for (ucit = 6; ucit < receiveBufferLength - 2; ucit++) {
uiit += receiveBuffer[ucit];
}
if (uiit == receiveCheckSum) {
//校验正确,发射消息响应
receiveCmdNotify = 1;
receiveEventStatus = sendCmdStatus - 100; //事件类型根据发送类型对应
waitForReceive = 0; //解除等待锁
waitTimes = 0; //等待响应次数复位
}
//清空指令buffer
receiveBufferLength = 0;
}
}
}
/**
* 给sendBuffer变量构建发送指令
* 命令和参数来自于全局变量sendCmdAndParams
* @param capLength [命令+参数的长度]
*/
void buildSendCmd(uchar capLength){
uint checkSum;
uchar packageLength = capLength + 2; //包长度 = 指令集长度 + 校验和长度
sendBufferLength = 11 + capLength; // 7 + 2 + capLength + 2
sendBuffer[7] = 0; //包长度高位为0x00
sendBuffer[8] = packageLength; //包长度低位为实际包长度
//构建发送指令串口消息中的指令和参数
for(ucharTemp = 0; ucharTemp < capLength; ucharTemp++){
sendBuffer[9+ucharTemp] = sendCmdAndParams[ucharTemp];
}
checkSum = getCheckSum(packageLength, sendCmdAndParams, capLength);
sendBuffer[9 + capLength] = checkSum>>8;
sendBuffer[10 + capLength] = checkSum;
}
/**
* [计算校验和]
* @param packageLength [包长度]
* @param cmdAndParams [命令和参数数组]
* @param capLength [命令和参数长度]
* @return [2byte 校验和]
*/
uint getCheckSum(uchar packageLength, uchar* cmdAndParams, uchar capLength){
uintTemp = packageLength;
for(ucharTemp = 0; ucharTemp < capLength; ucharTemp++){
uintTemp += cmdAndParams[ucharTemp];
}
return uintTemp + 1;
}
/**
* @TODO:临时模拟信号
* 检查输入端口有没有录入信号(P2高4位),录入信号需要阶段时间内维持稳定信号
* @return 如果没有,返回0,如果有,返回P2高4位的低三位作为权限数据
*/
uchar checkInputSignal(){
uchar inputValue = GPIO_INPUT;
uintTemp = 500;
while(uintTemp--){
ucharTemp = (inputValue<<1);
if((ucharTemp & 0x80) == 0x80)
return 0x00;
}
return 0x05;
}
/* 根据receiveEventStatus,解析串口响应 */
void receiveEventFunction(){
switch(receiveEventStatus){
case EVENT_GET_IMAGE_FOR_CHECK:
if(cfmCode == 0){
//传感器采集到指纹
sendCmdStatus = ACTION_BUILD_CB1_FOR_CHECK;
}else if(cfmCode == 2){
//传感器上没有手指,延时后继续发送采集命令
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
delay(3000);
}
break;
case EVENT_BUILD_CB1_FOR_CHECK:
if(cfmCode == 0){
//生成特征码成功
sendCmdStatus = ACTION_SEARCH;
delay(3000);
}else{
//生成特征码失败
showWarning();
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
delay(3000);
}
break;
case EVETN_SEARCH:
if(cfmCode == 0){
//@TODO:搜索到匹配指纹
uartSendByte(receiveParams[0]);
uartSendByte(receiveParams[1]);
uintTemp = receiveParams[0];
uintTemp = uintTemp<<8;
uintTemp += receiveParams[1];
uintTemp = uintTemp / 100;
P1 = display_code[uintTemp + 1];
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
delay(65535);
}else{
//搜索失败
showWarning();
P1 = 0x3F;
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
delay(3000);
}
break;
case EVENT_GET_IMAGE_FOR_INPUT1:
if(cfmCode == 0){
//传感器采集到指纹
sendCmdStatus = ACTION_BUILD_CB1_FOR_INPUT;
noFingureTimesWhenInput = 0; //录入时没有指纹的次数归零
}else if(cfmCode == 2){
//传感器上没有手指,延时后继续发送采集命令,计数30次后重置为验证指纹
noFingureTimesWhenInput++;
if(noFingureTimesWhenInput > NO_FINGURE_WHEN_INPUT_MAX_TIME)
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
else
sendCmdStatus = ACTION_GET_IMAGE_FOR_INPUT1;
delay(3000);
}
break;
case EVENT_BUILD_CB1_FOR_INPUT:
if(cfmCode == 0){
//生成特征码成功
sendCmdStatus = ACTION_GET_IMAGE_FOR_INPUT2;
delay(3000);
}else{
//生成特征码失败
showWarning();
sendCmdStatus = ACTION_GET_IMAGE_FOR_INPUT1;
delay(3000);
}
break;
case EVENT_GET_IMAGE_FOR_INPUT2:
if(cfmCode == 0){
//传感器采集到指纹
sendCmdStatus = ACTION_BUILD_CB2_FOR_INPUT;
noFingureTimesWhenInput = 0;
}else if(cfmCode == 2){
//传感器上没有手指,延时后继续发送采集命令,计数30次后重置为验证指纹
noFingureTimesWhenInput++;
if(noFingureTimesWhenInput > NO_FINGURE_WHEN_INPUT_MAX_TIME)
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
else
sendCmdStatus = ACTION_GET_IMAGE_FOR_INPUT2;
delay(3000);
}
break;
case EVENT_BUILD_CB2_FOR_INPUT:
if(cfmCode == 0){
//生成特征码成功
sendCmdStatus = ACTION_MEARGE_CODE;
delay(3000);
}else{
//生成特征码失败
showWarning();
sendCmdStatus = ACTION_GET_IMAGE_FOR_INPUT2;
delay(3000);
}
break;
case EVENT_MEARGE_CODE:
if(cfmCode == 0){
//特征码合并成功
sendCmdStatus = ACTION_SAVE_ADDRESS;
delay(3000);
}else{
//特征码合并失败
showWarning();
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
delay(3000);
}
break;
case EVENT_SAVE_ADDRESS:
if(cfmCode == 0){
//指纹特征保存成功
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
delay(3000);
updateFingureAddress(newFingureAddressIndex);
}else{
//特征码合并失败
showWarning();
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
delay(3000);
}
break;
}
}
/* 根据sendCmdStatus,构造发送命令 */
void sendCmdFunction(){
/* 串口接受的相关状态复位 */
receiveEventStatus = 0;
waitForReceive = 1;
receiveBufferLength = 0;
switch(sendCmdStatus){
case ACTION_GET_IMAGE_FOR_CHECK:
P1 = display_code[10];
sendCmdAndParams[0] = 0x01;
buildSendCmd(1);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_BUILD_CB1_FOR_CHECK:
sendCmdAndParams[0] = 0x02;
sendCmdAndParams[1] = 0x01;
buildSendCmd(2);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_SEARCH:
sendCmdAndParams[0] = 0x04;
sendCmdAndParams[1] = 0x01;
sendCmdAndParams[2] = 0x00;
sendCmdAndParams[3] = 0x00;
sendCmdAndParams[4] = 0x03;
sendCmdAndParams[5] = 0xE7;
buildSendCmd(6);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_GET_FINGURE_ADDRESS_LIST0:
sendCmdAndParams[0] = 0x1F;
sendCmdAndParams[1] = 0x00;
buildSendCmd(2);
uartSendBuffer(sendBuffer, sendBufferLength);
break;
case ACTION_GET_FINGURE_ADDRESS_LIST1:
sendCmdAndParams[0] = 0x1F;
sendCmdAndParams[1] = 0x01;
buildSendCmd(2);
uartSendBuffer(sendBuffer, sendBufferLength);
break;
case ACTION_GET_FINGURE_ADDRESS_LIST2:
sendCmdAndParams[0] = 0x1F;
sendCmdAndParams[1] = 0x02;
buildSendCmd(2);
uartSendBuffer(sendBuffer, sendBufferLength);
break;
case ACTION_GET_FINGURE_ADDRESS_LIST3:
sendCmdAndParams[0] = 0x1F;
sendCmdAndParams[1] = 0x03;
buildSendCmd(2);
uartSendBuffer(sendBuffer, sendBufferLength);
break;
case ACTION_GET_IMAGE_FOR_INPUT1:
P1 = display_code[11];
sendCmdAndParams[0] = 0x01;
buildSendCmd(1);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_GET_IMAGE_FOR_INPUT2:
sendCmdAndParams[0] = 0x01;
buildSendCmd(1);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_BUILD_CB1_FOR_INPUT:
sendCmdAndParams[0] = 0x02;
sendCmdAndParams[1] = 0x01;
buildSendCmd(2);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_BUILD_CB2_FOR_INPUT:
sendCmdAndParams[0] = 0x02;
sendCmdAndParams[1] = 0x02;
buildSendCmd(2);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_MEARGE_CODE:
sendCmdAndParams[0] = 0x05;
buildSendCmd(1);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
case ACTION_SAVE_ADDRESS:
sendCmdAndParams[0] = 0x06;
sendCmdAndParams[1] = 0x01;
sendCmdAndParams[2] = (uchar)(newFingureAddressIndex>>8);
sendCmdAndParams[3] = (uchar)newFingureAddressIndex;
buildSendCmd(4);
uartSendBuffer(sendBuffer, sendBufferLength);
delay(65535);
break;
}
}
/* 等待下位机反馈的延时计数函数 */
void waitForReceiveFunction(){
waitTimes++;
delay(500);
}
/* 对指纹模块的复位函数 */
void resetFingureFunction(){
waitTimes = 0;
//@TODO:控制引脚让指纹下位机复位
delay(65535);
delay(65535);
delay(65535);
delay(65535);
initMain();
sendCmdStatus = ACTION_GET_IMAGE_FOR_CHECK;
}
/**
* 获取指纹模块的有效指纹列表
* @return [0:成功,1:超时失败,2:反馈错误]
*/
uchar getAddressListFunction(){
sendCmdStatus = ACTION_GET_FINGURE_ADDRESS_LIST0;
for(ut1 = 0; ut1 < 4; ut1++){
sendCmdFunction();
if(waitForReceive)
delay(65535);
if(waitForReceive)
delay(65535);
if(waitForReceive)
delay(65535);
if(waitForReceive)
delay(65535);
//等待4 * 65535个机器步骤,如果依然没有反馈则失败
if(waitForReceive)
return 1;
if(cfmCode || receivePackageLength != 35)
return 2;
//从串口反馈参数中提取列表索引数据
for(uintTemp = 0; uintTemp < 33; uintTemp++){
fingureAddressIndex[ ut1 * 32 + uintTemp] = receiveParams[uintTemp];
}
sendCmdStatus++; //将指令移到下一页
}
return 0;
}
/**
* 根据内存中的指纹库,和传入的权限,构造一个新的未使用的指纹索引
* @param uchar [权限,1-10]
* @return [未使用的指纹库索引]
*/
uint getNewAddressIndexByPower(uchar power){
uintTemp = (power - 1) * 100;
ucharTemp = fingureAddressIndex[uintTemp / 8]<<(uintTemp % 8);
while((ucharTemp & 0x80) == 0x80){
uintTemp++;
ucharTemp = fingureAddressIndex[uintTemp / 8]<<(uintTemp % 8);
}
return uintTemp;
}
/**
* 更新指纹库,将指定位置的bit置为1
* @param address [指定地址]
* @return []
*/
void updateFingureAddress(uint address){
ucharTemp = fingureAddressIndex[address/8];
ut1 = 0x80 >> (address % 8);
ucharTemp = ucharTemp | ut1;
fingureAddressIndex[address/8] = ucharTemp;
}
/* @TODO:交互反馈 */
void showWarning(){
}