基于FPGA的OV7725摄像头的HDMI显示(含源码)

1、概述

  本文FPGA通过SCCB接口初始化OV7725摄像头寄存器,然后采集OV7725的摄像头数据,使用DDR3对数据进行暂存,最后将数据输出到HDMI显示器上进行显示。

  该工程对应系统框图如下所示,主要包含OV7725驱动及数据处理模块、DDR3读写控制模块、HDMI控制模块。其中DDR3读写控制模块和HDMI显示控制模块在前文设计中已经进行详细讲解过了,本文直接使用即可,不再对其功能的实现进行赘述,不了解的可以参考前文。

  由于只需要向OV7725的寄存器中写入数据,所以可以直接使用前文编写的I2C驱动模块代替SCCB驱动模块。iic_drive模块是I2C的驱动模块,兼容SCCB的写时序。init_contrl模块主要功能是控制初始化OV7725的哪些寄存器。Capture_data模块将摄像头输出的8位数据拼接为16位数据,然后传输给DDR3读写模块,将数据存入DDR3中。

在这里插入图片描述

图1 系统框图

  后面DDR3控制模块和HDMI显示模块的设计思路与以太网传输图片中两个模块的设计基本一致。

  外部的晶振输入100MHz时钟,通过锁相环进行倍频、分频处理,给OV7725提供12MHz的系统时钟XCLK,给DDR3控制模块提供200MHz的参考时钟和MIG IP工作时钟。由于显示器分辨率为1024*768,所以还需要给HDMI模块提供65MHz时钟和325MHz的参考时钟信号。

  对于异步信号,首先DDR3读写控制模块的读、写两侧都是异步FIFO,相应的数据就能够异步FIFO交换数据,不需要做额外处理。

