指纹考勤机的设计与实现.docx

上传人:b****3 文档编号:10676871 上传时间:2023-05-27 格式:DOCX 页数:35 大小:1.53MB
下载 相关 举报
指纹考勤机的设计与实现.docx_第1页
第1页 / 共35页
指纹考勤机的设计与实现.docx_第2页
第2页 / 共35页
指纹考勤机的设计与实现.docx_第3页
第3页 / 共35页
指纹考勤机的设计与实现.docx_第4页
第4页 / 共35页
指纹考勤机的设计与实现.docx_第5页
第5页 / 共35页
指纹考勤机的设计与实现.docx_第6页
第6页 / 共35页
指纹考勤机的设计与实现.docx_第7页
第7页 / 共35页
指纹考勤机的设计与实现.docx_第8页
第8页 / 共35页
指纹考勤机的设计与实现.docx_第9页
第9页 / 共35页
指纹考勤机的设计与实现.docx_第10页
第10页 / 共35页
指纹考勤机的设计与实现.docx_第11页
第11页 / 共35页
指纹考勤机的设计与实现.docx_第12页
第12页 / 共35页
指纹考勤机的设计与实现.docx_第13页
第13页 / 共35页
指纹考勤机的设计与实现.docx_第14页
第14页 / 共35页
指纹考勤机的设计与实现.docx_第15页
第15页 / 共35页
指纹考勤机的设计与实现.docx_第16页
第16页 / 共35页
指纹考勤机的设计与实现.docx_第17页
第17页 / 共35页
指纹考勤机的设计与实现.docx_第18页
第18页 / 共35页
指纹考勤机的设计与实现.docx_第19页
第19页 / 共35页
指纹考勤机的设计与实现.docx_第20页
第20页 / 共35页
亲,该文档总共35页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

指纹考勤机的设计与实现.docx

《指纹考勤机的设计与实现.docx》由会员分享,可在线阅读,更多相关《指纹考勤机的设计与实现.docx(35页珍藏版)》请在冰点文库上搜索。

指纹考勤机的设计与实现.docx

指纹考勤机的设计与实现

指纹考勤机硬件部分完成---小记

最初的想法

一直以来都对一些技术感兴趣,比如指纹识别算法、无线通信、红外感应、微处理器体系架构等等,在大二的时候就想做一台指纹考勤机,进门的时候手指按一下,什么都搞定了,不用看着老师被忽悠,我也不解,如果我是一个技术出身的老师,我早就做这件事情了,何必点名,费劲。

这段时间,有了空档,我就着手做这件事情。

是这样设计的,硬件由指纹模块和控制板,上位机用VB开发。

实现的功能大致是:

上位机数据库保存人员信息,即指纹号对应学号、姓名等信息,指纹机可以脱机采集到岗信息(指纹号),在通信模式下,与上位机连接,将采集到的指纹号上传,上位机处理这些信息,生成缺勤名单文件(txt/word/excel皆可),并将缺勤名单发到指定的邮箱。

硬件平台的选择求助了一下淘宝,可选的不多,一个能存储162枚指纹的指纹模块进入了我的视线,4线,VCC/GND/TXD/RXD,还提供51例程,它用的是国产指纹识别专用DSP,只开放用串口用户命令接口。

看到51就知道就知道它跟识别算法之类的没有关系,注定要对着daasheet编写驱动。

但可以短时间内达到设计目标并以此为契机继续学习也不错。

很明显,需要用VB实现的是:

串行通信、数据库编程、文件操作、网络编程。

串行通信和数据库编程毕业设计的时候用过,后两者要现学。

开始的时候模块资料上写单片机的RXDP3.0和TXDP3.1只能连模块,连max232都不能有,所以至少双串口才可以实现与上位机通信,打算使用双串口的60S2,而且没有用户flsah,只能在录取完信息保持开机状态知道传输完信息给上位机处理。

但测试后发现,模块在链接max232的情况下仍能正常工作,而且文档显示它有用户16页共512字节flash可以使用。

