基于FPGA的实时图像边缘检测系统设计(下)
今天给大侠带来基于FPGA的实时图像边缘检测系统设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,话不多说,上货。
导读
随着科学技术的高速发展,FPGA在系统结构上为数字图像处理带来了新的契机。图像中的信息并行存在,因此可以并行对其施以相同的操作,使得图像处理的速度大大提高,这正好适合映射到FPGA架构中用硬件算法得以实现。
本篇阐述了基于FPGA设计一个能够实时采集、实时处理并实时显示的数字图像处理系统的设计思想和流程,分析了摄像头接口的时序;阐述了图像信息的捕获原理;详细介绍了图像边缘检测部分各模块的功能;重点介绍了具有去噪功能的中值滤波模块的设计;简单描述了边缘检测算子的选用;系统的介绍了SDRAM的工作原理以及控制方式;介绍了VGA时序;最后针对整个系统做了验证和总结,包括仿真波形的验证以及板级验证。
该系统基于实体FPGA开发板实现了图像数据的实时采集、实时边缘检测和实时显示,运行稳定,实时性能较高,从而也表明FPGA确实具有海量数据高速传输的能力。
本篇为本人当年的毕业设计部分整理,各位大侠可依据自己的需要进行阅读,参考学习。
第三篇内容摘要:本篇会介绍系统验证、结论以及各个模块主要代码,包括图像实时采集模块的主要代码,图像实时捕获模块的主要代码,中值滤波模块的主要代码,边缘检测模块的主要代码,图像缓存模块的主要代码,图像实时显示模块的主要代码等相关内容。
五、系统验证
在本系统设计过程中,我以自顶向下的层次化设计思想为主进行系统的顶层架构设计,明确各模块的功能以及各模块之间的握手关系,之后分模块编写代码并加以验证,调试代码使得各模块功能得以实现,最后基于顶层模块进行仿真验证,如图5-1和5-2为系统顶层模块的仿真波形,其中图5-1为全局波形,图5-2为局部放大的波形。
图5-1 系统顶层模块的全局仿真波形
图5-2 系统顶层模块的局部仿真波形
随后连接FPGA开发实验板并更新其驱动程序,按照开发板的配置文件分配引脚,全编译通过后下板进行板级测试。本系统验证时所采用的开发板是实体FPGA开发板。
实体FPGA开发板采用的是Altera Cyclone IV代系列的EP4CE10E22C8N芯片。该开发板是一款FPGA图像开发板,其核心芯片EP4CE10E22C8N拥有6272个逻辑单元和150个IO引脚,开发板上配置有VGA、USB、CMOS接口、SDRAM、按键、LED等很多种外部设备,可以作为本系统设计验证的硬件工具。
实体FPGA开发板的主要参数如下表6-1所示。
表5-1 FPGA开发板的主要参数
下板结果表明我所设计的数字图像边缘检测系统的功能已经实现,能够实时采集图像、实时处理并实时显示,这里截取的是图片,现实场景显示可以根据摄像头的移动实时显示。
六、结论
本系统设计中,我基于FPGA驱动的主要设备如下:型号为Ov7725的摄像头;具有通用性的VGA接口。同时,我研究了相关的边缘检测算法,为了数据处理结果更加准确,我还根据系统需要进行了图像数据的预处理操作:先将彩色图像转换成为灰度文件;接着采用中值滤波技术对采集到的图像数据进行了有效去噪。通过本系统的设计,我深刻理解了基于FPGA驱动外部设备的基本原理,掌握了基于FPGA、运用Verilog语言驱动外部设备和实现算法的能力,感受到了FPGA的先进,也进一步确定了自己的发展方向。在进行系统验证时,基于FPGA开发板实现了图像数据的实时采集、实时边缘检测和实时显示,系统性能良好,实时性能较高,结果证明FPGA能够轻松实现海量数据的高速传输。
附:部分主要代码
图像实时采集模块的主要代码:
代码语言:javascript复制1 module sccb_config_ctrl(
2 clk, //24Mhz输入时钟
3 rst_n, //系统复位
4 scl, //iic的时钟线
5 sda, //iic的数据线
6 config_done //配置完成标志
7 );
8 //系统输入
9 input clk; //外部输入时钟24Mhz
10 input rst_n; //系统复位
11 //系统输出
12 output reg scl; //iic的时钟线
13 output reg config_done; //配置完成标志
14
15
16 inout sda; //iic的数据线
17
18 reg sda_buffer; //写入数据的中间寄存器
19 reg flag; //控制系统是否占有总线控制权
20 reg [7:0] lut_cnt; //指针寄存器计数器
21 reg [15:0] lut_data; //寄存器地址和配置数据
22 reg [3:0] s;
23
24 assign sda = (flag) ? sda_buffer : 1'bz;//当flag为高电平时,系统拥有总线控制权
25 //并发送sda_buffer中的数据。当flag为低电平时,
26 //释放总线。
27
28 //----------延时1ms计数器-----------------
29 reg [31:0] delay_cnt;
30 reg delay_done;
31
32 always @ (posedge clk or negedge rst_n)
33 begin
34 if(!rst_n)
35 begin
36 delay_done <= 0;
37 delay_cnt <= 0;
38 end
39 else if(delay_cnt == 20000) //23809
40 delay_done <= 1;
41 else
42 begin
43 delay_cnt <= delay_cnt 1;
44 delay_done <= 0;
45 end
46 end
47
48 //----------------分频产生400Khz时钟clk_sys----------
49 reg [7:0] count;//计数器
50 reg clk_sys;//系统时钟
51 reg [5:0] state;//状态寄存器
52
53 always @ (posedge clk or negedge rst_n)
54 begin
55 if (!rst_n)
56 begin
57 clk_sys <= 1'b1;
58 count <= 8'd0;
59 end
60 else
61 if (count < 100)//分频成为近200K的时钟
62 count <= count 1;
63 else
64 begin
65 count <= 8'd0;
66 clk_sys <= ~clk_sys;
67 end
68 end
69
70 //------------------输出scl-------------
71 always @ (negedge clk_sys or negedge rst_n)
72 begin
73 if (!rst_n)
74 begin
75 scl <= 1'b1;//复位时,scl为高
76 end
77 else
78 begin
79 if(config_done == 1 || delay_done == 0)//当总线忙的时候,scl为近400K的时钟
80 scl <= 1;
81 else
82 scl <= ~scl;//空闲时,scl为高
83 end
84 end
85
86 reg [3:0] cnt;//发送或者接收数据的个数
87 reg [15:0] memory;//发送或者接受数据的中间寄存器
88
89 always @ (posedge clk_sys or negedge rst_n)
90 begin
91 if (!rst_n)
92 begin
93 config_done <= 0;
94 flag <= 1'b1; //复位时,系统获得总线的控制权
95 sda_buffer <= 1'b1; //向iic的数据线上发送高电平
96 state <= 0;
97 cnt <= 0;
98 memory <= 16'd0;
99 lut_cnt <= 2;
100 s <= 0;
101 end
102 else
103 case(state)
104 0 :if(scl)
105 begin
106 if(delay_done)//延时标志信号拉高
107 begin
108 sda_buffer <= 1'b0; //发送启动信号
109 state <= 1;
110 memory <= 16'h0042;//准备ID地址
111 end
112 else
113 state <= 0;
114 end
115 else
116 state <= 0;
117
118 1 :if((scl == 0) && (cnt < 8))//发送ID地址
119 begin
120 sda_buffer <= memory[7];
121 cnt <= cnt 1;
122 memory = {memory[14:0],memory[15]};
123 state <= 1;
124 end
125 else
126 begin
127 if ((scl == 0) && (cnt == 8))
128 begin
129 cnt <= 0;
130 flag <= 0;//释放总线控制权
131 state <= 2;
132 end
133 else
134 begin
135 state <= 1;
136 end
137 end
138
139 2 :
140 if(scl)//在SCL高电平期间接收数据
141 begin
142 if(!sda)//检测应答信号
143 begin
144 state <= 3;
145 memory <= lut_data;//指针寄存器地址
146 end
147 else
148 begin
149 state <= 0;
150 end
151 end
152 else
153 state <= 2;
154
155 3 : if((scl == 0) && (cnt < 8)) //发送指针寄存器地址
156 begin
157 flag <= 1;//获得总线控制权
158 sda_buffer <= memory[15];
159 cnt <= cnt 1;
160 memory = {memory[14:0],memory[15]};
161 state <= 3;
162 end
163 else
164 begin
165 if ((scl == 0) && (cnt == 8))
166 begin
167 cnt <= 0;
168 flag <= 0;//释放总线控制权
169 state <= 4;
170 end
171 else
172 begin
173 state <= 3;
174 end
175 end
176
177 4 :
178 if(scl)
179 begin
180 if(!sda)//检测应答信号
181 begin
182 state <= 5;
183 end
184 else
185 begin
186 state <= 0;
187 end
188 end
189
190 5 : if((scl == 0) && (cnt < 8))//发送八位控制字
191 begin
192 flag <= 1; //获得总线控制权
193 sda_buffer <= memory[15];
194 cnt <= cnt 1;
195 memory <= {memory[14:0],memory[15]};
196 state <= 5;
197 end
198 else
199 begin
200 if ((scl == 0) && (cnt == 8))
201 begin
202 cnt <= 0;
203 flag <= 0; //释放总线控制权
204 state <= 6;
205 lut_cnt <= lut_cnt 1; //指针寄存器 1
206 end
207 else
208 begin
209 state <= 5;
210 end
211 end
212
213 6 :
214 if(scl) //在SCL高电平期间,接收ACK
215 begin
216 if(!sda)//检测应答信号
217 begin
218 state <= 7;
219 end
220 else
221 begin
222 state <= 0;
223 end
224 end
225
226 7 : if (scl == 0)
227 begin
228 flag <= 1;
229 sda_buffer <= 0;//拉低数据线(为发送停止信号做准备)
230 state <= 8;
231 end
232 else
233 state <= 7;
234
235 8 : if (scl == 1) //发送停止信号
236 begin
237 sda_buffer <= 1;
238 begin
239 if (s == 8)
240 begin
241 if(lut_cnt < 70)
242 begin
243 state <= 0;
244 s <= 0;
245 end
246 else
247 config_done <= 1; //配置完成
248 end
249 else
250 s <= s 1;
251 end
252 end
253 else
254 state <= 8;
255
256 default : state <= 0;
257 endcase
258 end
259
260 always @ (*)
261 begin
262 case (lut_cnt)
263 // OV7725 : VGA RGB565 Config
264 //Read Data Index
265 // 0 : LUT_DATA = {8'h0A, 8'h77}; //Product ID Number MSB (Read only)
266 // 1 : LUT_DATA = {8'h0B, 8'h21}; //Product ID Number LSB (Read only)
267 0 : lut_data = {8'h1C, 8'h7F}; //Manufacturer ID Byte - High (Read only)
268 1 : lut_data = {8'h1D, 8'hA2}; //Manufacturer ID Byte - Low (Read only)
269 //Write Data Index
270 2 : lut_data = {8'h12, 8'h80}; // BIT[7]-Reset all the Reg
271 3 : lut_data = {8'h3d, 8'h03}; //DC offset for analog process
272 4 : lut_data = {8'h15, 8'h02}; //COM10: href/vsync/pclk/data reverse(Vsync H valid)
273 5 : lut_data = {8'h17, 8'h22}; //VGA: 8'h22; QVGA: 8'h3f;
274 6 : lut_data = {8'h18, 8'ha4}; //VGA: 8'ha4; QVGA: 8'h50;
275 7 : lut_data = {8'h19, 8'h07}; //VGA: 8'h07; QVGA: 8'h03;
276 8 : lut_data = {8'h1a, 8'hf0}; //VGA: 8'hf0; QVGA: 8'h78;
277 9 : lut_data = {8'h32, 8'h00}; //HREF / 8'h80
278 10 : lut_data = {8'h29, 8'hA0}; //VGA: 8'hA0; QVGA: 8'hF0
279 11 : lut_data = {8'h2C, 8'hF0}; //VGA: 8'hF0; QVGA: 8'h78
280 //如果不使用内部PLL,这个命令是无效的
281 12 : lut_data = {8'h0d, 8'h41}; //Bypass PLL 00:0 01:4x 10:6x 11:8x
282 13 : lut_data = {8'h11, 8'h01}; //CLKRC,Finternal clock = Finput clk*PLL multiplier/[(CLKRC[5:0] 1)*2] = 25MHz*4/[(x 1)*2]
283 //00: 50fps, 01:25fps, 03:12.5fps (50Hz Fliter)
284 14 : lut_data = {8'h12, 8'h06}; //BIT[6]: 0:VGA; 1;QVGA
285 //BIT[3:2]: 01:RGB565
286 //VGA: 00:YUV; 01:Processed Bayer RGB; 10:RGB; 11:Bayer RAW; BIT[7]-Reset all the Reg
287 15 : lut_data = {8'h0C, 8'h10}; //COM3: Bit[7:6]:Vertical/Horizontal mirror image ON/OFF, Bit[0]:Color bar; Default:8'h10
288 //DSP control
289 16 : lut_data = {8'h42, 8'h7f}; //BLC Blue Channel Target Value, Default: 8'h80
290 17 : lut_data = {8'h4d, 8'h09}; //BLC Red Channel Target Value, Default: 8'h80
291 18 : lut_data = {8'h63, 8'hf0}; //AWB Control
292 19 : lut_data = {8'h64, 8'hff}; //DSP_Ctrl1:
293 20 : lut_data = {8'h65, 8'h00}; //DSP_Ctrl2:
294 21 : lut_data = {8'h66, 8'h00}; //{COM3[4](0x0C), DSP_Ctrl3[7]}:00:YUYV; 01:YVYU; [10:UYVY] 11:VYUY
295 22 : lut_data = {8'h67, 8'h00}; //DSP_Ctrl4:00/01: YUV or RGB; 10: RAW8; 11: RAW10
296 //AGC AEC AWB
297 23 : lut_data = {8'h13, 8'hff};
298 24 : lut_data = {8'h0f, 8'hc5};
299 25 : lut_data = {8'h14, 8'h11};
300 26 : lut_data = {8'h22, 8'h98}; //Banding Filt er Minimum AEC Value; Default: 8'h09
301 27 : lut_data = {8'h23, 8'h03}; //Banding Filter Maximum Step
302 28 : lut_data = {8'h24, 8'h40}; //AGC/AEC - Stable Operating Region (Upper Limit)
303 29 : lut_data = {8'h25, 8'h30}; //AGC/AEC - Stable Operating Region (Lower Limit)
304 30 : lut_data = {8'h26, 8'ha1}; //AGC/AEC Fast Mode Operating Region
305 31 : lut_data = {8'h2b, 8'h9e}; //TaiWan: 8'h00:60Hz Filter; Mainland: 8'h9e:50Hz Filter
306 32 : lut_data = {8'h6b, 8'haa}; //AWB Control 3
307 33 : lut_data = {8'h13, 8'hff}; //8'hff: AGC AEC AWB Enable; 8'hf0: AGC AEC AWB Disable;
308 //matrix sharpness brightness contrast UV
309 34 : lut_data = {8'h90, 8'h0a};
310 35 : lut_data = {8'h91, 8'h01};
311 36 : lut_data = {8'h92, 8'h01};
312 37 : lut_data = {8'h93, 8'h01};
313 38 : lut_data = {8'h94, 8'h5f};
314 39 : lut_data = {8'h95, 8'h53};
315 40 : lut_data = {8'h96, 8'h11};
316 41 : lut_data = {8'h97, 8'h1a};
317 42 : lut_data = {8'h98, 8'h3d};
318 43 : lut_data = {8'h99, 8'h5a};
319 44 : lut_data = {8'h9a, 8'h1e};
320 45 : lut_data = {8'h9b, 8'h3f}; //Brightness
321 46 : lut_data = {8'h9c, 8'h25};
322 47 : lut_data = {8'h9e, 8'h81};
323 48 : lut_data = {8'ha6, 8'h06};
324 49 : lut_data = {8'ha7, 8'h65};
325 50 : lut_data = {8'ha8, 8'h65};
326 51 : lut_data = {8'ha9, 8'h80};
327 52 : lut_data = {8'haa, 8'h80};
328 //Gamma correction
329 53 : lut_data = {8'h7e, 8'h0c};
330 54 : lut_data = {8'h7f, 8'h16}; //
331 55 : lut_data = {8'h80, 8'h2a};
332 56 : lut_data = {8'h81, 8'h4e};
333 57 : lut_data = {8'h82, 8'h61};
334 58 : lut_data = {8'h83, 8'h6f};
335 59 : lut_data = {8'h84, 8'h7b};
336 60 : lut_data = {8'h85, 8'h86};
337 61 : lut_data = {8'h86, 8'h8e};
338 62 : lut_data = {8'h87, 8'h97};
339 63 : lut_data = {8'h88, 8'ha4};
340 64 : lut_data = {8'h89, 8'haf};
341 65 : lut_data = {8'h8a, 8'hc5};
342 66 : lut_data = {8'h8b, 8'hd7};
343 67 : lut_data = {8'h8c, 8'he8};
344 68 : lut_data = {8'h8d, 8'h20};
345 //Others
346 69 : lut_data = {8'h0e, 8'h65};//night mode auto frame rate control
347 default : lut_data = {8'h1C, 8'h7F};
348 endcase
349 end
350
351 endmodule
图像实时捕获模块的主要代码:
代码语言:javascript复制1 module coms_capture_rgb565(clk_cmos, rst_n, pclk, vsync, href, din, xclk,
2 frame_data, frame_clk, frame_href, frame_vsync, cmos_fps_rate);
3
4 input clk_cmos; //24Mhz驱动时钟输入
5 input rst_n;
6 input pclk; //输入的像素时钟
7 input vsync; //输入场同步信号
8 input href; //输入的行同步信号
9 input [7:0] din; //输入的像素数据
10
11 output xclk; //输出的CMOS Sensor的驱动时钟 24Mhz
12 output frame_clk; //输出拼接后的像素数据的时钟
13 output [15:0] frame_data; //输出拼接后的像素数据
14 output frame_href; //输出同步的行同步信号
15 output frame_vsync; //输出同步的场同步信号
16 output reg cmos_fps_rate; //输出帧率
17
18 assign xclk = clk_cmos;
19
20 //-------------检测场、行同步信号------------
21 reg href_r, vsync_r;
22 always @(posedge pclk or negedge rst_n)
23 begin
24 if (!rst_n)
25 begin
26 href_r <= 1;
27 vsync_r <= 1;
28 end
29 else
30 begin
31 href_r <= href;
32 vsync_r <= vsync;
33 end
34 end
35 //行同步信号由低电平变为高电平时,说明数据有效
36 assign pose_href = (~href_r) & href;
37 //场同步信号由高电平变为低电平时,说明一帧数据接收完毕
38 assign nege_vsync = vsync_r & (~vsync);
39
40 //----------延时10帧产生一个标志编号----------
41 reg frame_cnt_end; //延时10帧数据结束标志
42 reg [3:0] frame_cnt; //帧计数器
43 always @(posedge pclk or negedge rst_n)
44 begin
45 if(!rst_n)
46 begin
47 frame_cnt <= 0;
48 frame_cnt_end <= 0;
49 end
50 else if (frame_cnt == 10)
51 frame_cnt_end <= 1;
52 else if(nege_vsync)
53 frame_cnt <= frame_cnt 1;
54 else
55 frame_cnt <= frame_cnt;
56 end
57
58 reg [15:0] din_buffer2;
59 reg [7:0] din_buffer1;
60 reg byte_flag;
61 reg [10:0] cnt;
62 always @(posedge pclk or negedge rst_n)
63 begin
64 if(!rst_n)
65 begin
66 byte_flag <= 0;
67 din_buffer1 <= 0;
68 din_buffer2 <= 0;
69 cnt <= 0;
70 end
71 else if(href)
72 begin
73 cnt <= cnt 1;
74 din_buffer1 <= din;
75 if(cnt >= 1278)
76 byte_flag <= 0;
77 else
78 byte_flag <= ~byte_flag;
79
80 if(byte_flag == 1)
81 din_buffer2 <= {din_buffer1,din};
82 else
83 din_buffer2 <= din_buffer2;
84 end
85 else
86 begin
87 byte_flag <= 0;
88 din_buffer1 <= 0;
89 din_buffer2 <= din_buffer2;
90 cnt <= 0;
91 end
92 end
93
94 reg byte_flag_r;
95 always@(posedge pclk or negedge rst_n)
96 begin
97 if(!rst_n)
98 byte_flag_r <= 0;
99 else
100 byte_flag_r <= byte_flag;
101 end
102
103 assign frame_data = frame_cnt_end & href ? din_buffer2 : 0;
104 assign frame_clk = frame_cnt_end ? byte_flag_r : 0;
105 assign frame_vsync = frame_cnt_end ? vsync_r : 1'b0;
106 assign frame_href = frame_cnt_end ? href_r : 1'b0;
107
108 reg [27:0] delay_cnt;
109 always@(posedge pclk or negedge rst_n)
110 begin
111 if(!rst_n)
112 delay_cnt <= 0;
113 else if(delay_cnt < 48000000 - 1'b1)
114 delay_cnt <= delay_cnt 1'b1;
115 else
116 delay_cnt <= 0;
117 end
118 wire delay_2s = (delay_cnt == 48000000 - 1'b1) ? 1'b1 : 1'b0;
119
120 reg [8:0] cmos_fps_cnt;
121 always @(posedge pclk or negedge rst_n)
122 begin
123 if(!rst_n)
124 begin
125 cmos_fps_cnt <= 0;
126 cmos_fps_rate <= 0;
127 end
128 else if(delay_2s == 1'b0)
129 begin
130 cmos_fps_cnt <= nege_vsync ? cmos_fps_cnt 1'b1 : cmos_fps_cnt;
131 cmos_fps_rate <= cmos_fps_rate;
132 end
133 else
134 begin
135 cmos_fps_cnt <= 0;
136 cmos_fps_rate <= cmos_fps_cnt[8:1];
137 end
138 end
139
140 endmodule
中值滤波模块的主要代码:
代码语言:javascript复制1 module zhongzhilvbo (clk, rst_n, data_in, fifo_empty, data_out, wrreq, rdreq);
2
3 input clk;
4 input rst_n;
5 input [23:0] data_in;
6 input fifo_empty;
7
8 output [7:0] data_out;
9 output reg wrreq;
10 output reg rdreq;
11
12 reg [7:0] data [8:0];
13 wire [7:0] data_n[8:0];
14 reg shift;
15
16 assign data_out = data_n[4];
17
18 always @ (posedge clk or negedge rst_n)
19 begin
20 if (!rst_n)
21 begin
22 data [8] <= 0;
23 data [7] <= 0;
24 data [6] <= 0;
25 data [5] <= 0;
26 data [4] <= 0;
27 data [3] <= 0;
28 data [2] <= 0;
29 data [1] <= 0;
30 data [0] <= 0;
31 end
32 else
33 begin
34 if (shift)
35 begin
36 data[8] <= data[5];
37 data[7] <= data[4];
38 data[6] <= data[3];
39 data[5] <= data[2];
40 data[4] <= data[1];
41 data[3] <= data[0];
42 data[2] <= data_in[23:16];
43 data[1] <= data_in[15:8];
44 data[0] <= data_in[7:0];
45 end
46 end
47 end
48
49 reg compara_rst_n;
50 genvar i;
51 reg [7:0] temp;
52 reg temp_rst_n;
53 reg [3:0] count;
54
55 always @ (posedge clk or negedge temp_rst_n)
56 begin
57 if (!temp_rst_n)
58 begin
59 temp <= data [8];
60 count <= 0;
61 end
62 else
63 begin
64 temp <= data[count];
65 count <= count 1;
66 end
67
68 end
69 generate
70 for (i = 0; i < 9; i = i 1)
71 begin : compara
72 if (i == 0)
73 begin
74 comparaer u1(.clk(clk), .rst_n(compara_rst_n), .ex_data(temp), .up_data(8'hff), .self_data(data_n[i]));
75 end
76 else
77 begin
78 comparaer comparaer(.clk(clk), .rst_n(compara_rst_n), .ex_data(temp), .up_data(data_n[i-1]), .self_data(data_n[i]));
79 end
80 end
81 endgenerate
82
83 reg [2:0] state;
84 reg [3:0] cnt;
85
86 always @ (posedge clk or negedge rst_n)
87 begin
88 if (!rst_n)
89 begin
90 rdreq <= 0;
91 compara_rst_n <= 0;
92 wrreq <= 0;
93 state <= 0;
94 shift <= 0;
95 cnt <= 0;
96 temp_rst_n <= 0;
97 end
98 else
99 begin
100 case (state)
101 0 : begin
102 if (fifo_empty)
103 begin
104 state <= 0;
105 wrreq <= 0;
106 compara_rst_n <= 0;
107 end
108 else
109 begin
110 state <= 1;
111 rdreq <= 1;
112 wrreq <= 0;
113 compara_rst_n <= 0;
114 end
115 end
116
117 1 : begin
118 rdreq <= 0;
119 shift <= 1;
120 state <= 2;
121 end
122
123 2 : begin
124 shift <= 0;
125 temp_rst_n <= 1;
126 state <= 3;
127 end
128
129 3 : begin
130 if (cnt < 8)
131 begin
132 cnt <= cnt 1;
133 compara_rst_n <= 1;
134 state <= 3;
135 end
136 else
137 begin
138 cnt <= 0;
139 temp_rst_n <= 0;
140 state <= 4;
141 end
142 end
143
144 4 : begin
145 wrreq <= 1;
146 state <= 0;
147 end
148
149 endcase
150 end
151 end
152 endmodule
边缘检测模块的主要代码:
代码语言:javascript复制1 module sob (clk, rst_n, data, result, fifo_wr, shift_en);
2
3 input clk;
4 input rst_n;
5 input [23:0] data;
6 input shift_en;
7
8 output reg [7:0] result;
9 output reg fifo_wr;
10
11
12 reg [7:0] O[-1:1][-1:1];
13 reg signed [10:0] Dx, Dy;
14
15 function [10:0] abs ( input signed [10:0] x);
16 abs = x >=0 ? x : -x ; // 取x的绝对值
17 endfunction
18
19 always @ (posedge clk or negedge rst_n)
20 begin
21 if (!rst_n)
22 begin
23 result <= 8'd0;
24 Dx <= 0;
25 Dy <= 0;
26 end
27 else
28 begin
29 if ( shift_en )
30 begin
31 result <= (abs(Dx) abs(Dy))>>3 ;// 右移三位实现除以8的运算
32 Dx <= -$signed({3'b000, O[-1][-1]}) //-1* O[-1][-1]
33 $signed({3'b000, O[-1][ 1]}) // 1* O[-1][ 1]
34 -($signed({3'b000, O[ 0][-1]}) //-2* O[ 0][-1]
35 <<1)
36 ($signed({3'b000, O[ 0][ 1]}) // 2* O[ 0][ 1]
37 <<1)
38 -$signed({3'b000, O[ 1][-1]}) //-1* O[ 1][-1]
39 $signed({3'b000, O[ 1][ 1]}); // 1* O[ 1][ 1]
40 Dy <= $signed({3'b000, O[-1][-1]}) // 1* O[-1][-1]
41 ($signed({3'b000, O[-1][ 0]}) // 2* O[-1][0]
42 <<1)
43 $signed({3'b000, O[-1][ 1]}) // 1* O[-1][ 1]
44 -$signed({3'b000, O[ 1][-1]})//-1* O[ 1][-1]
45 -($signed({3'b000, O[ 1][ 0]}) //-2* O[ 1][ 0]
46 <<1)
47 -$signed({3'b000, O[ 1][ 1]}); //-1* O[ 1][ 1]
48 O[-1][-1] <= O[-1][0];
49 O[-1][ 0] <= O[-1][ 1];
50 O[-1][ 1] <= data[23:16];
51 O[ 0][-1] <= O[0][0];
52 O[ 0][ 0] <= O[0][ 1];
53 O[ 0][ 1] <= data[15:8];
54 O[ 1][-1] <= O[ 1][0];
55 O[ 1][ 0] <= O[ 1][ 1];
56 O[ 1][ 1] <= data[7:0];
57 end
58 end
59 end
60
61
62
63 reg [2:0] state;
64
65 always @ (posedge clk or negedge rst_n)
66 begin
67 if (!rst_n)
68 begin
69 fifo_wr <= 1'b0;
70 state <= 0;
71 end
72 else
73 begin
74 case (state)
75 0 : begin
76 if (shift_en)
77 begin
78 state <= 2;
79 fifo_wr <= 0;
80 end
81 else
82 begin
83 state <= 0;
84 fifo_wr <= 0;
85 end
86 end
87
88 1 : begin
89 if (shift_en)
90 begin
91 fifo_wr <= 1'b1;
92 end
93 else
94 fifo_wr <= 0;
95 end
96
97 2 : state <= 3;
98
99 3 : state <= 4;
100
101 4 : state <= 1;
102
103 default : state <= 0;
104
105 endcase
106 end
107 end
108
109 endmodule
图像缓存模块的主要代码:
代码语言:javascript复制1 `include "sdram_head.v"
2
3 module sdr_fsm(soft_rst_n, sys_clk, init_done, ref_done, rd_done, wr_done, ref_time, mux_sel,
4 init_rst_n, ref_rst_n, rd_rst_n, wr_rst_n, time_rst_n, int_addr,
5 local_rdreq, local_wrreq, local_ready,wr_ddr,rd_ddr,rd_finish, wr_finish,local_finish);
6
7 input soft_rst_n;
8 input sys_clk;
9 input init_done;
10 input ref_done;
11 input rd_done;
12 input wr_done;
13 input [9:0] ref_time;
14 input [24:0] wr_ddr;
15 input [24:0] rd_ddr;
16
17 // input [24:0] local_addr;
18 // output reg [31:0] local_rdata;
19 // input [31:0] local_wdata;
20 input local_rdreq, local_wrreq;
21 output reg local_ready,local_finish;
22 output reg rd_finish;
23 output reg wr_finish;
24
25 output reg [1:0] mux_sel;
26 output reg init_rst_n;
27 output reg ref_rst_n;
28 output reg rd_rst_n;
29 output reg wr_rst_n;
30 output reg time_rst_n;
31 // output reg [31:0] wr_data;
32 output reg [24:0] int_addr;
33
34 localparam s0 = 3'b000;
35 localparam s1 = 3'b001;
36 localparam s2 = 3'b010;
37 localparam s3 = 3'b011;
38 localparam s4 = 3'b100;
39
40 reg [2:0] state;
41
42 reg rd,rd_en;
43
44 always @ (posedge sys_clk)
45 begin
46 if (!soft_rst_n)
47 begin
48 rd <= 0;
49 end
50 else
51 begin
52 if (local_rdreq && rd_en)
53 rd <= local_rdreq;
54 else
55 if (!rd_en)
56 rd <= 0;
57 else
58 rd <= rd;
59 end
60 end
61
62 reg wr,wr_en;
63
64 always @ (posedge sys_clk)
65 begin
66 if (!soft_rst_n)
67 begin
68 wr <= 0;
69 end
70 else
71 begin
72 if (local_wrreq && wr_en)
73 wr <= local_wrreq;
74 else
75 if (!wr_en)
76 wr <= 0;
77 else
78 wr <= wr;
79 end
80 end
81
82
83 always @ (posedge sys_clk)
84 begin
85 if (!soft_rst_n)
86 begin
87 mux_sel <= `INIT;
88 init_rst_n <= 0;
89 ref_rst_n <= 0;
90 wr_rst_n <= 0;
91 rd_rst_n <= 0;
92 time_rst_n <= 0;
93 state <= s0;
94 // local_rdata <= 32'd0;
95 local_ready <= 0;
96 rd_finish <= 0;
97 wr_finish <= 0;
98 // wr_data <= 32'd0;
99 int_addr <= 25'd0;
100 wr_en <= 1;
101 rd_en <= 1;
102 local_finish <= 0;
103 end
104 else
105 case (state)
106 s0 : if (!init_done)
107 init_rst_n <= 1;
108 else
109 begin
110 init_rst_n <= 0;
111 mux_sel <= `REF;
112 time_rst_n <= 1;
113 state <= s1;
114 local_ready <= 1;
115 wr_en <= 1;
116 rd_en <= 1;
117 end
118
119 s1 : if ((ref_time < `ctREFR) && (!wr) && (!rd))
120 state <= s1;
121 else if (rd)
122 begin
123 int_addr <= rd_ddr;
124 rd_rst_n <= 1;
125 mux_sel <= `READ;
126 local_ready <= 0;
127 rd_finish <= 0;
128 state <= s3;
129 rd_en <= 0;
130 end
131 else if (wr)
132 begin
133 int_addr <= wr_ddr;
134// wr_data <= local_wdata;
135 wr_rst_n <= 1;
136 mux_sel <= `WRITE;
137 local_ready <= 0;
138 wr_finish <= 0;
139 state <= s4;
140 wr_en <= 0;
141 end
142 else if (ref_time >= `ctREFR)
143 begin
144 ref_rst_n <= 1;
145 time_rst_n <= 0;
146 mux_sel <= `REF;
147 state <= s2;
148 local_ready <= 0;
149 local_finish <= 0;
150 end
151
152 s2 : if (!ref_done)
153 state <= s2;
154 else
155 begin
156 state <= s1;
157 time_rst_n <= 1;
158 ref_rst_n <= 0;
159 local_finish <= 1;
160 local_ready <= 1;
161 end
162
163 s3 : if (!rd_done)
164 state <= s3;
165 else
166 begin
167 local_ready <= 1;
168 rd_finish <= 1;
169 rd_rst_n <= 0;
170// local_rdata <= rd_data;
171 state <= s1;
172 rd_en <= 1;
173 end
174
175 s4 : if (!wr_done)
176 state <= s4;
177 else
178 begin
179 local_ready <= 1;
180 wr_finish <= 1;
181 wr_rst_n <= 0;
182 state <= s1;
183 wr_en <= 1;
184 end
185
186 default : state <= s0;
187 endcase
188 end
189 endmodule
图像实时显示模块的主要代码:
代码语言:javascript复制1 module lcd_driver
2 (
3 //global clock
4 input clk, //system clock
5 input rst_n, //sync reset
6
7 //lcd interface
8 output lcd_dclk, //lcd pixel clock
9 output lcd_blank, //lcd blank
10 output lcd_sync, //lcd sync
11 output lcd_hs, //lcd horizontal sync
12 output lcd_vs, //lcd vertical sync
13 output lcd_en, //lcd display enable
14 output [15:0] lcd_rgb, //lcd display data
15
16 //user interface
17 output lcd_request, //lcd data request
18 output [10:0] lcd_xpos, //lcd horizontal coordinate
19 output [10:0] lcd_ypos, //lcd vertical coordinate
20 input [15:0] lcd_data //lcd data
21);
22`include "lcd_para.v"
23
24/*******************************************
25 SYNC--BACK--DISP--FRONT
26*******************************************/
27//------------------------------------------
28//h_sync counter & generator
29 reg [10:0] hcnt;
30 always @ (posedge clk or negedge rst_n)
31 begin
32 if (!rst_n)
33 hcnt <= 11'd0;
34 else
35 begin
36 if(hcnt < `H_TOTAL - 1'b1) //line over
37 hcnt <= hcnt 1'b1;
38 else
39 hcnt <= 11'd0;
40 end
41 end
42 assign lcd_hs = (hcnt <= `H_SYNC - 1'b1) ? 1'b0 : 1'b1;
43
44//------------------------------------------
45//v_sync counter & generator
46 reg [10:0] vcnt;
47 always@(posedge clk or negedge rst_n)
48 begin
49 if (!rst_n)
50 vcnt <= 11'b0;
51 else if(hcnt == `H_TOTAL - 1'b1) //line over
52 begin
53 if(vcnt < `V_TOTAL - 1'b1) //frame over
54 vcnt <= vcnt 1'b1;
55 else
56 vcnt <= 11'd0;
57 end
58 end
59 assign lcd_vs = (vcnt <= `V_SYNC - 1'b1) ? 1'b0 : 1'b1;
60
61//------------------------------------------
62//LCELL LCELL(.in(clk),.out(lcd_dclk));
63 assign lcd_dclk = ~clk;
64 assign lcd_blank = lcd_hs & lcd_vs;
65 assign lcd_sync = 1'b0;
66
67//-----------------------------------------
68 assign lcd_en = (hcnt >= `H_SYNC `H_BACK && hcnt < `H_SYNC `H_BACK `H_DISP) &&
69 (vcnt >= `V_SYNC `V_BACK && vcnt < `V_SYNC `V_BACK `V_DISP)
70 ? 1'b1 : 1'b0;
71 assign lcd_rgb = lcd_en ? (lcd_data > 5) ? 16'd0 : 16'hffff : 16'd0;
72////assign lcd_rgb = lcd_en ? {lcd_data[10:6],lcd_data[10:5],lcd_data[10:6]} : 16'd0;
73//assign lcd_rgb = lcd_en ? {lcd_data[7:3],lcd_data[7:2],lcd_data[7:3]} : 16'd0;
74//assign lcd_rgb = lcd_en ? lcd_data : 16'd0;
75
76//------------------------------------------
77//ahead x clock
78 localparam H_AHEAD = 2'd1;
79 assign lcd_request = (hcnt >= `H_SYNC `H_BACK - H_AHEAD && hcnt < `H_SYNC `H_BACK `H_DISP - H_AHEAD) &&
80 (vcnt >= `V_SYNC `V_BACK && vcnt < `V_SYNC `V_BACK `V_DISP)
81 ? 1'b1 : 1'b0;
82//-----------------------------------------
83//lcd xpos & ypos
84 assign lcd_xpos = lcd_request ? (hcnt - (`H_SYNC `H_BACK - 1'b1)) : 11'd0;
85 assign lcd_ypos = lcd_request ? (vcnt - (`V_SYNC `V_BACK - 1'b1)) : 11'd0;
86 endmodule
本篇到此结束,基于FPGA的实时图像边缘检测系统设计介绍完毕,各位大侠,关注不迷路哦,有缘再见。
完
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!