2、OV7725初始化控制模块

  根据官方提供的初始化参数,对70个寄存器进行初始化,最终输出PCLK时钟频率为24MHz,640*480分辨率的RGB565像素数据。根据前文时序的介绍,首先对8’h12寄存器进行设置,使所有寄存器复位,发出该命令之后,需要等待1ms才能开始配置其余寄存器。

  因此通过一个复位计数器和复位标志信号来对复位状态进行指示,为了简化电路,此处使用的计数器依靠溢出清零。

  如下代码所示,复位指示信号初始值为0,wdata_cnt计数器用于表示已经初始化的寄存器个数。因为最先初始化的是复位计数器,因此当wdata_cnt等于1并且I2C驱动模块空闲的时候,证明复位寄存器已经被写入数据了,此时复位指示信号拉高,当复位计数器所有位均为高电平时,表示复位的持续时间大于1ms,此时可以配置后续寄存器了。

    //生成复位指示信号,初始为低电平,当复位寄存器且等待1ms之后拉低,表示复位完成;always@(posedge clk)beginif(rst_n==1'b0)begin//初始值为0;rst_flag <= 1'b0;end//当延时计数器全为1时,表示延时1.3ms,复位完成。else if(&delay_cnt)beginrst_flag <= 1'b0;end//当配置第0个数据之后,如果I2C驱动模块空闲,表示复位寄存器初始化完成,之后需要延时1ms才能继续配置其他寄存器。else if(wdata_cnt == 7'd1 && rdy)beginrst_flag <= 1'b1;endend

  下面代码就是复位的延时计数器,当复位指示信号有效时,对系统时钟进行计数,当溢出时清零,系统时钟周期为10ns,17位计数器从0计数到最大值需要131071个时钟,即1.31ms。

    //为了便于计数,直接使用一个17位计数器对100MHz时钟进行计数。always@(posedge clk)beginif(rst_n==1'b0)begin//初始值为0;delay_cnt <= 17'd0;endelse if(rst_flag)begin//处于复位状态下,对系统时钟进行计数。delay_cnt <= delay_cnt + 17'd1;endend

  之后就是计数器wdata_cnt,对初始化的寄存器个数进行计数。初始值为0,当初始化复位计数器时,要等延时计数器计数结束才能加一,如果初始化的不是复位寄存器,且已配置寄存器个数小于需要配置的寄存器个数,且I2C驱动模块处于空闲时加1。

    //wdata_cnt计数器用于记录配置的寄存器个数;always@(posedge clk)beginif(rst_n==1'b0)begin//wdata_cnt <= 0;endelse if(add_wdata_cnt)beginwdata_cnt <= wdata_cnt + 1;endend//记录初始化寄存器的个数,由于第0个寄存器初始化之后需要延时1ms,所以当计数器等于1时,需要等待延时计数器计数结束才能加1。//其余时间只需要等待I2C驱动模块空闲,就可以发送数据。assign add_wdata_cnt = (((wdata_cnt == 7'd1) && (&delay_cnt)) || ((wdata_cnt != 7'd1) && rdy && (wdata_cnt < REG_NUM)));

  将计数器加一条件延时一个时钟周期作为I2C驱动模块的开始信号,由于只需要向寄存器写入数据,所以读写标志信号一直拉低即可。根据计数器的数值生成需要写入寄存器的地址和数据。

    //写开始信号,当计数器加一条件有效且没有配置完所有寄存器时拉高;always@(posedge clk)beginif(rst_n==1'b0)begin//初始值为0;start <= 1'b0;endelse beginstart <= add_wdata_cnt;endendassign rw_flag = 1'b0;//读写控制信号置为低电平,因为只需要对寄存器进行初始化,不会有读操作。//设置寄存器的地址和数据;always@(posedge clk)beginif(rst_n==1'b0)begin//初始值为0;{reg_addr,wdata} <=	{8'h1C, 8'h7F}; //MIDH 制造商ID 高8位;endelse if(add_wdata_cnt)begincase(wdata_cnt)//先对寄存器进行软件复位,使寄存器恢复初始值;//寄存器软件复位后,需要延时1ms才能配置其它寄存器;7'd0  : {reg_addr,wdata} <= {8'h12, 8'h80}; //COM7 BIT[7]:复位所有的寄存器;7'd1  : {reg_addr,wdata} <= {8'h3d, 8'h03}; //COM12 模拟过程直流补偿;7'd2  : {reg_addr,wdata} <= {8'h15, 8'h02}; //COM10 href/vsync/pclk/data信号控制;7'd3  : {reg_addr,wdata} <= {8'h17, 8'h23}; //HSTART 水平起始位置;7'd4  : {reg_addr,wdata} <= {8'h18, 8'ha0}; //HSIZE 水平尺寸;7'd5  : {reg_addr,wdata} <= {8'h19, 8'h07}; //VSTRT 垂直起始位置;7'd6  : {reg_addr,wdata} <= {8'h1a, 8'hf0}; //VSIZE 垂直尺寸;7'd7  : {reg_addr,wdata} <= {8'h32, 8'h00}; //HREF 图像开始和尺寸控制,控制低位;7'd8  : {reg_addr,wdata} <= {8'h29, 8'ha0}; //HOutSize 水平输出尺寸;7'd9  : {reg_addr,wdata} <= {8'h2a, 8'h00}; //EXHCH 虚拟像素MSB;7'd10 : {reg_addr,wdata} <= {8'h2b, 8'h00}; //EXHCL 虚拟像素LSB;7'd11 : {reg_addr,wdata} <= {8'h2c, 8'hf0}; //VOutSize 垂直输出尺寸;7'd12 : {reg_addr,wdata} <= {8'h0d, 8'h41}; //COM4 PLL倍频设置(multiplier);                                   7'd13 : {reg_addr,wdata} <= {8'h11, 8'h00}; //CLKRC 内部时钟配置;7'd14 : {reg_addr,wdata} <= {8'h12, 8'h06}; //COM7 输出VGA RGB565格式;7'd15 : {reg_addr,wdata} <= {8'h0c, 8'h10}; //COM3 Bit[0]: 0:图像数据 1:彩条测试;//DSP 控制7'd16 : {reg_addr,wdata} <= {8'h42, 8'h7f}; //TGT_B 黑电平校准蓝色通道目标值;7'd17 : {reg_addr,wdata} <= {8'h4d, 8'h09}; //FixGain 模拟增益放大器;7'd18 : {reg_addr,wdata} <= {8'h63, 8'hf0}; //AWB_Ctrl0 自动白平衡控制字节0;7'd19 : {reg_addr,wdata} <= {8'h64, 8'hff}; //DSP_Ctrl1 DSP控制字节1;7'd20 : {reg_addr,wdata} <= {8'h65, 8'h00}; //DSP_Ctrl2 DSP控制字节2;7'd21 : {reg_addr,wdata} <= {8'h66, 8'h00}; //DSP_Ctrl3 DSP控制字节3;7'd22 : {reg_addr,wdata} <= {8'h67, 8'h00}; //DSP_Ctrl4 DSP控制字节4;//AGC AEC AWB        //COM8 Bit[2]:自动增益使能 Bit[1]:自动白平衡使能 Bit[0]:自动曝光功能;7'd23 : {reg_addr,wdata} <= {8'h13, 8'hff}; //COM8;7'd24 : {reg_addr,wdata} <= {8'h0f, 8'hc5}; //COM6;7'd25 : {reg_addr,wdata} <= {8'h14, 8'h11};  7'd26 : {reg_addr,wdata} <= {8'h22, 8'h98}; 7'd27 : {reg_addr,wdata} <= {8'h23, 8'h03};  7'd28 : {reg_addr,wdata} <= {8'h24, 8'h40}; 7'd29 : {reg_addr,wdata} <= {8'h25, 8'h30};  7'd30 : {reg_addr,wdata} <= {8'h26, 8'ha1};      7'd31 : {reg_addr,wdata} <= {8'h6b, 8'haa}; 7'd32 : {reg_addr,wdata} <= {8'h13, 8'hff};  //matrix sharpness brightness contrast UV7'd33 : {reg_addr,wdata} <= {8'h90, 8'h0a}; //EDGE1 边缘增强控制1;//DNSOff 降噪阈值下限,仅在自动模式下有效7'd34 : {reg_addr,wdata} <= {8'h91, 8'h01}; //DNSOff;7'd35 : {reg_addr,wdata} <= {8'h92, 8'h01}; //EDGE2 锐度(边缘增强)强度上限;7'd36 : {reg_addr,wdata} <= {8'h93, 8'h01}; //EDGE3 锐度(边缘增强)强度下限;7'd37 : {reg_addr,wdata} <= {8'h94, 8'h5f}; //MTX1 矩阵系数1;7'd38 : {reg_addr,wdata} <= {8'h95, 8'h53}; //MTX1 矩阵系数2;7'd39 : {reg_addr,wdata} <= {8'h96, 8'h11}; //MTX1 矩阵系数3;7'd40 : {reg_addr,wdata} <= {8'h97, 8'h1a}; //MTX1 矩阵系数4;7'd41 : {reg_addr,wdata} <= {8'h98, 8'h3d}; //MTX1 矩阵系数5;7'd42 : {reg_addr,wdata} <= {8'h99, 8'h5a}; //MTX1 矩阵系数6;7'd43 : {reg_addr,wdata} <= {8'h9a, 8'h1e}; //MTX_Ctrl 矩阵控制;7'd44 : {reg_addr,wdata} <= {8'h9b, 8'h3f}; //BRIGHT 亮度;7'd45 : {reg_addr,wdata} <= {8'h9c, 8'h25}; //CNST 对比度;7'd46 : {reg_addr,wdata} <= {8'h9e, 8'h81}; 7'd47 : {reg_addr,wdata} <= {8'ha6, 8'h06}; //SDE 特殊数字效果控制;7'd48 : {reg_addr,wdata} <= {8'ha7, 8'h65}; //USAT "U"饱和增益;7'd49 : {reg_addr,wdata} <= {8'ha8, 8'h65}; //VSAT "V"饱和增益;     7'd50 : {reg_addr,wdata} <= {8'ha9, 8'h80}; //VSAT "V"饱和增益;7'd51 : {reg_addr,wdata} <= {8'haa, 8'h80}; //VSAT "V"饱和增益;//伽马控制 7'd52 : {reg_addr,wdata} <= {8'h7e, 8'h0c}; 7'd53 : {reg_addr,wdata} <= {8'h7f, 8'h16}; 7'd54 : {reg_addr,wdata} <= {8'h80, 8'h2a}; 7'd55 : {reg_addr,wdata} <= {8'h81, 8'h4e}; 7'd56 : {reg_addr,wdata} <= {8'h82, 8'h61}; 7'd57 : {reg_addr,wdata} <= {8'h83, 8'h6f}; 7'd58 : {reg_addr,wdata} <= {8'h84, 8'h7b}; 7'd59 : {reg_addr,wdata} <= {8'h85, 8'h86};   7'd60 : {reg_addr,wdata} <= {8'h86, 8'h8e}; 7'd61 : {reg_addr,wdata} <= {8'h87, 8'h97}; 7'd62 : {reg_addr,wdata} <= {8'h88, 8'ha4}; 7'd63 : {reg_addr,wdata} <= {8'h89, 8'haf}; 7'd64 : {reg_addr,wdata} <= {8'h8a, 8'hc5}; 7'd65 : {reg_addr,wdata} <= {8'h8b, 8'hd7}; 7'd66 : {reg_addr,wdata} <= {8'h8c, 8'he8}; 7'd67 : {reg_addr,wdata} <= {8'h8d, 8'h20};             7'd68 : {reg_addr,wdata} <= {8'h0e, 8'h65}; //COM5;7'd69 : {reg_addr,wdata} <= {8'h09, 8'h00}; //COM2  Bit[1:0] 输出电流驱动能力;//只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写;default:{reg_addr,wdata} <=	{8'h1C, 8'h7F}; //MIDH 制造商ID 高8位;endcaseendend

  当所有寄存器配置完成后,将配置完成信号拉高。

    //初始化完成信号;always@(posedge clk)beginif(rst_n==1'b0)begin//初始值为0;init_done <= 1'b0;end//当所有寄存器写入数据,且I2C驱动模块处于空闲状态时,表示初始化完成;else if((wdata_cnt == REG_NUM) && rdy)begininit_done <= 1'b1;endend

  由于该模块的逻辑比较简单,因此没有进行仿真,后续直接上板即可,参考代码如下:

3、摄像头数据处理模块

  由于配置摄像头寄存器之后,需要10帧图像数据的时间,才能正常传输数据。当寄存器初始化完成之后,对场同步信号的上升沿进行检测,直到检测到10个为止。

    //将场同步信号延迟两个时钟周期,用于检测其上升沿;always@(posedge cam_pclk)begincam_vsync_r <= {cam_vsync_r[0],cam_vsync};cam_href_r <= {cam_href_r[0],cam_href};end//检测场同步信号上升沿;assign cam_vsync_pos = cam_vsync_r[0] & (~cam_vsync_r[1]);assign cam_href_neg = (~cam_href_r[0]) & cam_href_r[1];//延时计数器,用于记录复位后,前几帧数据;always@(posedge cam_pclk)beginif(rst_n==1'b0)begin//delay_cnt <= 0;end//当寄存器初始化完成,且检测到场同步上升沿,且小于10帧时加1;else if(ov7725_init_done && cam_vsync_pos && (delay_cnt < WAIT_FRAME - 1))begindelay_cnt <= delay_cnt + 1;endend//等待完成信号;always@(posedge cam_pclk)beginif(rst_n==1'b0)begin//初始值为0;delay_done <= 1'b0;end//else if(ov7725_init_done && cam_vsync_pos && (delay_cnt >= WAIT_FRAME - 1))begindelay_done <= 1'b1;endend

  由于需要把输入的8位像素数据拼接为16位像素数据输出,需要一个标志信号byte_flag,每行结束或者每帧数据开始时清零该信号,当像素有效信号HREF为高电平时,byte_flag翻转。

    //相当于一个计数器,用于记录采集数据的个数,当数据有效时翻转,为1时表示采集了两个数据;always@(posedge cam_pclk)beginif(rst_n==1'b0)begin//初始值为0;byte_flag <= 1'b0;endelse if(cam_href_neg | cam_vsync_pos)begin//在一帧数据开始或者一行数据接收结束时清零,便于下次计数的正确;byte_flag <= 1'b0;endelse if(cam_href)beginbyte_flag <= ~byte_flag;endend

  当输入像素有效(HREF位高电平),如果byte_flag为低电平,表示输入高字节数据,如果byte_flag为高电平,表示输入低字节数据。之后将像素输出有效指示信号拉高。最后可以把场同步信号输出,作为DDR3读、写控制模块写FIFO的复位信号,每帧数据开始时会对写FIFO进行复位,保证下一帧数据正确存储。

    //将8位数据转换为16位数据输出,摄像头先传输高字节数据,后传输低字节数据;always@(posedge cam_pclk)beginif(rst_n==1'b0)begin//初始值为0;cmos_frame_data <= 16'd0;endelse if(cam_href)beginif(byte_flag)//采集低字节数据;cmos_frame_data[7:0] <= cam_data;else//采集高字节数据;cmos_frame_data[15:8] <= cam_data;endend//输出像素有效指示信号,当采集完两次数据后输出一次有效数据;always@(posedge cam_pclk)beginif(rst_n==1'b0)begin//初始值为0;cmos_frame_valid <= 1'b0;endelse begin//当采集完两次数据且已经过了延时时输出一次有效数据cmos_frame_valid <= cam_href & byte_flag & delay_done;endend//输出场同步信号,延时完成后,将行同步信号延时一个时钟输出;assign cmos_frame_vsync = delay_done ? cam_vsync_r[0] : 1'b0;

  该模块的设计就这么简单,起始可以不用关心前10帧图像数据,可以继续简化模块设计。