这样,录入过程中将信息存入flash,在上位机通信模式下,重新初始化串口波特率实现上位机通信,为了提高运行速度,没有使用89C52,还是使用了60S2。

这样软硬件都清晰了。

任务示意如下:

初步调试:

基本资源、12864

对于60S2的使用,绝对可以用轻车熟路来形容了。

实验室正好有一块51单片机开发板,串口、中断按钮、LED、12864屏都有,就是没有任何资料,管脚信息只能用万用表一点点测量。

下载keil、下载STC_ISP,单片机精灵、串口助手、拷贝之前的设计资料,测量端口、用了一天的时间,基本把LED、定时器、串口、按键、外部中断全部搞定了。

对于12864的资料网上有很多,找到了一篇很有用的文章《非常好-12864带字库液晶学习》,跟着上面的步骤,用了一下午时间把LCD显示也搞好了。

形成了第一个测试工程代码standard1。

12864的端口定义如下:

12864顾名思义有128*64个像素点,即是横向128个点,竖向64个点,由于该液晶控制器支持的字符为8*16,汉字为16*16,因此只能显示四行,如果是汉字,为每行显示8个,如果是字符,每行显示16个。

    驱动函数一般包括四个函数:

    1、写命令函数;    2、写数据函数;

    3、读状态函数;    4、读数据函数;

    这四个函数并不是必须全部写的,具体要看你实现的功能,如果只是单纯的显示汉字和字符,写命令、写数据、读状态这三个函数就够了,如过你还需要进行一些绘图的操作,那读数据函数也必须书写。

    另外关于读状态函数,其实也就是用于判忙操作,我看郭天祥的书里面是这样说的:

原则上每次对控制器进行读写操作之前,都必须进行读写检测,由于单片机的操作速度慢于液晶控制器的反应速度,因此可不进行读写检测,或者只进行简短的延时即可。

因此,读状态函数也可以不写,只用简短的延时函数替换即可。

知道这些信息后,下面就是驱动函数的移植和使用了,在三个基本驱动函数、初始化函数、延时函数的基础上,用户要调用的函数有下面几个:

voidSet_Cursor(unsignedcharx,unsignedchary)//设置光标

voidDisplay_Char(unsignedcharAlphabet)//(设置光标后)显示单个字符

voidLcd_ClrScreen()//清屏

voidDisplay_String(unsignedcharx,unsignedchary,unsignedchar*Alphabet)

//在指定位置显示字符串

voidDisplay_HZ(unsignedcharx,unsignedchary,unsignedchar*HZ)

//在指定位置显示汉字

voidDisplay_HZ_Line(unsignedcharx,unsignedchary,unsignedchar*HZ)

//在制定位置显示汉字,可自动换行

初步调试:

例程的学习及移植

成功移植

模块的默认波特率是9600bps,但是开发板用的是12M晶振,产生不了该波特率,误差太大,总是产生握手失败的错误,只能选用11.0592的晶振(从蛟哥的板子上取下),例程中的12864的工作方式是串行工作方式,一直显示不正常,于是我把之前测试通过的并行工作方式代码移植进了例程。

又对例程中的端口进行了重定义,对工程代码进行了规范化(函数化、模块化、头文件)处理,将模块TXD连到P3.0,RXD连到P3.1,在接通开发板上的5V。

成功运行了例程,实现了:

录入指纹、指纹识别、删除全部指纹的基本功能。

形成了standard2工程文件包。

此时工程文件如下,也是最终的样式。

端口重定义如下(io.h):

模块通过串口与单片机相连,通过查询的方式发送和接收,没有使用串口中断,串口初始化代码和发送代码在uart.c中。

Timer.c中只有一个初始化函数和中断函数,不是很关键,只是为了实现命令发送函数中的一个毫秒级延时。

Io.c中有端口定义和外部中外部中断相关的代码。

Fingerprint.c中是与模块相关的驱动函数。

指纹识别算法是模块内部的DSP实现的,对用户提供了串行命令接口,使用的时候只需要调用这些命令帧,加上校验码就行了,再等待模块响应看是否成功。

