野火FPGA强化(10):基于Sobel算法的边缘检测

文章目录

    • 第46讲:FIFO求和实验
      • 理论部分
      • 设计与实现
      • uart_rx
      • uart_tx
      • fifo_sum_ctrl
      • fifo_sum
      • tb_fifo_sum
    • 第47讲:基于Sobel算法的边缘检测设计与实现
      • 设计与实现
      • uart_rx
      • uart_tx
      • vga_ctrl
      • vga_pic
      • vga
      • sobel_ctrl
      • sobel

第46讲:FIFO求和实验

理论部分

野火FPGA强化(10):基于Sobel算法的边缘检测_第1张图片
野火FPGA强化(10):基于Sobel算法的边缘检测_第2张图片

设计与实现

野火FPGA强化(10):基于Sobel算法的边缘检测_第3张图片
野火FPGA强化(10):基于Sobel算法的边缘检测_第4张图片

野火FPGA强化(10):基于Sobel算法的边缘检测_第5张图片

野火FPGA强化(10):基于Sobel算法的边缘检测_第6张图片

uart_rx

`timescale  1ns/1ns

module  uart_rx
#(
    parameter   UART_BPS    =   'd9600,         //串口波特率
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(
    input   wire            sys_clk     ,   //系统时钟50MHz
    input   wire            sys_rst_n   ,   //全局复位
    input   wire            rx          ,   //串口接收数据

    output  reg     [7:0]   po_data     ,   //串转并后的8bit数据
    output  reg             po_flag         //串转并后的数据有效标志信号
);

//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;

//reg   define
reg         rx_reg1     ;
reg         rx_reg2     ;
reg         rx_reg3     ;
reg         start_nedge ;
reg         work_en     ;
reg [12:0]  baud_cnt    ;
reg         bit_flag    ;
reg [3:0]   bit_cnt     ;
reg [7:0]   rx_data     ;
reg         rx_flag     ;

//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg1 <= 1'b1;
    else
        rx_reg1 <= rx;

//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg2 <= 1'b1;
    else
        rx_reg2 <= rx_reg1;

//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg3 <= 1'b1;
    else
        rx_reg3 <= rx_reg2;

//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        start_nedge <= 1'b0;
    else    if((~rx_reg2) && (rx_reg3))
        start_nedge <= 1'b1;
    else
        start_nedge <= 1'b0;

//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        work_en <= 1'b0;
    else    if(start_nedge == 1'b1)
        work_en <= 1'b1;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        work_en <= 1'b0;

//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        baud_cnt <= 13'b0;
    else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
        baud_cnt <= 13'b0;
    else    if(work_en == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;

//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_flag <= 1'b0;
    else    if(baud_cnt == BAUD_CNT_MAX/2 - 1)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;

//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        bit_cnt <= 4'b0;
     else    if(bit_flag ==1'b1)
         bit_cnt <= bit_cnt + 1'b1;

//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_data <= 8'b0;
    else    if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
        rx_data <= {rx_reg3, rx_data[7:1]};

//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_flag <= 1'b0;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        rx_flag <= 1'b1;
    else
        rx_flag <= 1'b0;

//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_data <= 8'b0;
    else    if(rx_flag == 1'b1)
        po_data <= rx_data;

//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_flag <= 1'b0;
    else
        po_flag <= rx_flag;

endmodule

uart_tx

`timescale  1ns/1ns

module  uart_tx
#(
    parameter   UART_BPS    =   'd9600,         //串口波特率
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(
     input   wire            sys_clk     ,   //系统时钟50MHz
     input   wire            sys_rst_n   ,   //全局复位
     input   wire    [7:0]   pi_data     ,   //模块输入的8bit数据
     input   wire            pi_flag     ,   //并行数据有效标志信号
 
     output  reg             tx              //串转并后的1bit数据
);

//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;

//reg   define
reg [12:0]  baud_cnt;
reg         bit_flag;
reg [3:0]   bit_cnt ;
reg         work_en ;