4、顶层模块

  本次设计由于生成的时钟比较多,需要例化两个锁相环模块才能完成。另外摄像头采集的场同步信号作为DDR3读写控制模块的写FIFO复位,由于场同步信号拉高会提前有效像素几千个时钟,这段时间完成FIFO的复位完全没问题。

  DDR3读写控制模块使用乒乓模式,因为读速率比较快,所以始终读与写地址相反的地址区域即可。

  另外需要对HDMI数据请求信号修改,由于显示器的像素为1024*768,而摄像头采集数据的像素是640*480,需要把图像显示在显示器的中心区域。

  则水平像素显示区域为191831,垂直像素显示区域为143623,这段时间才能把DDR3读写控制模块的读使能信号拉高,一个时钟后得到像素数据。

在这里插入图片描述

图2 数据请求信号的范围进行更改

  将HDMI的场同步信号作为DDR3读写控制模块的读FIFO的复位信号,每读取一帧数据就对读FIFO的数据清零,确保下一帧图像正确显示。

  由于摄像头采集的数据一行包含640个像素点,为了DDR3读侧FIFO不溢出,FIFO深度设置为2048。

  整个模块的RTL视图如下所示:

在这里插入图片描述

图3 RTL系统视图

  参考代码如下:

    assign power_en = 1'b1;//使能模块电源,仅对此模块有用;//例化锁相环,输出200MHZ时钟,作为DDR的参考时钟;//生成65MHz时钟作为HDMI的参考时钟信号;clk_wiz_0 u_clk_wiz_0(.clk_out1   ( clk_200m      ),//output clk_out1.clk_out2   ( dvi_clk       ),//output clk_out2.clk_out3   ( dvi_clk_5x    ),//output clk_out3.resetn     ( rst_n         ),//input resetn.locked     ( sys_rst_n     ),//output locked.clk_in1    ( clk           ) //input clk_in1);//还要生成一路频率位12MHz的时钟输出给摄像头模块;clk_wiz_1 u_clk_wiz_1(.clk_out1   ( cam_xclk      ),//output clk_out1.resetn     ( rst_n         ),//input resetn.clk_in1    ( clk           ) //input clk_in1);      //例化OV7725摄像头采集模块;ov7725_top u_ov7725_top (.clk                ( clk               ),//系统时钟信号,100MHz;.rst_n              ( sys_rst_n         ),//系统复位信号,低电平有效;.cam_pclk           ( cam_pclk          ),//摄像头数据像素时钟;.cam_vsync          ( cam_vsync         ),//摄像头场同步信号;.cam_href           ( cam_href          ),//摄像头行同步信号;.cam_data           ( cam_data          ),//摄像头输入数据信号;.cmos_frame_vsync   ( cmos_frame_vsync  ),//帧有效信号;.cmos_frame_valid   ( cmos_frame_valid  ),//数据有效使能信号;.cmos_frame_data    ( cmos_frame_data   ),//有效数据;.scl                ( scl               ),//SCCB串行时钟信号;.sda                ( sda               ) //SCCB双向串行数据信号;);//例化DDR3顶层模块ddr3_top u_ddr3_top (.sys_clk_i          ( clk_200m          ),//MIG IP核输入时钟,200MHz;.rst_n              ( sys_rst_n         ),//复位,低有效;.ddr3_init_done     ( ddr3_init_done    ),//ddr3初始化完成信号;//DDR3接口信号.ddr3_addr          ( ddr3_addr         ),//ddr3 地址;.ddr3_ba            ( ddr3_ba           ),//ddr3 banck地址;.ddr3_ras_n         ( ddr3_ras_n        ),//ddr3 行选择;.ddr3_cas_n         ( ddr3_cas_n        ),//ddr3 列选择;.ddr3_we_n          ( ddr3_we_n         ),//ddr3 读写选择;.ddr3_reset_n       ( ddr3_reset_n      ),//ddr3 复位;.ddr3_ck_p          ( ddr3_ck_p         ),//ddr3 时钟正;.ddr3_ck_n          ( ddr3_ck_n         ),//ddr3 时钟负;.ddr3_cke           ( ddr3_cke          ),//ddr3 时钟使能;.ddr3_cs_n          ( ddr3_cs_n         ),//ddr3 片选;.ddr3_dm            ( ddr3_dm           ),//ddr3_dm;.ddr3_odt           ( ddr3_odt          ),//ddr3_odt;.ddr3_dq            ( ddr3_dq           ),//ddr3 数据;.ddr3_dqs_n         ( ddr3_dqs_n        ),//ddr3 dqs负;.ddr3_dqs_p         ( ddr3_dqs_p        ),//ddr3 dqs正;//复位及突发读写长度设置信号;.app_addr_wr_min    ( 29'd0             ),//读ddr3的起始地址;.app_addr_wr_max    ( 29'd307200        ),//读ddr3的结束地址;.app_wr_bust_len    ( 8'd80             ),//从ddr3中读数据时的突发长度;.app_addr_rd_min    ( 29'd0             ),//读ddr3的起始地址;.app_addr_rd_max    ( 29'd307200        ),//读ddr3的结束地址;.app_rd_bust_len    ( 8'd80             ),//从ddr3中读数据时的突发长度;.wr_rst             ( cmos_frame_vsync  ),//写复位信号,上升沿有效,持续时间必须大于ui_clk的周期;.rd_rst             ( video_vs          ),//读复位信号,上升沿有效,持续时间必须大于ui_clk周期;//写数据相关信号;.wfifo_wclk         ( cam_pclk          ),//写FIFO写时钟信号;.wfifo_wren         ( cmos_frame_valid  ),//写FIFO写使能信号;.wfifo_wdata        ( cmos_frame_data   ),//写FIFO写数据信号;.wfifo_wcount       (                   ),//写FIFO中的数据个数;.wfifo_full         ( wfifo_full        ),//写FIFO满指示信号;.wfifo_wrst_busy    ( wfifo_wrst_busy   ),//写FIFO复位完成指示信号,低电平表示复位完成;//读数据相关信号.rfifo_rclk         ( dvi_clk           ),//读FIFO读时钟;.rfifo_rden         ( data_req          ),//读FIFO读使能信号;.rfifo_rdata        ( pixel_data        ),//读FIFO读数据;.rfifo_rcount       ( rfifo_rcount      ),//读FIFO中的数据个数;.rfifo_empty        (                   ),//读FIFO空指示信号;.rfifo_rrst_busy    ( rfifo_rrst_busy   ) //读FIFO复位状态指示信号,高电平表示处于复位过程中。);//例化DVI接口驱动模块dvi_top  u_dvi_top (.dvi_clk            ( dvi_clk           ),//DVI时钟信号,1024*768分辨率时为65MHz.dvi_clk_5x         ( dvi_clk_5x        ),//DVI的5倍参考时钟信号,325MHz..rst_n              ( sys_rst_n         ),//复位信号,低电平有效。.ddr3_init_done     ( ddr3_init_done    ),//DDR3初始化完成;.rfifo_rrst_busy    ( rfifo_rrst_busy   ),//读FIFO的复位状态指示信号;.pixel_data         ( pixel_data        ),.data_req           ( data_req          ),.video_vs           ( video_vs          ),//HDMI接口信号.tmds_oen           ( tmds_oen          ),.tmds_clk_p         ( tmds_clk_p        ),.tmds_clk_n         ( tmds_clk_n        ),.tmds_data_p        ( tmds_data_p       ),.tmds_data_n        ( tmds_data_n       ));

