IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于OV7670摄像头的实时边沿检测系统 -> 正文阅读

[嵌入式]基于OV7670摄像头的实时边沿检测系统

边沿检测系统

系统介绍

摄像头复位引脚保持至少3ms时间的低电平后拉高使得摄像头处于硬件复位状态,同时SDRAM模块初始化完成,在摄像头复位引脚保持2ms高电平后开始通过SCCB或IIC通信协议写入115个不同的寄存器地址数据,写入数据成功后摄像头初始化模块产生初始化完成信号传入SDRAM模块中读缓存模块并保持高电平表示SDRAM模块可读状态。初始化完成之后在DVP摄像头传输模块产生的24Mhz频率时钟驱动下摄像头产生PCLK时钟信号通过DVP通信协议传输16位图像,每生成一个16位图像数据,DVP摄像头传输模块同时输出维持一个时钟周期的写请求信号输入到SDRAM模块中的写缓存模块。写缓存模块收到写请求信号后将16位图像数据依次写入不同的存储器逻辑单元地址,当写缓存模块中的图像数据满足一次突发读写数据长度条件后写入SDRAM存储器中。在图像数据写入SDRAM同时当VGA显示模块中扫描计数器为零及开始扫描初状态时产生输入图像信息请求信号,该信号输入到SDRAM模块中读缓存信号。当读缓存模块中的数据小于一次读写突发长度时输出读请求信号传入SDRAM控制模块,SDRAM在100Mhz频率时钟下输出数据16位数据传入到读缓存模块。读缓存的数据直接通过VGA模块后单通道图像数据传输到sobel边缘检测模块。该模块输入端口只输入去除其他图像数据的G通道6位数据, 将图像信息的3*3像素矩阵与sobel算子做卷积运算后得到的8位数据以RGB332格式实时显示到屏幕上。
系统信号连接设计图如下:
在这里插入图片描述

系统模块

边沿检测模块设计思路

FIFO求和模块

在学习算法模块之前要了解算法原理,设计FIFO求和模块,设计5*4矩阵输入到求和模块计算。此模块将三行数据累加求和并输出。将第一行的数据写入到FIFO_1中,第二行数据写入FIFO_2中,当第三行数据输入时读出第一与第二行数据,同时FIFO_1写入FIFO_2读出的第二行的数据,并且将这三行数据累加。信号波形图设计如下;
在这里插入图片描述
FIFO求和模块设计图如下:
在这里插入图片描述
该模块的代码如下,可参考野火教程在此不做赘述。

module  FIFO_SUM(
    Clk         ,
    Rst_n       ,
    Pi_data     ,
    Pi_flag     ,
                
    Po_data     ,
    Po_flag
);

input                               Clk         ;
input                               Rst_n       ;
input               [7:0]           Pi_data     ;
input                               Pi_flag     ;

output              [7:0]           Po_data     ;
output                              Po_flag     ;

reg                 [10:0]          cnt_col         ;
reg                 [10:0]          cnt_row         ;
reg                                 wr_en_1         ;
reg                                 wr_en_2         ;
reg                 [7:0]           wr_data_1       ;
reg                 [7:0]           wr_data_2       ;
reg                                 rd_en           ;
wire                [7:0]           rd_data_1       ;            
wire                [7:0]           rd_data_2       ;
reg                                 mid_flag        ;
reg                                 sum_flag        ;
reg                 [7:0]           Po_data         ;
reg                                 Po_flag         ;

