基于System-Verilog的FPGA设计超声波测距

实验原理
理论原理
超声波原理:
HC-SR04超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。图1为HC-SR04外观,其基本工作原理为给予此超声波测距模块触发信号后模块发射超声波,当超声波投射到物体而反射回来时,模块输出回响信号,以触发信号和回响信号间的时间差,来判定物体的距离。

                               

硬件时序模块

系统架构设计

模块说明

这里要求超声波模块的正负极分别接入5V和GND,其余trigger和echo自由接线,我这里使用的是GPIO[0]和GPIO[1]

设计文件

Trig.sv

module Trig(
	input  logic		clk_us	, //system clock 1MHz
	input  logic		rst_n	, //reset ,low valid	   
	output logic 		trig	  //触发测距信号
);
//Parameter Declarations
	parameter CYCLE_MAX = 19'd300_000;

//Interrnal wire/reg declarations
	logic	[18:00]	cnt		; //Counter 
	logic			add_cnt ; //Counter Enable
	logic			end_cnt ; //Counter Reset 

//Logic Description	
	
	always @(posedge clk_us or negedge rst_n)begin  
		if(!rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CYCLE_MAX - 9'd1; 
	
	assign trig = cnt < 15 ? 1'b1 : 1'b0;

endmodule 

clk_us.sv

module 	clk_us(
	input  logic		clk	, //system clock 50MHz
	input  logic		rst_n	, //reset ,low valid	   
	output logic 		clk_us 	  //
);
//Parameter Declarations
	parameter CNT_MAX = 19'd50;//1us的计数值为 50 * Tclk(20ns)

//Interrnal wire/reg declarations
	logic	[5:00]	cnt		; //Counter 
	logic			add_cnt ; //Counter Enable
	logic			end_cnt ; //Counter Reset 
	
//Logic Description
	
	always @(posedge clk or negedge rst_n)begin  
		if(!rst_n)begin  
			cnt <= 'd0; 
		end  
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= 'd0; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  
			cnt <= cnt;  
		end  
	end 
	
	assign add_cnt = 1'b1; 
	assign end_cnt = add_cnt && cnt >= CNT_MAX - 19'd1;
	
	assign clk_us = end_cnt;
	

endmodule 

Echo.sv

module 	Echo(
	input logic 		clk		, //clock 50MHz
	input logic			clk_us	, //system clock 1MHz
	input logic 		rst_n	, //reset ,low valid  
	input logic 		echo	, //
	output logic [18:00]	data_o	  //检测距离,保留3位小数,*1000实现
);
/* 		S(um) = 17 * t 		-->  x.abc cm	*/
//Parameter Declarations
	parameter T_MAX = 16'd60_000;//510cm 对应计数值

//Interrnal wire/reg declarations
	logic			r1_echo,r2_echo; //边沿检测	
	logic			echo_pos,echo_neg; //
	
	logic	[15:00]	cnt		; //Counter 
	logic			add_cnt ; //Counter Enable
	logic			end_cnt ; //Counter Reset 

	logic	[18:00]	data_r	;
//Logic Description
	//如果使用clk_us 检测边沿,延时2us,差值过大
	always @(posedge clk or negedge rst_n)begin  
		if(!rst_n)begin  
			r1_echo <= 1'b0;
			r2_echo <= 1'b0;
		end  
		else begin  
			r1_echo <= echo;
			r2_echo <= r1_echo;
		end  
	end
	
	assign echo_pos = r1_echo & ~r2_echo;
	assign echo_neg = ~r1_echo & r2_echo;
	
	
	always @(posedge clk_us or negedge rst_n)begin  
		if(!rst_n)begin  
			cnt <= 'd0; 
		end 
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= cnt; 
			end  
			else begin  
				cnt <= cnt + 1'b1; 
			end  
		end  
		else begin  //echo 低电平 归零
			cnt <= 'd0;  
		end  
	end 
	
	assign add_cnt = echo; 
	assign end_cnt = add_cnt && cnt >= T_MAX - 1; //超出最大测量范围则保持不变,极限
	
	always @(posedge clk or negedge rst_n)begin  
		if(!rst_n)begin  
			data_r <= 'd2;
		end  
		else if(echo_neg)begin  
			data_r <= (cnt << 4) + cnt;
		end  
		else begin  
			data_r <= data_r;
		end  
	end //always end
	
	assign data_o = data_r >> 1;

endmodule 

seg.sv

module seg(
    input   logic        clk     ,
    input   logic        rst_n   ,
    input   logic [18:0] data_o  ,
    output  logic [6:0]  hex1    ,
    output  logic [6:0]  hex2    ,
    output  logic [6:0]  hex3    ,
    output  logic [6:0]  hex4    ,
    output  logic [6:0]  hex5    ,
    output  logic [6:0]  hex6    ,
    output  logic [6:0]  hex7    ,
    output  logic [6:0]  hex8     
);

parameter   NOTION  = 4'd10,
            FUSHU   = 4'd11;
parameter   MAX20us = 10'd1000;
logic [9:0]   cnt_20us;
logic [7:0]   sel_r;
logic [3:0]   number;
logic [6:0]   seg_r;
logic [6:0]   hex1_r;
logic [6:0]   hex2_r;
logic [6:0]   hex3_r;
logic [6:0]   hex4_r;
logic [6:0]   hex5_r;
logic [6:0]   hex6_r;
logic [6:0]   hex7_r;
logic [6:0]   hex8_r;



//20微妙计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_20us <= 10'd0;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        cnt_20us <= 10'd0;
    end
    else begin
        cnt_20us <= cnt_20us + 1'd1;
    end
end



//单个信号sel_r位拼接约束
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sel_r <= 8'b11_11_11_10;
    end
    else if (cnt_20us == MAX20us - 1'd1) begin
        sel_r <= {sel_r[6:0],sel_r[7]};
    end
    else begin
        sel_r <= sel_r;
    end
end

/*拿到数字*/
always @(*) begin
    case (sel_r)
        8'b11_11_11_10:     number  = NOTION                                        ;
        8'b11_11_11_01:     number  = data_o/10_0000                                ;
        8'b11_11_10_11:     number  = (data_o%10_0000)/1_0000                       ;
        8'b11_11_01_11:     number  = ((data_o%10_0000)%1_0000)/1000                ;
        8'b11_10_11_11:     number  = FUSHU                                         ;
        8'b11_01_11_11:     number  = (((data_o%10_0000)%1_0000)%1000)/100          ;
        8'b10_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)/10     ;
        8'b01_11_11_11:     number  = ((((data_o%10_0000)%1_0000)%1000)%100)%10     ;
        default:            number  = 4'd0                                          ;
    endcase
end

/*通过数字解析出seg值*/
always @(*) begin
    case (number)
        4'd0    :       seg_r   =  7'b100_0000;
        4'd1    :       seg_r   =  7'b111_1001;
        4'd2    :       seg_r   =  7'b010_0100;
        4'd3    :       seg_r   =  7'b011_0000;
        4'd4    :       seg_r   =  7'b001_1001;
        4'd5    :       seg_r   =  7'b001_0010;
        4'd6    :       seg_r   =  7'b000_0010;
        4'd7    :       seg_r   =  7'b111_1000;
        4'd8    :       seg_r   =  7'b000_0000;
        4'd9    :       seg_r   =  7'b001_0000;
        NOTION  :       seg_r   =  7'b111_1111;
        FUSHU   :       seg_r   =  7'b011_1111;
        default :       seg_r   =  7'b111_1111;
    endcase
end

always @(*) begin
    case (sel_r)
		8'b11_11_11_10:     hex1_r = seg_r;
		8'b11_11_11_01:     hex2_r = seg_r;
		8'b11_11_10_11:     hex3_r = seg_r;
		8'b11_11_01_11:     hex4_r = seg_r;
		8'b11_10_11_11:     hex5_r = seg_r;
		8'b11_01_11_11:     hex6_r = seg_r;
		8'b10_11_11_11:     hex7_r = seg_r;
		8'b01_11_11_11:     hex8_r = seg_r;
		default:            seg_r  = seg_r;
	endcase
end

assign  hex1 = hex1_r;
assign  hex2 = hex2_r;
assign  hex3 = hex3_r;
assign  hex4 = hex4_r;
assign  hex5 = hex5_r;
assign  hex6 = hex6_r;
assign  hex7 = hex7_r;
assign  hex8 = hex8_r;

endmodule

LED.sv

module LED(
    input   logic clk,
    input   logic rst_n,
    input   logic [18:0]dis,
    output  logic  [3:0]led
);


logic [6:0]an;
logic [6:0]bn;


assign an=(dis%10_0000)/1_0000;
assign bn=((dis%10_0000)%1_0000)/1000 ; 
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        led<=4'b0000;
    end
    else if((an*10+bn)<20&&(an*10+bn)>=10)begin
        led<=4'b0001;
end
    else if((an*10+bn)<10)begin
        led<=4'b0011;
    end
        else if((an*10+bn)>20)begin
        led<=4'b0111;
    end
    else begin
        led<=4'b1111;
    end
end
endmodule

top.sv

module top (
    input   logic       clk    ,
    input   logic       rst_n  ,
    input   logic       echo    ,
    output  logic       [3:0]led,
    output  logic       trig    , 

    output  logic [6:0]  hex1    ,
    output  logic [6:0]  hex2    ,
    output  logic [6:0]  hex3    ,
    output  logic [6:0]  hex4    ,
    output  logic [6:0]  hex5    ,
    output  logic [6:0]  hex6    ,
    output  logic [6:0]  hex7    ,
    output  logic [6:0]  hex8   
);

wire    [18:0]  data_o;

Trig inster_Trig(
.clk_us	   (clk_us	), //system clock 1MHz
.rst_n	   (rst_n	), //reset ,low valid
.trig	   (trig	)  //触发测距信号
);


clk_us  insert_clk_us(
.clk	    (clk	),
.rst_n	    (rst_n),
.clk_us     (clk_us)	 
);

Echo 	inster_Echo(
.clk	     (clk    	),
.clk_us	     (clk_us	),
.rst_n	     (rst_n  	),  
.echo	     (echo	    ), 
.data_o	     (data_o	) 
);

LED inster_LED(
.clk       (clk  ) ,
.rst_n     (rst_n) ,
.dis       (data_o ) ,
.led       (led  ) 
);

seg inster_seg(
   .clk    (clk   ) ,
   .rst_n  (rst_n ) ,
   .data_o (data_o) ,
   .hex1   (hex1)   ,
   .hex2   (hex2)   ,
   .hex3   (hex3)   ,
   .hex4   (hex4)   ,
   .hex5   (hex5 )  ,
   .hex6   (hex6 )  ,
   .hex7   (hex7 )  ,
   .hex8   (hex8 )  
);
endmodule

上板

首先这里提出引脚配置,其中trig和echo引脚与自己所接线的位置向同即可

可见所测距离与实际距离一致,可见功能基本实现。

当所测距离小于10cm时,亮两个led灯,当距离大于20cm时亮3个led灯,当距离大于10小于20cm时,亮一个led灯。

总结

本次实验借用了一些学长的代码,也带有自己的一些思考,补全了学长没有写进代码的部分。能够自己补全一部分代码,对于我来说还是很有成就感的,同时熟悉了System-Verilog语法。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值