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

简介: FPGA强化(10):基于Sobel算法的边缘检测(二)

FPGA强化(10):基于Sobel算法的边缘检测(一)+https://developer.aliyun.com/article/1556601

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

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

设计与实现

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

文章知识点与

目录
相关文章
|
2月前
|
算法 异构计算
m基于FPGA的MPPT最大功率跟踪算法verilog实现,包含testbench
该内容包括三部分:1) 展示了Vivado 2019.2和Matlab中关于某种算法的仿真结果图像,可能与太阳能光伏系统的最大功率点跟踪(MPPT)相关。2) 简述了MPPT中的爬山法原理,通过调整光伏电池工作点以找到最大功率输出。3) 提供了一个Verilog程序模块`MPPT_test_tops`,用于测试MPPT算法,其中包含`UI_test`和`MPPT_module_U`两个子模块,处理光伏电流和电压信号。
26 1
|
2天前
|
算法 异构计算
FPGA强化(10):基于Sobel算法的边缘检测(一)
FPGA强化(10):基于Sobel算法的边缘检测
8 0
|
4天前
|
算法 安全 数据库
基于结点电压法的配电网状态估计算法matlab仿真
**摘要** 该程序实现了基于结点电压法的配电网状态估计算法,旨在提升数据的准确性和可靠性。在MATLAB2022a中运行,显示了状态估计过程中的电压和相位估计值,以及误差随迭代变化的图表。算法通过迭代计算雅可比矩阵,结合基尔霍夫定律解决线性方程组,估算网络节点电压。状态估计过程中应用了高斯-牛顿或莱文贝格-马夸尔特法,处理量测数据并考虑约束条件,以提高估计精度。程序结果以图形形式展示电压幅值和角度估计的比较,以及估计误差的演变,体现了算法在处理配电网状态估计问题的有效性。
|
1天前
|
数据采集 存储 算法
基于BP算法的SAR成像matlab仿真
**摘要:** 基于BP算法的SAR成像研究,利用MATLAB2022a进行仿真。SAR系统借助相对运动合成大孔径,提供高分辨率图像。BP算法执行回波数据预处理、像素投影及图像重建,实现精确成像。优点是高精度和强适应性,缺点是计算量大、内存需求高。代码示例展示了回波生成、数据处理到插值显示的全过程。
|
8天前
|
机器学习/深度学习 自然语言处理 算法
m基于深度学习的OFDM+QPSK链路信道估计和均衡算法误码率matlab仿真,对比LS,MMSE及LMMSE传统算法
**摘要:** 升级版MATLAB仿真对比了深度学习与LS、MMSE、LMMSE的OFDM信道估计算法,新增自动样本生成、复杂度分析及抗频偏性能评估。深度学习在无线通信中,尤其在OFDM的信道估计问题上展现潜力,解决了传统方法的局限。程序涉及信道估计器设计,深度学习模型通过学习导频信息估计信道响应,适应频域变化。核心代码展示了信号处理流程,包括编码、调制、信道模拟、降噪、信道估计和解调。
30 8
|
10天前
|
算法
基于GA遗传优化的混合发电系统优化配置算法matlab仿真
**摘要:** 该研究利用遗传算法(GA)对混合发电系统进行优化配置,旨在最小化风能、太阳能及电池储能的成本并提升系统性能。MATLAB 2022a用于实现这一算法。仿真结果展示了一系列图表,包括总成本随代数变化、最佳适应度随代数变化,以及不同数据的分布情况,如负荷、风速、太阳辐射、弃电、缺电和电池状态等。此外,代码示例展示了如何运用GA求解,并绘制了发电单元的功率输出和年变化。该系统原理基于GA的自然选择和遗传原理,通过染色体编码、初始种群生成、适应度函数、选择、交叉和变异操作来寻找最优容量配置,以平衡成本、效率和可靠性。
|
2天前
|
算法 vr&ar
基于自适应波束成形算法的matlab性能仿真,对比SG和RLS两种方法
```markdown - MATLAB2022a中比较SG与RLS自适应波束成形算法。核心程序实现阵列信号处理,强化期望信号,抑制干扰。RLS以其高效计算权重,而SG则以简单和低计算复杂度著称。[12345] [6666666666] [777777] ```
|
3天前
|
算法 索引
基于Prony算法的系统参数辨识matlab仿真
Prony算法在MATLAB2022a中用于信号分析,识别复指数信号成分。核心程序通过模拟信号X1,添加不同SNR的噪声,应用Prony方法处理并计算误差。算法基于离散序列的复指数叠加模型,通过构建矩阵并解线性方程组估计参数,实现LTI系统动态特性的辨识。
|
11天前
|
机器学习/深度学习 算法
基于鲸鱼优化的knn分类特征选择算法matlab仿真
**基于WOA的KNN特征选择算法摘要** 该研究提出了一种融合鲸鱼优化算法(WOA)与K近邻(KNN)分类器的特征选择方法,旨在提升KNN的分类精度。在MATLAB2022a中实现,WOA负责优化特征子集,通过模拟鲸鱼捕食行为的螺旋式和包围策略搜索最佳特征。KNN则用于评估特征子集的性能。算法流程包括WOA参数初始化、特征二进制编码、适应度函数定义(以分类准确率为基准)、WOA迭代搜索及最优解输出。该方法有效地结合了启发式搜索与机器学习,优化特征选择,提高分类性能。
|
6天前
|
机器学习/深度学习 存储 算法
基于SFLA算法的神经网络优化matlab仿真
**摘要:** 使用MATLAB2022a,基于SFLA算法优化神经网络,降低训练误差。程序创建12个神经元的前馈网络,训练后计算性能。SFLA算法寻找最优权重和偏置,更新网络并展示训练与测试集的预测效果,以及误差对比。SFLA融合蛙跳与遗传算法,通过迭代和局部全局搜索改善网络性能。通过调整算法参数和与其他优化算法结合,可进一步提升模型预测精度。