5、上板测试

  综合工程之后,下载到开发板实测结果如下图所示;

在这里插入图片描述

图4 开发板测试平台

  由于我手里这颗摄像头年代太过久远,且镜头上有一些杂质,导致摄像头成像比较差。

图5 显示器显示摄像头数据

  可以通过修改配置寄存器的数值,如下图所示,将摄像头改成输出彩条图像。即寄存器8’h0c的最低位改为1,摄像头被设置为输出彩条测试模式。

在这里插入图片描述

图6 修改测试程序

  最终得到的彩条显示结果如下图所示,证明FPGA整个工程的数据处理是没有问题的,后续更换一个摄像头就好了。

在这里插入图片描述

图7 显示器显示摄像头输出的彩条测试图像

  本次工程设计到此结束了,有前文的DDR3设计和HDMI设计作为保障,摄像头采集数据通过HDMI显示在显示器上的工程其实并不复杂。

  积少成多,量变终究引发质变,对于每个细节都要找到问题原因,一起加油!!!

  本工程可以在公众号后台回复“基于OV7725摄像头的HDMI显示”(不包括引号)获取,工程项目使用vivado2021.1在zynq7030上进行开发。


  如果对文章内容理解有疑惑或者对代码不理解,可以在评论区或者后台留言,看到后均会回复!

  如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!您的支持是我更新的最大动力!将持续更新工程!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/743771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS概念及入门

