前言

VGA显示模式:分辨率为640*480,刷新速率为60hz
ov7725输出格式:RGB565
ov7725摄像头分辨率:640×480
ov7725输出时序:VGA时序
需求:处理ov7725传输到FPGA的图像,经过图像处理后,再将图像使用VGA传输到显示屏

正文

原理图上摄像头和FPGA的引脚相连的地方,下图位为野火开发板原理图:

一、摄像头配置模块

在使用ov7725之前,需要对ov7725里面的寄存器进行配置,这里使用I2C对其内部寄存器进行配置

1.1 寄存器配置模块

这个模块用来提供寄存器的地址和数据
如对所有寄存器进行复位配置:7'd0 : i2c_data <= {8'h12, 8'h80};
在ov7725中,高8位是地址,低8位是数据

通过这些寄存器的配置,可以控制摄像头输出图像的分辨率大小、图像格式、图像处理及图像方向

// 功能:把数据传给i2c驱动,进而实现对摄像头内部70个寄存器进行配置
// 传地址和数据给驱动
// 注意信号间的依赖关系module i2c_ov7725_rgb565_cfg(input                 clk,//由i2c驱动模块输出的时钟input                i2c_done,// i2c完成一次传输,从 start——> stop 完成一个寄存器的配置,一共要配置70个input                 rst_n,output reg            init_done,//初始化完成信号:70个寄存器都配置完成,并且最后一个寄存器的i2c_done也传回来了,此时即可拉高该信号output reg [15:0]     i2c_data,//高8位地址、低8位数据output reg            i2c_exec //拉高时, i2c 开始工作(start信号)
);parameter REG_70 = 70; //需要配置的寄存器总数// 延时计数器
// 延时2次:
// 1、复位释放后延时
// 2、第一个寄存器配置完成后,延时
reg [10:0] cnt_delay_2;//实现延迟2次的计数器,计到1023清零
reg [6:0]  cnt_reg_70;// =============================================================================
// 延时的目的:等待ov7725稳定下来,ov7725数据手册规定,复位后需要延时
// 复位:1、硬件复位:上电复位、复位按键复位
//       2、软件复位:配置的第一个寄存器,复位所有寄存器,即对ov7725进行软件复位
//
//                   第一个输出信号:i2c_exec
// =============================================================================always@(posedge clk or negedge rst_n)beginif(!rst_n )begincnt_delay_2 <= 10'd0;end   else if(cnt_delay_2 < 10'd1023)begincnt_delay_2 <= cnt_delay_2 + 10'd1;endelse if((cnt_reg_70 == 7'd1) && (i2c_done))begin// 完成第一个寄存器的配置cnt_delay_2 <= 10'd0;end  endalways@(posedge clk or negedge rst_n)beginif(!rst_n )begincnt_reg_70 <= 7'd0;end   else if(i2c_exec)begincnt_reg_70 <= cnt_reg_70 + 7'd1;// i2c开始信号到来,就代表开始配置寄存器endelsecnt_reg_70 <= cnt_reg_70;
endalways@(posedge clk or negedge rst_n)beginif(!rst_n )begini2c_exec <= 1'd0;endelse if(cnt_delay_2 == 10'd1022)begin //上电复位后已经延时1ms,才能去配置第一个寄存器;然后配置完第一个复位寄存器后,再延时1msi2c_exec <= 1'd1;endelse if(init_done && (cnt_reg_70 != 7'd1) && (cnt_reg_70 < REG_70)) // 上一个配置完成+除去第一个复位寄存器+还没配置完70个i2c_exec <= 1'd1;elsei2c_exec <= 1'd0;
end// =============================================================================
//                   第二个输出信号:init_done
// =============================================================================
always@(posedge clk or negedge rst_n)beginif(!rst_n )begininit_done <= 1'd0;endelse if((cnt_reg_70 == REG_70) && (i2c_done))begin //配置70个寄存器且最后一个配置完成信号传回来了init_done <= 1'd1;endelseinit_done <= 1'd0;end
// =============================================================================
//                   第三个输出信号:[15:0]i2c_data
// =============================================================================
always@(posedge clk or negedge rst_n)beginif(!rst_n )begini2c_data <= 16'd0;endelse begincase(cnt_reg_70)//先对寄存器进行软件复位,使寄存器恢复初始值//寄存器软件复位后,需要延时1ms才能配置其它寄存器7'd0  : i2c_data <= {8'h12, 8'h80}; //COM7 BIT[7]:复位所有的寄存器7'd1  : i2c_data <= {8'h3d, 8'h03}; //COM12 模拟过程直流补偿7'd2  : i2c_data <= {8'h15, 8'h00}; //COM10 href/vsync/pclk/data信号控制7'd3  : i2c_data <= {8'h17, 8'h26}; //HSTART 水平起始位置7'd4  : i2c_data <= {8'h18, 8'ha0}; //HSIZE 水平尺寸7'd5  : i2c_data <= {8'h19, 8'h07}; //VSTRT 垂直起始位置7'd6  : i2c_data <= {8'h1a, 8'hf0}; //VSIZE 垂直尺寸 7'd7  : i2c_data <= {8'h32, 8'h00}; //HREF 图像开始和尺寸控制,控制低位7'd8  : i2c_data <= {8'h29, 8'ha0}; //HOutSize 水平输出尺寸7'd9  : i2c_data <= {8'h2a, 8'h00}; //EXHCH 虚拟像素MSB7'd10 : i2c_data <= {8'h2b, 8'h00}; //EXHCL 虚拟像素LSB7'd11 : i2c_data <= {8'h2c, 8'hf0}; //VOutSize 垂直输出尺寸7'd12 : i2c_data <= {8'h0d, 8'h41}; //COM4 PLL倍频设置(multiplier)  设置4倍频//Bit[7:6]:  0:1x 1:4x 2:6x 3:8x7'd13 : i2c_data <= {8'h11, 8'h00}; //CLKRC 内部时钟配置 //Freq=multiplier/[(CLKRC[5:0]+1)*2]7'd14 : i2c_data <= {8'h12, 8'h06}; //COM7 输出VGA RGB565格式                                     7'd15 : i2c_data <= {8'h0c, 8'h10}; //COM3 Bit[0]: 0:图像数据 1:彩条测试//DSP 控制7'd16 : i2c_data <= {8'h42, 8'h7f}; //TGT_B 黑电平校准蓝色通道目标值7'd17 : i2c_data <= {8'h4d, 8'h09}; //FixGain 模拟增益放大器7'd18 : i2c_data <= {8'h63, 8'hf0}; //AWB_Ctrl0 自动白平衡控制字节07'd19 : i2c_data <= {8'h64, 8'hff}; //DSP_Ctrl1 DSP控制字节17'd20 : i2c_data <= {8'h65, 8'h00}; //DSP_Ctrl2 DSP控制字节27'd21 : i2c_data <= {8'h66, 8'h00}; //DSP_Ctrl3 DSP控制字节37'd22 : i2c_data <= {8'h67, 8'h00}; //DSP_Ctrl4 DSP控制字节4    //AGC AEC AWB        //COM8 Bit[2]:自动增益使能 Bit[1]:自动白平衡使能 Bit[0]:自动曝光功能7'd23 : i2c_data <= {8'h13, 8'hff}; //COM8 7'd24 : i2c_data <= {8'h0f, 8'hc5}; //COM67'd25 : i2c_data <= {8'h14, 8'h11};  7'd26 : i2c_data <= {8'h22, 8'h98}; 7'd27 : i2c_data <= {8'h23, 8'h03};  7'd28 : i2c_data <= {8'h24, 8'h40}; 7'd29 : i2c_data <= {8'h25, 8'h30};  7'd30: i2c_data <= {8'h26, 8'ha1};      7'd31: i2c_data <= {8'h6b, 8'haa}; 7'd32: i2c_data <= {8'h13, 8'hff};  //matrix sharpness brightness contrast UV7'd33 : i2c_data <= {8'h90, 8'h0a}; //EDGE1 边缘增强控制1//DNSOff 降噪阈值下限,仅在自动模式下有效7'd34 : i2c_data <= {8'h91, 8'h01}; //DNSOff 7'd35 : i2c_data <= {8'h92, 8'h01}; //EDGE2 锐度(边缘增强)强度上限7'd36 : i2c_data <= {8'h93, 8'h01}; //EDGE3 锐度(边缘增强)强度下限7'd37 : i2c_data <= {8'h94, 8'h5f}; //MTX1 矩阵系数17'd38 : i2c_data <= {8'h95, 8'h53}; //MTX1 矩阵系数27'd39 : i2c_data <= {8'h96, 8'h11}; //MTX1 矩阵系数37'd40 : i2c_data <= {8'h97, 8'h1a}; //MTX1 矩阵系数47'd41 : i2c_data <= {8'h98, 8'h3d}; //MTX1 矩阵系数57'd42 : i2c_data <= {8'h99, 8'h5a}; //MTX1 矩阵系数67'd43 : i2c_data <= {8'h9a, 8'h1e}; //MTX_Ctrl 矩阵控制7'd44 : i2c_data <= {8'h9b, 8'h3f}; //BRIGHT 亮度7'd45 : i2c_data <= {8'h9c, 8'h25}; //CNST 对比度            7'd46 : i2c_data <= {8'h9e, 8'h81}; 7'd47 : i2c_data <= {8'ha6, 8'h06}; //SDE 特殊数字效果控制7'd48 : i2c_data <= {8'ha7, 8'h65}; //USAT "U"饱和增益7'd49 : i2c_data <= {8'ha8, 8'h65}; //VSAT "V"饱和增益            7'd50 : i2c_data <= {8'ha9, 8'h80}; //VSAT "V"饱和增益   7'd51 : i2c_data <= {8'haa, 8'h80}; //VSAT "V"饱和增益//伽马控制 :伽马校准和文档上的一样7'd52 : i2c_data <= {8'h7e, 8'h0c}; 7'd53 : i2c_data <= {8'h7f, 8'h16}; 7'd54 : i2c_data <= {8'h80, 8'h2a}; 7'd55 : i2c_data <= {8'h81, 8'h4e}; 7'd56 : i2c_data <= {8'h82, 8'h61}; 7'd57 : i2c_data <= {8'h83, 8'h6f}; 7'd58 : i2c_data <= {8'h84, 8'h7b}; 7'd59 : i2c_data <= {8'h85, 8'h86};   7'd60 : i2c_data <= {8'h86, 8'h8e}; 7'd61 : i2c_data <= {8'h87, 8'h97}; 7'd62 : i2c_data <= {8'h88, 8'ha4}; 7'd63 : i2c_data <= {8'h89, 8'haf}; 7'd64 : i2c_data <= {8'h8a, 8'hc5}; 7'd65 : i2c_data <= {8'h8b, 8'hd7}; 7'd66 : i2c_data <= {8'h8c, 8'he8}; 7'd67 : i2c_data <= {8'h8d, 8'h20}; 7'd68 : i2c_data <= {8'h0e, 8'h65}; //COM57'd69 : i2c_data <= {8'h09, 8'h00}; //COM2  Bit[1:0] 输出电流驱动能力//只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写default:i2c_data <=    {8'h1C, 8'h7F}; //MIDH 制造商ID 高8位endcaseendelse
end
endmodule