是用模块的过程是:

设备握手、探测手指获取图像、生成特征模版1存入缓冲区、生成特征模版2存入缓冲区、将两个特征文件合成一个指纹模版存入指纹库、从库中进行指纹对比。

这些功能都是有具体的指令进行操作的。

此外,删除全部指纹、删除单个指纹、也是有专用的命令的。

所以指纹模块的文档就显得非常重要。

程序中比较重要的指令和变量:

Savenumber是当前已经存储的指纹个数;searchnum是识别函数返回的搜索到的指纹号;modeflag是模式标志,例程有:

识别模式、录入模式。

由于中断中不能写太多的东西,主程序中通过查询clearallflag和changeflag进行删除全部指纹和模式转换的具体操作。

外部中断转换模式的代码如下:

消抖方式很有特色。

FIFO是发送命令后接受模块相应的缓冲区,FIFOnumber是缓冲区中的数据个数。

这个数据在命令发送函数中使用。

标志为在中断中

Fingerprint.c中模块操作的主要函数:

一个最最重要的函数是命令发送函数,所有的操作都是通过这个函数。

其帧处理方式还是很值得学习的。

这个函数的处理过程:

发送命令、接收响应帧到FIFO、判断校验码、返回值。

bitCommand(unsignedchar*p,unsignedcharMaxTime)//命令解析,给模块发送一个命令

{

unsignedcharcount=0,tmpdat=0,temp=0,i=0,package=0,flag=0;

unsignedcharchecksum=0;

bitresult=0,start=0,stop=0;

TxdByte(0xef);//数据包包头识别码

TxdByte(0x01);//数据包包头识别码

i=*p;//数组的第“0”个元素、里面存放了本数组的长度,把这个长度给变量i,方便进行操作

p++;

p++;//不知道为什么它命令中定义了一个无效字节,所以挪了两次

for(count=i-1;count!

=1;count--)//SentcommandString

{

temp=*p++;

TxdByte(temp);//将命令发送出去

}

result=TURE;//发送完成,结果为真(真为1)

FifoNumber=0;

for(count=MAX_NUMBER+1;count!

=0;count--)//清空所有FIFO[]数组里面的内容,写入0X00

{

FIFO[count-1]=0x00;

}

if(result)

{

result=FALSE;

start=FALSE;

stop=FALSE;

count=0;

clk0=0;//清零CL0计数

do/////////////////////////////do的内容////////////////////////////////

{

restart0:

if(RI==1)//如果接收到数据

{

tmpdat=SBUF;//先把接收到的数据放到tmpdat中

RI=0;

if((tmpdat==0xef)&&(start==FALSE))//这个数据为第一个传回来的数据,也就是“指令应答”的第一个字节

{

count=0;

FIFO[0]=tmpdat;//读入第一个应答字节(0XEF),存在第“0”个元素中

flag=1;

goto

restart0;//继续接受收

}

if(flag==1)//第一个字节已经回来,所以flag==1成立

{

if(tmpdat!

=0x01)//接收数据错误,将重新从缓冲区接收数据

{

flag=0;//接收应答失败

result=FALSE;

start=FALSE;

stop=FALSE;

count=0;

goto

restart0;

}

//如果成功接收到0xef01,可以开始接收数据

flag=2;//flag=2;表示应答成功,可以开始接收数据了

count++;//现在count=1;

FIFO[count]=tmpdat;//读入第二个应答字节(0X01),存在第“1”个元素中

start=TURE;//应答成功可以开始接收数据

goto

restart0;

}

if((flag==2)&&(start==TURE))

{

count++;//数据元素下标++

FIFO[count]=tmpdat;//依次存入

if(count>=6)

{

checksum=FIFO[count]+checksum;//从这里才是计算校验和,这与帧格式有关

}

if(count==8)

{

package=FIFO[7]*0X100+FIFO[8];//计算包长度,这是帧格式规定的

stop=TURE;

}

if(stop)

{

if(count==package+8)

{//校验不完全正确,因为没有比对第二个校验码

checksum=checksum-FIFO[count-1];

if(checksum!

=FIFO[count]&0xff)

result=FALSE;//校验失败,置结果标志为0

else

result=TURE;

flag=0;

break;

}

}

}

}

}/////////////////////////////do的内容----------------结束////////////////////////////////

while((clk0<=MaxTime)&&(count<=MAX_NUMBER)&&(changeflag==0));

FifoNumber=count;//保存接收到的数据个数

}

return(result);

}