CSS概念及入门 简介 CSS 的全称为&#xff1a;层叠样式表 ( Cascading Style Sheets ) 。 CSS 也是一种标记语言&#xff0c;用于给 HTML 结构设置样式&#xff0c;例如&#xff1a;文字大小、颜色、元素宽高等等。 主流的布局方式:divcss。 组成 选择器 用于选择页面中的…

防御安全(IPSec实验)

目录 需求&#xff1a; pc1 ping通 pc2 ,使用IPSec VPN 拓扑图&#xff1a; ​编辑实验配置&#xff1a; 注意&#xff1a; 直接在路由器r1和r2分别配置即可&#xff0c;路由器r1和r2要写一条缺省指向ISP 实验配置截图如下&#xff1a; 2. r1​编辑 3. r3​编辑 3.r…

Go——数组

Golang Array和以往认知的数组有很大的。 数组是同一种数据类型的固定长度的序列。数组定义&#xff1a;var a[len] int&#xff0c;比如&#xff1a;var a [5]int&#xff0c;数组长度必须是常量&#xff0c;且类型的组成部分。一旦定义&#xff0c;长度不能变。长度是数组类…

docker镜像ssh服务

基于commit命令实现 首先我们是基于Ubuntu:18.04版本做ssh服务&#xff0c;拉取镜像 [rootmaster ~]# docker pull ubuntu:18.04 [rootmaster ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 18.04 f9a80a5…