parameter           COL_MAX     =   4   ; 
parameter           ROW_MAX     =   5   ; 

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        cnt_col     <=  1'b0;
    else
    if(Pi_flag && (cnt_col  ==  COL_MAX - 1'b1))
        cnt_col     <=  1'b0;
    else
    if(Pi_flag)
        cnt_col <=  cnt_col +   1'b1;
    else
        cnt_col <=  cnt_col;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        cnt_row     <=  1'b0;
    else
    if((cnt_col  ==  COL_MAX - 1'b1)    &&  Pi_flag &&  (cnt_row    ==  ROW_MAX - 1'b1))
        cnt_row     <=  1'b0;
    else
    if((cnt_col  ==  COL_MAX - 1'b1)    &&  Pi_flag )
        cnt_row     <=  cnt_row +   1'b1;
    else
        cnt_row <=  cnt_row;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        wr_en_1 <=  1'b0;
    else
    if((cnt_row  ==  0) && Pi_flag) 
        wr_en_1 <=  1'b1 ;
    else
        wr_en_1 <=  mid_flag;


always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        wr_en_2 <= 1'b0;
    else
    if((cnt_row  >= 1'b1)   &&  ((cnt_row    <=  ROW_MAX - 2'd1))   && Pi_flag)
        wr_en_2 <=  1'b1;
    else
        wr_en_2 <= 1'b0;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        wr_data_1   <=  1'b0;
    else
    if((cnt_row  ==  0) && Pi_flag)
        wr_data_1   <=  Pi_data;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        wr_data_2   <=  1'b0;
    else
    if((cnt_row  >= 1'b1)   &&  ((cnt_row    <=  ROW_MAX - 2'd1))   && Pi_flag)
        wr_data_2   <=  Pi_data;
    else
        wr_data_2   <=  wr_data_2;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        rd_en   <=  1'b0;
    else
    if(cnt_row  >=  2'd2)
        rd_en   <=  Pi_flag;
    else
        rd_en   <=  1'b0;
        
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        mid_flag    <=  1'b0;
    else
    if(wr_en_2  &&  rd_en)
        mid_flag    <=  1'b1;
    else
        mid_flag    <=  1'b0;
        
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        sum_flag    <=  1'b0;
    else
        sum_flag   <=  rd_en;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Po_data <=  1'b0;
    else
        Po_data <=  rd_data_1   +   rd_data_2   +   Pi_data;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Po_flag <=  1'b0;
    else
        Po_flag <=  sum_flag;

FIFO	FIFO_inst_1 (
	.clock ( Clk ),
	.data ( wr_data_1 ),
	.rdreq ( rd_en),
	.wrreq ( wr_en_1 ),
	.q ( rd_data_1 )
	);

FIFO	FIFO_inst_2 (
	.clock ( Clk ),
	.data ( wr_data_2 ),
	.rdreq ( rd_en),
	.wrreq ( wr_en_2 ),
	.q ( rd_data_2 )
	);
    
endmodule   
sobel模块

sobel算子
在这里插入图片描述

将VGA输出的显示像素数据的单通道G输入到边缘检测模块中。处理模块运行流程图如图所示。模块中的两个算子如图所示,将两个算子与图像数据的三乘三矩阵相乘并相加得到的两个值and_b与and_a,将这两个值的平方根的和做开方运算得到compare,该值与阈值做比较,大于阈值则为0,小于阈值则为1。最终显示为只有黑白的图像数据,将计算后的图像数据以RGB332格式输出到显示硬件引脚上进行显示。SOBEL算子比其他的常用算子比如ROBERTS算子的计算简单,效率更高。但是准确率不高。模块设计如图所示。

在这里插入图片描述
在这里插入图片描述
sobel模块波形图如下所示,在此模拟了5*5矩阵与sobel算子卷积原理,与FIFO求和类似,增加计算标志位count_flag,在高电平下计算Gx=(A3-A1)+(B3-B1)*2+(C3-C1);
在这里插入图片描述

模拟矩阵:
在这里插入图片描述

模块设计代码如下:

LineBuffer、MAC_3、PA_3、SQRT分别为行缓存、相乘相加、求和、平方IP核。

module  sobel_test(

input               Clk                ,     
input               Rst_n              ,
input               Po_flag            ,   
input   [7:0]       Po_data            ,
input   [7:0]       Threshold          ,

output  reg   [7:0]     Out_data       , 
output  reg             Out_flag            

);

parameter A1 = 8'hff, A2 = 8'h00, A3 = 8'h01;  
parameter A4 = 8'hfe, A5 = 8'h00, A6 = 8'h02;
parameter A7 = 8'hff, A8 = 8'h00, A9 = 8'h01;

parameter B1 = 8'h01, B2 = 8'h02, B3 = 8'h01;
parameter B4 = 8'h00, B5 = 8'h00, B6 = 8'h00;
parameter B7 = 8'hff, B8 = 8'hfe, B9 = 8'hff;
wire  [7:0] count0;
wire  [7:0] count1;
wire  [7:0] count2;

wire  [17:0]  amass_a_0;
wire  [17:0]  amass_a_1;
wire  [17:0]  amass_a_2;    //乘积累加结果

wire  [17:0]  amass_b_0;
wire  [17:0]  amass_b_1;
wire  [17:0]  amass_b_2;

wire  [19:0]  and_b;        
wire  [19:0]  and_a;

wire  [15:0]  compare;

wire    [7:0]   shiftout;

LineBuffer	LineBuffer_inst (
	.clken (       Po_flag      ),
	.clock (       Clk         ),
	.shiftin (     Po_data        ),
	.shiftout (     shiftout        ),
    
	.taps0x (        count0         ),
	.taps1x (        count1         ),
	.taps2x (        count2         )
	);

//相乘后累加
MAC_3 A0_inst(
  .aclr3(!Rst_n),
  .clock0(Clk),
  .dataa_0(count2),
  
  .datab_0(A1),
  .datab_1(A2),
  .datab_2(A3),
  .result(amass_a_0)
);
MAC_3 A1_inst(
  .aclr3(!Rst_n),
  .clock0(Clk),
  .dataa_0(count1),
  
  .datab_0(A4),
  .datab_1(A5),
  .datab_2(A6),
  .result(amass_a_1)
);
MAC_3 A2_inst(
  .aclr3(!Rst_n),
  .clock0(Clk),
  .dataa_0(count0),
  
  .datab_0(A7),
  .datab_1(A8),
  .datab_2(A9),
  .result(amass_a_2)
);

MAC_3 B0_inst(
  .aclr3(!Rst_n),
  .clock0(Clk),
  .dataa_0(count2),
  
  .datab_0(B1),
  .datab_1(B2),
  .datab_2(B3),
  .result(amass_b_0)
);

MAC_3 B1_inst(
  .aclr3(!Rst_n),
  .clock0(Clk),
  .dataa_0(count1),
  
  .datab_0(B4),
  .datab_1(B5),
  .datab_2(B6),
  .result(amass_b_1)
);

MAC_3 B2_inst(
  .aclr3(!Rst_n),
  .clock0(Clk),
  .dataa_0(count0),
  
  .datab_0(B7),
  .datab_1(B8),
  .datab_2(B9),
  .result(amass_b_2)
);


PA_3 pa0 (                //求和
  .clock    (Clk),
  .data0x   (amass_a_0),
  .data1x   (amass_a_1),
  .data2x   (amass_a_2),
  .result   (and_a)
);

PA_3 pb0 (                //求和
  .clock    (Clk),
  .data0x   (amass_b_0),
  .data1x   (amass_b_1),
  .data2x   (amass_b_2),
  .result   (and_b)
);


SQRT sqrt_inst (      //平方
  .clk(Clk),
  .radical(and_a * and_a + and_b * and_b),
  .q(compare) 
);

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Out_flag <=  1'b0;
    else
        Out_flag <=  Po_flag;
    
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Out_data <=  1'b0;
    else
    if(Po_flag)
        Out_data <=  (compare  >  Threshold) ? 0 : 255   ;
    else
        Out_data <=  0;

endmodule

对于负数的表示法:-1+1=0等价于h’ff+1=0,所以h’ff=-1。同理 h’fe+2=0,所以h’fe为-2。以此类推可以表示负数。

系统内模块测试情况

在这里插入图片描述

系统顶层文件


module      DVP_SDRAM_VGA(
    //global    port
input       wire                Clk             ,
input       wire                Rst_n           ,

input       wire                Key_in1           ,
input       wire                Key_in2           ,
    //camera    interface    
input       wire                Cmos_pclk       ,
input       wire                Cmos_vsync      ,
input       wire                Cmos_href       ,
input       wire    [7:0]       Cmos_data       ,
output      wire                Cmos_xclk       ,       //驱动摄像头时钟
output      wire                Cmos_sclk       ,
inout       wire                Cmos_sda        ,
output      wire                Cmos_pwdn       ,
output      wire                Cmos_rst_n      ,
    //SDRAM     port
output      wire                Sdram_clk       ,
output      wire                Sdram_cke       ,                                
output      wire                Sdram_cs_n      ,
output      wire                Sdram_cas_n     ,
output      wire                Sdram_ras_n     ,
output      wire                Sdram_we_n      ,
output      wire    [1:0]       Sdram_ba        ,
output      wire    [12:0]      Sdram_addr      ,
inout       wire    [15:0]      Sdram_dq        ,    
output      wire    [1:0]       Sdram_dqm       ,  

    //VGA       port
output      wire     [7:0]      Vga_rgb                        ,
output      wire                Hsync                          ,
output      wire                Vsync                          ,
output      wire                Clk_vga                        ,
output      wire                Clk_blk                         ,
               
output      wire                Led         ,   

        //HEX_8                             
output      wire                SHCP        , 
output      wire                STCP        ,
output      wire                DS   

);

reg         [31:0]              cnt             ;
wire                             go              ;
wire                            sys_rst_n       ;
wire                            clk_cmos_24M    ; 
wire                            clk_100M        ; 
wire                            clk_shift_100M  ; 
wire                            clk_vga_24M     ; 
wire                            lock            ; 
wire                            init_done       ;
wire                            wr_req          ;       //读SDRAM请求信号
wire        [15:0]              data_cmos       ;       //摄像头信号
wire                            pix_reg         ;
wire        [15:0]              pix_data        ;
wire                            wr_rst          ;
wire        [10:0]              pix_x           ;
wire        [10:0]              pix_y           ;
wire                            rd_value_r           ;
reg                             rd_value          ;
wire                            po_flag            ;

wire            key_data1           ;
wire            key_flag1            ;
wire            key_data2            ;
wire            key_flag2            ;
wire        [7:0]           change  ;
reg         [31:0]    hex_data          ;

assign Cmos_pwdn    = 1'b0;
assign Cmos_rst_n   = (cnt > 32'd175_000);    //3.5ms
assign  sys_rst_n = Rst_n &&  lock;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        cnt <=  1'b0    ;
    else
    if(cnt  <   32'd6500_001)     //  6.5ms
        cnt <=  cnt +   1'b1    ;
    else
        cnt <=  cnt ;
       
assign  go = (cnt   == 32'd6500_000 ) ? 1'b1:1'b0;

assign  rd_value_r =    ((pix_x == 0) && (pix_y == 0))?1'b1:1'b0; //读缓存模块清零标志位

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        rd_value  <= 1'b0;
    else
    if(rd_value_r)
        rd_value  <=  1'b1;
    else
    rd_value  <=  rd_value  ;

HEX_8_top   HEX_8_top_inst(
    .Clk           (Clk)  ,
    .Rst_n         (Rst_n)  ,
    .Data_in       ({24'd0,change})  ,

    .SHCP          (SHCP )  ,
    .STCP          (STCP )  ,
    .DS            (DS   )
    );


Key_shake   Key_shake_inst1(
  .Clk(                 Clk             ),
  .Rst_n(               Rst_n           ),
  .Key_in(              Key_in1         ),
  
  .Key_flag(            key_flag1       ),
  .Key_data(            key_data1       )
  );
  
Key_shake   Key_shake_inst2(
  .Clk(                 Clk             ),
  .Rst_n(               Rst_n           ),
  .Key_in(              Key_in2         ),
  
  .Key_flag(            key_flag2       ),
  .Key_data(            key_data2       )
  );
  
change      change_inst(

    .Clk       (Clk        )         ,  
    .Rst_n     (Rst_n      )    ,   
    .Key_data1 ( key_data1 )          ,
    .Key_flag1 ( key_flag1 )          ,
    .Key_data2 ( key_data2 )          ,
    .Key_flag2 ( key_flag2 )          ,

    .Change    (change      )          ,
    .Led       (Led         )          
);

pll	pll_inst (
	.areset ( !Rst_n ),
	.inclk0 ( Clk ),
	.c0     ( clk_cmos_24M      ),
	.c1     ( clk_100M          ),
	.c2     ( clk_shift_100M    ),
	.c3     ( clk_vga_24M       ),
	.locked ( lock              )
	);

OV7670_INIT_IIC OV7670_INIT_IIC_inst(
	.Clk        (Clk             )           ,
	.Rst_n      (sys_rst_n       )        ,
	.Start      (go              )            ,

	.Iic_clk    (Cmos_sclk       )        ,
	.Sda        (Cmos_sda        )        ,
	.Init_done  (init_done       )
);
// OV7670_INIT_SCCB    OV7670_INIT_SCCB_inst(
	// .Clk         (Clk             )        ,
	// .Rst_n       (sys_rst_n       )        ,
	// .Start       (go              )        ,
                  
	// .Sccb_clk    (Cmos_sclk       )        ,
	// .Sda         (Cmos_sda        )        ,
	// .Init_done   (init_done       )
// );
 CAMERA_OV7670_DVP  CAMERA_OV7670_DVP_inst(

	.Rst_n           (sys_rst_n)    ,         
    .Clk_cmos        (clk_cmos_24M)    ,            //驱动摄像头时钟
    
    .Cmos_pclk       (Cmos_pclk )    ,              //摄像头输入时钟
	.Cmos_vsync      (Cmos_vsync)    ,
	.Cmos_href       (Cmos_href )    ,
	.Cmos_data       (Cmos_data )    ,

	.Cmos_data_value (wr_req   )    ,
	.Cmos_data_pixel (data_cmos)    ,
	.Xaddress        ()    ,
	.Yaddress        ()    ,
    .Wr_rst          (wr_rst)       ,
    .Cmos_xclk       (Cmos_xclk)    
);
SDRAM_TOP   SDRAM_TOP_inst(

    .Clk               (clk_100M)      ,
    .Rst_n             (sys_rst_n)      ,
    .Clk_out           (clk_shift_100M)      ,     //输入相位偏移时钟
  
    .Wr_fifo_wr_clk    (Cmos_pclk)      ,    
    .Wr_fifo_wr_req    (wr_req)      ,          //  wr_req
    .Wr_fifo_wr_data   (data_cmos)      ,      //写入写FIFO中的
    .Sdram_wr_b_addr   (0)      ,
    .Sdram_wr_e_addr   (640*480)      ,
    .Wr_burst_len      (10'd512)      ,
    .Wr_rst            (!sys_rst_n)      ,      //写复位信号
   
    .Rd_fifo_rd_clk    (clk_vga_24M)      ,
    .Rd_fifo_rd_req    (vga_data_reg)      ,
    .Sdram_rd_b_addr   (0)      ,
    .Sdram_rd_e_addr   (640*480)      ,
    .Rd_burst_len      (10'd512)      ,      //读突发长度
    .Rd_rst            (!sys_rst_n)      ,      //读复位信号
    .Rd_value          (rd_value)      ,
    .Rd_fifo_rd_data   (pix_data)      ,      //读FIFO中读出的数据
    .Rd_fifo_num       ()      ,      //读FIFO中存在的数据个数
 
    .Sdram_clk         (Sdram_clk  )      ,
    .Sdram_cke         (Sdram_cke  )      ,                                
    .Sdram_cs_n        (Sdram_cs_n )      ,
    .Sdram_cas_n       (Sdram_cas_n)      ,
    .Sdram_ras_n       (Sdram_ras_n)      ,
    .Sdram_we_n        (Sdram_we_n )      ,
    .Sdram_ba          (Sdram_ba   )      ,
    .Sdram_addr        (Sdram_addr )      ,
    .Sdram_dq          (Sdram_dq   )      ,     // SDRAM 数据总线
    .Sdram_dqm         (Sdram_dqm  )     
);
VGA_CTRL    VGA_CTRL_inst(
    .Clk          (clk_vga_24M)  ,               
    .Rst_n        (sys_rst_n)  ,
    .Pix_data     (pix_data)  , 
   
    .Disp_data    (disp_data)        ,
    .Hsync        (Hsync  )  ,              
    .Vsync        (Vsync  )  ,
    .Pix_x        (pix_x)            ,
    .Pix_y        (pix_y)            ,
    .Clk_vga      (Clk_vga)  ,
    .Vga_blk      (Clk_blk)  ,  //VGA 场消隐信号
    .Pix_reg      (pix_reg)  
);   
wire    [15:0]      disp_data;
wire    vga_data_reg;
wire        [7:0]      po_data           ;
assign   vga_data_reg = pix_reg;
assign  Vga_rgb   =   po_data;
sobel_test  sobel_test_inst(

.Clk            (clk_vga_24M)               ,
.Rst_n          (sys_rst_n)                 ,  
.Po_flag        (pix_reg)                   ,
.Po_data        ({2'd0,disp_data[10:5]})    ,
.Threshold      (change)                    ,

.Out_data       (po_data)                   ,
.Out_flag       ()    
);
endmodule  
 

系统板级验证

阈值为12时系统运行结果图
在这里插入图片描述
阈值为20时系统运行结果图
在这里插入图片描述
原始摄像头采集图像系统运行结果图
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-24 18:23:18  更:2022-05-24 18:25:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:46:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码