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
文章知识点与