第12周
前言
DE2-E115 FPGA开发板 + Quartus II + HC_SR04超声波检测模块
一、实验原理
超声波原理:
HC-SR04超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。图1为HC-SR04外观,其基本工作原理为给予此超声波测距模块触发信号后模块发射超声波,当超声波投射到物体而反射回来时,模块输出回响信号,以触发信号和回响信号间的时间差,来判定物体的距离。
HC-SR04超声波测距模块实物图:
超声波测距模块时序图:
系统结构设计:
二、代码
1.顶层模块
module top_Ranging(
input CLK_50M,
input RST,
//超声波测距用的端口
input wire Echo,
output Trig,
//数码管显示
output [6:0] seg_duan,
output [2:0] seg_sel
);
wire [15:0] data;
measurement U1(
.CLK_50M(CLK_50M),
.RST (RST),
.Echo (Echo),
.Trig (Trig) ,
.data(data)
);
display U2(
.CLK_50M (CLK_50M),
.RST (RST),
.data(data),
.seg_duan (seg_duan),
.seg_sel (seg_sel)
);
endmodule
2.测量模块
module measurement(
input CLK_50M,
input RST,
input Echo,
output reg Trig,
output [15:0] data
);
//Trig
reg [23:0] cnt_trig;
always @ (posedge CLK_50M or negedge RST)
begin
if(!RST)
cnt_trig<=1'b0;
else
if(cnt_trig =='d500) begin //高电平时间
Trig<=0;
cnt_trig<=cnt_trig+1'b1;
end
else
begin
if(cnt_trig=='d1_000_000)//低电平时间,两者加起来就是周期
begin
Trig<=1;
cnt_trig<=0;
end
else
cnt_trig<=cnt_trig+1'b1;
end
end
//检测上升沿下降沿
reg Echo_2,Echo_1,cnt_en,flag;
assign pose_Echo =(~Echo_2)&&Echo_1;//这里是表示上升下降沿的方法,可以细细品味一下,以后直接用就完事了
assign nege_Echo = Echo_2&&(~Echo_1);
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10;
reg[1:0] curr_state;
reg [15:0] cnt;
reg [15:0] dis_reg;
reg [15:0] cnt_17k;
always @ (posedge CLK_50M or negedge RST)
begin
if(!RST)
begin
Echo_1 <= 1'b0;
Echo_2 <= 1'b0;
cnt_17k <=1'b0;
dis_reg <=1'b0;
curr_state <= S0;
end
else
begin
Echo_1<=Echo;
Echo_2<=Echo_1;
case(curr_state)
S0:begin
if (pose_Echo)
curr_state <= S1;
else
begin
cnt <= 1'b0;
end
end
S1:begin
if(nege_Echo)
curr_state <= S2;
else
begin
if(cnt_17k <16'd2940)//这个是因为有小数,大致的17khz计数,不是最准确的,但是也很准了
begin
cnt_17k <= cnt_17k + 1'b1;
end
else
begin//下面大家可以看到,判断语句》=’d10咱们就进位,就不会出现例子的错误了,如果不在乎资源
//那么你简单的cnt++也可以试一试,只是后面要用到除法取位,后面数码管那边赋值不能跟我的方法一样了
cnt_17k <= 1'b0;
cnt[3:0] <= cnt[3:0] +1'b1;
end
if(cnt[3:0] >= 'd10)
begin
cnt [3:0] <=1'b0;
cnt [7:4]<=cnt[7:4]+1'b1;
end
if (cnt[7:4] >= 'd10)
begin
cnt[7:4]<=1'b0;
cnt[11:8]<=cnt[11:8]+1'b1;
end
if (cnt[11:8]>='d10)
begin
cnt[11:8]<=1'b0;
cnt[15:12]<=cnt[15:12]+1'b1;
end
if(cnt[15:12]>='d10)
begin
cnt[15:12]<=1'b0;
end
end
end
S2:begin
dis_reg<=cnt;
cnt <=1'b0;
curr_state <= S0;
end
endcase
end
end
assign data = dis_reg ; //对输出的data赋值,因为取的时钟频率是17Khz,340*T/2=170*(1/17000)*100=T单位是cm
endmodule
3.显示模块
module display(
input CLK_50M,
input RST,
input [15:0]data,
output reg [6:0]seg_duan,//显示器段选
output reg [2:0]seg_sel//显示器位选
);
reg [3:0] clk_cnt; // 时钟分频计数器
reg dri_clk; // 数码管的驱动时钟,5MHz
reg[3:0] scan_sel; //Scan select counter
reg[3:0] seg_data;
reg [15:0] num;
reg flag ; // 标志信号(标志着cnt0计数达1ms)
reg [2:0] cnt_sel; // 数码管位选计数器
reg [12:0] cnt0; // 数码管驱动时钟计数器
always @ (posedge CLK_50M or negedge RST)
begin
if(!RST) begin
clk_cnt <= 4'd0;
dri_clk <= 1'b1;
end
else if(clk_cnt ==4) begin
clk_cnt <= 4'd0;
dri_clk <= ~dri_clk;
end
else begin
clk_cnt <= clk_cnt + 1'b1;
dri_clk <= dri_clk;
end
end
always @ ( posedge dri_clk or negedge RST)
begin
if (!RST)
num<= 16'd0;
else
begin
num[15:12] <= data [15:12];
num[11:8] <= data[11:8] ;
num[7:4] <= data[7:4] ;
num[3:0] <= data [3:0];
end
end
always @ (posedge dri_clk or negedge RST) begin
if (RST == 1'b0) begin
cnt0 <= 13'b0;
flag <= 1'b0;
end
else if (cnt0 < 'd4999) begin
cnt0 <= cnt0 + 1'b1;
flag <= 1'b0;
end
else begin
cnt0 <= 13'b0;
flag <= 1'b1;
end
end
always @ (posedge dri_clk or negedge RST) begin
if (RST == 1'b0)
cnt_sel <= 3'b0;
else if(flag) begin
if(cnt_sel < 3'd3) //六位数码管轮流显示
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= 3'b0;
end
else
cnt_sel <= cnt_sel;
end
always@(posedge dri_clk or negedge RST)
begin
if(!RST)
begin
seg_sel <= 3'b111;
seg_data <= 4'd0;
end
else
begin
case(cnt_sel)
//first digital led
4'd0:
begin
seg_sel <= 3'b110;
seg_data <= num[3:0];
end
//second digital led
4'd1:
begin
seg_sel <= 3'b101;
seg_data <= num[7:4];
end
//...
4'd2:
begin
seg_sel <= 3'b011;
seg_data <= num[11:8];
end
default:
begin
seg_sel <= 3'b111;
seg_data <= 4'b0;
end
endcase
end
end
//七段译码器(显示器)
always@(*)
begin
case(seg_data)
//*共阳
'd0:seg_duan<=7'b1000000;
'd1:seg_duan<=7'b1111001;
'd2:seg_duan<=7'b0100100;
'd3:seg_duan<=7'b0110000;
'd4:seg_duan<=7'b0011001;
'd5:seg_duan<=7'b0010010;
'd6:seg_duan<=7'b0000010;
'd7:seg_duan<=7'b1111000;
'd8:seg_duan<=7'b0000000;
'd9:seg_duan<=7'b0010000;
default seg_duan<=7'b1000000;
endcase
end
endmodule
三、引脚和RTL视图
引脚配置图:
RTL视图:
四、效果
效果如图:
总结
本次实验让我学会了如何基于FPGA对超声波进行测距。了解了超声波测距的原理,并上手实践了。另外让我对相关软硬件的应用更加熟练,也学会了使用HC-SR04模块。