基于OV7670摄像头视频传输

系统总设计图

在这里插入图片描述

系统组成部分

摄像头初始化模块

摄像头初始化通过IIC协议或者SCCB协议写入寄存器改写数据。初始化之前满足的条件如图所示。
在这里插入图片描述

IIC初始化模块代码

module OV7670_INIT_IIC(
	Clk,
	Rst_n,
	Start,
	
	Iic_clk,
	Sda,
	Init_done
);
input	Clk;
input	Rst_n;
input	Start;
	
output Iic_clk;
inout Sda;
output reg Init_done;

reg [7:0]data_cnt;//计数115个数据计数计数器
localparam DATA_SIZE = 8'd115;
wire [15:0]q_rom;
wire done_iic;
reg wr_en;
wire [7:0]wr_data;//写入的数据
wire [15:0]word_adrr;
reg  [1:0]main_state;
wire        ack     ;
reg     [9:0]   cnt;
reg     ok      ;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        cnt <=  1'b0;
    else
    if(done_iic)
        cnt <=  1'b0;
    else
    if(cnt  ==  10'd99)         //计数2us
        cnt <=  1'b0;
    else
        cnt <=  cnt +   1'b1;
        
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        ok  <=  1'b0;
    else
    if(cnt  ==  10'd99)
        ok  <=  1'b1;
    else
        ok  <=  1'b0;



always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        data_cnt <= 1'b0;
    else 
    if(Start)
        data_cnt <= 1'b0;
    else 
    if(data_cnt < DATA_SIZE)
        begin
            if(done_iic && (!ack))
                data_cnt <= data_cnt + 1'b1;
            else 
                data_cnt <= data_cnt;
        end
    else 
        data_cnt <= DATA_SIZE;

//产生初始化完成标志信号
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Init_done <= 1'b0;
    else 
    if(data_cnt == DATA_SIZE)
        Init_done <= 1'b1;
    else 
        Init_done <= 1'b0;

//状态机发送数据
always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        begin
            main_state <= 2'b0;
            wr_en <= 1'b0;
        end
    else 
        begin
            if(data_cnt < DATA_SIZE)
                begin
                    case(main_state)
                    2'b0:
                        begin
                            if(Start)	
                                main_state <= 2'd1;
                            else 
                                main_state <= 2'd0;
                        end
                    
                    2'd1:
                        begin
                            wr_en <= 1'b1;
                            main_state <= 2'd2;
                        end
                    
                    2'd2:
                        begin
                            wr_en <= 1'b0;
                                if(ok)
                                    main_state <= 2'd1;
                                else 
                                    main_state <= 2'd2;
                        end
                
                    default : main_state <= 1'b0;
                    endcase 
	
	
        end
	else 
        begin
            wr_en <= 1'b0;
            main_state <= 1'b0;
        end

end

//IIC模块
IIC IIC(
	.Clk(Clk),
	.Rst_n(Rst_n),
	.Wr(wr_en),
	.Read(1'b0),
	.Wdata_num(1),
	.Rdata_num(1'b1),
	.Address_num(2'd1),
	.Device_adress(8'h42), //器件片选地址
	.Word_adrr(word_adrr), //存储单元地址
	.Wr_data(wr_data),
	
	.Rd_data(),
	.Wr_data_vaule(),
	.Rd_data_vaule(),
	.Done(done_iic),
    .ack(ack),
	.Sda(Sda),
	.Iic_clk(Iic_clk)
);

assign wr_data = q_rom[7:0];
assign word_adrr = q_rom[15:8];

OV7670_TABLE_ROM OV7670_TABLE_ROM
(
	.addr(data_cnt),
	.clk(Clk), 
	.q(q_rom)
);

endmodule 

IIC单次写入8位115个不同寄存器地址的数据。

IIC初始化模块问题与原因

使用IIC协议初始化失败的原因主要是IIC总线空闲时间太短,及上一次写入完成产生停止位(上升沿)与下一次开始写入产生起始位(下降沿)间隔时间太短,不满足摄像头器件要求。器件要求如图所示。器件要求
而使用逻辑分析仪测得实际波形如图所示。
在这里插入图片描述

由图可以清楚的看到,当IIC协议第二次写入不同的寄存器地址时,从机未产生应答位,导致初始化失败,实际的总线空闲时间为700ns。

SCCB初始化模块代码

module  OV7670_INIT_SCCB(
	Clk                 ,
	Rst_n               ,
	Start               ,
	
	Sccb_clk            ,
	Sda                 ,
	Init_done
);

input	            Clk             ;
input	            Rst_n           ;
input	            Start           ;    
output              Sccb_clk        ; 
output              Sda             ;
output   reg        Init_done       ;
reg      [7:0]      addr_cnt        ;       //计数115次地址计数器                                
wire     [15:0]     q_rom          ;
wire     [7:0]      wr_data         ;
wire     [7:0]      word_adrr       ;
wire                wr_done         ;    
reg                 wr_en           ;      
reg      [1:0]      main_state      ;


localparam      DATA_SIZE    =   115         ;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        addr_cnt    <=  1'b0;
    else
    if(Start)
        addr_cnt    <=  1'b0;
    else
    if(addr_cnt <   DATA_SIZE)
        begin
            if(wr_done)
                addr_cnt    <=  addr_cnt    +   1'b1;
            else
                addr_cnt    <=  addr_cnt    ;   
        end
    else
        addr_cnt    <=  DATA_SIZE    ;

always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        Init_done   <=  1'b0;
    else
    if(addr_cnt ==  DATA_SIZE)
        Init_done   <=  1'b1;
    else
        Init_done   <=  1'b0;


always @(posedge Clk or negedge Rst_n)
    if(!Rst_n)
        begin
            main_state <= 2'b0;
            wr_en <= 1'b0;
        end
    else 
        begin
            if(addr_cnt < DATA_SIZE)
                begin
                    case(main_state)
                    2'b0:
                        begin
                            if(Start)	
                                main_state <= 2'd1;
                            else 
                                main_state <= 2'd0;
                        end
                    
                    2'd1:
                        begin
                            wr_en <= 1'b1;
                            main_state <= 2'd2;
                        end
                     
                    2'd2:
                        begin
                            wr_en <= 1'b0;
                                if(wr_done)
                                    main_state <= 2'd1;

                        end
                
                    default : main_state <= 1'b0;
                    endcase 
	
	
        end
	else 
        begin
            wr_en <= 1'b0;
            main_state <= 1'b0;
        end

end
    
assign wr_data      = q_rom[7:0]        ;
assign word_adrr    = q_rom[15:8]       ;

SCCB    SCCB_inst(
	.Clk             (Clk           )       ,
	.Rst_n           (Rst_n         )       ,
        
	.Wr              (wr_en         )    ,
	.Wr_data         (wr_data       )    ,
	.Wr_data_vaule   ()    ,
	.Wr_done         (wr_done       )    ,

	.Word_adrr       (word_adrr     )    ,           //存储单元地址

	.Device_adress   (8'h42)    ,           //器件地址

    .Read            ()    ,   
	.Rd_data         ()    ,
	.Rd_data_vaule   ()    ,
    .Rd_done         ()    ,

	.Sda             (Sda           )    ,
	.Sccb_clk        (Sccb_clk      )
);

    OV7670_TABLE_ROM    OV7670_TABLE_ROM_insy
(
	 .addr     (addr_cnt    )     ,
	 .clk      (Clk         )     , 
	 .q        (q_rom       )
);


endmodule   

与IIC初始化代码基本相同,因为只写不读数据。

SCCB初始化遇到的问题及原因

SCCB模块代码中,在同一个always语句中第一个if语句判断优先级高于第二个if判断,由于初始化代码中的SCCB使能信号保持高电平导致一直产生SCCB协议时钟信号CLK,在CLK高电平时SDA信号未有产生下降沿及起始位,导致初始化失败。问题代码如图所示。

在这里插入图片描述

实际问题波形与正确波形比较如图所示。两个波形在CLK信号为高电平时产生上升沿即停止位,但是错误波形在CLK为高时没有产生下降沿即停止位。
请添加图片描述

摄像头DVP协议

使用IIC协议初始化摄像头(改写摄像头中的寄存器的值)

创建ROM,将IIC控制数据保存到ROM中,使用查找表输入到IIC控制。
module  OV7670_TABLE_ROM
#(parameter DATA_WIDTH=16, parameter ADDR_WIDTH=8)
(
	input [(ADDR_WIDTH-1):0] addr,
	input clk, 
	output reg [(DATA_WIDTH-1):0] q
);

	// Declare the ROM variable
	reg [DATA_WIDTH-1:0] rom[2**ADDR_WIDTH-1:0];

	// Initialize the ROM with $readmemb.  Put the memory contents
	// in the file single_port_rom_init.txt.  Without this file,
	// this design will not compile.

	// See Verilog LRM 1364-2001 Section 17.2.8 for details on the
	// format of this file, or see the "Using $readmemb and $readmemh"
	// template later in this section.

	initial
	begin
		/*OV7670 VGA RGB565参数  */
		rom[0  ][15:0] = 16'h3a_04;	//
		rom[1  ][15:0] = 16'h40_d0;	
		rom[2  ][15:0] = 16'h12_04;	//VGA,RGB输出
		
		//输出窗口设置
		rom[3  ][15:0] = 16'h32_b6;	
		rom[4  ][15:0] = 16'h17_13;	
		rom[5  ][15:0] = 16'h18_01;	//5
		rom[6  ][15:0] = 16'h19_02;	
		rom[7  ][15:0] = 16'h1a_7a;	//0x7a,
		rom[8  ][15:0] = 16'h03_0a;	//0x0a,
		
		rom[9  ][15:0] = 16'h0c_00;	
		rom[10 ][15:0] = 16'h15_00;	
		rom[11 ][15:0] = 16'h3e_00;	//10
		rom[12 ][15:0] = 16'h70_00;	
		rom[13 ][15:0] = 16'h71_01;	
		rom[14 ][15:0] = 16'h72_11;	
		rom[15 ][15:0] = 16'h73_00;	//
		
		rom[16 ][15:0] = 16'ha2_02;	//15
		rom[17 ][15:0] = 16'h11_80;	//时钟分频设置,0,不分频.
		rom[18 ][15:0] = 16'h7a_20;	
		rom[19 ][15:0] = 16'h7b_1c;	
		rom[20 ][15:0] = 16'h7c_28;
		
		rom[21 ][15:0] = 16'h7d_3c;	//20
		rom[22 ][15:0] = 16'h7e_55;	
		rom[23 ][15:0] = 16'h7f_68;	
		rom[24 ][15:0] = 16'h80_76;	
		rom[25 ][15:0] = 16'h81_80;
		
		rom[26 ][15:0] = 16'h82_88;	
		rom[27 ][15:0] = 16'h83_8f;	
		rom[28 ][15:0] = 16'h84_96;	
		rom[29 ][15:0] = 16'h85_a3;	
		rom[30 ][15:0] = 16'h86_af;
		
		rom[31 ][15:0] = 16'h87_c4;	//30
		rom[32 ][15:0] = 16'h88_d7;	
		rom[33 ][15:0] = 16'h89_e8;	
		rom[34 ][15:0] = 16'h13_e0;	
		rom[35 ][15:0] = 16'h00_00;	//AGC
      
		rom[36 ][15:0] = 16'h10_00;	
		rom[37 ][15:0] = 16'h0d_00;	 
		rom[38 ][15:0] = 16'h14_28;	//0x38, limit the max gain
		rom[39 ][15:0] = 16'ha5_05;	
		rom[40 ][15:0] = 16'hab_07;
		
		rom[41 ][15:0] = 16'h24_75;	//40
		rom[42 ][15:0] = 16'h25_63;	
		rom[43 ][15:0] = 16'h26_A5;	
		rom[44 ][15:0] = 16'h9f_78;	
		rom[45 ][15:0] = 16'ha0_68;
		
		rom[46 ][15:0] = 16'ha1_03;	//0x03,
		rom[47 ][15:0] = 16'ha6_df;	//0xdf,
		rom[48 ][15:0] = 16'ha7_df;	//0xdf,
		rom[49 ][15:0] = 16'ha8_f0;	
		rom[50 ][15:0] = 16'ha9_90;
		
		rom[51 ][15:0] = 16'haa_94;	//
		rom[52 ][15:0] = 16'h13_ef;	
		rom[53 ][15:0] = 16'h0e_61;	
		rom[54 ][15:0] = 16'h0f_4b;	
		rom[55 ][15:0] = 16'h16_02;
		
		rom[56 ][15:0] = 16'h1e_11;	//图像输出镜像控制.0x07,
		rom[57 ][15:0] = 16'h21_02;	
		rom[58 ][15:0] = 16'h22_91;	
		rom[59 ][15:0] = 16'h29_07;	
		rom[60 ][15:0] = 16'h33_0b;
		
		rom[61 ][15:0] = 16'h35_0b;	//60
		rom[62 ][15:0] = 16'h37_1d;	
		rom[63 ][15:0] = 16'h38_71;	
		rom[64 ][15:0] = 16'h39_2a;	
		rom[65 ][15:0] = 16'h3c_78;
		
		rom[66 ][15:0] = 16'h4d_40;	
		rom[67 ][15:0] = 16'h4e_20;	
		rom[68 ][15:0] = 16'h69_00;	
		rom[69 ][15:0] = 16'h6b_00;	//PLL*4=48Mhz
		rom[70 ][15:0] = 16'h74_19;	
		rom[71 ][15:0] = 16'h8d_4f;
		
		rom[72 ][15:0] = 16'h8e_00;	//70
		rom[73 ][15:0] = 16'h8f_00;	
		rom[74 ][15:0] = 16'h90_00;	
		rom[75 ][15:0] = 16'h91_00;	
		rom[76 ][15:0] = 16'h92_00;	//0x19,//0x66
		
		rom[77 ][15:0] = 16'h96_00;	
		rom[78 ][15:0] = 16'h9a_80;	
		rom[79 ][15:0] = 16'hb0_84;	
		rom[80 ][15:0] = 16'hb1_0c;	
		rom[81 ][15:0] = 16'hb2_0e;
		
		rom[82 ][15:0] = 16'hb3_82;	//80
		rom[83 ][15:0] = 16'hb8_0a;	
		rom[84 ][15:0] = 16'h43_14;	
		rom[85 ][15:0] = 16'h44_f0;	
		rom[86 ][15:0] = 16'h45_34;
		
		rom[87 ][15:0] = 16'h46_58;	
		rom[88 ][15:0] = 16'h47_28;	
		rom[89 ][15:0] = 16'h48_3a;	
		rom[90 ][15:0] = 16'h59_88;	
		rom[91 ][15:0] = 16'h5a_88;
		
		rom[92 ][15:0] = 16'h5b_44;	//90
		rom[93 ][15:0] = 16'h5c_67;	
		rom[94 ][15:0] = 16'h5d_49;	
		rom[95 ][15:0] = 16'h5e_0e;	
		rom[96 ][15:0] = 16'h64_04;	
		rom[97 ][15:0] = 16'h65_20;
		
		rom[98 ][15:0] = 16'h66_05;	
		rom[99 ][15:0] = 16'h94_04;	
		rom[100][15:0] = 16'h95_08;	
		rom[101][15:0] = 16'h6c_0a;	
		rom[102][15:0] = 16'h6d_55;
		
		rom[103][15:0] = 16'h4f_80;	
		rom[104][15:0] = 16'h50_80;	
		rom[105][15:0] = 16'h51_00;	
		rom[106][15:0] = 16'h52_22;	
		rom[107][15:0] = 16'h53_5e;	
		rom[108][15:0] = 16'h54_80;
		
		rom[109][15:0] = 16'h09_03;	//驱动能力最大
		rom[110][15:0] = 16'h6e_11;	//100
		rom[111][15:0] = 16'h6f_9f;	//0x9e for advance AWB
		rom[112][15:0] = 16'h55_00;	//亮度
		rom[113][15:0] = 16'h56_40;	//对比度
		rom[114][15:0] = 16'h57_80;	//0x40,  change according to Jim's request	
	end

	always @ (posedge clk)
	begin
		q <= rom[addr];
	end

endmodule

DVP协议如图所示
在这里插入图片描述

PCLK:摄像头输出时钟信号传输FPGA,不同分辨率频率不同。
VSYNC: 传输一张图片产生两个VSYNC脉冲,脉冲之间的低电平传输一次显示的整张图片。
HREF:在VSYNC两次脉冲之间传输有效,一次HREF高电平表示传输一行图片像素点,第二个HREF高电平表示传输第二行图片像素点。
Data:输出为RGB565数据(红5位,绿6位,蓝5位, 节省存储空间,提高存储器带宽利用率)。在HREF为高电平时传有效数据,每个PCLK上升沿变换数据。
每一个像素点由RGB三种颜色表示,两个8位Data数据传输一个像素点RGB(16位)数据。

DVP模块设计图如图所示
在这里插入图片描述

DVP协议文件
module CAMERA_OV7670_DVP(

	Rst_n           ,         
    Clk_cmos        ,          //驱动摄像头时钟
    
    Cmos_pclk       ,          //摄像头输入时钟
	Cmos_vsync      ,
	Cmos_href       ,
	Cmos_data       ,
	
	Cmos_data_value ,
	Cmos_data_pixel ,
	Xaddress        ,
	Yaddress        ,
    Wr_rst          ,           //·SDRAM中写缓存清零标志位
    Cmos_xclk       

    
);
input	            Cmos_pclk                       ;
input	            Rst_n                           ;
input	            Cmos_vsync                      ;
input	            Cmos_href                       ;
input  [7:0]        Cmos_data                  ;
input               Clk_cmos                        ;
	
output              Cmos_data_value               ;//一行传输一个像素点RGB数据有效标志位
output [15:0]       Cmos_data_pixel         ;   
output [11:0]       Xaddress           ;
output [11:0]       Yaddress           ;
output              Cmos_xclk           ;
output  reg         Wr_rst              ;


reg mid_Cmos_vsync;
reg mid_Cmos_href;
reg [7:0]mid_Cmos_data;
reg [12:0]hcnt; //计数一行像素计数器 比地址多一位 地址两倍 每个像素点16位计数一个传8位
reg [11:0]ycnt; //计数多列像素计数器
reg [15:0]mid_Cmos_data_pixel;
reg mid_Cmos_data_value;//一行传输一个像素点RGB数据有效标志位
reg [3:0]del_frame_cnt;
reg delete_en;

assign Cmos_data_pixel = mid_Cmos_data_pixel;
assign Cmos_data_value = mid_Cmos_data_value && delete_en;

assign  Cmos_xclk = Clk_cmos;

always @(posedge Cmos_pclk or negedge Rst_n)
    if(!Rst_n)
        Wr_rst  <=  1'b1;
    else 
    if(mid_Cmos_vsync)
        Wr_rst  <=  1'b0;
    else
        Wr_rst  <=  Wr_rst;

always @(posedge Cmos_pclk or negedge Rst_n)  //快速IO 使用IO寄存器提高时序性能
    if(!Rst_n)
        begin
            mid_Cmos_href <= 1'b0;
            mid_Cmos_vsync <= 1'b0;
            mid_Cmos_data <= 8'd0;
        end
    else 
        begin
            mid_Cmos_href <= Cmos_href;    
            mid_Cmos_vsync <= Cmos_vsync;
            mid_Cmos_data <= Cmos_data;
        end

//计数每行Cmos_data数据,每个Cmos_data8位
always @(posedge Cmos_pclk or negedge Rst_n)
    if(!Rst_n)
        hcnt <= 1'b0;
    else 
    if(mid_Cmos_href)
        hcnt <= hcnt + 1'b1;
    else 
        hcnt <= 1'b0;

assign Xaddress = hcnt[12:1];  //取高12位 相当于右移 FPGA避免除法

//输出两个Cmos_data8位数据 组成一个像素点16位数据
always @(posedge Cmos_pclk or negedge Rst_n)
    if(!Rst_n)
        mid_Cmos_data_pixel <= 16'd0;
    else 
    if(!hcnt[0])  //偶数传高8位 奇数传低8位
        mid_Cmos_data_pixel[15:8] <= mid_Cmos_data;   //偶数
    else 
        mid_Cmos_data_pixel[7:0] <= mid_Cmos_data;

//一个像素点RGB数据传输成功标志信号
always @(posedge Cmos_pclk or negedge Rst_n)
    if(!Rst_n)
        mid_Cmos_data_value <= 1'd0;
    else 
    if(hcnt[0])  
        mid_Cmos_data_value <= 1'd1;   //奇数
    else 
        mid_Cmos_data_value <= 1'd0;

//多列计数器计数多列像素点
always @(posedge Cmos_pclk or negedge Rst_n)
    if(!Rst_n)
        ycnt <= 1'b0;
    else 
    if(mid_Cmos_vsync)
        ycnt <= 1'b0;
    else 
    if({mid_Cmos_href,Cmos_href} == 2'b01) //检测mid_Cmos_href上升沿  前 后
        ycnt <= ycnt + 1'b1;
    else 
        ycnt <= ycnt;


assign Yaddress = ycnt;

//舍弃前10帧
always @(posedge Cmos_pclk or negedge Rst_n)
    if(!Rst_n)
        del_frame_cnt <= 1'b0;
    else 
    if({mid_Cmos_vsync,Cmos_vsync} == 2'b01)
        begin
            if(del_frame_cnt >= 4'd10)  //高速数据
                del_frame_cnt <= 4'd10;
            else 
                del_frame_cnt <= del_frame_cnt + 1'b1;
        end
    else
        del_frame_cnt <= del_frame_cnt;


always @(posedge Cmos_pclk or negedge Rst_n)
    if(!Rst_n)
        delete_en <= 1'b0;
    else 
    if(del_frame_cnt >= 4'd10)
        delete_en <= 1'b1;
    else 
        delete_en <= 1'b0;


endmodule 
模拟摄像头信号仿真DVP接口
`timescale 1ns/1ns
`define Clk_period 60
module  CAMERA_OV7670_DVP_tb;
reg Pclk;
reg Rst_n;
reg Vsync;
reg Href;
reg [7:0]Data;
	
wire Data_value;
wire [15:0]Data_pixel;
wire [11:0]Xaddress;
wire [11:0]Yaddress;
CAMERA_OV7670_DVP CAMERA_OV7670_DVP(
	.Pclk(Pclk),
	.Rst_n(Rst_n),
	.Vsync(Vsync),
	.Href(Href),
	.Data(Data),
	
	.Data_value(Data_value),
	.Data_pixel(Data_pixel),
	.Xaddress(Xaddress),
	.Yaddress(Yaddress)
);


integer i,j ;   //定义变量
parameter WITH = 16;
parameter HIGH = 12;

initial Pclk = 1;
always #(`Clk_period) Pclk = ~Pclk;

initial 
begin
Rst_n = 0;
Vsync = 0;
Href = 0;
Data = 0;
#(200+1);
Rst_n = 1;
#200;
repeat(15)
	begin
	Vsync = 1;
	#200;
	Vsync = 0;	
	#300
	for(i=0;i<HIGH;i=i+1)
		begin
			for(j=0;j<WITH;j=j+1)
			begin
			Href = 1;
			Data = Data + 1;
			#(`Clk_period*2);
			end
		Href = 0;
		#400;	
		end
	end

$stop;
end
endmodule 

仿真结果如图所示
在这里插入图片描述
Cmos_data_pixel输出Cmos_data位拼接的16位数据.

实际IIC与DVP协议波形

在这里插入图片描述
与设计波形一致。

系统顶层文件代码

`include "disp_parameter.v"

module      DVP_SDRAM_VGA(
    //global    port
input       wire                Clk             ,
input       wire                Rst_n           ,
    //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    [`Red_Bits - 1 :0]          Disp_red       ,           
output      wire    [`Green_Bits - 1 :0]        Disp_green     ,
output      wire    [`Blue_Bits - 1 :0]         Disp_blue      ,
output      wire                Hsync                          ,
output      wire                Vsync                          ,
output      wire                Clk_vga                        ,
output      wire                Clk_blk                        

);

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          ;

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  ;
    
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       )
);

 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_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    (pix_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[15:11],3'd0,pix_data[10:5],2'd0,pix_data[4:0],3'd0})  , //R G B

    .Disp_red     (Disp_red  )  ,
    .Disp_green   (Disp_green)  ,
    .Disp_blue    (Disp_blue )  ,
    .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)  
);                                            

// VGA_CTRL    VGA_CTRL_inst(

    // .Clk          (clk_vga_24M)  ,               
    // .Rst_n        (sys_rst_n)  ,
    // .Pix_data     (pix_data)  , //R G B

    // .Disp_red     (Disp_red  )  ,
    // .Disp_green   (Disp_green)  ,
    // .Disp_blue    (Disp_blue )  ,       
    // .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)  
// );   

endmodule  
  

在文件中调用"disp_parameter.v"文件,可以选择RGB565或者RGB888模式展示。
实际运行如图所示。
在这里插入图片描述

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
51单片机是一种常用的单片机,具有高性价比和易学易用的特点。而OV7670摄像头则是一款常用的低成本摄像头,基于CMOS技术,具有较高的像素和图像质量。 要实现51单片机OV7670摄像头的通信和图像采集功能,需要编写相应的程序。以下是一种可能的OV7670摄像头程序的代码示例: 1. 定义IO口: sbit SC = P3^4; // SCCB时钟 sbit SD = P3^5; // SCCB数据 sbit SIOC = P3^6; // SCCB输出时钟 2. 初始化OV7670摄像头: void init_OV7670() { // 初始化SCCB总线 SIOC = 1; SC = 1; SD = 1; delay(10); SCCB_reset(); // 设置OV7670寄存器 SCCB_write(0x12, 0x80); // 复位寄存器 delay(10); // 等待复位完成 SCCB_write(0x11, 0x81); // 设置CLK为外部输入 SCCB_write(0x3A, 0x04); // 设置输出格式为RGB565 SCCB_write(0x70, 0x3A); // 使能输出窗口 //... // 其他初始化设置... } 3. SCCB总线通信函数: void SCCB_write(unsigned char reg, unsigned char dat) { unsigned char i; SIOC = 0; delay(1); for (i = 0; i < 8; i++) { SIOC = 0; SD = (reg << i) & 0x80; delay(1); SIOC = 1; delay(1); } SIOC = 0; delay(1); for (i = 0; i < 8; i++) { SIOC = 0; SD = (dat << i) & 0x80; delay(1); SIOC = 1; delay(1); } SIOC = 0; delay(1); SIOC = 1; delay(1); } 4. 主函数: void main() { init_OV7670(); while (1) { // 图像采集和处理代码... // 显示图像... // 图像存储或传输... // 延时... // 其他功能代码... } } 以上代码仅为示例代码,实际使用时需要根据OV7670摄像头的具体配置和所需功能进行相应的修改。通过以上代码,可以实现51单片机OV7670摄像头的基本通信和图像采集功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值