vue3 el-form中嵌套el-tabale 对输入动态校验

简单案例 <el-form :model"Form" :rules"rules" ref"FormRef" class"formDiv"><el-table :data"Form.copyWriters" style"width: 100%"><el-table-column label"文案链接"><temp…

rancher是什么

Rancher Labs是制作Rancher的公司。Rancher Labs成立于2014年&#xff0c;是一家专注于企业级容器管理软件的公司。它的产品设计旨在简化在分布式环境中部署和管理容器的过程&#xff0c;帮助企业轻松地采用容器技术和Kubernetes。Rancher Labs提供的Rancher平台支持Docker容器…

H5 简单四按钮个人主页源码

源码名称&#xff1a;简单四按钮个人主页源码 源码介绍&#xff1a;一款简单的带4个按钮选项的个人主页源码&#xff0c;可自行修改内容作为自己的个人主页。 需求环境&#xff1a;H5 下载地址&#xff1a; https://www.changyouzuhao.cn/11458.html

ubuntu 23.04 安装 中文输入法

1、安装 fcitx sudo apt install fcitxfcitx 安装好后&#xff0c;可以使用 fcitx-configtool 命令进行配置&#xff0c;其界面如下所示。在这里可以配置不同输入法的切换快捷键&#xff0c;默认输入法等。刚安装系统后&#xff0c;这里只有一个输入法&#xff0c;所以接下来要…

元宇宙崛起:区块链与金融科技共绘数字新世界

文章目录 一、引言二、元宇宙与区块链的深度融合三、区块链在元宇宙金融中的应用四、金融科技在元宇宙中的创新应用五、面临的挑战与机遇《区块链与金融科技》亮点内容简介获取方式 一、引言 随着科技的飞速发展&#xff0c;元宇宙概念逐渐走进人们的视野&#xff0c;成为数字…

先进电气技术 —— 片上宽禁带器件的集成与应用