//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            work_en <= 1'b0;
        else    if(pi_flag == 1'b1)
            work_en <= 1'b1;
        else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
            work_en <= 1'b0;

//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else    if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;

//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_flag <= 1'b0;
        else    if(baud_cnt == 13'd1)
            bit_flag <= 1'b1;
        else
            bit_flag <= 1'b0;

//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (work_en == 1'b1))
        bit_cnt <= bit_cnt + 1'b1;

//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            tx <= 1'b1; //空闲状态时为高电平
        else    if(bit_flag == 1'b1)
            case(bit_cnt)
                0       : tx <= 1'b0;
                1       : tx <= pi_data[0];
                2       : tx <= pi_data[1];
                3       : tx <= pi_data[2];
                4       : tx <= pi_data[3];
                5       : tx <= pi_data[4];
                6       : tx <= pi_data[5];
                7       : tx <= pi_data[6];
                8       : tx <= pi_data[7];
                9       : tx <= 1'b1;
                default : tx <= 1'b1;
            endcase

endmodule

fifo_sum_ctrl

`timescale  1ns/1ns

module  fifo_sum_ctrl
(
    input   wire          sys_clk     ,   //频率为50MHz
    input   wire          sys_rst_n   ,   //复位信号,低有效
    input   wire  [7:0]   pi_data     ,   //rx传入的数据信号
    input   wire          pi_flag     ,   //rx传入的标志信号

    output  reg   [7:0]   po_sum      ,   //求和运算后的信号
    output  reg           po_flag         //输出数据标志信号
);

//parameter define
parameter   CNT_ROW_MAX = 7'd49 ,   //行计数最大值
            CNT_COL_MAX = 7'd49 ;   //列计数最大值

//wire  define
wire  [7:0]   data_out1   ;   //fifo1数据输出
wire  [7:0]   data_out2   ;   //fifo2数据输出

//reg   define 
reg   [6:0]   cnt_row     ;   //行计数
reg   [6:0]   cnt_col     ;   //场计数
reg           wr_en1      ;   //fifo1写使能
reg           wr_en2      ;   //fifo2写使能
reg   [7:0]   data_in1    ;   //fifo1写数据输入  
reg   [7:0]   data_in2    ;   //fifo2写数据输入
reg           rd_en       ;   //fifo1、fifo2共用的读使能
reg           dout_flag   ;   //控制fifo1,2-84行的写使能
reg           po_flag_reg ;   //输出标志位缓存,rd_en延后一拍得到,控制计算po_sum

//cnt_row:行计数器,计数一行数据个数
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        cnt_row <=  7'd0;
    else    if((cnt_row == CNT_ROW_MAX) && (pi_flag == 1'b1))
        cnt_row <=  7'd0;
    else    if(pi_flag == 1'b1)
        cnt_row <=  cnt_row + 1'b1;
end

//cnt_col:列计数器,计数数据行数
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        cnt_col <=  7'd0;
    else    if((cnt_col == CNT_COL_MAX) && (pi_flag == 1'b1) && (cnt_row == CNT_ROW_MAX))
        cnt_col <=  7'd0;
    else    if((cnt_row == CNT_ROW_MAX) && (pi_flag == 1'b1))
        cnt_col <=  cnt_col + 1'b1;
end

//wr_en1:fifo1写使能信号,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        wr_en1  <=  1'b0;
    else    if((cnt_col == 7'd0) && (pi_flag == 1'b1))
        wr_en1  <=  1'b1;          //第0行写入fifo1
    else
        wr_en1  <=  dout_flag;  //2-84行写入fifo1
end

//wr_en2:fifo2写使能信号,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        wr_en2  <=  1'b0;
    else    if((cnt_col >= 7'd1) && (cnt_col <= CNT_COL_MAX - 1'b1) && (pi_flag == 1'b1))
        wr_en2  <=  1'b1;          //2-CNT_COL_MAX行写入fifo2
    else
      wr_en2  <=  1'b0;
end

//data_in1:fifo1数据输入
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        data_in1  <=  8'b0;
    else    if((pi_flag == 1'b1) && (cnt_col == 7'd0))
        data_in1  <=  pi_data;  //第0行数据暂存fifo1中
    else    if(dout_flag == 1'b1)
      data_in1  <=  data_out2;//第2-CNT_COL_MAX-1行时,fifo2读出数据存入fifo1
    else
        data_in1  <=  data_in1;
end

//data_in2:fifo2数据输入
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        data_in2  <=  8'b0;
    else    if((pi_flag == 1'b1)&&(cnt_col >= 7'd1)&&(cnt_col <= (CNT_COL_MAX - 1'b1)))
        data_in2  <=  pi_data;
    else
        data_in2  <=  data_in2;
end

//rd_en:fifo1和fifo2的共用读使能信号
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        rd_en <=  1'b0;
    else    if((pi_flag == 1'b1)&&(cnt_col >= 7'd2)&&(cnt_col <= CNT_COL_MAX))
        rd_en <=  1'b1;
    else
        rd_en <=  1'b0;
end

//dout_flag:控制2-CNT_COL_MAX-1行wr_en1信号
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        dout_flag <=  0;
    else    if((wr_en2 == 1'b1) && (rd_en == 1'b1))
        dout_flag <=  1'b1;
    else
        dout_flag <=  1'b0;
end

//po_flag_reg:输出标志位缓存,延后rd_en一拍,控制po_sum信号
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        po_flag_reg <=  1'b0;
    else    if(rd_en == 1'b1)
        po_flag_reg <=  1'b1;
    else
        po_flag_reg <=  1'b0;
end

//po_flag:输出标志信号,延后输出标志位缓存一拍,与po_sum同步输出
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        po_flag <=  1'b0;
    else
        po_flag <=  po_flag_reg;
end

//po_sum:求和数据输出
always@(posedge sys_clk or  negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
        po_sum  <=  8'b0;
    else    if(po_flag_reg == 1'b1)
        po_sum  <=  data_out1 + data_out2 + pi_data;
    else
        po_sum  <=  po_sum;
end

//------------- fifo_data_inst1 --------------
fifo_data   fifo_data_inst1
(
    .clock  (sys_clk    ),  //input clock
    .data   (data_in1   ),  //input [7:0] data
    .wrreq  (wr_en1     ),  //input wrreq
    .rdreq  (rd_en      ),  //input rdreq

    .q      (data_out1  )   //output [7:0] q
);

//------------- fifo_data_inst2 --------------
fifo_data   fifo_data_inst2
(
    .clock  (sys_clk    ),  //input clock
    .data   (data_in2   ),  //input [7:0] data
    .wrreq  (wr_en2     ),  //input wrreq
    .rdreq  (rd_en      ),  //input rdreq

    .q      (data_out2  )   //output [7:0] q
);

endmodule

fifo_sum

`timescale  1ns/1ns

module  fifo_sum
(
    input     wire    sys_clk       ,   //输入系统时钟,50MHz
    input     wire    sys_rst_n     ,   //复位信号,低电平有效
    input     wire    rx            ,   //串口数据接收

    output    wire    tx                //串口数据发送
);

//parameter define
parameter   UART_BPS    =   14'd9600        ,   //比特率
            CLK_FREQ    =   26'd50_000_000  ;   //时钟频率

//wire define
wire    [7:0]   pi_data ;   //输入待求和数据
wire            pi_flag ;   //输入数据标志信号
wire    [7:0]   po_sum  ;   //输出求和后数据
wire            po_flag ;   //输出数据标志信号

//------------- uart_rx_inst --------------
uart_rx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_rx_inst
(
    .sys_clk    (sys_clk    ),  //系统时钟50Mhz
    .sys_rst_n  (sys_rst_n  ),  //全局复位
    .rx         (rx         ),  //串口接收数据

    .po_data    (pi_data    ),  //串转并后的数据
    .po_flag    (pi_flag    )   //串转并后的数据有效标志信号
);

//------------- fifo_sum_ctrl_inst --------------
fifo_sum_ctrl  fifo_sum_ctrl_inst
(
    .sys_clk    (sys_clk    ),  //频率为50MHz
    .sys_rst_n  (sys_rst_n  ),  //复位信号,低有效
    .pi_data    (pi_data    ),  //rx传入的数据信号
    .pi_flag    (pi_flag    ),  //rx传入的标志信号

    .po_sum     (po_sum     ),  //求和运算后的信号
    .po_flag    (po_flag    )   //输出数据标志信号
);

//------------- uart_tx_inst --------------
uart_tx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_tx_inst
(
    .sys_clk    (sys_clk    ),  //系统时钟50Mhz
    .sys_rst_n  (sys_rst_n  ),  //全局复位
    .pi_data    (po_sum     ),  //并行数据
    .pi_flag    (po_flag    ),  //并行数据有效标志信号

    .tx         (tx         )   //串口发送数据
);

endmodule

tb_fifo_sum

`timescale  1ns/1ns
module  tb_fifo_sum();

//wire  define
wire            tx      ;

//reg   define
reg             clk     ;
reg             rst_n   ;
reg             rx      ;
reg     [7:0]   data_men[2499:0]    ;

//读取数据
initial
   $readmemh("E:/sources/fifo_sum/matlab/fifo_data.txt",data_men);

//生成时钟和复位信号
initial
  begin
    clk = 1'b1;
    rst_n <=  1'b0;
    #30
    rst_n <=  1'b1;
  end

always  #10 clk = ~clk;

//rx赋初值,调用rx_byte
initial
  begin
    rx  <=  1'b1;
    #200
    rx_byte();
  end

//rx_byte
task  rx_byte();
  integer j;
    for(j=0;j<2500;j=j+1)
      rx_bit(data_men[j]);
  endtask

//rx_bit
task  rx_bit(input[7:0] data);//data是data_men[j]的值。
  integer i;
    for(i=0;i<10;i=i+1)
      begin
        case(i)
          0:  rx  <=  1'b0;     //起始位
          1:  rx  <=  data[0];
          2:  rx  <=  data[1];
          3:  rx  <=  data[2];
          4:  rx  <=  data[3];
          5:  rx  <=  data[4];
          6:  rx  <=  data[5];
          7:  rx  <=  data[6];
          8:  rx  <=  data[7];  //上面8个发送的是数据位
          9:  rx  <=  1'b1;     //停止位
        endcase
        #1040;
      end
endtask

//重定义defparam,用于修改参数
defparam fifo_sum_inst.uart_rx_inst.CLK_FREQ    = 500000  ;
defparam fifo_sum_inst.uart_tx_inst.CLK_FREQ    = 500000  ;

//------------- fifo_sum_inst --------------
fifo_sum    fifo_sum_inst
(
  .sys_clk      (clk    ),
  .sys_rst_n    (rst_n  ),
  .rx           (rx     ),

  .tx           (tx     )
);

endmodule

第47讲:基于Sobel算法的边缘检测设计与实现

边缘检测,针对的是灰度图像,顾名思义,检测图像的边缘,是针对图像像素点的一种计算,目的是标识数字图像中灰度变化明显的点,图像的边缘检测,在保留了图像的重要结构信息的同时,剔除了可以认为不相关的信息,大幅度减少了数据量,便于图像的传输和处理。
野火FPGA强化(10):基于Sobel算法的边缘检测_第7张图片

设计与实现

野火FPGA强化(10):基于Sobel算法的边缘检测_第8张图片
野火FPGA强化(10):基于Sobel算法的边缘检测_第9张图片
野火FPGA强化(10):基于Sobel算法的边缘检测_第10张图片

uart_rx

`timescale  1ns/1ns

module  uart_rx
#(
    parameter   UART_BPS    =   'd9600,         //串口波特率
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(
    input   wire            sys_clk     ,   //系统时钟50MHz
    input   wire            sys_rst_n   ,   //全局复位
    input   wire            rx          ,   //串口接收数据

    output  reg     [7:0]   po_data     ,   //串转并后的8bit数据
    output  reg             po_flag         //串转并后的数据有效标志信号
);

//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;

//reg   define
reg         rx_reg1     ;
reg         rx_reg2     ;
reg         rx_reg3     ;
reg         start_nedge ;
reg         work_en     ;
reg [12:0]  baud_cnt    ;
reg         bit_flag    ;
reg [3:0]   bit_cnt     ;
reg [7:0]   rx_data     ;
reg         rx_flag     ;

//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg1 <= 1'b1;
    else
        rx_reg1 <= rx;

//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg2 <= 1'b1;
    else
        rx_reg2 <= rx_reg1;

//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg3 <= 1'b1;
    else
        rx_reg3 <= rx_reg2;

//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        start_nedge <= 1'b0;
    else    if((~rx_reg2) && (rx_reg3))
        start_nedge <= 1'b1;
    else
        start_nedge <= 1'b0;

//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        work_en <= 1'b0;
    else    if(start_nedge == 1'b1)
        work_en <= 1'b1;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        work_en <= 1'b0;

//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        baud_cnt <= 13'b0;
    else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
        baud_cnt <= 13'b0;
    else    if(work_en == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;

//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_flag <= 1'b0;
    else    if(baud_cnt == BAUD_CNT_MAX/2 - 1)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;

//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        bit_cnt <= 4'b0;
     else    if(bit_flag ==1'b1)
         bit_cnt <= bit_cnt + 1'b1;

//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_data <= 8'b0;
    else    if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
        rx_data <= {rx_reg3, rx_data[7:1]};

//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_flag <= 1'b0;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        rx_flag <= 1'b1;
    else
        rx_flag <= 1'b0;

//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_data <= 8'b0;
    else    if(rx_flag == 1'b1)
        po_data <= rx_data;

//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_flag <= 1'b0;
    else
        po_flag <= rx_flag;

endmodule

uart_tx

`timescale  1ns/1ns

module  uart_tx
#(
    parameter   UART_BPS    =   'd9600,         //串口波特率
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(
     input   wire            sys_clk     ,   //系统时钟50MHz
     input   wire            sys_rst_n   ,   //全局复位
     input   wire    [7:0]   pi_data     ,   //模块输入的8bit数据
     input   wire            pi_flag     ,   //并行数据有效标志信号
 
     output  reg             tx              //串转并后的1bit数据
);

//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;

//reg   define
reg [12:0]  baud_cnt;
reg         bit_flag;
reg [3:0]   bit_cnt ;
reg         work_en ;

//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            work_en <= 1'b0;
        else    if(pi_flag == 1'b1)
            work_en <= 1'b1;
        else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
            work_en <= 1'b0;

//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else    if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;

//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_flag <= 1'b0;
        else    if(baud_cnt == 13'd1)
            bit_flag <= 1'b1;
        else
            bit_flag <= 1'b0;

//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (work_en == 1'b1))
        bit_cnt <= bit_cnt + 1'b1;

//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            tx <= 1'b1; //空闲状态时为高电平
        else    if(bit_flag == 1'b1)
            case(bit_cnt)
                0       : tx <= 1'b0;
                1       : tx <= pi_data[0];
                2       : tx <= pi_data[1];
                3       : tx <= pi_data[2];
                4       : tx <= pi_data[3];
                5       : tx <= pi_data[4];
                6       : tx <= pi_data[5];
                7       : tx <= pi_data[6];
                8       : tx <= pi_data[7];
                9       : tx <= 1'b1;
                default : tx <= 1'b1;
            endcase

endmodule

vga_ctrl

`timescale  1ns/1ns

module  vga_ctrl
(
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [7:0]   pix_data    ,   //输入像素点色彩信息

    output  wire    [9:0]   pix_x       ,   //输出VGA有效显示区域像素点X轴坐标
    output  wire    [9:0]   pix_y       ,   //输出VGA有效显示区域像素点Y轴坐标
    output  wire            hsync       ,   //输出行同步信号
    output  wire            vsync       ,   //输出场同步信号
    output  wire    [7:0]   rgb             //输出像素点色彩信息
);

//parameter define
parameter H_SYNC    =   10'd96  ,   //行同步
          H_BACK    =   10'd40  ,   //行时序后沿
          H_LEFT    =   10'd8   ,   //行时序左边框
          H_VALID   =   10'd640 ,   //行有效数据
          H_RIGHT   =   10'd8   ,   //行时序右边框
          H_FRONT   =   10'd8   ,   //行时序前沿
          H_TOTAL   =   10'd800 ;   //行扫描周期
parameter V_SYNC    =   10'd2   ,   //场同步
          V_BACK    =   10'd25  ,   //场时序后沿
          V_TOP     =   10'd8   ,   //场时序左边框
          V_VALID   =   10'd480 ,   //场有效数据
          V_BOTTOM  =   10'd8   ,   //场时序右边框
          V_FRONT   =   10'd2   ,   //场时序前沿
          V_TOTAL   =   10'd525 ;   //场扫描周期

//wire  define
wire            rgb_valid       ;   //VGA有效显示区域
wire            pix_data_req    ;   //像素点色彩信息请求信号

//reg   define
reg     [9:0]   cnt_h           ;   //行同步信号计数器
reg     [9:0]   cnt_v           ;   //场同步信号计数器

//cnt_h:行同步信号计数器
always@(posedge vga_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h   <=  10'd0   ;
    else    if(cnt_h == H_TOTAL - 1'd1)
        cnt_h   <=  10'd0   ;
    else
        cnt_h   <=  cnt_h + 1'd1   ;

//hsync:行同步信号
assign  hsync = (cnt_h  <=  H_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

//cnt_v:场同步信号计数器
always@(posedge vga_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v   <=  10'd0 ;
    else    if((cnt_v == V_TOTAL - 1'd1) && (cnt_h == H_TOTAL-1'd1))
        cnt_v   <=  10'd0 ;
    else    if(cnt_h == H_TOTAL - 1'd1)
        cnt_v   <=  cnt_v + 1'd1 ;
    else
        cnt_v   <=  cnt_v ;

//vsync:场同步信号
assign  vsync = (cnt_v  <=  V_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

//rgb_valid:VGA有效显示区域
assign  rgb_valid = (((cnt_h >= H_SYNC + H_BACK + H_LEFT)
                    && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID))
                    &&((cnt_v >= V_SYNC + V_BACK + V_TOP)
                    && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
                    ? 1'b1 : 1'b0;

//pix_data_req:像素点色彩信息请求信号,超前rgb_valid信号一个时钟周期
assign  pix_data_req = (((cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1)
                    && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1))
                    &&((cnt_v >= V_SYNC + V_BACK + V_TOP)
                    && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
                    ? 1'b1 : 1'b0;

//pix_x,pix_y:VGA有效显示区域像素点坐标
assign  pix_x = (pix_data_req == 1'b1)
                ? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 10'h3ff;
assign  pix_y = (pix_data_req == 1'b1)
                ? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 10'h3ff;

//rgb:输出像素点色彩信息
assign  rgb = (rgb_valid == 1'b1) ? pix_data : 8'b0 ;

endmodule

vga_pic

`timescale  1ns/1ns

module  vga_pic
(
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_clk     ,   //输入RAM写时钟,频率50MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [7:0]   pi_data     ,   //输入RAM写数据
    input   wire            pi_flag     ,   //输入RAM写使能
    input   wire    [9:0]   pix_x       ,   //输入有效显示区域像素点X轴坐标
    input   wire    [9:0]   pix_y       ,   //输入有效显示区域像素点Y轴坐标

    output  wire    [7:0]   pix_data_out    //输出VGA显示图像数据
);

parameter   H_VALID =   10'd640     ,   //行有效数据
            V_VALID =   10'd480     ;   //场有效数据

parameter   H_PIC   =   10'd98     ,   //sobel算法处理后的图片长度
            W_PIC   =   10'd98     ,   //sobel算法处理后的图片宽度
            PIC_SIZE=   14'd9604   ;   //sobel算法处理后的图片像素个数

parameter   RED     =   8'b1110_0000    ,   //红色
            GREEN   =   8'b0001_1100    ,   //绿色
            BLUE    =   8'b0000_0011    ,   //蓝色
            BLACK   =   8'b0000_0000    ,   //黑色
            WHITE   =   8'b1111_1111    ;   //白色

//wire  define
wire            rd_en       ;   //ROM读使能
wire    [7:0]   pic_data    ;   //自ROM读出的图片数据

//reg   define
reg     [13:0]  wr_addr     ;   //ram写地址
reg     [13:0]  rd_addr     ;   //ram读地址
reg             pic_valid   ;   //图片数据有效信号
reg     [7:0]   pix_data    ;   //背景色彩信息

//wr_addr:ram写地址
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_addr <=  14'd0;
    else    if((wr_addr == (PIC_SIZE - 1'b1)) && (pi_flag == 1'b1))
        wr_addr <=  14'd0;
    else    if(pi_flag == 1'b1)
        wr_addr <=  wr_addr + 1'b1;

//rd_addr:ram读地址
always@(posedge vga_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_addr <=  14'd0;
    else    if(rd_addr == (PIC_SIZE - 1'b1))
        rd_addr <=  14'd0;
    else    if(rd_en == 1'b1)
        rd_addr <=  rd_addr + 1'b1;
    else
        rd_addr <=  rd_addr;

//rd_en:ROM读使能
assign  rd_en = (((pix_x >= (((H_VALID - H_PIC)/2) - 1'b1))
                && (pix_x < (((H_VALID - H_PIC)/2) + H_PIC - 1'b1))) 
                &&((pix_y >= ((V_VALID - W_PIC)/2))
                && ((pix_y < (((V_VALID - W_PIC)/2) + W_PIC)))));

//pic_valid:图片数据有效信号
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pic_valid   <=  1'b1;
    else
        pic_valid   <=  rd_en;

//pix_data_out:输出VGA显示图像数据
assign  pix_data_out = (pic_valid == 1'b1) ? pic_data : pix_data;

//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pix_data    <=  8'd0;
    else    if((pix_x >= 0) && (pix_x < (H_VALID/10)*1))
        pix_data    <=  RED;
    else    if((pix_x >= (H_VALID/10)*1) && (pix_x < (H_VALID/10)*2))
        pix_data    <=  GREEN;
    else    if((pix_x >= (H_VALID/10)*2) && (pix_x < (H_VALID/10)*3))
        pix_data    <=  BLUE;
    else    if((pix_x >= (H_VALID/10)*3) && (pix_x < (H_VALID/10)*4))
        pix_data    <=  BLACK;
    else    if((pix_x >= (H_VALID/10)*4) && (pix_x < (H_VALID/10)*5))
        pix_data    <=  WHITE;
    else    if((pix_x >= (H_VALID/10)*5) && (pix_x < (H_VALID/10)*6))
        pix_data    <=  RED;
    else    if((pix_x >= (H_VALID/10)*6) && (pix_x < (H_VALID/10)*7))
        pix_data    <=  GREEN;
    else    if((pix_x >= (H_VALID/10)*7) && (pix_x < (H_VALID/10)*8))
        pix_data    <=  BLUE;
    else    if((pix_x >= (H_VALID/10)*8) && (pix_x < (H_VALID/10)*9))
        pix_data    <=  BLACK;
    else    if((pix_x >= (H_VALID/10)*9) && (pix_x < H_VALID))
        pix_data    <=  WHITE;
    else
        pix_data    <=  BLACK;

//------------- ram_pic_inst -------------
ram_pic ram_pic_inst
(
    .inclock    (sys_clk    ),    //输入RAM写时钟,50MHz,1bit
    .wren       (pi_flag    ),    //输入RAM写使能,1bit
    .wraddress  (wr_addr    ),    //输入RAM写地址,15bit
    .data       (pi_data    ),    //输入写入RAM的图片数据,8bit
    .outclock   (vga_clk    ),    //输入RAM读时钟,25MHz,1bit
    .rdaddress  (rd_addr    ),    //输入RAM读地址,15bit

    .q          (pic_data   )     //输出读取RAM的图片数据,8bit
);

endmodule

vga

`timescale  1ns/1ns

module  vga
(
    input   wire            sys_clk     ,   //输入工作时钟,频率50MHz
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire            pi_flag     ,   //输入数据标志信号
    input   wire    [7:0]   pi_data     ,   //输入数据

    output  wire            hsync       ,   //输出行同步信号
    output  wire            vsync       ,   //输出场同步信号
    output  wire    [7:0]   rgb             //输出像素信息

);

//wire  define
wire    [9:0]   pix_x       ;   //VGA有效显示区域X轴坐标
wire    [9:0]   pix_y       ;   //VGA有效显示区域Y轴坐标
wire    [7:0]   pix_data    ;   //VGA像素点色彩信息

//------------- vga_ctrl_inst -------------
vga_ctrl    vga_ctrl_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_rst_n  (sys_rst_n  ),  //输入复位信号,低电平有效,1bit
    .pix_data   (pix_data   ),  //输入像素点色彩信息,8bit

    .pix_x      (pix_x      ),  //输出VGA有效显示区域像素点X轴坐标,10bit
    .pix_y      (pix_y      ),  //输出VGA有效显示区域像素点Y轴坐标,10bit
    .hsync      (hsync      ),  //输出行同步信号,1bit
    .vsync      (vsync      ),  //输出场同步信号,1bit
    .rgb        (rgb        )   //输出像素点色彩信息,16bit
);

//------------- vga_pic_inst -------------
vga_pic     vga_pic_inst
(
    .vga_clk        (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_clk        (sys_clk    ),  //输入RAM写时钟,1bit
    .sys_rst_n      (sys_rst_n  ),  //输入复位信号,低电平有效,1bit
    .pi_flag        (pi_flag    ),  //输入RAM写使能,1bit
    .pi_data        (pi_data    ),  //输入RAM写数据,8bit
    .pix_x          (pix_x      ),  //输入VGA有效显示区域像素点X轴坐标,10bit
    .pix_y          (pix_y      ),  //输入VGA有效显示区域像素点Y轴坐标,10bit

    .pix_data_out   (pix_data   )   //输出像素点色彩信息,8bit
);

endmodule

sobel_ctrl

`timescale  1ns/1ns

module  sobel_ctrl
(
    input   wire            sys_clk     ,   //输入系统时钟,频率50MHz
    input   wire            sys_rst_n   ,   //复位信号,低有效
    input   wire    [7:0]   pi_data     ,   //rx传入的数据信号
    input   wire            pi_flag     ,   //rx传入的标志信号

    output  reg     [7:0]   po_data     ,   //fifo加法运算后的信号
    output  reg             po_flag         //输出标志信号
);

//parameter define
parameter   LENGTH_P    =   10'd100         ,   //图片长度
            WIDE_P      =   10'd100         ;   //图片宽度
parameter   THRESHOLD   =   8'b000_011_00   ;   //比较阈值
parameter   BLACK       =   8'b0000_0000    ,   //黑色
            WHITE       =   8'b1111_1111    ;   //白色

//wire  define
wire    [7:0]   data_out1   ;   //fifo1数据输出
wire    [7:0]   data_out2   ;   //fifo2数据输出

//reg   define
reg     [7:0]   cnt_h       ;   //行计数
reg     [7:0]   cnt_v       ;   //场计数
reg     [7:0]   pi_data_dly ;   //pi_data数据寄存
reg             wr_en1      ;   //fifo1写使能
reg             wr_en2      ;   //fifo2写使能
reg     [7:0]   data_in1    ;   //fifo1写数据
reg     [7:0]   data_in2    ;   //fifo2写数据
reg             rd_en       ;   //fifo1,fifo2共用读使能
reg     [7:0]   data_out1_dly   ;   //fifo1数据输出寄存
reg     [7:0]   data_out2_dly   ;   //fifo2数据输出寄存
reg             dout_flag   ;   //使能信号
reg             rd_en_dly1  ;   //输出数据标志信号,延后rd_en一拍
reg             rd_en_dly2  ;   //a,b,c赋值标志信号
reg             gx_gy_flag  ;   //gx,gy计算标志信号
reg             gxy_flag    ;   //gxy计算标志信号
reg             compare_flag;   //阈值比较标志信号
reg     [7:0]   cnt_rd      ;   //读出数据计数器
reg     [7:0]   a1          ;
reg     [7:0]   a2          ;
reg     [7:0]   a3          ;
reg     [7:0]   b1          ;
reg     [7:0]   b2          ;
reg     [7:0]   b3          ;
reg     [7:0]   c1          ;
reg     [7:0]   c2          ;
reg     [7:0]   c3          ;   //图像数据
reg     [8:0]   gx          ;
reg     [8:0]   gy          ;   //gx,gy
reg     [7:0]   gxy         ;   //gxy

//cnt_h:行数据个数计数器
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h   <=  8'd0;
    else    if((cnt_h == (LENGTH_P - 1'b1)) && (pi_flag == 1'b1))
        cnt_h   <=  8'd0;
    else    if(pi_flag == 1'b1)
        cnt_h   <=  cnt_h + 1'b1;

//cnt_v:场计数器
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v   <=  8'd0;
    else    if((cnt_v == (WIDE_P - 1'b1)) && (pi_flag == 1'b1)
            && (cnt_h == (LENGTH_P - 1'b1)))
        cnt_v   <=  8'd0;
    else    if((cnt_h == (LENGTH_P - 1'b1)) && (pi_flag == 1'b1))
        cnt_v   <=  cnt_v + 1'b1;

//cnt_rd:fifo数据读出个数计数,用来判断何时对gx,gy进行运算
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_rd   <=  8'd0;
    else    if((cnt_rd == (LENGTH_P - 1'b1)) && (rd_en == 1'b1))
        cnt_rd   <=  8'd0;
    else    if(rd_en == 1'b1)
        cnt_rd   <=  cnt_rd + 1'b1;

//wr_en1:fifo1写使能,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_en1  <=  1'b0;
    else    if((cnt_v == 8'd0) && (pi_flag == 1'b1))
        wr_en1  <=  1'b1;      //第0行写入fifo1
    else
        wr_en1  <=  dout_flag;  //2-198行写入fifo1

//wr_en2,fifo2的写使能,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        wr_en2  <=  1'b0;
    else    if((cnt_v >= 8'd1)&&(cnt_v <= ((WIDE_P - 1'b1) - 1'b1))
            && (pi_flag == 1'b1))
        wr_en2  <=  1'b1;      //2-199行写入fifo2
    else
        wr_en2  <=  1'b0;

//data_in1:fifo1的数据写入
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in1    <=  8'b0;
    else    if((pi_flag == 1'b1) && (cnt_v == 8'b0))
        data_in1    <=  pi_data;
    else    if(dout_flag == 1'b1)
        data_in1    <=  data_out2;
    else
        data_in1    <=  data_in1;

//data_in2:fifo2的数据写入
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in2    <=  8'b0;
    else    if((pi_flag == 1'b1) && (cnt_v >= 8'd1)
            && (cnt_v <= ((WIDE_P - 1'b1) - 1'b1)))
        data_in2    <=  pi_data;
    else
        data_in2    <=  data_in2;

//rd_en:fifo1和fifo2的共用读使能,高电平有效
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_en   <=  1'b0;
    else    if((pi_flag == 1'b1) && (cnt_v >= 8'd2)
            && (cnt_v <= (WIDE_P - 1'b1)))
        rd_en   <=  1'b1;  
    else
        rd_en   <=  1'b0;

//dout_flag:控制fifo1写使能wr_en1
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        dout_flag   <=  1'b0;
    else    if((wr_en2 == 1'b1) && (rd_en == 1'b1))
        dout_flag   <=  1'b1;
    else
        dout_flag   <=  1'b0;

//rd_en_dly1:输出数据标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_en_dly1  <=  1'b0;
    else    if(rd_en == 1'b1)
        rd_en_dly1  <=  1'b1;
    else
        rd_en_dly1  <=  1'b0;

//data_out1_dly:data_out1数据寄存
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_out1_dly   <=  8'b0;
    else    if(rd_en_dly1 == 1'b1)
        data_out1_dly   <=  data_out1;

//data_out2_dly:data_out2数据寄存
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_out2_dly   <=  8'b0;
    else    if(rd_en_dly1 == 1'b1)
        data_out2_dly   <=  data_out2;

//pi_data_dly:输入数据pi_data寄存
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_data_dly <=  8'b0;
    else    if(rd_en_dly1 == 1'b1)
        pi_data_dly <=  pi_data;

//rd_en_dly2:a,b,c赋值标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_en_dly2  <=  1'b0;
    else    if(rd_en_dly1 == 1'b1)
        rd_en_dly2  <=  1'b1;
    else
        rd_en_dly2  <=  1'b0;

//gx_gy_flag:gx,gy计算标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gx_gy_flag  <=  1'b0;
    else    if((rd_en_dly2 == 1'b1) && ((cnt_rd >= 8'd3) || (cnt_rd == 8'd0)))
        gx_gy_flag  <=  1'b1;
    else
        gx_gy_flag  <=  1'b0;

//gxy_flag:gxy计算标准信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gxy_flag    <=  1'b0;
    else    if(gx_gy_flag == 1'b1)
        gxy_flag    <=  1'b1;
    else
        gxy_flag    <=  1'b0;

//compare_flag,阈值比较标志信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        compare_flag    <=  1'b0;
    else    if(gxy_flag == 1'b1)
        compare_flag    <=  1'b1;
    else
        compare_flag    <=  1'b0;

//a,b,c赋值
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
    begin
        a1  <=  8'd0;
        a2  <=  8'd0;
        a3  <=  8'd0;
        b1  <=  8'd0;
        b2  <=  8'd0;
        b3  <=  8'd0;
        c1  <=  8'd0;
        c2  <=  8'd0;
        c3  <=  8'd0;
    end
    else    if(rd_en_dly2==1)
    begin
        a1  <=  data_out1_dly;
        b1  <=  data_out2_dly;
        c1  <=  pi_data_dly;
        a2  <=  a1;
        b2  <=  b1;
        c2  <=  c1;
        a3  <=  a2;
        b3  <=  b2;
        c3  <=  c2;
    end

//gx:计算gx
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gx  <=  9'd0;
    else    if(gx_gy_flag == 1'b1)
        gx  <=  a3 - a1 + ((b3 - b1) << 1) + c3 - c1;
    else
        gx  <=  gx;

//gy:计算gy
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gy  <=  9'd0;
    else    if(gx_gy_flag == 1'b1)
        gy  <=  a1 - c1 + ((a2 - c2) << 1) + a3 - c3;
    else
        gy  <=  gy;

//gxy:gxy计算
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        gxy <=  0;
    else    if((gx[8] == 1'b1) && (gy[8] == 1'b1) && (gxy_flag == 1'b1))
        gxy <=  (~gx[7:0] + 1'b1) + (~gy[7:0] + 1'b1);
    else    if((gx[8] == 1'b1) && (gy[8] == 1'b0) && (gxy_flag == 1'b1))
        gxy <=  (~gx[7:0] + 1'b1) + (gy[7:0]);
    else    if((gx[8] == 1'b0) && (gy[8] == 1'b1) && (gxy_flag == 1'b1))
        gxy <=  (gx[7:0]) + (~gy[7:0] + 1'b1);
    else    if((gx[8] == 1'b0) && (gy[8] == 1'b0) && (gxy_flag == 1'b1))
        gxy <=  (gx[7:0]) + (gy[7:0]);

//po_data:通过gxy与阈值比较,赋值po_data
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_data <=  8'b0;
    else    if((gxy >= THRESHOLD) && (compare_flag == 1'b1))
        po_data <=  BLACK;
    else    if(compare_flag == 1'b1)
        po_data <=  WHITE;

//po_flag:输出标志位
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_flag <=  1'b0;
    else    if(compare_flag == 1'b1)
        po_flag <=  1'b1;
    else
        po_flag <=  1'b0;

//-------------fifo_pic_inst1--------------
fifo_pic    fifo_pic_inst1
(
    .clock  (sys_clk    ),  // input sys_clk
    .data   (data_in1   ),  // input [7 : 0] din
    .wrreq  (wr_en1     ),  // input wr_en
    .rdreq  (rd_en      ),  // input rd_en

    .q      (data_out1  )   // output [7 : 0] dout
);

//-------------fifo_pic_inst2--------------
fifo_pic    fifo_pic_inst2
(
    .clock  (sys_clk    ),  // input sys_clk
    .data   (data_in2   ),  // input [7 : 0] din
    .wrreq  (wr_en2     ),  // input wr_en
    .rdreq  (rd_en      ),  // input rd_en

    .q      (data_out2  )   // output [7 : 0] dout
);

endmodule

sobel

`timescale  1ns/1ns

module  sobel
(
    input   wire            sys_clk     ,   //系统时钟50Mhz
    input   wire            sys_rst_n   ,   //系统复位
    input   wire            rx          ,   //串口接收数据

    output  wire            tx          ,   //串口发送数据
    output  wire            hsync       ,   //输出行同步信号
    output  wire            vsync       ,   //输出场同步信号
    output  wire    [7:0]   rgb             //输出像素信息
);

//parameter define
parameter   UART_BPS    =   14'd9600        ,   //比特率
            CLK_FREQ    =   26'd50_000_000  ;   //时钟频率

//wire  define
wire            vga_clk ;
wire    [7:0]   pi_data ;
wire            pi_flag ;
wire    [7:0]   po_data ;
wire            po_flag ;
wire            locked  ;
wire            rst_n   ;
wire            clk_50m ;

//rst_n:VGA模块复位信号
assign  rst_n = (sys_rst_n & locked);

//------------- clk_gen_inst -------------
clk_gen     clk_gen_inst
(
    .areset     (~sys_rst_n ),  //输入复位信号,高电平有效,1bit
    .inclk0     (sys_clk    ),  //输入50MHz晶振时钟,1bit

    .c0         (vga_clk    ),  //输出VGA工作时钟,频率25Mhz,1bit
    .c1         (clk_50m    ),  //输出串口工作时钟,频率50Mhz,1bit
    .locked     (locked     )   //输出pll locked信号,1bit
);

//------------- uart_rx_inst --------------
uart_rx
#(
    .UART_BPS    (UART_BPS),    //串口波特率
    .CLK_FREQ    (CLK_FREQ)     //时钟频率
)
uart_rx_inst
(
    .sys_clk    (clk_50m    ),  //系统时钟50Mhz
    .sys_rst_n  (rst_n      ),  //全局复位
    .rx         (rx         ),  //串口接收数据

    .po_data    (pi_data    ),  //串转并后的数据
    .po_flag    (pi_flag    )   //串转并后的数据有效标志信号
);

//------------- sobel_ctrl_inst --------------
sobel_ctrl  sobel_ctrl_inst
(
    .sys_clk    (clk_50m    ),  //输入系统时钟,频率50MHz
    .sys_rst_n  (rst_n      ),  //复位信号,低有效
    .pi_data    (pi_data    ),  //rx传入的数据信号
    .pi_flag    (pi_flag    ),  //rx传入的标志信号

    .po_data    (po_data    ),  //fifo加法运算后的信号
    .po_flag    (po_flag    )   //输出标志信号
);

//------------- vga_ctrl_inst -------------
vga     vga_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率50MHz
    .sys_clk    (clk_50m    ),  //输入工作时钟,频率25MHz
    .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效
    .pi_data    (po_data    ),  //输入数据
    .pi_flag    (po_flag    ),  //输入数据标志信号

    .hsync      (hsync      ),  //输出行同步信号
    .vsync      (vsync      ),  //输出场同步信号
    .rgb        (rgb        )   //输出像素信息
);

//------------- uart_tx_inst --------------
uart_tx
#(
    .UART_BPS    (UART_BPS),    //串口波特率
    .CLK_FREQ    (CLK_FREQ)     //时钟频率
)
uart_tx_inst
(
    .sys_clk    (clk_50m    ),  //系统时钟50Mhz
    .sys_rst_n  (rst_n      ),  //全局复位
    .pi_data    (po_data    ),  //并行数据
    .pi_flag    (po_flag    ),  //并行数据有效标志信号

    .tx         (tx         )   //串口发送数据
);

endmodule

野火FPGA强化(10):基于Sobel算法的边缘检测_第11张图片

你可能感兴趣的:(FPGA,fpga开发,算法)