1.软件版本
MATLAB2013b,vivado2019.2
2.本算法理论知识
指纹识别技术是指使用取像设备读取指纹图像,通过识别软件提取出指纹图像中的特征数据,然后根据匹配算法得到的结果鉴别指纹所有人身份的生物特征识别技术。指纹识别系统主要涉及三大步骤:指纹图像预处理、特征提取、特征匹配三个部分,其中预处理部分又可分为归一化、图像滤波增强、二值化和细化等几个步骤。系统流程框图如图1-1所示。下面对这三个个部分做一下简单的介绍。
指纹其实是比较复杂的。与人工处理不同,许多生物识别技术公司并不直接存储指纹的图象。多年来在各个公司及其研究机构产生了许多数字化的算法(美国有关法律认为,指纹图象属于个人隐私,因此不能直接存储指纹图象)。但指纹识别算法最终都归结为在指纹图象上找到并比对指纹的特征。
指纹识别系统中,通常采用全局和局部两种层次的结构特征。两枚指纹可能具有相同的全局特征,但局部特征却不可能完全相同。
全局特征是指那些用人眼直接就可以观察到的特征,包括:基本纹路图案环型(loop),弓型(arch),螺旋型(whorl)如图2-1所示。其他的指纹图案都基于这三种基本图案。仅仅依靠图案类型来分辨指纹是远远不够的,这只是一个粗略的分类,但通过分类使得在大数据库中搜寻指纹更为方便。
模式区是指指纹上包括了总体特征的区域,即从模式区就能够分辨出指纹是属于那一种类型的。有的指纹识别算法只使用模式区的数据。Secure Touch的指纹识别算法使用了所取得的完整指纹而不仅仅是模式区进行分析和识别,如图2所示。
图2模式区
核心点位于指纹纹路的渐进中心,它在读取指纹和比对指纹时作为参考点。许多算法是基于核心点的,既只能处理和识别具有核心点的指纹。核心点对于Secure Touch的指纹识别算法很重要,但没有核心点的指纹它仍然能够处理,如图3所示。
图3核心点
三角点位于从核心点开始的第一个分叉点或者断点、或者两条纹路会聚处、孤立点、折转处,或者指向这些奇异点。三角点提供了指纹纹路的计数跟踪的开始之处,如图4所示。
指模式区内指纹纹路的数量。在计算指纹的纹数时,一般先在连接核心点和三角点,这条连线与指纹纹路相交的数量即可认为是指纹的纹数,如图2-5所示。
细节特征提取的方法分为两种:一种是从灰度图像中提取特征,另一种是从细化二值图像中提取特征。直接从灰度图像中提取特征的算法一般是对灰度指纹纹线进行跟踪,根据跟踪结果寻找特征的位置和判断特征的类型。这种方法省去了复杂的指纹图像预处理过程,但是特征提取的算法却十分复杂,而且由于噪声等因素影响,特征信息(位置、方向等)也不够准确。目前大多数系统采用第二种方法,从细化二值图像中提取特征,该方法比较简单,在得到可靠的细化二值图像后,只需要一个3×3的模板就可以将端点和分叉点提取出来。
特征点提取的好坏将直接影响匹配的结果。现实中,指纹输入时,由于汗渍、干燥、按压力度不同等影响,得到的指纹图像大都含有断纹、褶皱、模糊、灰度不均匀等质量问题,虽然经过预处理,图像质量会有所改观,但预处理算法对各个指纹的适应性和有效性也会不同,并且会引入新的噪声,因此得到的细化二值图像往往含有大量的伪特征点。伪特征点不仅会影响匹配的速度,严重的会影响整个识别的正确率。所以提取特征点后要进行去伪处理,尽可能滤除伪特征点、保留真特征点。实践中发现,伪特征点的数量一般占总特征数量的一半以上,所以去伪是必不可少的过程。去伪过程可以在两个阶段进行:一是在特征提取之前对细化二值图像进行平滑、去除毛刺、连接断纹等操作,然后提取特征作为真特征;另一种是在特征提取之后,根据特征之间的相互关系,尽可能准确的识别伪特征点并滤除它们。前者直接对图像进行修补,操作比较复杂,容易引入新的伪特征;后者对特征提取后的数据进行判断,识别比较麻烦,但是速度较快本文采用第二种方法,即从已提取的特征点中滤除伪特征,保留真特征。
3.部分核心代码
`timescale 1ns / 1ps
//
// Company:
// Engineer: ThinkSpark(CJY)
//
// Create Date: 10:46:32 08/21/2009
// Design Name:
// Module Name: spisensor
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
`define effectvalue 1
module spisensor(//Output
cmd2tx_din_w,
rd_data_cmd_w,
send_rd_spidata_cmd_n_w,
clk180, //spi transfer enable
SCK_CPOL_0, //clk for slave
send_n_w,
tx_rd_en_w,
tx_wr_en_w,
rx_wr_en_w,
locked_out0,
clk_24MHz,
div10_cnt_w,
sck_cnt8_w,
//Input
rx_full_n,
rx_first_n,
rx_empty_n,
clk, //system clock
rst
);
output [7:0] cmd2tx_din_w;
output [7:0] rd_data_cmd_w;
output SCK_CPOL_0;
output clk180;
output send_n_w;
output tx_wr_en_w;
output tx_rd_en_w;
output rx_wr_en_w;
output locked_out0;
output clk_24MHz;
output [3:0] div10_cnt_w;
output [2:0] sck_cnt8_w;
output send_rd_spidata_cmd_n_w;
input clk;
input rst;
input rx_full_n;
input rx_empty_n;
input rx_first_n;
reg [7:0] cmdpad[31:0]; //filled with commands to be sent to slave after initialization
reg [7:0] rd_data_cmd_pad[1:0];
reg [7:0] cmd2tx_din;
reg [7:0] rd_data_cmd;
reg [3:0] div10_cnt; //the time while div10_cnt=0 and div10_cnt=0- equals to an SCK period
reg [2:0] sck_cnt8; //sck_cnt8=7 indicates that 8bits have been transferred
reg [3:0] dcm_rst_delaycnt;
reg [1:0] rd_spidata_cmd_cnt;
reg rd_spidata_cmd_cnt_en;
reg send_rd_spidata_cmd_n;
reg rd_data_cmd_rd_en;
reg [15:0] bytecnt;
reg [5:0] incr;
reg tx_wr_en;
reg tx_rd_en;
reg rx_wr_en;
reg transmision_done;
reg addr;
reg delaycnt_ctrl_n;
reg transfer_n; //data transfer enable bit,active low
reg send_n; //data send enable bit,active low
reg recv_n; //data receive enable bit,active low
reg [7:0] pre_state;
reg [7:0] nx_state;
wire clk0_out0;
wire locked_out0;
wire clk0_out1;
wire locked_out1;
wire clk_24MHz;
wire clk180;
wire SCK_CPOL_0;
wire SCK_CPOL_1;
wire send_n_w;
//wire transfer_n_w;
wire tx_rd_en_w;
wire tx_wr_en_w;
wire rx_wr_en_w;
wire [7:0] cmd2tx_din_w;
wire [3:0] div10_cnt_w;
wire [2:0] sck_cnt8_w;
wire send_rd_spidata_cmd_n_w;
parameter idle = 8'b00000000,
cmd2fifo = 8'b00000001,
sensor_initial = 8'b00000010,
rd_sensor = 8'b00000100,
rd_spistat = 8'b00001000,
rd_spidata = 8'b00010000,
send_data2uart = 8'b00100000,
last_data2uart = 8'b01000000,
spi_stop = 8'b10000000;
dcm0 mydcm0 (
.CLKIN_IN(clk),
.RST_IN(transfer_n),
.CLKFX_OUT(SCK_CPOL_1),
.CLKFX180_OUT(SCK_CPOL_0),
.CLK0_OUT(),
.LOCKED_OUT(locked_out0)
);
dcm1 mydcm1 (
.CLKIN_IN(clk),
.CLKFX_OUT(clk_24MHz),
.CLK0_OUT(),
.CLK180_OUT(clk180),
.LOCKED_OUT(locked_out1)
);
//assign transfer_n_w =transfer_n;
assign tx_wr_en_w=tx_wr_en;
assign tx_rd_en_w=tx_rd_en;
assign rx_wr_en_w=rx_wr_en;
assign send_n_w =send_n;
assign cmd2tx_din_w=cmd2tx_din;
assign rd_data_cmd_w = rd_data_cmd;
assign div10_cnt_w = div10_cnt;
assign sck_cnt8_w = sck_cnt8;
assign send_rd_spidata_cmd_n_w = send_rd_spidata_cmd_n;
//initialize cmdpad and transfer data in pad to Tx_fifo
always @(posedge clk)
begin
if(rst == `effectvalue)
begin
cmdpad[0] <= 8'h75;
cmdpad[1] <= 8'h7F;
cmdpad[2] <= 8'h76;
cmdpad[3] <= 8'h02;
cmdpad[4] <= 8'h77;
cmdpad[5] <= 8'h01;
cmdpad[6] <= 8'h11;
cmdpad[7] <= 8'h00;
cmdpad[8] <= 8'h21;
cmdpad[9] <= 8'h00;
cmdpad[10] <= 8'h20;
cmdpad[11] <= 8'h00;
cmdpad[12] <= 8'h50;
cmdpad[13] <= 8'h00;
cmdpad[14] <= 8'h00;
cmdpad[15] <= 8'h00;
end
end
always @(posedge clk)
begin
if(rst == `effectvalue)
begin
rd_data_cmd_pad[0] <= 8'h20;
rd_data_cmd_pad[1] <= 8'h00;
end
end
always @(posedge clk)
begin
if(rst == `effectvalue)
cmd2tx_din <= 8'b0;
else
cmd2tx_din <= cmdpad[incr];
end
//address point to data be wrote to Tx_fifo
always @(posedge clk)
begin
if(rst == `effectvalue)
incr <= 6'b0;
else if(incr == 31)
incr <= 31 ;
else
incr <= incr + 1;
end
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//transfer_n-\________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
//clk |--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|
//div10_cnt [ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ]
//SCK XXXXXXX________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/
//sck_cnt8 [00000000000000000000000000000000000000000000000000000][1111111111111111111111111111111111111111111111111111111111][2222222222222222222222222222222222222222222222222222222222][3333333333333333333333333333333333333333333333333333333333][4444444444444444444444444444444444444444444444444444444444][5555555555555555555555555555555555555555555555555555555555][6666666666666666666666666666666666666666666666666666666666][7777777777777777777777777777777777777777777777777777777777][0000000000000000000000000000000000000000000000000000000000][11111111111111111111111111111111111111]
//tx_rd_en ------|_____|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/----------------------------------------------------------------------------------
//tx_shifterOOOOOOOOOOOOOOOOOOO[ d7 d6 d5 d4 d3 d2 d1 d0 ][ d6 d5 d4 d3 d2 d1 d0 0 ][ d5 d4 d3 d2 d1 d0 0 0 ][ d4 d3 d2 d1 d0 0 0 0 ][ d3 d2 d1 d0 0 0 0 0 ][ d2 d1 d0 0 0 0 0 0 ][ d1 d0 0 0 0 0 0 0 ][ d0 0 0 0 0 0 0 0 ][ d7 d6 d5 d4 d3 d2 d1 d0 ][ d6 d5 d4 d3 d2 d1 d0 0 ]
//MOSI OOOOOOOOOOOOOO000000000000000000[----------------------------d7----------------------------][----------------------------d6----------------------------][----------------------------d5----------------------------][----------------------------d4----------------------------][----------------------------d3----------------------------][----------------------------d2----------------------------][----------------------------d1----------------------------][----------------------------d0----------------------------][----------------------------d7----------------------------][--d6--]
//MISO XXXXX[----------------------------D7-----------------------------][----------------------------D6----------------------------][----------------------------D5----------------------------][----------------------------D4----------------------------][----------------------------D3----------------------------][----------------------------D2----------------------------][----------------------------D1----------------------------][----------------------------D0----------------------------][----------------------------D7----------------------------][----------------------------D7--------
//rx_shifter0000000000000000000000000000000[ 0 0 0 0 0 0 0 D7 ][ 0 0 0 0 0 0 D7 D6 ][ 0 0 0 0 0 D7 D6 D5 ][ 0 0 0 0 D7 D6 D5 D4 ][ 0 0 0 D7 D6 D5 D4 D3 ][ 0 0 D7 D6 D5 D4 D3 D2 ][ 0 D7 D6 D5 D4 D3 D2 D1 ][ D7 D6 D5 D4 D3 D2 D1 D0 ][ 0 0 0 0 0 0 0 D7 ]
//rx_wr_en------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/-----------------------------------------------------------------
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
//the time while div10_cnt=0 and div10_cnt=0- equals to an SCK period
always @(posedge clk)
begin
if( (rst == `effectvalue) || (transfer_n == 1'b1) )
div10_cnt <= 4'b0;
else if(div10_cnt == 9)
div10_cnt <= 4'b0;
else if(locked_out0 == 1'b1)
div10_cnt <= div10_cnt + 1;
end
//----------------------------------------------------------------------------------------
//3bits counter for SCK cycles, one counting cycle indicates one Byte transmission done
always @ (posedge clk)
begin
if( (rst == `effectvalue) || (transfer_n == 1'b1) )
sck_cnt8 <= 3'b0;
else if( (div10_cnt == 9) && (locked_out0 == 1'b1) ) //?????????????????????
sck_cnt8 <= sck_cnt8 + 1;
end
//--------------------------------------------------------------------------------------------------
//------------control reading from tx_fifo and writing to rx_fifo----------------------------------
//---------------------------------begin-----------------------------------------------------------
always @(posedge clk180) //---- @posedge clk180 will work more precisely-----
begin
if( (rst == `effectvalue) || (send_n == 1'b1) ) //not to read data from tx_fifo when send_n=1
tx_rd_en <= 1'b1;
else if( (locked_out0 == 1'b1) && (sck_cnt8 == 0) &&
(div10_cnt == 0) )
tx_rd_en <= 1'b0;
else
tx_rd_en <= 1'b1;
end
always @(posedge clk180)
begin
if( (rst == `effectvalue) || (send_rd_spidata_cmd_n == 1'b1) )
rd_data_cmd_rd_en <= 1'b1;
else if( (locked_out0 == 1'b1) && (sck_cnt8 == 0) &&
(div10_cnt == 0) )
rd_data_cmd_rd_en <= 1'b0;
else
rd_data_cmd_rd_en <= 1'b1;
end
always @(posedge clk)
begin
if(rst == `effectvalue)
rd_data_cmd <= 8'b0;
else if(rd_data_cmd_rd_en == 1'b0)
rd_data_cmd <= rd_data_cmd_pad[addr];
end
always @(posedge clk)
begin
if(rst == `effectvalue)
addr <= 1'b0;
else if (rd_data_cmd_rd_en == 1'b0)
addr <= ~addr;
end
always @(posedge clk)
begin
if( (rst == `effectvalue) || (rx_full_n == 1'b0) )
rd_spidata_cmd_cnt <= 2'b0;
else if(rd_spidata_cmd_cnt == 2)
rd_spidata_cmd_cnt <= 2;
else if( (rd_spidata_cmd_cnt_en == 1'b0) && ( sck_cnt8 == 7 ) &&
(div10_cnt == 9) )
rd_spidata_cmd_cnt <= rd_spidata_cmd_cnt + 1;
end
///
always @(posedge clk180) //---- @posedge clk180 will work more precisely-----
begin
if( (rst == `effectvalue) || (recv_n == 1'b1) ) //not to write to rx_fifo when recv_n=1
rx_wr_en <= 1'b1;
else if( (locked_out0 == 1'b1) && (sck_cnt8 == 7) &&
(div10_cnt == 6) ) //rx_wr_en be active while div10_cnt=6 and sck_cnt8=7 can
rx_wr_en <= 1'b0; //leave some time space for bytecnt
else
rx_wr_en <= 1'b1;
end
//------------control reading from tx_fifo and writing to rx_fifo----------------------------------
//---------------------------------end-----------------------------------------------------------
always @(posedge clk)
begin
if( (rst == `effectvalue) ||
( (transfer_n == 1'b1) && (transmision_done == 1'b1) ) )
bytecnt <= 16'b0;
else if( (sck_cnt8 == 7) && ( div10_cnt == 7 ) ) // one more byte has been sent and received the moment
bytecnt <= bytecnt + 1; //sck_cnt8=7 and div10_cnt=7(as the wave showed following)
else
bytecnt <= bytecnt;
end
always @(posedge clk)
begin
if( rst == `effectvalue )
transmision_done <= 1'b0;
else if( (transmision_done == 1'b1) && (div10_cnt == 0) )
transmision_done <= 1'b0;
else if( (pre_state == sensor_initial) && (bytecnt == 6) )
transmision_done <= 1'b1;
else if( (pre_state == rd_sensor) && (bytecnt == 370) )
transmision_done <= 1'b1;
else if( (pre_state == rd_spistat) && (bytecnt == 3) )
transmision_done <= 1'b1;
//else if( (pre_state == rd_regs) && (bytecnt == 18) )
//transmision_done <= 1'b1;
else if( (pre_state == rd_spidata) && (bytecnt == 31352) )
transmision_done <= 1'b1;
end
always @( posedge clk )
begin
if( (rst == `effectvalue) || (transmision_done == 1'b1) || (rx_full_n == 1'b0) )
dcm_rst_delaycnt <= 4'b0;
else if( dcm_rst_delaycnt == 9 )
dcm_rst_delaycnt <= 9;
else if( delaycnt_ctrl_n == 1'b0 )
dcm_rst_delaycnt <= dcm_rst_delaycnt + 1;
end
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//transfer_n-\________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
//clk |--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|--|__|
//div10_cnt [ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ][ 9 ][ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ]
//SCK XXXXXXX________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/-----------------------------\_____________________________/
//sck_cnt8 [00000000000000000000000000000000000000000000000000000][1111111111111111111111111111111111111111111111111111111111][2222222222222222222222222222222222222222222222222222222222][3333333333333333333333333333333333333333333333333333333333][4444444444444444444444444444444444444444444444444444444444][5555555555555555555555555555555555555555555555555555555555][6666666666666666666666666666666666666666666666666666666666][7777777777777777777777777777777777777777777777777777777777][0000000000000000000000000000000000000000000000000000000000][11111111111111111111111111111111111111]
//tx_rd_en ------\_____/-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/----------------------------------------------------------------------------------
//tx_shifterOOOOOOOOOOOOOOOOOOO[ d7 d6 d5 d4 d3 d2 d1 d0 ][ d6 d5 d4 d3 d2 d1 d0 0 ][ d5 d4 d3 d2 d1 d0 0 0 ][ d4 d3 d2 d1 d0 0 0 0 ][ d3 d2 d1 d0 0 0 0 0 ][ d2 d1 d0 0 0 0 0 0 ][ d1 d0 0 0 0 0 0 0 ][ d0 0 0 0 0 0 0 0 ][ d7 d6 d5 d4 d3 d2 d1 d0 ][ d6 d5 d4 d3 d2 d1 d0 0 ]
//MOSI OOOOOOOOOOOOOO000000000000000000[----------------------------d7----------------------------][----------------------------d6----------------------------][----------------------------d5----------------------------][----------------------------d4----------------------------][----------------------------d3----------------------------][----------------------------d2----------------------------][----------------------------d1----------------------------][----------------------------d0----------------------------][----------------------------d7----------------------------][--d6--]
//MISO XXXXX[----------------------------D7-----------------------------][----------------------------D6----------------------------][----------------------------D5----------------------------][----------------------------D4----------------------------][----------------------------D3----------------------------][----------------------------D2----------------------------][----------------------------D1----------------------------][----------------------------D0----------------------------][----------------------------D7----------------------------][----------------------------D7--------
//rx_shifter0000000000000000000000000000000[ 0 0 0 0 0 0 0 D7 ][ 0 0 0 0 0 0 D7 D6 ][ 0 0 0 0 0 D7 D6 D5 ][ 0 0 0 0 D7 D6 D5 D4 ][ 0 0 0 D7 D6 D5 D4 D3 ][ 0 0 D7 D6 D5 D4 D3 D2 ][ 0 D7 D6 D5 D4 D3 D2 D1 ][ D7 D6 D5 D4 D3 D2 D1 D0 ][ 0 0 0 0 0 0 0 D7 ]
//rx_wr_en------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\_____/-------------------------------------------------------------
//----------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
//-------------------------------FSM---------------------------------------------
always @(posedge clk)
begin
if(rst == `effectvalue)
pre_state <= idle;
else
pre_state <= nx_state;
end
//-----------------------------------------------------------------------
//FSM state transform---------------------------------------------------
always @(pre_state or div10_cnt or incr or transmision_done or
rx_empty_n or rx_full_n)
begin
case(pre_state)
idle : nx_state = cmd2fifo;
cmd2fifo : begin
if( incr == 31) //all 16 commands in cmdpad were wrote to Tx_fifo when incr=15
nx_state = sensor_initial;
else
nx_state = cmd2fifo;
end
sensor_initial: begin
if( (transmision_done == 1'b1) && (div10_cnt == 0))
nx_state = rd_sensor;
else
nx_state = sensor_initial;
end
rd_sensor :begin
if( (transmision_done == 1'b1) && (div10_cnt == 0))
nx_state = rd_spistat;
else
nx_state = rd_sensor;
end
rd_spistat :begin
if( (transmision_done == 1'b1) && (div10_cnt == 0))
nx_state = rd_spidata;
else
nx_state = rd_spistat;
end
rd_spidata :begin
if( (transmision_done == 1'b1) && (div10_cnt == 0))
nx_state = last_data2uart;
else if(rx_full_n == 1'b0) //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
nx_state = send_data2uart;
else
nx_state = rd_spidata;
end
send_data2uart:begin
if(rx_empty_n == 1'b0)
nx_state = rd_spidata;
else
nx_state = send_data2uart;
end
last_data2uart:begin
if(rx_empty_n == 1'b0)
nx_state = spi_stop;
else
nx_state = last_data2uart;
end
spi_stop : nx_state = spi_stop;
default : nx_state = idle;
endcase
end
//---------FSM state transform-----------------------------------------------
//-----------------------------------------------------------------------------
//-------------------------------------------
//FSM control signals output
always @(pre_state or rx_full_n or div10_cnt or
incr or bytecnt or dcm_rst_delaycnt or
rd_spidata_cmd_cnt or rx_empty_n or rx_first_n )
begin
case(pre_state)
idle :begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
cmd2fifo :begin
if( (incr == 0) && (incr == 31) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else
begin
tx_wr_en = 1'b0;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
end
sensor_initial :begin
if( (bytecnt == 6) && ( div10_cnt == 9) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1; // this will reset bytecnt when div10_cnt=9
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( dcm_rst_delaycnt <= 8)
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b0;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if(dcm_rst_delaycnt == 9)
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b0;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1; // this will reset bytecnt when div10_cnt=9
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
end
rd_sensor :begin
if( dcm_rst_delaycnt <= 8)
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b0;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( (bytecnt < 2 ) && (dcm_rst_delaycnt == 9) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b0;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( (bytecnt >=2) && (bytecnt <=370) && (dcm_rst_delaycnt == 9))
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
end
rd_spistat :begin
if( dcm_rst_delaycnt <= 8)
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b0;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( (bytecnt < 2) && (dcm_rst_delaycnt == 9) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b0;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( (bytecnt >= 2) && (dcm_rst_delaycnt == 9) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b1;
recv_n = 1'b0;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
end
rd_spidata :begin
if( dcm_rst_delaycnt <= 8)
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b0;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( (bytecnt > 10) && (rx_first_n == 1'b1) &&
(rx_empty_n == 1'b0) && ( rd_spidata_cmd_cnt < 2 ) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b0;
rd_spidata_cmd_cnt_en = 1'b0;
end
else if( (bytecnt > 10) && (rd_spidata_cmd_cnt == 2) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b1;
recv_n = 1'b0;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( (bytecnt < 2) && (dcm_rst_delaycnt == 9) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b0;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else if( (bytecnt >= 2) && (rx_full_n == 1'b1) )
begin
tx_wr_en = 1'b1;
transfer_n = 1'b0;
send_n = 1'b1;
recv_n = 1'b0;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
else
begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
end
send_data2uart,
last_data2uart,
spi_stop :begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
default : begin
tx_wr_en = 1'b1;
transfer_n = 1'b1;
send_n = 1'b1;
recv_n = 1'b1;
delaycnt_ctrl_n = 1'b1;
send_rd_spidata_cmd_n = 1'b1;
rd_spidata_cmd_cnt_en = 1'b1;
end
endcase
end
//FSM control signals output
//--------------------------------------------
endmodule
%ProcessOfFingerPrint.m
clc;
clear;
clear all;
%--------------加载指纹文本文件-----------------------
fid=fopen('1x1.txt','r');
dd=fscanf(fid,'%x');
fclose(fid);
array=dd';
for i=0:199
OriginFingerPrint(i+1,1:152)=array(i*152+1:i*152+152);
end
figure('name','OriginFingerPrint');
imshow(uint8(OriginFingerPrint));
%---------------灰度图像取反--------------------------
ReverseFingerPrint=255-OriginFingerPrint;
figure('name','ReverseFingerPrint');
imshow(uint8(ReverseFingerPrint));
%---------------进行二维适应性去噪过滤处理------------
FrontFilt=wiener2(ReverseFingerPrint,[3 3]);
figure('name','FrontFilt');
imshow(uint8(FrontFilt));
%---------------扩大图像的像素至400x304---------------
EnhanceFingerPrint=enhance_finger(FrontFilt);
%---------------取图像的中心点------------------------
[XofCenter,YofCenter] = centralizing(EnhanceFingerPrint);
figure('name','EnhanceFingerPrint');
imshow(uint8(EnhanceFingerPrint));
hold on;
plot(XofCenter,YofCenter,'or');
hold off;
%---------------二值化图像-----------------------------
[BinarizationFingerPrint,theta]=orientation(EnhanceFingerPrint);
figure('name','BinarizationFingerPrint');
imshow(uint8(BinarizationFingerPrint));
%----------------进行中值滤波处理----------------------
AfterFilt=median_filter(BinarizationFingerPrint);
figure('name','AfterFilt');
imshow(uint8(AfterFilt));
%----------------二值化图像细化处理--------------------
ThinFingerPrint=thinning(AfterFilt);
figure('name','ThinFingerPrint');
imshow(uint8(ThinFingerPrint));
%----------------找寻细化图像的特征点------------------
[Dpx,Dpy,Dpcount,Fpx,Fpy,Fpcount]=characterpoint(ThinFingerPrint);
hold on;
plot(Dpy,Dpx,'o');%特征端点用'o'标注
plot(Fpy,Fpx,'+');%特征分叉点用'+'标注
plot(XofCenter,YofCenter,'*r');%中心点用红色'*'标注
hold off;
%-----------------生成各特征点相对中心点的距离向量---------------
Dpcount=size(Dpx,2);
Fpcount=size(Fpx,2);
for i=1:Dpcount
Dpdistant(i)=sqrt((Dpx(i)-YofCenter)^2+(Dpy(i)-XofCenter)^2);
end
for j=1:Fpcount
Fpdistant(j)=sqrt((Fpx(j)-YofCenter)^2+(Fpy(j)-XofCenter)^2);
end
%------------------特征模板建立----------------------------------------------
for i=1:Dpcount
PointOfModel(i,1)=1;%特征端点分类为1
PointOfModel(i,2)=Dpdistant(i);%特征端点相对中心点的距离向量
PointOfModel(i,3)=theta(Dpx(i),Dpy(i))-theta(YofCenter,XofCenter);%特征端点相对中心点的方向向量
end
for i=Dpcount+1:Dpcount+Fpcount
PointOfModel(i,1)=2;%特征分叉点分类为2
PointOfModel(i,2)=Fpdistant(i-Dpcount);%特征分叉点相对中心点的距离向量
PointOfModel(i,3)=theta(Fpx(i-Dpcount),Fpy(i-Dpcount))-theta(YofCenter,XofCenter);%特征分叉点相对中心点的方向向量
end
%--------------------------------------------------------
4.操作步骤与仿真结论
- FSM模块:其主要的功能是在系统复位后初始化Tx FIFO(发送FIFO),即把随后要发送给SPI传感器的命令写入Tx FIFO内,然后在满足SPI传感器时序的前提下,FSM模块通过控制Tx_rd_en信号读出Tx FIFO里的命令并传送到SPI模块;在Rx FIFO接收指纹数据时,当数满标志位Rx_full_n有效后说明接收FIFO里的数据已满,这时FSM就会通过相关信号来控制SPI停止接收数据,当检测到Rx_empty_n有效后(接收FIFO已空),FSM就会发出相应的信号启动SPI继续接收数据,直到指纹数据全部接收完毕。
- Tx FIFO模块:主要功能是在初始化的时候装载待发命令,然后在Tx_rd_en信号的控制下把命令发送出去,因为总的命令数不超过FIFO的深度,所以无须空满标志位。
- SPI模块:其主要功能是在与外部传感器通信的时候向传感器提供时钟信号SCK,以及片选信号SS,其中SCK和SS信号最初由FSM产生并由FSM进行控制;当需要向传感器发送命令时,FSM会启动SCK和SS信号,同时SPI接受从Tx FIFO读出的命令并暂存到一个8bit移位寄存器tx_shifter[7:0]中,每过一个SCK周期发送一位到至MOSI,发送完1Byte后tx_shifter会重新装载新命令继续发送直到命令发送完毕;当SPI从传感器接收数据时,FSM会启动SCK和SS信号,SPI中移位寄存器rx_shifter[7:0]会在SCK的上升沿采集输入端口MISO的数据并移一位,每8个SCK时钟周期rx_shifter中的数据就会在FSM的控制下写入Rx FIFO,直到数据接收完毕。
- Rx FIFO模块:此模块的主要功能是对已接收到的指纹数据进行缓存,避免指纹的数据丢失,因为此系统中SPI串口的工作频率为5MHz,而UART串口的工作频率为38400Hz,UART从Rx FIFO取数据的速度远小于SPI往Rx FIFO中写数据的速度。Rx FIFO可以向UART和FSM提供数空和数满标志位rx_empty_n,和rx_full_n,因此SPI和UART可以协调工作。
- UART模块:些模块主要功能是和计算机进行通信,把接收到的指纹数据通过计算机的终端显示出来。当UART检测到rx_full_n有效后,就会发出读信号Rx_rd_en读出FIFO中的数据发送给计算机,当检测到rx_empty_n有效后停止。
5.参考文献
[1]赵锦明, 钱磊, 吴东. 一种基于FPGA指纹识别加速结构的设计与实现[J]. 网络空间安全, 2016, 7(005):59-64.
D234
6.完整源码获得方式
方式1:微信或者QQ联系博主