1.2 i2c驱动

这个模块用来传输需要配置的寄存器的值

//
module i2c_dri(input                clk        , //250K   input                rst_n      ,   //i2c 接口                      input                i2c_exec   ,  //I2C触发执行信号input                bit_ctrl   ,  //字地址位控制(16b/8b)input                i2c_rh_wl  ,  //I2C读写控制信号input        [15:0]  i2c_addr   ,  //I2C器件内地址input        [ 7:0]  i2c_data_w ,  //I2C要写的数据output  reg  [ 7:0]  i2c_data_r ,  //I2C读出的数据output  reg          i2c_done   ,  //I2C一次操作完成output  reg          i2c_ack    ,  //I2C应答标志 0:应答 1:未应答output  reg          scl        ,  //I2C的SCL时钟信号inout                sda        ,  //I2C的SDA信号//用户接口                   output  reg          dri_clk       //驱动scl、sda这2根信号线,从clk  4倍频得到25K*4=1M
);parameter SLAVE_ADDR = 7'b1010000;// 从机地址
parameter CLK_FREQ   = 26'd50_000_000;
parameter I2C_FREQ   = 18'd250_000;parameter DIV_CLK_MAX = (clk_cnt_24 >> 1'd1)-1'd1;//分频计数器计满值// 定义状态量
localparam IDLE       = 8'b0000_0001;
localparam SLAVE_ADDR = 8'b0000_0010;
localparam ADDR_H     = 8'b0000_0100;
localparam ADDR_L     = 8'b0000_1000;
localparam W_DATA     = 8'b0001_0000;
localparam R_ADDR     = 8'b0010_0000;
localparam R_DATA     = 8'b0100_0000;
localparam STOP       = 8'b1000_0000;
reg state;
reg next_state;assign sda     = sda_en ? sda_out : 1'bz;
assign sda_in = sda;
// ============================================================
// 求分频系数
// 分频系数越小,频率越大
wire [5:0] div_50; //分频系数
assign div_50 = (CLK_FREQ/I2C_FREQ) >> 2'd2;// 通过求得的分频系数,作为分频数
reg [4:0] clk_cnt_24;always@(posedge clk or negedge rst_n)beginif(!rst_n )beginclk_cnt_24 <= 5'd0;endelse if(clk_cnt_24 == DIV_CLK_MAX)beginclk_cnt_24 <= 5'd0;endelse clk_cnt_24 <= clk_cnt_24 + 5'd1;
endalways@(posedge clk or negedge rst_n)beginif(!rst_n )begindri_clk <= 1'd0;endelse if(clk_cnt_24 == DIV_CLK_MAX)begindri_clk <= ~dri_clk;endelsedri_clk <= dri_clk;
end
// ============================================================// ----------------------------------------------------------------------
// 状态机第一段
always@(posedge clk or negedge rst_n)beginif(!rst_n )beginstate <= IDLE;endelse beginstate <= next_state;end
end// 状态机第二段
// 状态之间的转换看跳转图!!很清晰
reg now_state_done;
reg bit_ctrl;
always@(*)beginnext_state <= IDLE;case(state)IDLE:if(i2c_exec)next_state = SLAVE_ADDR;elsenext_state = next_state;SLAVE_ADDR:if(now_state_done)beginif(bit_ctrl)// bit_ctrl=1表示传16bit地址next_state = ADDR_H;//高8位elsenext_state = ADDR_L;elsenext_state = SLAVE_ADDR;endADDR_H:if(now_state_done)next_state = ADDR_L;elsenext_state = ADDR_H;// 读数据     ADDR_L:if(now_state_done)beginif(wr_flage)//读next_state = R_ADDR;elsenext_state = W_DATA;endelse next_state = ADDR_L;R_ADDR:if(now_state_done)next_state = R_DATA;elsenext_state = R_ADDR;R_DATA:if(now_state_done)next_state = STOP;elsenext_state = R_DATA;//写数据W_DATA:if(now_state_done)next_state = STOP;elsenext_state = W_DATA;STOP:if(now_state_done)next_state = IDLE;elsenext_state = STOP;default: next_state = IDLE;endcaseend
// 状态机第三段
//i2c的2个接口在空闲状态是高电平
reg         now_state_done;
reg [6:0]   cnt_always_add;
reg         i2c_rh_wl_reg;
reg [7:0]   i2c_data_w_reg;
reg [7:0]   i2c_data_r_reg;
reg [15:0]  i2c_addr_reg;
always@(posedge clk or negedge rst_n)beginif(!rst_n )beginscl  <= 1'd1;sda_out <= 1'd1;sda_en  <= 1'd1;// 一直在的信号now_state_done  <= 1'd0;cnt_always_add  <= 7'd0;i2c_rh_wl_reg   <= 1'd0;i2c_data_w_reg  <= 8'd0;i2c_data_r_reg  <= 8'd0;i2c_addr_reg    <= 16'd0;i2c_ack      <= 1'd0;   end// 在外部让now_state_done=0,只有在内部每个状态完成后,才将其拉高now_state_done <= 1'd0;// 在外部一直+1,只有在内部结束才清零cnt_always_add <= cnt_always_add + 7'd1;case(state)IDLE:if(i2c_exec)begin//驱动IDLE的都是i2c_exec信号,将输入信号寄存到内部寄存器i2c_rh_wl_reg   <= i2c_rh_wl;//其他模块传来的读写控制信号i2c_data_w_reg  <= i2c_data_w;i2c_addr_reg    <= i2c_addr;    endSLAVE_ADDR:begin // sda_out在scl低电平中间更新case(cnt_always_ad)7'd1:   scl     <= 1'd1;7'd3: scl     <= 1'd0;7'd4: sda_out <= SLAVE_ADDR[6];7'd5: scl     <= 1'd1;       7'd7:  scl     <= 1'd0;       7'd8:  sda_out <= SLAVE_ADDR[5];7'd9: scl     <= 1'd1;       7'd11: scl     <= 1'd0;7'd12:    sda_out <= SLAVE_ADDR[4];7'd13:    scl     <= 1'd1;       7'd15: scl     <= 1'd0;7'd16:  sda_out <= SLAVE_ADDR[3];7'd17:  scl     <= 1'd1;7'd19:    scl     <= 1'd0;7'd20:    sda_out <= SLAVE_ADDR[2];7'd21:  scl   <= 1'd1;7'd23:    scl     <= 1'd0;7'd24:    sda_out <= SLAVE_ADDR[1];7'd25:  scl   <= 1'd1;7'd27:    scl     <= 1'd0;7'd28:    sda_out <= SLAVE_ADDR[0];   7'd29:  scl    <= 1'd1;           7'd31: scl     <= 1'd0;//=======================================================以上相同7'd32:    sda_out <= 1'd0;//最低位=0:写, 到此传完8bit数据7'd23:  scl  <= 1'd1;           7'd35: scl     <= 1'd0;           7'd36: sda_en  <= 1'd0;// sda为输入端口,输入从机给的应答信号      7'd37: scl  <= 1'd1;       7'd38:  beginst_done <= 1'b1;if(sda_in)//从机给的无应答信号i2c_ack <= 1'd1;//拉高,无应答end
//虽然在38时st_done已经拉高,此时状态已经跳转,但是跳转的是next_state,而此处case里面是state,state比next_state慢一拍,因此还是要执行39         7'd39:  begincnt_always_add  <= 6'd0;scl          <= 1'd0;//?????enddefault: ;endcaseendADDR_H:begincase(cnt_always_ad)7'd0:    beginsda_en         <= 1'd1;//让sda位输出端口sda_out     <= i2c_addr_reg[15];//将寄存的地址输出end7'd1: scl     <= 1'd1;7'd3: scl     <= 1'd0;                   7'd4:  sda_out <= i2c_addr_reg[14];            7'd5:  scl     <= 1'd1;                   7'd7:  scl     <= 1'd0;                   7'd8:  sda_out <= i2c_addr_reg[13];            7'd9:  scl     <= 1'd1;                   7'd11: scl     <= 1'd0;           7'd12: sda_out <= i2c_addr_reg[12];            7'd13: scl     <= 1'd1;                   7'd15: scl     <= 1'd0;           7'd16:  sda_out <= i2c_addr_reg[11];           7'd17: scl     <= 1'd1;           7'd19: scl     <= 1'd0;           7'd20: sda_out <= i2c_addr_reg[10];            7'd21:  scl    <= 1'd1;           7'd23: scl     <= 1'd0;           7'd24: sda_out <= i2c_addr_reg[9];         7'd25:  scl    <= 1'd1;           7'd27: scl     <= 1'd0;7'd28:    sda_out <= i2c_addr_reg[8]; 7'd29:  scl    <= 1'd1;           7'd31: scl     <= 1'd0;           7'd32: sda_en  <= 1'd1;           7'd33: scl  <= 1'd1;           7'd34:  beginst_done <= 1'b1;if(sda_in)//从机给的无应答信号i2c_ack <= 1'd1;//拉高,无应答end7'd35:  begincnt_always_add  <= 6'd0;scl           <= 1'd0;//?????end         default:;endcaseendADDR_L:begincase(cnt_always_add)7'd0:   beginsda_en         <= 1'd1;//让sda位输出端口sda_out     <= i2c_addr_reg[7];//将寄存的地址输出end7'd1:  scl     <= 1'd1;7'd3: scl     <= 1'd0;                   7'd4:  sda_out <= i2c_addr_reg[6];         7'd5:  scl     <= 1'd1;                   7'd7:  scl     <= 1'd0;                   7'd8:  sda_out <= i2c_addr_reg[5];         7'd9:  scl     <= 1'd1;                   7'd11: scl     <= 1'd0;           7'd12: sda_out <= i2c_addr_reg[4];         7'd13: scl     <= 1'd1;                   7'd15: scl     <= 1'd0;           7'd16:  sda_out <= i2c_addr_reg[3];            7'd17: scl     <= 1'd1;           7'd19: scl     <= 1'd0;           7'd20: sda_out <= i2c_addr_reg[2];     7'd21:  scl    <= 1'd1;           7'd23: scl     <= 1'd0;           7'd24: sda_out <= i2c_addr_reg[1];         7'd25:  scl    <= 1'd1;           7'd27: scl     <= 1'd0;7'd28:    sda_out <= i2c_addr_reg[0]; 7'd29:  scl    <= 1'd1;           7'd31: scl     <= 1'd0;           7'd32: sda_en  <= 1'd1;           7'd33: scl  <= 1'd1; 7'd34:  beginst_done <= 1'b1;if(sda_in)//从机给的无应答信号i2c_ack <= 1'd1;//拉高,无应答end7'd35:  begincnt_always_add  <= 6'd0;scl             <= 1'd0;//?????end         default:;endcaseendW_DATA:begincase(cnt_always_add)7'd0:   beginsda_en         <= 1'd1;sda_out     <= i2c_data_w_reg[7];end7'd1: scl     <= 1'd1;7'd3: scl     <= 1'd0;                   7'd4:  sda_out <= i2c_data_w_reg[6];           7'd5:  scl     <= 1'd1;                   7'd7:  scl     <= 1'd0;                   7'd8:  sda_out <= i2c_data_w_reg[5];           7'd9:  scl     <= 1'd1;                   7'd11: scl     <= 1'd0;           7'd12: sda_out <= i2c_data_w_reg[4];           7'd13: scl     <= 1'd1;                   7'd15: scl     <= 1'd0;       7'd16:  sda_out <= i2c_data_w_reg[3];      7'd17: scl     <= 1'd1;           7'd19: scl     <= 1'd0;           7'd20: sda_out <= i2c_data_w_reg[2];           7'd21:  scl    <= 1'd1;           7'd23: scl     <= 1'd0;           7'd24: sda_out <= i2c_data_w_reg[1];           7'd25:  scl    <= 1'd1;           7'd27: scl     <= 1'd0;7'd28:    sda_out <= i2c_data_w_reg[0];   7'd29:  scl    <= 1'd1;           7'd31: scl     <= 1'd0;           7'd32: sda_en  <= 1'd1;           7'd33: scl  <= 1'd1;           7'd34:  beginst_done <= 1'b1;if(sda_in)//从机给的无应答信号i2c_ack <= 1'd1;//拉高,无应答end7'd35:  begincnt_always_add  <= 6'd0;scl           <= 1'd0;//?????end             default:;endcaseendR_ADDR:begin // 从哪个从机读case(cnt_always_ad)7'd0:   sda_en  <= 1'd1;           7'd1:  scl     <= 1'd1;7'd3: scl     <= 1'd0;                   7'd4:  sda_out <= SLAVE_ADDR[6];           7'd5:  scl     <= 1'd1;                   7'd7:  scl     <= 1'd0;                   7'd8:  sda_out <= SLAVE_ADDR[5];           7'd9:  scl     <= 1'd1;                   7'd11: scl     <= 1'd0;           7'd12: sda_out <= SLAVE_ADDR[4];           7'd13: scl     <= 1'd1;                   7'd15: scl     <= 1'd0;           7'd16:  sda_out <= SLAVE_ADDR[3];          7'd17: scl     <= 1'd1;           7'd19: scl     <= 1'd0;           7'd20: sda_out <= SLAVE_ADDR[2];           7'd21:  scl    <= 1'd1;           7'd23: scl     <= 1'd0;           7'd24: sda_out <= SLAVE_ADDR[1];           7'd25:  scl    <= 1'd1;           7'd27: scl     <= 1'd0;7'd28:    sda_out <= SLAVE_ADDR[0];   7'd29:  scl    <= 1'd1;           7'd31: scl     <= 1'd0;//=======================================================以上相同7'd32:    sda_out <= 1'd1;//最低位=1:读, 到此传完8bit数据7'd33:  scl  <= 1'd1;       7'd35: scl     <= 1'd0;           7'd36: sda_en  <= 1'd0;// sda为输入端口,输入从机给的应答信号          7'd37: scl  <= 1'd1;           7'd38:  beginst_done <= 1'b1;if(sda_in)//从机给的无应答信号i2c_ack <= 1'd1;//拉高,无应答end
//虽然在38时st_done已经拉高,此时状态已经跳转,但是跳转的是next_state,而此处case里面是state,state比next_state慢一拍,因此还是要执行39         7'd39:  begincnt_always_add  <= 6'd0;scl          <= 1'd0;//?????enddefault: ;endcaseendR_DATA:begincase(cnt_always_ad)7'd0: sda_en  <= 1'd0;               7'd1:  i2c_data_r_reg[7] <= sda_in;7'd3:  scl     <= 1'd0;           7'd5:  beginscl              <= 1'd1;i2c_data_r_reg[6] <= sda_in;end              7'd7:  scl     <= 1'd0;           7'd9:  beginscl              <= 1'd1;i2c_data_r_reg[5] <= sda_in;end                      7'd11: scl     <= 1'd0;       7'd13: beginscl              <= 1'd1;i2c_data_r_reg[4] <= sda_in;end  7'd15: scl     <= 1'd0;           7'd17: beginscl              <= 1'd1;i2c_data_r_reg[3] <= sda_in;end              7'd19: scl     <= 1'd0;7'd21:    beginscl              <= 1'd1;i2c_data_r_reg[2] <= sda_in;end              7'd23: scl     <= 1'd0;           7'd25: beginscl              <= 1'd1;i2c_data_r_reg[1] <= sda_in;end              7'd27: scl     <= 1'd0;7'd29:    beginscl              <= 1'd1;i2c_data_r_reg[0] <= sda_in;end  7'd31: scl     <= 1'd0;//=======================================================以上相同7'd32:    sda_en  <= 1'd1;//不需要从机应答7'd33:  scl  <= 1'd1;           7'd34:  now_state_done     <= 1'd1;7'd35:    beginscl        <= 1'd0;cnt        <= 1'd0;i2c_data_r <=  i2c_data_r_reg;enddefault: ;endcase         endSTOP: begincase(cnt)7'd0: beginsda_en <= 1'b1;             //结束I2Csda_out <= 1'b0;end7'd1 : scl     <= 1'b1;7'd3 : sda_out <= 1'b1;7'd15: now_state_done <= 1'b1;7'd16: begincnt      <= 1'b0;i2c_done <= 1'b1;            //向上层模块传递I2C结束信号enddefault  : ;endcase            end default: ;  endcase
endendmodule