一、背景 功率转换器设计的一个关键目标是降低功率损耗以提高转换效率&#xff0c;这对可再生能源等应用产生影响。通过降低功率损耗&#xff0c;可以减小变换器元件的尺寸&#xff0c;从而使整个变换器的尺寸更小。因此&#xff0c;转换器的大小和成本完全取决于设计要求和应…

Linux:kubernetes(k8s)prestop事件的使用(11)

他的作用是在结束pod容器之后进行的操作 apiVersion: v1 # api文档版本 kind: Pod # 资源对象类型 metadata: # pod相关的元数据&#xff0c;用于描述pod的数据name: nginx-po # pod名称labels: # pod的标签type: app #这个是随便写的 自定义的标签version: 1.0.0 #这个…

2024年谷歌SEO的趋势预测及应对建议(川圣SEO)#蜘蛛池

baidu搜索&#xff1a;如何联系八爪鱼SEO&#xff1f; baidu搜索&#xff1a;如何联系八爪鱼SEO&#xff1f; baidu搜索&#xff1a;如何联系八爪鱼SEO&#xff1f; 虽然说“SEO”已死这个口号已经喊了很多年了&#xff08;最终也没死&#xff09;&#xff0c;但是在2023年很…

mysql中的非空间数据导入sqlserver中空间化

以下操作都在Navicat Premium 15软件中操作 1、mysql导出数据 以导出csv为例 不修改导出路径的话默认就是在桌面 设置编码UTF-8 这边还是默认,最好不要修改,如果文本识别符号为空,导入的时候可能字段会错乱 开始即可 2、导入sqlserver数据库中

STM32---ADC

ADC 概念 众所周知&#xff0c;GPIO只能读入高电平或者低电平&#xff0c;那如果现有一个模拟量&#xff0c;该如何读取呢&#xff0c;比如电压的范围是0~3.3v&#xff0c;如何获取电压的值。就需要ADC&#xff08;Analog-Digital Converter&#xff09;了。ADC可以将引脚上连…

Linux环境下用IDEA运行Golang记录

一、背景 和存储同时开发AI项目&#xff0c;在Linux环境运行Golang项目&#xff0c;因此需要进行相关的配置。 二、Golang安装 参考&#xff1a;【Linux — 安装 Go】Linux 系统安装 Go 过程总结_linux 安装go-CSDN博客 三、IDEA中Golang配置 1、去除代理 否则在Plugins中…

4.MAC平台Python的下载、安装(含Python2.7+Python3.12双版本环境变量配置)——《跟老吕学Python编程》

4.MAC平台Python的下载、安装&#xff08;含Python2.7Python3.12双版本环境变量配置&#xff09;——《跟老吕学Python编程》&#xff09;——跟老吕学Python编程 一、下载MAC版Python1.Python官网2.MAC版Python下载网址 二、在MAC安装Python1.在MAC安装Python2.阅读Python重要…

数据结构与算法之美学习笔记:不定期福利第三期 | 刘超:我是怎么学习《数据结构与算法之美》的?

目录 前言 前言 本节课程思维导图&#xff1a; 你好&#xff0c;我是刘超&#xff0c;是隔壁《趣谈网络协议》专栏的作者。今天来“串个门儿”&#xff0c;讲讲我学习《数据结构与算法之美》这个专栏的一些体会和感受。 《数据结构与算法之美》是目前“极客时间”订阅量最多的…

【Python】成功解决NameError: name ‘sns‘ is not defined

【Python】成功解决NameError: name ‘sns’ is not defined &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到您…

国创证券策略:股指预计维持震荡格局 关注汽车、通信设备等板块

国创证券指出&#xff0c;近期两市指数持续反弹创新高&#xff0c;但沪指现已率先出现滞涨状况&#xff0c;一起均已进入阻力重压区。不过当时技术形状上坚持较好&#xff0c;可持续做多&#xff0c;一旦跌破重要支撑如沪指的3030点&#xff0c;则需降仓防卫&#xff0c;防止指…

Window11安装达梦数据库

由于现在流行国产化&#xff0c;很多公司的数据库产品都使用了国产数据库&#xff0c;所以&#xff0c;今天给大家讲解一下&#xff0c;达梦数据库的安装和试用&#xff0c;这样学完以后&#xff0c;就可以直接在公司里面用了。 首先&#xff0c;需要先注册账号&#xff0c;然…