其它的重要函数:

bitVefPSW(void)

//验证设备握手口令,成功返回1,通过发送VPWD指令来进行的。

通过判断FIFO中的响应帧中的确认码和响应帧字节数来知道是否成功执行。

具体如下:

while

(1)

{

if(Command(VPWD,20)&&(FifoNumber==11)&&(FIFO[9]==0x00))

{

return

(1);

}

count++;

if(count>=2)//如果不成功,再验证一次,如果两次不成功,返回失败

{

return(0);

}

}

voidClear_All(void)//清空所有指纹信息,清空前首先验证和指纹模块通讯是否正常

{

if(VefPSW()==1)//验证成功

{

Command(DELE_all,50);//清空指纹库

}

}

unsignedcharImgProcess(unsignedcharBUFID)//发获取图像并生成特征文件,存入BUFID中//输入参数为缓冲区号,1为生成特征文件1,2是生成特征文件2,这是通过发送GEN1和GEN2命令完成的。

在录入指纹的时候需要进行两次采集和成模版再存储。

在识别的时候只需要用这个函数采集一个特征文件去指纹库做比对。

bitSearchfinger(void)//搜索指纹(发送搜索命令、以及根据返回值确定是否存在),应该是默认使用特征文件1进行比对,如果比对成功,则结果放在Searchnum中。

unsignedcharsearch(void)//先获取一次特征文件,调用上一个函数,如果比对成功则返回searchnum,如果不成功则返回255。

bitsavefingure(unsignedcharID)//保存指纹

unsignedcharenroll(void)//采集两次指纹,生成1个指纹模板

voidnumshow(unsignedcharnum)//指纹号显示函数

