【指纹识别】基于MATLAB/FPGA的指纹识别算法仿真实现

1.软件版本

MATLAB2013b,vivado2019.2

2.本算法理论知识

       指纹识别技术是指使用取像设备读取指纹图像,通过识别软件提取出指纹图像中的特征数据,然后根据匹配算法得到的结果鉴别指纹所有人身份的生物特征识别技术。指纹识别系统主要涉及三大步骤:指纹图像预处理、特征提取、特征匹配三个部分,其中预处理部分又可分为归一化、图像滤波增强、二值化和细化等几个步骤。系统流程框图如图1-1所示。下面对这三个个部分做一下简单的介绍。

  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.操作步骤与仿真结论

 

  1. 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继续接收数据,直到指纹数据全部接收完毕。
  2. Tx FIFO模块:主要功能是在初始化的时候装载待发命令,然后在Tx_rd_en信号的控制下把命令发送出去,因为总的命令数不超过FIFO的深度,所以无须空满标志位。
  3. 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,直到数据接收完毕。
  4. Rx FIFO模块:此模块的主要功能是对已接收到的指纹数据进行缓存,避免指纹的数据丢失,因为此系统中SPI串口的工作频率为5MHz,而UART串口的工作频率为38400Hz,UART从Rx FIFO取数据的速度远小于SPI往Rx FIFO中写数据的速度。Rx FIFO可以向UART和FSM提供数空和数满标志位rx_empty_n,和rx_full_n,因此SPI和UART可以协调工作。
  5. 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联系博主

方式2:订阅MATLAB/FPGA教程,免费获得教程案例以及任意2份完整源码

猜你喜欢

转载自blog.csdn.net/ccsss22/article/details/124207560