二、图像采集模块

对摄像头的内存器配置完成后,摄像头就可以开始工作啦

2.1 ov7725输出的时序图

要看懂ov7725的VGA输出时序,才能在正确的地方采集到摄像头传输过来的数据

上面的信号是摄像头输出的,其中href和hsync用同一个引脚输出的,为了方便,使用href作为行同步信号
通过观察上图可知:

  1. 场同步信号有效部分传输480行
  2. 行同步信号有效部分传输640个像素点
  3. 只有当 行同步信号=1 && 场同步信号=0 时,此时数据线上的数据才有效
行同步信号有效:传一行数据

将上面图中其中一段有效部分放大得到OV7725输出RGB565格式的时序图:
由于ov7725在传输RGB图像时,只用到[9:2]这8根数据引脚,因此要传输GRB565的16位数据,需要分成2次传输

2.2 采集摄像头输出的图像

从上面可知,摄像头有8根数据线用来传输图像数据,但是要表示一个像素的完整信息,需要用16位数据,因此,需要将摄像头传输来的数据拼接成16bit

从摄像头采集数据,这个数据将存在SDRAM中

// 采集摄像头输出的图像数据
// RGB565格式的图像,一个像素点要用5+6+5=16bit 数据来表示
// 而ov7725的数据线只有8位,因此需要用2个时钟传输16bit数据module cmos_capture_data(input                  rst_n,// 从摄像头传入的信号input                     cam_pclk,// 像素时钟周期input                     cam_vsync,// 场同步input                   cam_href, // 行同步input       [7:0]       cam_data,// 用户接口    output reg              coms_frame_vsync,// 帧有效output reg               coms_frame_href, // 行有效output reg               coms_frame_valid,// 该信号拉高,表示此时数据有效output reg     [15:0]      coms_frame_data  // 采集到的有效数据
);// 70个寄存器配置完成后,不采集前10帧图像
//ov7725数据手册:Table5中的ts
parameter WAIT_10_frame = 4'd10;// 采集 场同步信号 的上升沿
reg     cam_vsync_reg1;
reg     cam_vsync_reg2;
reg     cam_href_reg1;
reg     cam_href_reg2;
wire pose_vsync;
always@(posedge cam_pclk or negedge rst_n)beginif(!rst_n )begincam_vsync_reg1 <= 1'd0;cam_vsync_reg2 <= 1'd0;endelse begincam_vsync_reg1 <= cam_vsync;cam_vsync_reg2 <= cam_vsync_reg1;      end
endalways@(posedge cam_pclk or negedge rst_n)beginif(!rst_n )begincam_href_reg1 <= 1'd0;cam_href_reg2 <= 1'd0;endelse begincam_href_reg1  <= cam_href;cam_href_reg2 <= cam_href_reg1;        end
endassign pose_vsync = (~cam_vsync_reg2) && cam_vsync_reg1;
// 帧有效、行有效打2拍的原因:采集高8位用了1 clk,采集低8位用了1 clk ,拼接用了 1clk
// 因此数据满了2 clk,于是要将帧有效、行有效打2拍来和拼接后的数据同步
assign coms_frame_vsync = frame_flage ? cam_vsync_reg2  : 1'd0;
assign coms_frame_href  = frame_flage ? cam_href_reg2   : 1'd0;
// 这里对数据有效信号打1拍也是为了和拼接后的数据同步
assign coms_frame_valid = frame_flage ? byte_flage_reg1 : 1'd0;
assign coms_frame_data  = frame_flage ? data_contact_16 : 16'd0;// 计数器:计数丢弃的10帧
reg [3:0] wait_10_frame;
always@(posedge cam_pclk or negedge rst_n)beginif(!rst_n )beginwait_10_frame <= 4'd0;endelse if((pose_vsync) && (wait_10_frame < WAIT_10_frame))beginwait_10_frame <= wait_10_frame + 4'd1;endelsewait_10_frame <= wait_10_frame;
end// 等10帧后,有个信号告诉其他信号,数据已经可以用了
reg     frame_flage;
always@(posedge cam_pclk or negedge rst_n)beginif(!rst_n )beginframe_flage <= 1'd0;endelse if((pose_vsync) && (wait_10_frame == WAIT_10_frame))beginframe_flage <= 1'd1;// 摄像头数据有效endelseframe_flage <= frame_flage;
end// 8bit拼接为16bit
reg [7:0]  data_reg1;
reg [15:0] data_contact_16;
reg        byte_flage;always@(posedge cam_pclk or negedge rst_n)beginif(!rst_n )begindata_reg1    <= 8'd0;data_contact_16 <= 16'd0;byte_flage   <= 1'd0;endelse if(cam_href)begin //行有效data_reg1  <= cam_data;// 先把高8位寄存起来byte_flage <= ~ byte_flage;// 表示已经传完8位,byte_flage=0,传输高8位;byte_flage=1,传输低8位if(byte_flage)begindata_contact_16 <= {data_reg1,cam_data};endendelse begindata_reg1    <= 8'd0;//data_contact_16 <= 16'd0;byte_flage   <= 1'd0;end
end// 将byte_flage打一拍
// 目的:使得数据有效信号和拼接后的数据同步
reg     byte_flage_reg1;
always@(posedge cam_pclk or negedge rst_n)beginif(!rst_n )beginbyte_flage_reg1 <= 1'd0;endelse beginbyte_flage_reg1 <= byte_flage;end
end
endmodule