{

strnum[0]=num/100+48;//+48是为了转换在ASCII码百

strnum[1]=(num%100)/10+48;//+48是为了转换在ASCII码十

strnum[2]=num%10+48;//+48是为了转换在ASCII码个

Display_HZ_Line(3,0,"指纹号:

");

Display_HZ_Line(3,4,strnum);

}

voidmodecheck(void)//模式指示函数

{

if(modeflag==0)

{

green=0;

red=1;

Display_HZ_Line(1,0,"识别模式");

}

else

{

red=0;

green=1;

Display_HZ_Line(1,0,"录入模式");

}

numshow(0);

}

voidshakehands(void)//握手函数,其实就是调用了若干次bitVefPSW(void)

主函数分析

voidmain(void)

{

timer_init();//定时器初始化

uart_init();//串口初始化

Display_Init();//12864初始化

Lcd_ClrScreen();//清屏

externalint_init();//外部中断初始化

Display_HZ_Line(0,0,"指纹识别系统");

shakehands();//与模块握手

while

(1)//查询四个标志

{

if(modeflag==1)//为录入指纹模式

{

if(k2==0)//按一次按键,录入一个指纹

{

delay1ms(10);

if(k2==0)//如果仍为低电平,表示按键有效

{

while(k2==0);//等待松手

if(SaveNumber<162)//还没有超过录入上限

{

if(enroll()==1)//采集两次,生成1个指纹模板成功

{

if(savefingure(SaveNumber+1)==1)//保存也成功

{

SaveNumber++;//加一次

Display_HZ_Line(2,0,"录入成功");

delay1ms(800);

Display_HZ_Line(2,0,"");

numshow(SaveNumber);

}

}

else

{

Display_HZ_Line(2,0,"录入失败");

delay1ms(800);

Display_HZ_Line(2,0,"");

}

}

}

}

}

if(modeflag==0)//为识别模式

{

searchnum=search();

if(searchnum>=1&&searchnum<=162)

{

numshow(searchnum);//显示搜索到的指纹

buzzer=0;delay1ms(100);buzzer=1;//蜂鸣器响三声

relay=0;delay1ms(3000);relay=1;//继电器打开3秒

}

if(searchnum==255)//识别指纹失败

{

//蜂鸣器响三声

numshow(0);

buzzer=0;delay1ms(100);buzzer=1;delay1ms(100);

buzzer=0;delay1ms(100);buzzer=1;delay1ms(100);

buzzer=0;delay1ms(100);buzzer=1;delay1ms(100);

}

}

if(clearallflag==1)

{

clearallflag=0;

Clear_All();

red=0;//红色灯亮

green=1;//蜂鸣器长响一次,表示清除所有指纹结束

modeflag=1;//进入录入指纹模式

buzzer=0;

delay1ms(800);

buzzer=1;

SaveNumber=0;

numshow(0);

modecheck();

}

if(changeflag==1)

{

modecheck();

changeflag=0;

}

}////////////////////////////while

(1)end////////////////////////////////

}

具体的操作是:

开机握手成功后,自动进入识别模式,该模式下可以进行指纹识别,若识别成功,则显示识别成功。

按中断1按钮转换到录入模式,有文字提示。

在该模式下按下K2键,可以录入一次指纹,录入的方法是,将手指放置,指纹头灯灭,待灯再次亮起,将手指第二次放置,LCD显示录入成功,并显示该指纹的指纹号。

按下外部中断0键可以删除所有指纹。

这些基本的功能是实现本次设计的基石。

指纹考勤机的硬件操作规范

在经过二次开发后,硬件的操作规范如下:

开机进入识别模式,按中断按钮1进入录入模式,按中断按钮0删除所有指纹(此时有pleasewait提示)。

定义了K4辅助键。

sbitk4=P3^5;

辅助键+外部中断0按钮清除1个指纹(该指纹为上一次识别的指纹)。

辅助键+外部中断1按钮保存残页,考勤信息满32个(1页)自动保存,而在录入完毕之后,需要这个功能保存残页。

录入键+外部中断1按钮进入上位机通信模式;该模式下串口的波特率被重新初始化,一旦进入则不可与模块再次通信,再次正常工作的方式只有重启。

 

二次开发的技术要点及其实现方法

实现了接续录入功能,这是很大的突破

例程有一个致命的缺点,那就是每次开机录入总是从001号指纹开始录入,因为savenumber总是初始化为0。

这就意味着不允许有人员的新加入,每次继续录入,总会覆盖之前的指纹,这是应用的最大障碍。

我觉得一个完善的模块不会有这么大的bug,难道要用户自己外接flash?

我查询了一下模块文档,文档上说模块在flash中开辟了512字节的用户记事本,共16页,每页32字节。

而且有专门的命令进行写记事本和读记事本操作。

这下就豁然开朗了,可以将存入的指纹个数存储到用户记事本中,每次开机将这个数读出,在这个个数的基础上继续录入,当录入、删除(单个、全部)动作时调用写入函数更新指纹数。

就解决了这个问题。

我就是这么做的,每次录入将指纹个数存储在第0页的首字节。

封装了两个函数,指纹数的存储和读出函数。

实现过程如下:

5standard3

这是模块文档上关于写记事本和读记事本的指令说明:

我在fingerprint.c中定义了读记事本和写记事本的两个命令帧

因为这两个命令的内容不固定,需要填入参数(比如读哪一页?

写哪些数据?

等等),所以没有定义成code类型,放在了RAM里。

我封装的两个函数如下

//实现对第0页的首字节的写操作,存储当前指纹数

voidfpnum_to_flash(unsignedchark)

{intcount=0;

intsum=0;

inti;

WENT[10]=0;//存放到第0页

WENT[11]=k;//存放的数据是输入参数

for(i=6;i<=42;i++)//开始计算校验和

{

sum+=WENT[i];

}

WENT[43]=(sum>>8)&0x00ff;//将两个字节校验

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2