HC-SR04超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。图1为HC-SR04外观,其基本工作原理为给予此超声波测距模块一触发信号后模块发射超声波,当超声波投射到物体而反射回来时,模块输出一回响信号,以触发信号和回响信号间的时间差,来判定物体的距离。图2为模块时序图。
图1 HC-SR04超声波测距模块实物图
图2 HC-SR04超声波测距模块时序图
以上时序图表明只需要提供一个10uS 以上脉冲触发信号,该模块内部将发出8 个40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。
公式:uS/58=厘米或者uS/148=英寸;或是:距离=高电平时间*声速(340M/S)/2;建议测量周期为60ms 以上,以防止发射信号对回响信号的影响。于是基于FPGA的电路实现主要包括触发信号产生、回响信号计时两个模块。
图3 电路框图
通过此模块产生一个周期为1s的触发信号,10us高电平,999990us低电平
信号名 | 类型 | 信号描述 |
---|---|---|
clk_1m | Input | 1MHz时钟输入,一个上升沿1us |
rst | Input | 复位信号 |
trig | Output | 触发信号 |
模块代码:
module TrigSignal(clk_1m, rst, trig); //产生10us的触发信号
input clk_1m, rst;
output trig;
reg trig;
reg[19:0] count;
// 模1000 000计数器
always@(posedge clk_1m, negedge rst)
begin
if (~rst)
count <= 0;
else
begin
if (9 == count)
begin
trig <= 0;
count <= count + 1;
end
else
begin
if (1000000 == count)
begin
trig <= 1;
count <= 0;
end
else
count <= count + 1;
end
end
end
endmodule
通过此模块计算回响信号高电平持续的时间,单位us
信号名 | 类型 | 信号描述 |
---|---|---|
clk_1m | Input | 1MHz时钟输入,一个上升沿1us |
rst | Input | 复位信号 |
echo | Input | 回响信号 |
dis_count | Output | 高电平持续时间 |
模块代码:
module PosCounter(clk_1m, rst, echo, dis_count); // 检测回波高电平持续时间
input clk_1m, rst, echo;
output[19:0] dis_count;
parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10; // 状态定义 S0:闲置, S1:开始测距计数, S2:结束测距计数
reg[1:0] curr_state, next_state;
reg echo_reg1, echo_reg2;
assign start = echo_reg1&~echo_reg2; //检测posedge
assign finish = ~echo_reg1&echo_reg2; //检测negedge
reg[19:0] count, dis_reg;
wire[19:0] dis_count; //测距计数
always@(posedge clk_1m, negedge rst)
begin
if(~rst)
begin
echo_reg1 <= 0;
echo_reg2 <= 0;
count <= 0;
dis_reg <= 0;
curr_state <= S0;
end
else
begin
echo_reg1 <= echo; // 当前
echo_reg2 <= echo_reg1; // 后一个
case(curr_state)
S0:begin
if (start) // 检测到上升沿
curr_state <= next_state; //S1
else
count <= 0;
end
S1:begin
if (finish) // 检测到下降沿
curr_state <= next_state; //S2
else
begin
count <= count + 1;
end
end
S2:begin
dis_reg <= count; // 缓存计数结果
count <= 0;
curr_state <= next_state; //S0
end
endcase
end
end
always@(curr_state)
begin
case(curr_state)
S0:next_state <= S1;
S1:next_state <= S2;
S2:next_state <= S0;
endcase
end
assign dis_count = dis_reg * 100 / 58; // 距离,乘100取小数部分
endmodule
各模块之间的连接
信号名 | 类型 | 信号描述 |
---|---|---|
clk_50m | Input | 50MHz时钟输入 |
rst | Input | 复位信号 |
Trig | Output | 触发信号 |
Echo | Input | 回响信号 |
Led | Output | 距离小于10cm点亮LED |
Distance | Output | 距离 |
模块代码:
module sonic_detect(clk_50m, rst, Trig, Echo, Led, distance);
input clk_50m, rst, Echo;
output Trig, Led;
output[34:0] distance; // 5位十进制*7段译码
// Vcc--GPIO10
// Gnd--GPIO11
wire clk_1m;
wire[19:0] dis; // 回波高电平持续时间us
wire[19:0] d; // 距离(单位cm),5位十进制,包括两位小数
Clk_1M u0(.clk_out(clk_1m), .clk_in(clk_50m), .rst(1)); // 50分频
TrigSignal u1(.clk_1m(clk_1m), .rst(rst), .trig(Trig));
PosCounter u2(.clk_1m(clk_1m), .rst(rst), .echo(Echo), .dis_count(dis));
assign d[19:16] = dis/10000; // 百位
assign d[15:12] = dis/1000%10; // 十位
assign d[11:8] = dis/100%10; // 个位
assign d[7:4] = dis/10%10; // 0.1
assign d[3:0] = dis%10; // 0.01
assign Led =((d[19:16] < 1)&(d[15:12] < 1)) ? 1 : 0;
translator u3(.in(d[19:16]), .out(distance[34:28])); // 七段译码
translator u4(.in(d[15:12]), .out(distance[27:21]));
translator u5(.in(d[11:8]), .out(distance[20:14]));
translator u6(.in(d[7:4]), .out(distance[13:7]));
translator u7(.in(d[3:0]), .out(distance[6:0]));
endmodule