三、图像存储模块

3.1 SDRAM

这部分先放一放

四、图像显示模块

4.1 VGA显示

该模块功能
1.给显示器输出行同步、场同步、图像数据
2.给SDRAM输入x、y坐标后,接收SDRAM传来的改 坐标下的图像数据

需要按照下面的时序,输出行同步、场同步,以及输出有效数据

module vga_div(input                     vga_clk,//25Minput                  rst_n,//vga_clk稳定后,释放复位//给显示器output reg              vga_hs,output reg               vga_vs,output reg   [15:0]      vga_rgb,//三原色output                 data_req,//向SADRAM请求输入像素点数据 output      [10:0]      pixel_x,output      [10:0]      pixel_y,input       [15:0]      pixel_data//根据输入到SDRAM中的x、y坐标,得到从SFRAM输出的该店坐标的像素点数据);//640*480 60FPS_25MHzparameter  H_SYNC   =  10'd96;    //行同步parameter  H_BACK   =  10'd48;    //行显示后沿parameter  H_DISP   =  10'd640;   //行有效数据parameter  H_FRONT  =  10'd16;    //行显示前沿parameter  H_TOTAL  =  10'd800;   //行扫描周期parameter  V_SYNC   =  10'd2;     //场同步parameter  V_BACK   =  10'd33;    //场显示后沿parameter  V_DISP   =  10'd480;   //场有效数据parameter  V_FRONT  =  10'd10;    //场显示前沿parameter  V_TOTAL  =  10'd525;   //场扫描周期// 声明2个计数器,分别用于行计数和场计数reg [10:0] cnt_h;reg [10:0] cnt_v;wire vga_en;wire data_req;always@(posedge clk or negedge rst_n)beginif(!rst_n )begincnt_h <= 11'd0;endelse if(cnt_h < H_TOTAL-1'd1)begin//一行计到799cnt_h <= cnt_h + 11'd1;endelsecnt_h <= 11'd0;endalways@(posedge clk or negedge rst_n)beginif(!rst_n )begincnt_v <= 11'd0;endelse if(cnt_v < V_TOTAL-1'd1)begin//一行计到799cnt_v <= cnt_v + 11'd1;endelsecnt_v <= 11'd0;end//根据VGA行同步时序、场同步时序得到行同步信号、场同步信号always@(*)beginif((cnt_h > V_SYNC + H_BACK) && (cnt_h < H_TOTAL - H_FRONT))begin//有效数据部分vga_hs <= 1'd1;endelse vga_hs <= 1'd0;endalways@(*)beginif((cnt_v > H_SYNC + V_BACK) && (cnt_v < V_TOTAL - V_FRONT))begin//有效数据部分vga_vs <= 1'd1;endelse vga_vs <= 1'd0;endassign vga_en = ((cnt_h > V_SYNC + H_BACK) && (cnt_h < H_TOTAL - H_FRONT))&&((cnt_v > H_SYNC + V_BACK) && (cnt_v < V_TOTAL - V_FRONT))? 1'd1:1'd0;//标志出有效数据部分assign vga_rgb = vga_en ? pixel_data : 16'd0;//请求像素点颜色数据输入                assign data_req = (((cnt_h >= H_SYNC+H_BACK-1'b1) && (cnt_h < H_SYNC+H_BACK+H_DISP-1'b1))&& ((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))?  1'b1 : 1'b0;//需要从SDRAM得到传回数据,因此需要提前一个时钟周期 //像素点坐标                assign pixel_x = data_req ? (cnt_h - (H_SYNC + H_BACK - 1'b1)) : 10'd0;assign pixel_y = data_req ? (cnt_v - (V_SYNC + V_BACK - 1'b1)) : 10'd0;endmodule 

VGA接口的缺点:
1.传输的信号是模拟信号,信号容易受干扰
2.体积大

4.2 VGA转HDMI

HDMI接口的有点:
1.抗干扰能力强
2.体积小
3.兼容性好,可以同时传输数字信号和音频

4.2.1 编码

8bit并行数据——10bit并行数据
直流均衡:0=1个数

module  encode
(input   wire            sys_clk     ,   //时钟信号input   wire            sys_rst_n   ,   //复位信号,低有效input   wire    [7:0]   data_in     ,   //输入8bit待编码数据input   wire            c0          ,   //控制信号c0input   wire            c1          ,   //控制信号c1input   wire            de          ,   //使能信号output  reg     [9:0]   data_out        //输出编码后的10bit数据
);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   DATA_OUT0   =   10'b1101010100,DATA_OUT1   =   10'b0010101011,DATA_OUT2   =   10'b0101010100,DATA_OUT3   =   10'b1010101011;//wire  define
wire            condition_1 ;   //条件1
wire            condition_2 ;   //条件2
wire            condition_3 ;   //条件3
wire    [8:0]   q_m         ;   //第一阶段转换后的9bit数据//reg   define
reg     [3:0]   data_in_n1  ;   //待编码数据中1的个数
reg     [7:0]   data_in_reg ;   //待编码数据打一拍
reg     [3:0]   q_m_n1      ;   //转换后9bit数据中1的个数
reg     [3:0]   q_m_n0      ;   //转换后9bit数据中0的个数
reg     [4:0]   cnt         ;   //视差计数器,0-1个数差别,最高位为符号位
reg             de_reg1     ;   //使能信号打一拍
reg             de_reg2     ;   //使能信号打两拍
reg             c0_reg1     ;   //控制信号c0打一拍
reg             c0_reg2     ;   //控制信号c0打两拍
reg             c1_reg1     ;   //控制信号c1打一拍
reg             c1_reg2     ;   //控制信号c1打两拍
reg     [8:0]   q_m_reg     ;   //q_m信号打一拍//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//data_in_n1:待编码数据中1的个数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_in_n1  <=  4'd0;elsedata_in_n1  <=  data_in[0] + data_in[1] + data_in[2]+ data_in[3] + data_in[4] + data_in[5]+ data_in[6] + data_in[7];//data_in_reg:待编码数据打一拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_in_reg <=  8'b0;elsedata_in_reg <=  data_in;//condition_1:条件1
assign  condition_1 = ((data_in_n1 > 4'd4) || ((data_in_n1 == 4'd4)//??直接写>=4不行吗&& (data_in_reg[0] == 1'b0)));//q_m:第一阶段转换后的9bit数据
assign q_m[0] = data_in_reg[0];
assign q_m[1] = (condition_1) ? (q_m[0] ^~ data_in_reg[1]) : (q_m[0] ^ data_in_reg[1]);
assign q_m[2] = (condition_1) ? (q_m[1] ^~ data_in_reg[2]) : (q_m[1] ^ data_in_reg[2]);
assign q_m[3] = (condition_1) ? (q_m[2] ^~ data_in_reg[3]) : (q_m[2] ^ data_in_reg[3]);
assign q_m[4] = (condition_1) ? (q_m[3] ^~ data_in_reg[4]) : (q_m[3] ^ data_in_reg[4]);
assign q_m[5] = (condition_1) ? (q_m[4] ^~ data_in_reg[5]) : (q_m[4] ^ data_in_reg[5]);
assign q_m[6] = (condition_1) ? (q_m[5] ^~ data_in_reg[6]) : (q_m[5] ^ data_in_reg[6]);
assign q_m[7] = (condition_1) ? (q_m[6] ^~ data_in_reg[7]) : (q_m[6] ^ data_in_reg[7]);
assign q_m[8] = (condition_1) ? 1'b0 : 1'b1;//q_m_n1:转换后9bit数据中1的个数
//q_m_n0:转换后9bit数据中0的个数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginq_m_n1  <=  4'd0;q_m_n0  <=  4'd0;endelsebeginq_m_n1  <=  q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];q_m_n0  <=  4'd8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);end//condition_2:条件2
assign  condition_2 = ((cnt == 5'd0) || (q_m_n1 == q_m_n0));//condition_3:条件3
assign  condition_3 = (((~cnt[4] == 1'b1) && (q_m_n1 > q_m_n0))|| ((cnt[4] == 1'b1) && (q_m_n0 > q_m_n1)));//数据打拍,为了各数据同步
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginde_reg1 <=  1'b0;de_reg2 <=  1'b0;c0_reg1 <=  1'b0;c0_reg2 <=  1'b0;c1_reg1 <=  1'b0;c1_reg2 <=  1'b0;q_m_reg <=  9'b0;endelsebeginde_reg1 <=  de;de_reg2 <=  de_reg1;c0_reg1 <=  c0;c0_reg2 <=  c0_reg1;c1_reg1 <=  c1;c1_reg2 <=  c1_reg1;q_m_reg <=  q_m;end//data_out:输出编码后的10bit数据
//cnt:视差计数器,0-1个数差别,最高位为符号位
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)begindata_out    <=  10'b0;cnt         <=  5'b0;endelsebeginif(de_reg2 == 1'b1)beginif(condition_2 == 1'b1)begindata_out[9]     <=  ~q_m_reg[8]; data_out[8]     <=  q_m_reg[8]; data_out[7:0]   <=  (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];cnt <=  (~q_m_reg[8]) ? (cnt + q_m_n0 - q_m_n1) : (cnt + q_m_n1 - q_m_n0);endelsebeginif(condition_3 == 1'b1)begindata_out[9]     <= 1'b1;data_out[8]     <= q_m_reg[8];data_out[7:0]   <= ~q_m_reg[7:0];cnt <=  cnt + {q_m_reg[8], 1'b0} + (q_m_n0 - q_m_n1);endelsebegindata_out[9]     <= 1'b0;data_out[8]     <= q_m_reg[8];data_out[7:0]   <= q_m_reg[7:0];cnt <=  cnt - {~q_m_reg[8], 1'b0} + (q_m_n1 - q_m_n0);endendendelsebegincase    ({c1_reg2, c0_reg2})2'b00:  data_out <= DATA_OUT0;2'b01:  data_out <= DATA_OUT1;2'b10:  data_out <= DATA_OUT2;default:data_out <= DATA_OUT3;endcasecnt <=  5'b0;endendendmodule

4.2.2 并串转换

10bit并行数据——10bit串行数据
单端信号——差分信号
单沿采样——双沿采样

module par_to_ser
(input   wire            clk_5x      ,   //输入系统时钟input   wire    [9:0]   par_data    ,   //输入并行数据output  wire            ser_data_p  ,   //输出串行差分数据output  wire            ser_data_n      //输出串行差分数据
);//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire  define
wire    [4:0]   data_rise = {par_data[8],par_data[6],par_data[4],par_data[2],par_data[0]};
wire    [4:0]   data_fall = {par_data[9],par_data[7],par_data[5],par_data[3],par_data[1]};//reg   define
reg     [4:0]   data_rise_s = 0;
reg     [4:0]   data_fall_s = 0;
reg     [2:0]   cnt = 0;always @ (posedge clk_5x)begincnt <= (cnt[2]) ? 3'd0 : cnt + 3'd1;data_rise_s  <= cnt[2] ? data_rise : data_rise_s[4:1];//计满就将5位上升沿数据补上,没计满就移位data_fall_s  <= cnt[2] ? data_fall : data_fall_s[4:1];end//********************************************************************//
//**************************** Instantiate ***************************//
//********************************************************************//
//------------- ddio_out_inst0 -------------
ddio_out    ddio_out_inst0
(.datain_h   (data_rise_s[0] ),.datain_l   (data_fall_s[0] ),.outclock   (~clk_5x        ),.dataout    (ser_data_p     )
);//------------- ddio_out_inst1 -------------
ddio_out    ddio_out_inst1
(.datain_h   (~data_rise_s[0]),.datain_l   (~data_fall_s[0]),.outclock   (~clk_5x        ),.dataout    (ser_data_n     )
);endmodule

五、附录

5.1 摄像头

本篇使用的摄像头引脚含义:

5.2 开发板

使用了下面几款开发板,其中列出摄像头模块的原理图

5.2.1 野火

5.2.2 黑金

FPGA:ov7725摄像头通过VGA/HDMI显示RGB565格式的图像相关推荐

  1. FPGA虚拟三阶魔方(HDMI显示版)

    目录 ​编辑 一.设计概述 二.设计模块 1.三阶魔方建模 (1)魔方基本操作: (2)魔方建模: 2.魔方转动控制: (1)控制概述: (2)按键消抖: (3)魔方控制: 3.HDMI显示模块: ( ...

  2. 基于FPGA的 TMDS 编码 及 HDMI 显示

    目录 引言 TMDS 编码 原理简介 TMDS编码实现 HDMI差分数据串行 实现方法 源码 HDMI显示方法 思路 实现 工程结构 源代码分享 板级调试视频 引言 最近在开发板上倒腾了一下 TMDS ...

  3. FPGA设计——CMOS摄像与HDMI显示(DVP版)

    1. 概述 本设计采用FPGA技术,将CMOS摄像头(DVP接口)的视频数据经过采集.存储.处理.帧率转换,最终通过HDMI接口显示在电视屏幕上. 2. 硬件系统框图 CMOS采用分辨率为1080p的 ...

  4. FPGA综合实验 05 - | VGA彩条信号显示控制电路设计

    一.实验目的和任务 学习VGA图像显示控制电路设计. 二.设计代码(或原理图).仿真波形及分析 1.rom 为图像数据存储模块 // megafunction wizard: %ROM: 1-PORT ...

  5. FPGA之OV7725摄像头采集与VGA显示实验--4--摄像头数据输出VAG协议分析

    大家好,前面几节给大家介绍了OV7725摄像头通过SCCB协议进行配置的内容,这一节我们来聊一下关于OV7725摄像头的VAG协议的知识,为后面的数据采集模块做铺垫. 学习目标 理解VGA协议传输数据 ...

  6. FPGA—VGA 显示器显示彩条(附代码)

    目录 1. 理论 2. 实操 2.1 顶层设计 2.1.1 模块框图 2.1.2 代码编写 2.1.3 仿真验证 2.2 时钟生成模块 2.3 VGA时序控制模块 2.3.1 模块框图 2.3.2 波 ...

  7. FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(一)

    第七章 实战项目提升,完善简历 19.OV7725摄像头实时采集送HDMI显示(一) 在例程"OV7725摄像头实时采集送HDMI显示"中,我们将走近FPGA图像处理的世界,图像处 ...

  8. FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(三)

    第七章 实战项目提升,完善简历 19.OV7725摄像头实时采集送HDMI显示(三) 在详细介绍过OV7725 CMOS Sensor的相关背景知识和如何初始化其内部寄存器达到输出预期视频流的目的后, ...

  9. 【正点原子FPGA连载】第三十九章OV7725摄像头RGB-LCD显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

    1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...

  10. 【正点原子FPGA连载】第四十四章MT9V034摄像头HDMI显示实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

    1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...

最新文章

  1. 学习在Unity中创建一个动作RPG游戏
  2. 【Android】附加Android源代码Androidandroid_gingerbread_javasrc
  3. WinDBG调试dNet程序总结
  4. 设置DateChooser控件的头部文字对齐方式.
  5. java中 == 与 equal 的区别
  6. 06-用两个栈实现队列
  7. 操作系统实战45讲01:运行HelloOS
  8. Effective C++ 之 Item 5:了解C++默默编写并调用哪些函数
  9. U盘刻录操作系统的详细步骤
  10. Pytorch加载.pth文件
  11. 2019北京大学研究生推免上机考试
  12. S32K116调试记录(1)SWD接口调试
  13. mongodb 用命令导入导出数据库,用命令在Robo3T 上查询。
  14. FHS--文件系统结构
  15. elo匹配算法c语言,王者荣耀elo算法被淘汰?全新匹配算法开测
  16. 菜鸟窝BAT企业安卓学习笔记
  17. cmwap和cmnet接入点的区别
  18. 小小白学Springboot(十一)——Security安全管理
  19. 中断深入-->休眠唤醒(通用)
  20. 显卡显存测试u盘 mats_【茶茶】非公路在何方?AORUS RTX 2060测试报告

热门文章

  1. Linux设置和取消定时关机,修改 linux 默认启动级别 设置系统时间   定时关机
  2. 如何查到营业执照_知道法人姓名,如何查营业执照?
  3. 英雄连的制作公司THQ历史
  4. 原形网络(Prototypical Networks)基于PyTorch的实现
  5. android添加nfc门禁卡,IOS14nfc怎么添加门禁卡?NFC门禁卡教程[多图]
  6. unity 查找所以物体_unity中查找物体的方法
  7. Python-----并发,并行,进程,多进程
  8. arduino期末考试题
  9. 计算机怎样安装硬盘,固态硬盘安装-笔记本和台式电脑分别如何安装SSD详细图文教程...
  10. HTML12张图片魔方,纯CSS3 实现3D魔方