HUBEI NORMAL UNIVERSITY
嵌入式课程设计报告
课题: 指纹识别门禁系统设计 : 万苗 学号:
院系: 电脑科学与技术学院 班级: 1303班 导师: 曹杉杉
学习文档 仅供参考
基于ARM的指纹识别门禁系统设计
【摘 要】 本设计介绍了基于ARM的指纹识别门禁系统的软硬件设计。其中硬件主要是Intel 公司基于Xscale内核的PXA255处理器和美国豪威公司的CMOS图像传感器FPS200。软件设计包括系统初始化, 指纹处理识别, 电控锁控制部分等。经过实际测试该系统工作稳定可靠, 到达了设计目的。
【关键词】 ARM 门禁系统 指纹识别 TCP/IP 图像
一、门禁系统概述
门禁系统(Access Contro l System ) , 又称出入口控制系统,是为保障人们生活、工作及财产安全, 对重要通道的出入口进行管理与控制的系统。随着技术的发展, 门禁系统已经从传统的卡式门禁系统发展到今天的生物特征识别门禁系统。生物特征识别门禁系统是以人体生物特征作为辨识条件的指纹比对、掌纹比对、语音比对等。这些生理特征相同的概率到达数十亿分之一,因此具有无法仿冒与借用、不怕遗失、不用携带、不会遗忘,有着个体特征独特性、唯一性、安全性的特点,适用于高度机密性场所的安全保护。其中指纹识别发展最早, 使用也最广泛。并逐渐与网络集成。
二、PXA 255处理器和指纹传感器FPS200简介
本系统采用Intel 公司基于Xscale 内核的PXA255处理器。Xscale微架构采用ARMV 5TE ISA 兼容指令集(浮点指令集除外),它以ARM 核为中心,在其周围扩展了指令和数据内存管理(Inst ruct ion andDataM emo ryM anagement Unit), 指令、数据和微小数据高速缓(Instruction,Data and Mini-DataCache),写缓冲、全缓冲、挂起缓冲和分支目标缓冲,电源管理单元, 性能监测单元, 调试和JTAG 单元以及协处理器接口、MAC 协处理器、核心存储总线等。FPS系列CMOS图像传感器芯片是美国豪威公司的产品。FPS200是高度集成的彩色摄像芯片, 可带1/4镜头。支持多种格式, 内设的SCCB (Serial Camera Cont ro lBus) 串行控制总线接口, 提供简单控制方式。通过该接口, 我们可以对FPS200芯片内部所有寄存器值进行修改, 从而完成对FPS200的控制, 包括色彩饱和度的调整、gamma 校正等等。该芯片最高能到达每秒钟30帧的传输速率, 并且用户可以控制图像质量, 可以根据自己的需要选择合适的图像质量。另外FPS200内置了640×480
学习文档 仅供参考
分辨率的镜像阵列,A/D转换器, 并支持外部水平、垂直同步输入格式, 数字视频输出、增益 控制、黑平衡和白平衡等在内的控制寄存器功能模块。其内部框图如图1:
图1 FPS200内部结构框图
学习文档 仅供参考
三、系统硬件设计
1、结构框图
系统的硬件架构原理框图如图2所示,本系统主要实现指纹的识别、处理、特征模板提取、
结果显示,以及完成个人身份识别/注册功能。主要由ARM9处理、VGA控制及结果显示等模块组成。
学习文档 仅供参考
2、指纹识别模块
×1.50cm,500dpi分辨率,内置有8位ADC,且有微处理器总线、SPI总线三种接口模式。其通过改变电容阵列的参数值可在一秒钟内扫描多副指纹图像便自动选择最好的一幅。本指纹防盗系统采用了传感器的USB模式传感器的数据线直接与STR912x芯片扩展口相接。
指纹采集电路的原理图如图4所示,其工作原理为:PXA255处理器通过I2C总线设置FPS200的寄存器,系统开GPIO72(VSYNC)的中断使能并检测中断,当GPIO72(V SYNC) 中断到来以后,打
学习文档 仅供参考
开GPIO73(HREF)中断使能,关闭其它的中断使能。当GPIO73(HREF)中断到来以后, 打开GPIO74(PCLK)中断使能, 关闭其它中断。每当GPIO74(PCLK)中断到来, 就将GPI2Obuffer 里的GPIO64~GPIO71数据采集出来, 保存到imgbuf数组中去。重复这一步一直到采满382×240 次为止。将imgbuf按照每隔320 个元素就舍弃62个元素进行处理,这样得到的数据就是320×240 大小的灰度指纹图像。
图4 指纹采集电路原理图
学习文档 仅供参考
3、数据处理模块
数据处理模块主要完成指纹识别的整个处理过程,包括指纹图像软化、方向图提取、图像增强、二值化、图像滤波、图像细化等。该模块采用了TMS320VC5402,使用FLASH和SDRAM分别作ARM处理器的程序存储器。TMS320VC5402是16位定点DSP,采用改良的哈佛结构适应远程通信等实时嵌入式的需要。为了提高速度,本文对一些核心的算法进行了优化。
4、全局逻辑控制单元
系统中大多数外围器件与DSP 的握手信号都是通过可编程逻辑器件来完成的,CPLD电路设
计按其所实现的功能可分为DSP寻址空间和芯片读写信号两个模块,其中DSP寻址空间模块根据DSP输出的控制信号和数据空间选择信号分时寻址SRAM和FLASH两个存储体。
四、系统软件设计
指纹识别系统的主程序流程图如图5所示。目标板上电后对整个识别系统进行初始化操作,包括DSP系统的初始化和目标板上外设的初始化,对他们进行参数设置。初始化完成后开始检测指纹传感器上是否有手指,如果有则进行指纹图像的识别识别完成后就对着枚指纹图像进行预处理工作,在预处理的前端,对识别进来的这枚指纹进行质量评估,以判断是否需要继续进行指纹图像的预处理工作,假设指纹质量比较好则继续进行预处理和数据上传;如果图像的质量很差,则作废这枚指纹数据。
指纹图像的识别是在中断程序中开始的,当指纹传感器上没有手指时,系统将进入省电模式,通过指纹传感器FPS200的手指自动检测中断来唤醒系统,并进行一次指纹图像识别、预处理和数据上传。指纹登记个数≥3000枚。系统设计完成后,可脱机值守工作。122×32点阵LCD实时显示时钟、操作状态,并具有15键操作键盘,可独立完成建档及查询功能。系统核查指纹1:N与1:1两种方式兼容,提供RS232/R485、RJ45接口支持局域网连接。
学习文档 仅供参考
五、结论及心得体会
本次设计主要介绍了基于ARM的指纹识别门禁系统的软硬件设计。ARM体系结构有丰富的接口, 在门禁、监控等领域正发挥越来越重要的作用, 面向可集成, 可扩展, 可移植的特定嵌入式系统越来越多的出现在工程领域。随着性价比的提高和软件开发的成熟,ARM 在嵌入式领域的应用会越来越广泛。本文从指纹识别的可靠性及速度上考虑, 在门禁系统中以ARM 微处理器做控制器,充分利用了其高速的运算处理能力。
通过此次课程设计,我真真正正的意识到,在以后的学习中,要理论联系实际,把我们所学的理论知识用到实际当中,学习嵌入式更是如此,程序只有在经常的写与读的过程中才能提高,这就是我在这次课程设计中的最大收获。
六、程序代码:
学习文档 仅供参考
#ifndef _FPS200_H_ #define _FPS200_H_ #define ROW_NUM 300 #define COL_NUM 256
#define FPS200_IOCRESET _IO(FPS200_IOC_MAGIC) #define FPS_RAH 0x00 #define FPS_RAL 0x01 #define FPS_CAL 0x02 #define FPS_REH 0x03 #define FPS_REL 0x04 #define FPS_CEL 0x05 #define FPS_DTR 0x06 #define FPS_DTR_TIME 0x70 #define FPS_DCR 0x07 #define FPS_DCR_CURRENT 0x6 #define FPS_CTRLA 0x08
#define FPS_CTRL_ASM_ARCH_EP7211_HA_GETSUB 0x04 #define FPS_CTRLA_GETIMG 0x02 #define FPS_CTRLA_GETROW 0x01 #define FPS_CTRLA_AINSEL 0x08 #define FPS_CTRLB 0x09 #define FPS_CTRLB_MODE 0xC0 #define FPS_CTRLB_RDY 0x20 #define FPS_CTRLB_AFDEN 0x08 #define FPS_CTRLB_AUTOINCEN 0x04 #define FPS_CTRLB_XTALSEL 0x02 #define FPS_CTRLB_ENABLE 0x01 #define FPS_CTRLC 0x0A
#define FPS_SRA_ASM_ARCH_EP7211_H 0x0B #define FPS_SRA_GETSUB 0x04
学习文档 仅供参考
#define FPS_SRA_GETIMG 0x02 #define FPS_SRA_GETROW 0x01 #define FPS_PGC 0x0C
#define FPS_PGC_VALUE 0x4//0xb #define FPS_ICR 0x0D
#define FPS_ICR_IP1_RISE 0x80 #define FPS_ICR_IP0_RISE 0x40 #define FPS_ICR_IT1_LEVEL 0x20 #define FPS_ICR_IT0_LEVEL 0x10 #define FPS_ICR_IM1 0x08 #define FPS_ICR_IM0 0x04 #define FPS_ICR_IE1 0x02 #define FPS_ICR_IE0 0x01 #define FPS_ISR 0x0E #define FPS_ISR_CLRINT 0x01 #define FPS_THR 0x0F #define FPS_THR_THV 0x40 #define FPS_THR_THC 0x09 #define FPS_CIDH 0x10 #define FPS_CIDL 0x11 #define FPS_TST 0x12 #include # define PDEBUG(fmt, args...) printk( KERN_DEBUG\"fps200: \" fmt, ## args) # else /* 用户空间 */ # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ##args) # endif #else 学习文档 仅供参考 # define PDEBUG(fmt, args...) /* 不调试*/ #endif #undef PDEBUGG #define PDEBUGG(fmt, args...) 调试*/ /* 设备结构类型 */ typedef struct FPS200_Dev { unsigned char flag; void *data; } FPS200_Dev; /* 用于 ioctl */ #define FPS200_IOC_MAGIC 'k' /* * S代表 \"Set\" through a ptr * G代表 \"Get\": reply by setting through a pointer * C代表 \"Check\" */ #define FPS200_IOCSDTR _IOC(_IOC_WRITE, FPS200_IOC_MAGIC, 1, 1) #define FPS200_IOCSDCR _IOC(_IOC_WRITE, FPS200_IOC_MAGIC, 2, 1) #define FPS200_IOCSPGC _IOC(_IOC_WRITE, FPS200_IOC_MAGIC, 3, 1) #define FPS200_IOCGDTR _IOC(_IOC_READ, FPS200_IOC_MAGIC, 4, 1) #define FPS200_IOCGDCR _IOC(_IOC_READ, FPS200_IOC_MAGIC, 5, 1) #define FPS200_IOCGPGC _IOC(_IOC_READ, FPS200_IOC_MAGIC, 6, 1) #define FPS200_IOCFCAP _IOC(_IOC_READ, FPS200_IOC_MAGIC,7, 4) #define FPS200_IOCGDATA _IOC(_IOC_READ, FPS200_IOC_MAGIC, 8, 4) #define FPS200_IOCEINT _IOC(_IOC_NONE, FPS200_IOC_MAGIC, 9, 0) #define FPS200_IOCDINT _IOC(_IOC_NONE, FPS200_IOC_MAGIC, 10, 0) 学习文档 仅供参考 不 /* #define FPS200_IOCCINT _IOC(_IOC_READ, FPS200_IOC_MAGIC, 11, 1) #define FPS200_IOCCRDY _IOC(_IOC_READ, FPS200_IOC_MAGIC, 12, 1) #define FPS200_IOCCLR _IOC(_IOC_NONE, FPS200_IOC_MAGIC, 13, 0) #define FPS200_IOC_MAXNR 13 int fps200_open(struct inode *inode, struct file *filp); int fps200_release(struct inode *inode, struct file *filp); int fps200_ioctl (struct inode *inode, struct file *filp, #ifndef __KERNEL__ # define __KERNEL__ #endif #ifndef MODULE # define MODULE #endif #include #include #include #include #include #include #include 学习文档 仅供参考 /* printk() /* kmalloc() /* error codes */ /* size_t */ /* udelay() /* /* #include #include \"fps200.h\" /* local definitions */ #define FPS200_VR 0xfd000000 #define FPS_INDEX (*(volatile unsigned char *)FPS200_VR) #define FPS_DATA (*(volatile unsigned char *)(FPS200_VR+1)) #define FPS200_MAJOR 240 #define FPS200_NR_DEVS 0 #define FPS200_IRQ IRQ_EINT2 // irq = 6 #define FPS200_DATASIZE 76800 int fps200_major = FPS200_MAJOR; int fps200_nr_devs = FPS200_NR_DEVS; /* number of bare fps200 devices (no use here) */ MODULE_PARM(fps200_major,\"i\"); MODULE_PARM(fps200_nr_devs,\"i\"); MODULE_AUTHOR(\"Nankai Unversity 5-304\"); MODULE_LICENSE(\"GPL\"); struct file_operations fps200_fops = { open: fps200_open, ioctl: fps200_ioctl, release: fps200_release }; struct file_operations *fps200_fop_array[]={ &fps200_fops, /* type 0 */ /* add more later */ }; #define FPS200_MAX_TYPE 0 学习文档 仅供参考 FPS200_Dev *fps200_device; void fps200_interrupt(int irq, void *dev_id, struct pt_regs *regs) { disable_irq(irq); //fps_get_image(); fps200_device->flag = 1; } void fps_get_image(void) { int i = 0; int j = 0; FPS_INDEX = FPS_CTRLA; FPS_DATA = FPS_CTRLA_GETIMG; for(i=0; i<300; i++) { FPS_INDEX = FPS_CTRLB; while(!(FPS_CTRLB_RDY&FPS_DATA)){udelay(1);}; for(j=0; j<256; j++) { FPS_INDEX = FPS_CTRLB; while(!(FPS_CTRLB_RDY&FPS_DATA)){udelay(1);}; FPS_INDEX = FPS_CTRLA; *((unsigned char *)(fps200_device->data+i*256+j))=FPS_DATA; } } } int fps200_open(struct inode *inode, struct file *filp) { MOD_INC_USE_COUNT; return(0); } int fps200_release(struct inode *inode, struct file *filp) { MOD_DEC_USE_COUNT; return(0); 学习文档 仅供参考 } int fps200_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0; int ret = 0; unsigned char tmp; if(_IOC_TYPE(cmd) != FPS200_IOC_MAGIC) return -ENOTTY; if(_IOC_NR(cmd) > FPS200_IOC_MAXNR) return -ENOTTY; if (_IOC_DIR(cmd) & _IOC_READ) err = verify_area(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = verify_area(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return err; switch(cmd) { case FPS200_IOCSDTR: ret = __get_user(tmp, (unsigned char *)arg); if(tmp > 0x7f) tmp = 0x7f; FPS_INDEX = FPS_DTR; FPS_DATA = tmp; break; case FPS200_IOCSDCR: ret = __get_user(tmp, (unsigned char *)arg); if(tmp > 0x1f) tmp = 0x1f; 学习文档 仅供参考 FPS_INDEX = FPS_DCR; FPS_DATA = tmp; break; case FPS200_IOCSPGC: ret = __get_user(tmp, (unsigned char *)arg); if(tmp > 0x0f) tmp = 0x0f; FPS_INDEX = FPS_PGC; FPS_DATA = tmp; break; case FPS200_IOCGDTR: FPS_INDEX = FPS_DTR; tmp = FPS_DATA; ret = __put_user(tmp, (unsigned char *)arg); break; case FPS200_IOCGDCR: FPS_INDEX = FPS_DCR; tmp = FPS_DATA; ret = __put_user(tmp, (unsigned char *)arg); break; case FPS200_IOCGPGC: FPS_INDEX = FPS_PGC; tmp = FPS_DATA; ret = __put_user(tmp, (unsigned char *)arg); break; case FPS200_IOCEINT: enable_irq(FPS200_IRQ); break; case FPS200_IOCDINT: disable_irq(FPS200_IRQ); break; case FPS200_IOCFCAP: 学习文档 仅供参考 fps_get_image(); case FPS200_IOCGDATA: copy_to_user((void *)arg, fps200_device->data, FPS200_DATASIZE); ret = 0; fps200_device->flag = 0; break; case FPS200_IOCCLR: memset(fps200_device->data, 0, FPS200_DATASIZE); fps200_device->flag = 0; break; case FPS200_IOCCINT: if(((clps_readw(INTSR1))&0x40) == 0) { udelay(100); if(((clps_readw(INTSR1))&0x40) == 0) ret = __put_user(0x01, (unsigned char *)arg); else ret = __put_user(0x0, (unsigned char *)arg); } else ret = __put_user(0x0, (unsigned char *)arg); break; case FPS200_IOCCRDY: ret = __put_user(fps200_device->flag, (unsigned char *)arg); break; default: return -ENOTTY; } return ret; } 学习文档 仅供参考 static int __init fps200_init_module(void) { int result; char tmp; if((result = check_region (FPS200_VR,2))) { printk (\"<1> can't get I/O port address \\n\"); return (result); } if (!request_region (FPS200_VR,2,\"fps200\")) return -EBUSY; SET_MODULE_OWNER(&fps200_fops); result = register_chrdev(fps200_major, \"fps200\ if(result < 0) { printk(\"<1>fps200: can't get major %d\\n\ return result; } if(fps200_major == 0) fps200_major = result; /* read chip id first, if not equal 0x20xx, print error*/ FPS_INDEX = FPS_CIDH; tmp = FPS_DATA; if(tmp != 0x20) { printk(\"<1>wrong chip ID, insmod fail.\\n\"); return -EIO; } /* row auto inc. inner 12MHz vibrator. no low-power state*/ 学习文档 仅供参考 /* dynamic */ FPS_INDEX = FPS_CTRLB; FPS_DATA = (FPS_CTRLB_AFDEN|FPS_CTRLB_AUTOINCEN|FPS_CTRLB_ENABLE); /* 等待30us */ udelay(35); // 使时延大于 30us /* 中断 */ FPS_INDEX = FPS_ICR; FPS_DATA = (FPS_ICR_IE0|FPS_ICR_IT0_LEVEL); FPS_INDEX = FPS_THR; FPS_DATA = ( FPS_THR_THV | FPS_THR_THC ); /* DTR, DCR, PGC */ FPS_INDEX = FPS_DTR; FPS_DATA = 0x23; FPS_INDEX = FPS_DCR; FPS_DATA = 0x1; FPS_INDEX = FPS_PGC; FPS_DATA = 0; /* other initial */ FPS_INDEX = FPS_RAL; // raw 地址 FPS_DATA = 0; FPS_INDEX = FPS_RAH; FPS_DATA = 0; FPS_INDEX = FPS_REL; FPS_DATA = 0; FPS_INDEX = FPS_REH; FPS_DATA = 0; FPS_INDEX = FPS_CAL; / column 地址 FPS_DATA = 0; 学习文档 仅供参考 / FPS_INDEX = FPS_CEL; FPS_DATA = 0; FPS_INDEX = FPS_CTRLC; FPS_DATA = 0; FPS_INDEX = FPS_CTRLA; FPS_DATA = 0;// clear FPS_CTRLA_AINSEL /* 设置 irq */ if(result) { printk(\"<1>can't get assigned irq.\\n\"); return -EIO; } fps200_device = kmalloc(sizeof(FPS200_Dev), GFP_KERNEL); if(!fps200_device) { FPS_INDEX = FPS_CTRLB; FPS_DATA = 0; return -ENOMEM; } memset(fps200_device, 0, sizeof(FPS200_Dev)); fps200_device->data = kmalloc(FPS200_DATASIZE, GFP_KERNEL); if(!fps200_device) { FPS_INDEX = FPS_CTRLB; FPS_DATA = 0; kfree(fps200_device); return -ENOMEM; } memset(fps200_device->data, 0, FPS200_DATASIZE); /* 设置 irq */ 学习文档 仅供参考 result = request_irq(FPS200_IRQ, fps200_interrupt, SA_INTERRUPT, \"fps200\ return(0); } static void __exit fps200_cleanup_module(void) { kfree(fps200_device->data); kfree(fps200_device); FPS_INDEX = FPS_CTRLB; FPS_DATA = 0; release_region (FPS200_VR,2); free_irq(FPS200_IRQ, NULL); void main(void) { BYTE temp; WORD port = 1001; LocalMACAddr[0]=0x52; LocalMACAddr[1]=0x54; LocalMACAddr[2]=0x4c; LocalMACAddr[3]=0x30; LocalMACAddr[4]=0x2e; LocalMACAddr[5]=0x2f; LocalIPAddress = 0xc0a8020d; /* 本地地址192.168.2.14*/ ServerIPAddress = 0xc0a8020e; /* 目的地址192.168.2.13*/ /*初始化 */ SerialInitial(); MemInitial(); NetInInitial(); 学习文档 仅供参考 RTLInitial(); Start8019(); InterruptInitial(); // 建立一个ARP包 p[0] =0xff; p[1] =0xff; p[2] =0xff; p[3] = 0xff; p[4] = 0xff; p[5] = 0xff; p[6] = 0x52; p[7] =0x54; p[8] =0x4c; p[9] =0x30; p[10] =0x2e; p[11] =0x2f; p[12] = 0x08; p[13] = 0x06; p[14] = 0x00; p[15] = 0x01; p[16] = 0x08; p[17] = 0x00; p[18] = 0x06; p[19] = 0x04; p[20] = 0x00; p[21] = 0x01; // 发送ARP包 RTLSendPacket(p,60); while(1); 学习文档 仅供参考 #ifdef DEBUG printf(\"\\n-------bigine-------\"); #endif /* 处理 */ TCPBind(port); if(TCPConnect(ServerIPAddress,1001) == TRUE) { while(UserFunc()); } /* 延时 */ for(temp;temp<255;temp++); #ifdef DEBUG printf(\"\\n run over!\"); #endif /* 存储 */ Stop8019(); while(1); } 学习文档 仅供参考 因篇幅问题不能全部显示,请点此查看更多更全内容